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.main.OpenCms;
031import org.opencms.util.CmsMacroResolver;
032import org.opencms.util.CmsStringUtil;
033import org.opencms.util.CmsUUID;
034import org.opencms.xml.content.CmsXmlContentProperty;
035
036import java.util.ArrayList;
037import java.util.Collection;
038import java.util.Collections;
039import java.util.LinkedHashMap;
040import java.util.LinkedHashSet;
041import java.util.List;
042import java.util.Locale;
043import java.util.Map;
044import java.util.Set;
045
046import org.apache.commons.lang3.builder.ToStringBuilder;
047
048/**
049 * A bean containing formatter configuration data as strings.<p>
050 *
051 * @since 8.0.0
052 */
053public class CmsFormatterBean implements I_CmsFormatterBean {
054
055    /** Default rank for formatters from formatter configuration files. */
056    public static final int DEFAULT_CONFIGURATION_RANK = 1000;
057
058    /** Default rank for formatters defined in schema. */
059    public static final int DEFAULT_SCHEMA_RANK = 10000;
060
061    /** Default formatter type constant. */
062    public static final String PREVIEW_TYPE = "_PREVIEW_";
063
064    /** The width of the preview window for the formatters. */
065    public static final int PREVIEW_WIDTH = 640;
066
067    /** Wildcard formatter type for width based formatters. */
068    public static final String WILDCARD_TYPE = "*";
069
070    /** The formatter container type. */
071    protected Set<String> m_containerTypes;
072
073    /** CSS Head includes. */
074    protected Set<String> m_cssHeadIncludes = new LinkedHashSet<String>();
075
076    /** The description text for the formatter. */
077    protected String m_description;
078
079    /** Provides the display type. If empty if this formatter should not be used by the display tag. */
080    protected String m_displayType;
081
082    /** The id for this formatter. */
083    protected String m_id;
084
085    /** Inline CSS snippets. */
086    protected String m_inlineCss;
087
088    /** Inline Javascript snippets. */
089    protected String m_inlineJavascript;
090
091    /** Is the formatter automatically enabled? */
092    protected boolean m_isAutoEnabled;
093
094    /** True if this formatter can be used for detail views. */
095    protected boolean m_isDetail;
096
097    /** Is the formatter from a formatter configuration file? */
098    protected boolean m_isFromFormatterConfigFile;
099
100    /** Indicates if this formatter is to be used as preview in the ADE gallery GUI. */
101    protected boolean m_isPreviewFormatter;
102
103    /** JavaScript head includes. */
104    protected List<String> m_javascriptHeadIncludes = new ArrayList<String>();
105
106    /** The formatter JSP. */
107    protected String m_jspRootPath;
108
109    /** The UUID of the JSP resource for this formatter. */
110    protected CmsUUID m_jspStructureId;
111
112    /** The location this formatter was configured in. */
113    protected String m_location;
114
115    /** If true, will match any container/width combination. */
116    protected boolean m_matchAll;
117
118    /** The formatter max width. */
119    protected int m_maxWidth;
120
121    /** The meta mappings. */
122    protected List<CmsMetaMapping> m_metaMappings;
123
124    /** The formatter min width. */
125    protected int m_minWidth;
126
127    /** Indicates whether nested formatter settings should be displayed. */
128    protected boolean m_nestedFormatterSettings;
129
130    /** The nice name. */
131    protected String m_niceName;
132
133    /** The rank. */
134    protected int m_rank;
135
136    /** The resource type name. */
137    protected Collection<String> m_resourceTypeNames;
138
139    /** Indicates if the content should be searchable in the online index when this formatter is used. */
140    protected boolean m_search;
141
142    /** The settings. */
143    protected Map<String, CmsXmlContentProperty> m_settings = new LinkedHashMap<String, CmsXmlContentProperty>();
144
145    /** Indicating if this formatter will always render all nested containers. */
146    protected boolean m_strictContainers;
147
148    /** Indicates whether meta mappings should be applied for all elements. */
149    protected boolean m_useMetaMappingsForNormalElements;
150
151    /** Flag indicating this formatter allows settings to be edited in the content editor. */
152    private boolean m_isAllowsSettingsInEditor;
153
154    /** Map of attributes. */
155    private Map<String, String> m_attributes = Collections.emptyMap();
156
157    /**
158     * Constructor for creating a new formatter configuration with resource structure id.<p>
159     *
160     * @param containerTypes the formatter container types
161     * @param jspRootPath the formatter JSP VFS root path
162     * @param jspStructureId the structure id of the formatter JSP
163     * @param minWidth the formatter min width
164     * @param maxWidth the formatter max width
165     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
166     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
167     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
168     * @param cssHeadIncludes the CSS head includes
169     * @param inlineCss the in-line CSS
170     * @param javascriptHeadIncludes the JavaScript headincludes
171     * @param inlineJavascript the in-line JavaScript
172     * @param niceName the configuration display name
173     * @param description the description text for the formatter
174     * @param resourceTypeNames the resource type names
175     * @param rank the configuration rank
176     * @param id the configuration id
177     * @param settings the settings configuration
178     * @param isFromConfigFile <code>true</code> if configuration file based
179     * @param isAutoEnabled <code>true</code> if auto enabled
180     * @param isDetail <code>true</code> if detail formatter
181     * @param displayType the display type
182     * @param isAllowsSettingsInEditor whether this formatter allows settings to be edited in the content editor
183     * @param strictContainers <code>true</code> if this formatter will always render all nested containers
184     * @param nestedFormatterSettings indicates whether nested formatter settings should be displayed
185     * @param metaMappings the meta mappings
186     * @param attributes the formatter attributes
187     * @param useMetaMappingsForNormalElements if true, meta mappings will be evaluated for normal container elements, not just detail elements
188     */
189    public CmsFormatterBean(
190        Set<String> containerTypes,
191        String jspRootPath,
192        CmsUUID jspStructureId,
193        int minWidth,
194        int maxWidth,
195        boolean preview,
196        boolean searchContent,
197        String location,
198        List<String> cssHeadIncludes,
199        String inlineCss,
200        List<String> javascriptHeadIncludes,
201        String inlineJavascript,
202        String niceName,
203        String description,
204        Collection<String> resourceTypeNames,
205        int rank,
206        String id,
207        Map<String, CmsXmlContentProperty> settings,
208        boolean isFromConfigFile,
209        boolean isAutoEnabled,
210        boolean isDetail,
211        String displayType,
212        boolean isAllowsSettingsInEditor,
213        boolean strictContainers,
214        boolean nestedFormatterSettings,
215        List<CmsMetaMapping> metaMappings,
216        Map<String, String> attributes,
217        boolean useMetaMappingsForNormalElements) {
218
219        m_jspRootPath = jspRootPath;
220        m_jspStructureId = jspStructureId;
221        m_containerTypes = containerTypes;
222        m_minWidth = minWidth;
223        m_maxWidth = maxWidth;
224
225        m_isPreviewFormatter = preview;
226        m_search = searchContent;
227        m_location = location;
228        m_description = description;
229
230        m_id = id;
231        m_niceName = niceName;
232        m_resourceTypeNames = resourceTypeNames;
233        m_rank = rank;
234        m_inlineCss = inlineCss;
235        m_inlineJavascript = inlineJavascript;
236        m_javascriptHeadIncludes.addAll(javascriptHeadIncludes);
237        m_cssHeadIncludes.addAll(cssHeadIncludes);
238        m_settings.putAll(settings);
239        m_isFromFormatterConfigFile = isFromConfigFile;
240        m_isAutoEnabled = isAutoEnabled;
241        m_isDetail = isDetail;
242        m_displayType = displayType;
243        m_nestedFormatterSettings = nestedFormatterSettings;
244        m_strictContainers = strictContainers;
245        m_metaMappings = metaMappings;
246        m_useMetaMappingsForNormalElements = useMetaMappingsForNormalElements;
247        m_isAllowsSettingsInEditor = isAllowsSettingsInEditor;
248        m_attributes = attributes != null ? attributes : Collections.emptyMap();
249    }
250
251    /**
252     * Constructor for creating a new formatter configuration with resource structure id.<p>
253     *
254     * @param containerType the formatter container types
255     * @param rootPath the formatter JSP VFS root path
256     * @param structureId the structure id of the formatter JSP
257     * @param minWidth the formatter min width
258     * @param maxWidth the formatter max width
259     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
260     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
261     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
262     */
263    public CmsFormatterBean(
264        String containerType,
265        String rootPath,
266        CmsUUID structureId,
267        int minWidth,
268        int maxWidth,
269        boolean preview,
270        boolean searchContent,
271        String location) {
272
273        this(
274            isWildcardType(containerType) ? Collections.<String> emptySet() : Collections.singleton(containerType),
275            rootPath,
276            structureId,
277            minWidth,
278            maxWidth,
279            preview,
280            searchContent,
281            location,
282            Collections.<String> emptyList(),
283            "",
284            Collections.<String> emptyList(),
285            "",
286            null,
287            rootPath,
288            Collections.<String> emptySet(),
289            1000,
290            null,
291            Collections.<String, CmsXmlContentProperty> emptyMap(),
292            false,
293            false,
294            true,
295            null,
296            false,
297            false,
298            false,
299            null,
300            null,
301            false);
302
303    }
304
305    /**
306     * Constructor for creating a new formatter configuration without resource structure id.<p>
307     *
308     * @param containerType the formatter container type
309     * @param jspRootPath the formatter JSP VFS root path
310     * @param minWidthStr the formatter min width
311     * @param maxWidthStr the formatter max width
312     * @param preview indicates if this formatter is to be used for the preview in the ADE gallery GUI
313     * @param searchContent indicates if the content should be searchable in the online index when this formatter is used
314     * @param location the location where this formatter was defined, should be an OpenCms VFS resource path
315     */
316    public CmsFormatterBean(
317        String containerType,
318        String jspRootPath,
319        String minWidthStr,
320        String maxWidthStr,
321        String preview,
322        String searchContent,
323        String location) {
324
325        m_jspRootPath = jspRootPath;
326        m_containerTypes = Collections.singleton(containerType);
327        if (isWildcardType(containerType)) {
328            m_containerTypes = Collections.emptySet();
329        }
330        m_minWidth = -1;
331        m_maxWidth = Integer.MAX_VALUE;
332
333        if (m_containerTypes.isEmpty()) {
334            // wildcard formatter; index by width
335            // if no width available, use -1
336
337            try {
338                m_minWidth = Integer.parseInt(minWidthStr);
339            } catch (NumberFormatException e) {
340                //ignore; width will be -1
341            }
342            try {
343                m_maxWidth = Integer.parseInt(maxWidthStr);
344            } catch (NumberFormatException e) {
345                //ignore; maxWidth will be max. integer
346            }
347        }
348
349        m_isPreviewFormatter = Boolean.valueOf(preview).booleanValue();
350
351        m_search = CmsStringUtil.isEmptyOrWhitespaceOnly(searchContent)
352        ? true
353        : Boolean.valueOf(searchContent).booleanValue();
354
355        m_location = location;
356        m_rank = DEFAULT_SCHEMA_RANK;
357    }
358
359    /**
360     * Constructor for creating a formatter bean which matches all container/width combinations.<p>
361     *
362     * @param jspRootPath the jsp root path
363     * @param jspStructureId the jsp structure id
364     * @param location the formatter location
365     * @param preview the preview formatter flag
366     */
367    CmsFormatterBean(String jspRootPath, CmsUUID jspStructureId, String location, boolean preview) {
368
369        this(
370            Collections.<String> emptySet(),
371            jspRootPath,
372            jspStructureId,
373            -1,
374            Integer.MAX_VALUE,
375            preview,
376            false,
377            location,
378            Collections.<String> emptyList(),
379            "",
380            Collections.<String> emptyList(),
381            "",
382            null,
383            jspRootPath,
384            Collections.<String> emptySet(),
385            DEFAULT_SCHEMA_RANK,
386            null,
387            Collections.<String, CmsXmlContentProperty> emptyMap(),
388            false,
389            false,
390            true,
391            null,
392            false,
393            false,
394            false,
395            null,
396            Collections.emptyMap(),
397            false);
398        m_matchAll = true;
399    }
400
401    /**
402     * Checks if the given container type matches the ADE gallery preview type.<p>
403     *
404     * @param containerType the container type to check
405     *
406     * @return <code>true</code> if the given container type matches the ADE gallery preview type
407     */
408    public static boolean isPreviewType(String containerType) {
409
410        return PREVIEW_TYPE.equals(containerType);
411    }
412
413    /**
414     * Checks whether the container type is a wildcard.<p>
415     *
416     * @param containerType the container type
417     *
418     * @return true if the container type is a wildcard
419     */
420    private static boolean isWildcardType(String containerType) {
421
422        return CmsStringUtil.isEmptyOrWhitespaceOnly(containerType) || WILDCARD_TYPE.equals(containerType);
423    }
424
425    /**
426     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getAttributes()
427     */
428    public Map<String, String> getAttributes() {
429
430        return m_attributes;
431    }
432
433    /**
434     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getContainerTypes()
435     */
436    @Override
437    public Set<String> getContainerTypes() {
438
439        return m_containerTypes == null
440        ? Collections.<String> emptySet()
441        : Collections.unmodifiableSet(m_containerTypes);
442    }
443
444    /**
445     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getCssHeadIncludes()
446     */
447    @Override
448    public Set<String> getCssHeadIncludes() {
449
450        return Collections.unmodifiableSet(m_cssHeadIncludes);
451    }
452
453    /**
454     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getDescription(Locale)
455     */
456    public String getDescription(Locale locale) {
457
458        if (locale == null) {
459            return m_description;
460        }
461        CmsMacroResolver resolver = new CmsMacroResolver();
462        resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(locale));
463        return resolver.resolveMacros(m_description);
464    }
465
466    /**
467     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getDisplayType()
468     */
469    public String getDisplayType() {
470
471        return m_displayType;
472    }
473
474    /**
475     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getId()
476     */
477    @Override
478    public String getId() {
479
480        return m_id;
481    }
482
483    /**
484     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getInlineCss()
485     */
486    @Override
487    public String getInlineCss() {
488
489        return m_inlineCss;
490    }
491
492    /**
493     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getInlineJavascript()
494     */
495    @Override
496    public String getInlineJavascript() {
497
498        return m_inlineJavascript;
499    }
500
501    /**
502     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJavascriptHeadIncludes()
503     */
504    @Override
505    public List<String> getJavascriptHeadIncludes() {
506
507        return Collections.unmodifiableList(m_javascriptHeadIncludes);
508    }
509
510    /**
511     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJspRootPath()
512     */
513    @Override
514    public String getJspRootPath() {
515
516        return m_jspRootPath;
517    }
518
519    /**
520     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getJspStructureId()
521     */
522    @Override
523    public CmsUUID getJspStructureId() {
524
525        return m_jspStructureId;
526    }
527
528    /**
529     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getLocation()
530     */
531    @Override
532    public String getLocation() {
533
534        return m_location;
535    }
536
537    /**
538     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMaxWidth()
539     */
540    @Override
541    public int getMaxWidth() {
542
543        return m_maxWidth;
544    }
545
546    /**
547     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMetaMappings()
548     */
549    public List<CmsMetaMapping> getMetaMappings() {
550
551        return m_metaMappings;
552    }
553
554    /**
555     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getMinWidth()
556     */
557    @Override
558    public int getMinWidth() {
559
560        return m_minWidth;
561    }
562
563    /**
564     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getNiceName(Locale)
565     */
566    @Override
567    public String getNiceName(Locale locale) {
568
569        if (locale == null) {
570            return m_niceName;
571        }
572        CmsMacroResolver resolver = new CmsMacroResolver();
573        resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(locale));
574        return resolver.resolveMacros(m_niceName);
575    }
576
577    /**
578     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getRank()
579     */
580    @Override
581    public int getRank() {
582
583        return m_rank;
584    }
585
586    /**
587     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getResourceTypeNames()
588     */
589    @Override
590    public Collection<String> getResourceTypeNames() {
591
592        return m_resourceTypeNames;
593    }
594
595    /**
596     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#getSettings()
597     */
598    @Override
599    public Map<String, CmsXmlContentProperty> getSettings() {
600
601        return Collections.unmodifiableMap(m_settings);
602    }
603
604    /**
605     * @see java.lang.Object#hashCode()
606     */
607    @Override
608    public int hashCode() {
609
610        return getContainerTypes().hashCode() ^ ((m_minWidth * 33) ^ m_maxWidth);
611    }
612
613    /**
614     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#hasNestedFormatterSettings()
615     */
616    public boolean hasNestedFormatterSettings() {
617
618        return m_nestedFormatterSettings;
619    }
620
621    /**
622     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isAllowsSettingsInEditor()
623     */
624    public boolean isAllowsSettingsInEditor() {
625
626        return m_isAllowsSettingsInEditor;
627    }
628
629    /**
630     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isAutoEnabled()
631     */
632    @Override
633    public boolean isAutoEnabled() {
634
635        return m_isAutoEnabled;
636    }
637
638    /**
639     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isDetailFormatter()
640     */
641    public boolean isDetailFormatter() {
642
643        return m_isDetail;
644    }
645
646    /**
647     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isDisplayFormatter()
648     */
649    public boolean isDisplayFormatter() {
650
651        return m_displayType != null;
652    }
653
654    /**
655     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isFromFormatterConfigFile()
656     */
657    @Override
658    public boolean isFromFormatterConfigFile() {
659
660        return m_isFromFormatterConfigFile;
661    }
662
663    /**
664     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isMatchAll()
665     */
666    @Override
667    public boolean isMatchAll() {
668
669        return m_matchAll || ((m_containerTypes != null) && m_containerTypes.contains(WILDCARD_TYPE));
670    }
671
672    /**
673     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isPreviewFormatter()
674     */
675    @Override
676    public boolean isPreviewFormatter() {
677
678        return m_isPreviewFormatter;
679    }
680
681    /**
682     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isSearchContent()
683     */
684    @Override
685    public boolean isSearchContent() {
686
687        return m_search;
688    }
689
690    /**
691     * Returns whether this formatter will always render all nested containers.<p>
692     *
693     * @return <code>true</code> if this formatter will always render all nested containers
694     */
695    public boolean isStrictContainers() {
696
697        return m_strictContainers;
698    }
699
700    /**
701     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#isTypeFormatter()
702     */
703    @Override
704    public boolean isTypeFormatter() {
705
706        return !getContainerTypes().isEmpty();
707    }
708
709    /**
710     * Sets the structure id of the JSP for this formatter.<p>
711     *
712     * This is "package visible" as it should be only called from {@link CmsFormatterConfiguration#initialize(org.opencms.file.CmsObject)}.<p>
713     *
714     * @param jspStructureId the structure id of the JSP for this formatter
715     */
716    public void setJspStructureId(CmsUUID jspStructureId) {
717
718        // package visibility is wanted
719        m_jspStructureId = jspStructureId;
720    }
721
722    /**
723     * @see java.lang.Object#toString()
724     */
725    @Override
726    public String toString() {
727
728        return ToStringBuilder.reflectionToString(this);
729    }
730
731    /**
732     * @see org.opencms.xml.containerpage.I_CmsFormatterBean#useMetaMappingsForNormalElements()
733     */
734    @Override
735    public boolean useMetaMappingsForNormalElements() {
736
737        return m_useMetaMappingsForNormalElements;
738    }
739}