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