001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.xml.containerpage;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.formatters.CmsSettingConfiguration;
032import org.opencms.ade.configuration.plugins.CmsTemplatePlugin;
033import org.opencms.main.CmsLog;
034import org.opencms.main.OpenCms;
035import org.opencms.util.CmsMacroResolver;
036import org.opencms.util.CmsStringUtil;
037import org.opencms.util.CmsUUID;
038import org.opencms.xml.content.CmsXmlContentProperty;
039
040import java.util.ArrayList;
041import java.util.Collection;
042import java.util.Collections;
043import java.util.HashSet;
044import java.util.LinkedHashSet;
045import java.util.List;
046import java.util.Locale;
047import java.util.Map;
048import java.util.Optional;
049import java.util.Set;
050
051import org.apache.commons.lang3.StringUtils;
052import org.apache.commons.lang3.builder.ToStringBuilder;
053import org.apache.commons.logging.Log;
054
055import com.google.common.collect.ImmutableList;
056
057/**
058 * A bean containing formatter configuration data as strings.<p>
059 *
060 * @since 8.0.0
061 */
062public class CmsFormatterBean implements I_CmsFormatterBean, Cloneable {
063
064    /** Default rank for formatters from formatter configuration files. */
065    public static final int DEFAULT_CONFIGURATION_RANK = 1000;
066
067    /** Default rank for formatters defined in schema. */
068    public static final int DEFAULT_SCHEMA_RANK = 10000;
069
070    /** Default formatter type constant. */
071    public static final String PREVIEW_TYPE = "_PREVIEW_";
072
073    /** The width of the preview window for the formatters. */
074    public static final int PREVIEW_WIDTH = 640;
075
076    /** Wildcard formatter type for width based formatters. */
077    public static final String WILDCARD_TYPE = "*";
078
079    /** Logger instance for this class. */
080    private static final Log LOG = CmsLog.getLog(CmsFormatterBean.class);
081
082    /** The formatter container type. */
083    protected Set<String> m_containerTypes;
084
085    /** CSS Head includes. */
086    protected Set<String> m_cssHeadIncludes = new LinkedHashSet<String>();
087
088    /** The description text for the formatter. */
089    protected String m_description;
090
091    /** Set of alias keys. */
092    protected Set<String> m_aliasKeys = new HashSet<>();
093
094    /** Set of all formatter keys (main + alias keys). */
095    private Set<String> m_allKeys = new HashSet<>();
096
097    /** Provides the display type. If empty if this formatter should not be used by the display tag. */
098    protected String m_displayType;
099
100    /** The id for this formatter. */
101    protected String m_id;
102
103    /** Inline CSS snippets. */
104    protected String m_inlineCss;
105
106    /** Inline Javascript snippets. */
107    protected String m_inlineJavascript;
108
109    /** Is the formatter automatically enabled? */
110    protected boolean m_isAutoEnabled;
111
112    /** True if this formatter can be used for detail views. */
113    protected boolean m_isDetail;
114
115    /** Is the formatter from a formatter configuration file? */
116    protected boolean m_isFromFormatterConfigFile;
117
118    /** Indicates if this formatter is to be used as preview in the ADE gallery GUI. */
119    protected boolean m_isPreviewFormatter;
120
121    /** JavaScript head includes. */
122    protected List<String> m_javascriptHeadIncludes = new ArrayList<String>();
123
124    /** The formatter JSP. */
125    protected String m_jspRootPath;
126
127    /** The UUID of the JSP resource for this formatter. */
128    protected CmsUUID m_jspStructureId;
129
130    /** The formatter key. */
131    protected String m_key;
132
133    /** The location this formatter was configured in. */
134    protected String m_location;
135
136    /** If true, will match any container/width combination. */
137    protected boolean m_matchAll;
138
139    /** The formatter max width. */
140    protected int m_maxWidth;
141
142    /** The meta mappings. */
143    protected List<CmsMetaMapping> m_metaMappings;
144
145    /** The formatter min width. */
146    protected int m_minWidth;
147
148    /** Indicates whether nested formatter settings should be displayed. */
149    protected boolean m_nestedFormatterSettings;
150
151    /** The nice name. */
152    protected String m_niceName;
153
154    /** The referenced plugins. */
155    protected List<CmsTemplatePlugin> m_plugins = Collections.emptyList();
156
157    /** The rank. */
158    protected int m_rank;
159
160    /** The resource type name. */
161    protected Collection<String> m_resourceTypeNames;
162
163    /** Indicates if the content should be searchable in the online index when this formatter is used. */
164    protected boolean m_search;
165
166    /** Indicating if this formatter will always render all nested containers. */
167    protected boolean m_strictContainers;
168
169    /** Indicates whether meta mappings should be applied for all elements. */
170    protected boolean m_useMetaMappingsForNormalElements;
171
172    /** Map of attributes. */
173    private Map<String, String> m_attributes = Collections.emptyMap();
174
175    /** Flag indicating this formatter allows settings to be edited in the content editor. */
176    private boolean m_isAllowsSettingsInEditor;
177
178    /** The setting configuration. */
179    private CmsSettingConfiguration m_settingConfig;
180
181    /**
182     * Constructor for creating a new formatter configuration with resource structure id.<p>
183     *
184     * @param containerTypes the formatter container types
185     * @param jspRootPath the formatter JSP VFS root path
186     * @param jspStructureId the structure id of the formatter JSP
187     * @param key the formatter key
188     * @param aliasKeys the alias keys
189     * @param minWidth the formatter min width
190     * @param maxWidth the formatter max width
191     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
192     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
193     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
194     * @param cssHeadIncludes the CSS head includes
195     * @param inlineCss the in-line CSS
196     * @param javascriptHeadIncludes the JavaScript headincludes
197     * @param inlineJavascript the in-line JavaScript
198     * @param plugins the template plugins
199     * @param niceName the configuration display name
200     * @param description the description text for the formatter
201     * @param resourceTypeNames the resource type names
202     * @param rank the configuration rank
203     * @param id the configuration id
204     * @param settingConfig the settings configuration
205     * @param isFromConfigFile <code>true</code> if configuration file based
206     * @param isAutoEnabled <code>true</code> if auto enabled
207     * @param isDetail <code>true</code> if detail formatter
208     * @param displayType the display type
209     * @param isAllowsSettingsInEditor whether this formatter allows settings to be edited in the content editor
210     * @param strictContainers <code>true</code> if this formatter will always render all nested containers
211     * @param nestedFormatterSettings indicates whether nested formatter settings should be displayed
212     * @param metaMappings the meta mappings
213     * @param attributes the formatter attributes
214     * @param useMetaMappingsForNormalElements if true, meta mappings will be evaluated for normal container elements, not just detail elements
215     */
216    public CmsFormatterBean(
217        Set<String> containerTypes,
218        String jspRootPath,
219        CmsUUID jspStructureId,
220        String key,
221        Set<String> aliasKeys,
222        int minWidth,
223        int maxWidth,
224        boolean preview,
225        boolean searchContent,
226        String location,
227        List<String> cssHeadIncludes,
228        String inlineCss,
229        List<String> javascriptHeadIncludes,
230        String inlineJavascript,
231        List<CmsTemplatePlugin> plugins,
232        String niceName,
233        String description,
234        Collection<String> resourceTypeNames,
235        int rank,
236        String id,
237        CmsSettingConfiguration settingConfig,
238        boolean isFromConfigFile,
239        boolean isAutoEnabled,
240        boolean isDetail,
241        String displayType,
242        boolean isAllowsSettingsInEditor,
243        boolean strictContainers,
244        boolean nestedFormatterSettings,
245        List<CmsMetaMapping> metaMappings,
246        Map<String, String> attributes,
247        boolean useMetaMappingsForNormalElements) {
248
249        m_jspRootPath = jspRootPath;
250        m_jspStructureId = jspStructureId;
251        m_key = key;
252        if (m_key != null) {
253            m_key = m_key.trim();
254            m_allKeys.add(m_key);
255        }
256        if (aliasKeys != null) {
257            m_aliasKeys.addAll(aliasKeys);
258            m_allKeys.addAll(aliasKeys);
259        }
260
261        m_containerTypes = containerTypes;
262        m_minWidth = minWidth;
263        m_maxWidth = maxWidth;
264
265        m_isPreviewFormatter = preview;
266        m_search = searchContent;
267        m_location = location;
268        m_description = description;
269
270        m_id = id;
271        m_niceName = niceName;
272        m_resourceTypeNames = resourceTypeNames;
273        m_rank = rank;
274        m_inlineCss = inlineCss;
275        m_inlineJavascript = inlineJavascript;
276        m_javascriptHeadIncludes.addAll(javascriptHeadIncludes);
277        m_cssHeadIncludes.addAll(cssHeadIncludes);
278        m_plugins = new ArrayList<>(plugins);
279        m_settingConfig = settingConfig;
280        m_isFromFormatterConfigFile = isFromConfigFile;
281        m_isAutoEnabled = isAutoEnabled;
282        m_isDetail = isDetail;
283        m_displayType = displayType;
284        m_nestedFormatterSettings = nestedFormatterSettings;
285        m_strictContainers = strictContainers;
286        m_metaMappings = metaMappings;
287        m_useMetaMappingsForNormalElements = useMetaMappingsForNormalElements;
288        m_isAllowsSettingsInEditor = isAllowsSettingsInEditor;
289        m_attributes = attributes != null ? attributes : Collections.emptyMap();
290    }
291
292    /**
293     * Constructor for creating a new formatter configuration with resource structure id.<p>
294     *
295     * @param containerType the formatter container types
296     * @param rootPath the formatter JSP VFS root path
297     * @param structureId the structure id of the formatter JSP
298     * @param minWidth the formatter min width
299     * @param maxWidth the formatter max width
300     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
301     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
302     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
303     */
304    public CmsFormatterBean(
305        String containerType,
306        String rootPath,
307        CmsUUID structureId,
308        int minWidth,
309        int maxWidth,
310        boolean preview,
311        boolean searchContent,
312        String location) {
313
314        this(
315            isWildcardType(containerType) ? Collections.<String> emptySet() : Collections.singleton(containerType),
316            rootPath,
317            structureId,
318            null,
319            new HashSet<String>(),
320            minWidth,
321            maxWidth,
322            preview,
323            searchContent,
324            location,
325            Collections.<String> emptyList(),
326            "",
327            Collections.<String> emptyList(),
328            "",
329            new ArrayList<CmsTemplatePlugin>(),
330            null,
331            rootPath,
332            Collections.<String> emptySet(),
333            1000,
334            null,
335            new CmsSettingConfiguration(),
336            false,
337            false,
338            true,
339            null,
340            false,
341            false,
342            false,
343            null,
344            null,
345            false);
346
347    }
348
349    /**
350     * Constructor for creating a new formatter configuration without resource structure id.<p>
351     *
352     * @param containerType the formatter container type
353     * @param jspRootPath the formatter JSP VFS root path
354     * @param minWidthStr the formatter min width
355     * @param maxWidthStr the formatter max width
356     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
357     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
358     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
359     */
360    public CmsFormatterBean(
361        String containerType,
362        String jspRootPath,
363        String minWidthStr,
364        String maxWidthStr,
365        String preview,
366        String searchContent,
367        String location) {
368
369        m_jspRootPath = jspRootPath;
370        m_containerTypes = Collections.singleton(containerType);
371        if (isWildcardType(containerType)) {
372            m_containerTypes = Collections.emptySet();
373        }
374        m_minWidth = -1;
375        m_maxWidth = Integer.MAX_VALUE;
376
377        if (m_containerTypes.isEmpty()) {
378            // wildcard formatter; index by width
379            // if no width available, use -1
380
381            try {
382                m_minWidth = Integer.parseInt(minWidthStr);
383            } catch (NumberFormatException e) {
384                //ignore; width will be -1
385            }
386            try {
387                m_maxWidth = Integer.parseInt(maxWidthStr);
388            } catch (NumberFormatException e) {
389                //ignore; maxWidth will be max. integer
390            }
391        }
392
393        m_isPreviewFormatter = Boolean.valueOf(preview).booleanValue();
394
395        m_search = CmsStringUtil.isEmptyOrWhitespaceOnly(searchContent)
396        ? true
397        : Boolean.valueOf(searchContent).booleanValue();
398
399        m_location = location;
400        m_rank = DEFAULT_SCHEMA_RANK;
401    }
402
403    /**
404     * Constructor for creating a formatter bean which matches all container/width combinations.<p>
405     *
406     * @param jspRootPath the jsp root path
407     * @param jspStructureId the jsp structure id
408     * @param location the formatter location
409     * @param preview the preview formatter flag
410     */
411    CmsFormatterBean(String jspRootPath, CmsUUID jspStructureId, String location, boolean preview) {
412
413        this(
414            Collections.<String> emptySet(),
415            jspRootPath,
416            jspStructureId,
417            null,
418            new HashSet<String>(),
419            -1,
420            Integer.MAX_VALUE,
421            preview,
422            false,
423            location,
424            Collections.<String> emptyList(),
425            "",
426            Collections.<String> emptyList(),
427            "",
428            new ArrayList<>(),
429            null,
430            jspRootPath,
431            Collections.<String> emptySet(),
432            DEFAULT_SCHEMA_RANK,
433            null,
434            new CmsSettingConfiguration(),
435            false,
436            false,
437            true,
438            null,
439            false,
440            false,
441            false,
442            null,
443            Collections.emptyMap(),
444            false);
445        m_matchAll = true;
446    }
447
448    /**
449     * Checks if the given container type matches the ADE gallery preview type.<p>
450     *
451     * @param containerType the container type to check
452     *
453     * @return <code>true</code> if the given container type matches the ADE gallery preview type
454     */
455    public static boolean isPreviewType(String containerType) {
456
457        return PREVIEW_TYPE.equals(containerType);
458    }
459
460    /**
461     * Checks whether the container type is a wildcard.<p>
462     *
463     * @param containerType the container type
464     *
465     * @return true if the container type is a wildcard
466     */
467    private static boolean isWildcardType(String containerType) {
468
469        return CmsStringUtil.isEmptyOrWhitespaceOnly(containerType) || WILDCARD_TYPE.equals(containerType);
470    }
471
472    /**
473     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getAliasKeys()
474     */
475    public Set<String> getAliasKeys() {
476
477        return Collections.unmodifiableSet(m_aliasKeys);
478    }
479
480    /**
481     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getAllKeys()
482     */
483    public Set<String> getAllKeys() {
484
485        return Collections.unmodifiableSet(m_allKeys);
486    }
487
488    /**
489     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getAttributes()
490     */
491    public Map<String, String> getAttributes() {
492
493        return m_attributes;
494    }
495
496    /**
497     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getContainerTypes()
498     */
499    @Override
500    public Set<String> getContainerTypes() {
501
502        return m_containerTypes == null
503        ? Collections.<String> emptySet()
504        : Collections.unmodifiableSet(m_containerTypes);
505    }
506
507    /**
508     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getCssHeadIncludes()
509     */
510    @Override
511    public Set<String> getCssHeadIncludes() {
512
513        return Collections.unmodifiableSet(m_cssHeadIncludes);
514    }
515
516    /**
517     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getDescription(Locale)
518     */
519    public String getDescription(Locale locale) {
520
521        if (locale == null) {
522            return m_description;
523        }
524        CmsMacroResolver resolver = new CmsMacroResolver() {
525
526            @Override
527            public String getMacroValue(String macro) {
528
529                if (macro.startsWith(CmsMacroResolver.KEY_LOCALIZED_PREFIX)) {
530                    String keyName = macro.substring(CmsMacroResolver.KEY_LOCALIZED_PREFIX.length());
531                    return m_messages.keyWithParams(keyName, key -> "");
532                } else {
533                    return super.getMacroValue(macro);
534                }
535            }
536
537            @Override
538            public String resolveMacros(String input) {
539
540                return StringUtils.trimToNull(super.resolveMacros(input));
541            }
542
543        };
544        resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(locale));
545        return resolver.resolveMacros(m_description);
546    }
547
548    /**
549     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getDisplayType()
550     */
551    public String getDisplayType() {
552
553        return m_displayType;
554    }
555
556    /**
557     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getId()
558     */
559    @Override
560    public String getId() {
561
562        return m_id;
563    }
564
565    /**
566     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getInlineCss()
567     */
568    @Override
569    public String getInlineCss() {
570
571        return m_inlineCss;
572    }
573
574    /**
575     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getInlineJavascript()
576     */
577    @Override
578    public String getInlineJavascript() {
579
580        return m_inlineJavascript;
581    }
582
583    /**
584     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJavascriptHeadIncludes()
585     */
586    @Override
587    public List<String> getJavascriptHeadIncludes() {
588
589        return Collections.unmodifiableList(m_javascriptHeadIncludes);
590    }
591
592    /**
593     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJspRootPath()
594     */
595    @Override
596    public String getJspRootPath() {
597
598        return m_jspRootPath;
599    }
600
601    /**
602     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJspStructureId()
603     */
604    @Override
605    public CmsUUID getJspStructureId() {
606
607        return m_jspStructureId;
608    }
609
610    /**
611     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getKey()
612     */
613    public String getKey() {
614
615        return m_key;
616    }
617
618    /**
619     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getLocation()
620     */
621    @Override
622    public String getLocation() {
623
624        return m_location;
625    }
626
627    /**
628     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMaxWidth()
629     */
630    @Override
631    public int getMaxWidth() {
632
633        return m_maxWidth;
634    }
635
636    /**
637     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMetaMappings()
638     */
639    public List<CmsMetaMapping> getMetaMappings() {
640
641        return m_metaMappings;
642    }
643
644    /**
645     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMinWidth()
646     */
647    @Override
648    public int getMinWidth() {
649
650        return m_minWidth;
651    }
652
653    /**
654     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getNiceName(Locale)
655     */
656    @Override
657    public String getNiceName(Locale locale) {
658
659        if (locale == null) {
660            return m_niceName;
661        }
662        CmsMacroResolver resolver = new CmsMacroResolver();
663        resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(locale));
664        return resolver.resolveMacros(m_niceName);
665    }
666
667    /**
668     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getRank()
669     */
670    @Override
671    public int getRank() {
672
673        return m_rank;
674    }
675
676    /**
677     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getResourceTypeNames()
678     */
679    @Override
680    public Collection<String> getResourceTypeNames() {
681
682        return m_resourceTypeNames;
683    }
684
685    /**
686     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getSettings(org.opencms.ade.configuration.CmsADEConfigData)
687     */
688    @Override
689    public Map<String, CmsXmlContentProperty> getSettings(CmsADEConfigData config) {
690
691        ImmutableList<CmsUUID> sharedSettingOverrides = config.getSharedSettingOverrides();
692        return m_settingConfig.getSettings(sharedSettingOverrides);
693    }
694
695    /**
696     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getTemplatePlugins()
697     */
698    public List<CmsTemplatePlugin> getTemplatePlugins() {
699
700        return Collections.unmodifiableList(m_plugins);
701    }
702
703    /**
704     * @see java.lang.Object#hashCode()
705     */
706    @Override
707    public int hashCode() {
708
709        return getContainerTypes().hashCode() ^ ((m_minWidth * 33) ^ m_maxWidth);
710    }
711
712    /**
713     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#hasNestedFormatterSettings()
714     */
715    public boolean hasNestedFormatterSettings() {
716
717        return m_nestedFormatterSettings;
718    }
719
720    /**
721     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isAllowsSettingsInEditor()
722     */
723    public boolean isAllowsSettingsInEditor() {
724
725        return m_isAllowsSettingsInEditor;
726    }
727
728    /**
729     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isAutoEnabled()
730     */
731    @Override
732    public boolean isAutoEnabled() {
733
734        return m_isAutoEnabled;
735    }
736
737    /**
738     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isDetailFormatter()
739     */
740    public boolean isDetailFormatter() {
741
742        return m_isDetail;
743    }
744
745    /**
746     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isDisplayFormatter()
747     */
748    public boolean isDisplayFormatter() {
749
750        return m_displayType != null;
751    }
752
753    /**
754     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isFromFormatterConfigFile()
755     */
756    @Override
757    public boolean isFromFormatterConfigFile() {
758
759        return m_isFromFormatterConfigFile;
760    }
761
762    /**
763     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isMatchAll()
764     */
765    @Override
766    public boolean isMatchAll() {
767
768        return m_matchAll || ((m_containerTypes != null) && m_containerTypes.contains(WILDCARD_TYPE));
769    }
770
771    /**
772     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isPreviewFormatter()
773     */
774    @Override
775    public boolean isPreviewFormatter() {
776
777        return m_isPreviewFormatter;
778    }
779
780    /**
781     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isSearchContent()
782     */
783    @Override
784    public boolean isSearchContent() {
785
786        return m_search;
787    }
788
789    /**
790     * Returns whether this formatter will always render all nested containers.<p>
791     *
792     * @return <code>true</code> if this formatter will always render all nested containers
793     */
794    public boolean isStrictContainers() {
795
796        return m_strictContainers;
797    }
798
799    /**
800     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isTypeFormatter()
801     */
802    @Override
803    public boolean isTypeFormatter() {
804
805        return !getContainerTypes().isEmpty();
806    }
807
808    /**
809     * Sets the structure id of the JSP for this formatter.<p>
810     *
811     * This is "package visible" as it should be only called from {@link CmsFormatterConfiguration#initialize(org.opencms.file.CmsObject)}.<p>
812     *
813     * @param jspStructureId the structure id of the JSP for this formatter
814     */
815    public void setJspStructureId(CmsUUID jspStructureId) {
816
817        // package visibility is wanted
818        m_jspStructureId = jspStructureId;
819    }
820
821    /**
822     * @see java.lang.Object#toString()
823     */
824    @Override
825    public String toString() {
826
827        return ToStringBuilder.reflectionToString(this);
828    }
829
830    /**
831     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#useMetaMappingsForNormalElements()
832     */
833    @Override
834    public boolean useMetaMappingsForNormalElements() {
835
836        return m_useMetaMappingsForNormalElements;
837    }
838
839    /**
840     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#withKeys(java.util.Collection)
841     */
842    public Optional<I_CmsFormatterBean> withKeys(Collection<String> keys) {
843
844        if ((getKey() != null) && !getAllKeys().equals(keys)) {
845            Set<String> newAllKeys = new HashSet<>(keys);
846            newAllKeys.add(getKey());
847            Set<String> newAliases = new HashSet<>(keys);
848            newAliases.remove(getKey());
849            CmsFormatterBean clonedBean;
850            try {
851                clonedBean = (CmsFormatterBean)clone();
852                clonedBean.m_aliasKeys = newAliases;
853                clonedBean.m_allKeys = new HashSet<>(keys);
854                return Optional.of(clonedBean);
855
856            } catch (CloneNotSupportedException e) {
857                LOG.error(e.getLocalizedMessage(), e);
858                return Optional.empty();
859            }
860        }
861        return Optional.of(this);
862    }
863}