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.jsp;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.containerpage.CmsElementUtil;
032import org.opencms.ade.containerpage.shared.CmsContainerElement;
033import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
034import org.opencms.file.CmsObject;
035import org.opencms.file.CmsResource;
036import org.opencms.file.CmsResourceFilter;
037import org.opencms.file.collectors.I_CmsCollectorPostCreateHandler;
038import org.opencms.flex.CmsFlexController;
039import org.opencms.jsp.util.CmsJspContentAccessValueWrapper;
040import org.opencms.jsp.util.CmsJspStandardContextBean;
041import org.opencms.loader.CmsJspLoader;
042import org.opencms.main.CmsException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.util.CmsRequestUtil;
046import org.opencms.util.CmsStringUtil;
047import org.opencms.util.CmsUUID;
048import org.opencms.workplace.editors.directedit.CmsAdvancedDirectEditProvider;
049import org.opencms.workplace.editors.directedit.CmsDirectEditMode;
050import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider;
051import org.opencms.xml.containerpage.CmsADESessionCache;
052import org.opencms.xml.containerpage.CmsContainerElementBean;
053import org.opencms.xml.containerpage.CmsFormatterConfiguration;
054import org.opencms.xml.containerpage.I_CmsFormatterBean;
055import org.opencms.xml.types.CmsXmlDisplayFormatterValue;
056import org.opencms.xml.types.I_CmsXmlContentValue;
057
058import java.util.HashMap;
059import java.util.LinkedHashMap;
060import java.util.List;
061import java.util.Locale;
062import java.util.Map;
063import java.util.Map.Entry;
064import java.util.stream.Collectors;
065
066import javax.servlet.ServletRequest;
067import javax.servlet.ServletResponse;
068import javax.servlet.http.HttpServletRequest;
069import javax.servlet.jsp.JspException;
070import javax.servlet.jsp.PageContext;
071import javax.servlet.jsp.tagext.BodyTagSupport;
072
073import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
074import org.apache.commons.logging.Log;
075
076/**
077 * The 'display' tag can be used to display a single resource using a formatter. It also allows to activate direct editing.<p>
078 */
079public class CmsJspTagDisplay extends BodyTagSupport implements I_CmsJspTagParamParent {
080
081    /** Setting used to store the display formatter key. */
082    public static final String DISPLAY_FORMATTER_SETTING = "SYSTEM::DISPLAY_FORMATTER";
083
084    /** The log object for this class. */
085    private static final Log LOG = CmsLog.getLog(CmsJspTagDisplay.class);
086
087    /** The serial version id. */
088    private static final long serialVersionUID = 2285680951218629093L;
089
090    /** The base URI. */
091    private String m_baseUri;
092
093    /** True if the display formatter include should go through the flex cache. */
094    private Boolean m_cacheable;
095
096    /** Flag, indicating if the create option should be displayed. */
097    private boolean m_canCreate;
098
099    /** Flag, indicating if the delete option should be displayed. */
100    private boolean m_canDelete;
101
102    /** The container type used to select a formatter. */
103    private String m_containerType;
104
105    /** The tag attribute's value, specifying the path to the (sub)sitemap where new content should be created. */
106    private String m_creationSiteMap;
107
108    /** The display formatter ids. */
109    private Map<String, String> m_displayFormatterIds;
110
111    /** The display formatter paths. */
112    private Map<String, String> m_displayFormatterPaths;
113
114    /** The editable flag. */
115    private boolean m_editable;
116
117    /** The settings parameter map. */
118    private Map<String, String> m_parameterMap;
119
120    /** The pass settings flag. */
121    private boolean m_passSettings;
122
123    /** The fully qualified class name of the post create handler to use. */
124    private String m_postCreateHandler;
125
126    /** The element settings to be used. */
127    private Map<String, String> m_settings;
128
129    /** The upload folder. */
130    private String m_uploadFolder;
131
132    /** The site path to the resource to display. */
133    private String m_value;
134
135    /**
136     * Constructor.<p>
137     */
138    public CmsJspTagDisplay() {
139
140        m_parameterMap = new LinkedHashMap<>();
141        m_displayFormatterPaths = new HashMap<>();
142        m_displayFormatterIds = new HashMap<>();
143    }
144
145    /**
146     * Includes the formatter rendering the given element.<p>
147     *
148     * @param element the element
149     * @param formatter the formatter configuration bean
150     * @param cacheable true if the flex cache should be used for calling the display formatter
151     * @param editable if editable
152     * @param canCreate if new resources may be created
153     * @param canDelete if the resource may be deleted
154     * @param creationSiteMap the create location sub site
155     * @param postCreateHandler the post create handler
156     * @param uploadFolder the upload folder to use
157     * @param context the page context
158     * @param request the request
159     * @param response the response
160     */
161    public static void displayAction(
162        CmsContainerElementBean element,
163        I_CmsFormatterBean formatter,
164        boolean cacheable,
165        boolean editable,
166        boolean canCreate,
167        boolean canDelete,
168        String creationSiteMap,
169        String postCreateHandler,
170        String uploadFolder,
171        PageContext context,
172        ServletRequest request,
173        ServletResponse response) {
174
175        if (CmsFlexController.isCmsRequest(request)) {
176            // this will always be true if the page is called through OpenCms
177            CmsObject cms = CmsFlexController.getCmsObject(request);
178            CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache(
179                cms,
180                cms.getRequestContext().getRootUri());
181            Locale locale = cms.getRequestContext().getLocale();
182            boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
183            CmsJspStandardContextBean contextBean = CmsJspStandardContextBean.getInstance(request);
184            CmsContainerElementBean parentElement = contextBean.getRawElement();
185
186            try {
187                if (formatter != null) {
188                    element.initResource(cms);
189                    element.initSettings(cms, adeConfig, formatter, locale, request, null);
190                    element.getSettings().put(DISPLAY_FORMATTER_SETTING, formatter.getKeyOrId());
191                    boolean openedEditable = false;
192                    contextBean.setElement(element);
193                    if (editable && contextBean.getIsEditMode()) {
194                        if (CmsJspTagEditable.getDirectEditProvider(context) == null) {
195                            I_CmsDirectEditProvider eb = new CmsAdvancedDirectEditProvider();
196                            eb.init(cms, CmsDirectEditMode.TRUE, element.getSitePath());
197                            request.setAttribute(I_CmsDirectEditProvider.ATTRIBUTE_DIRECT_EDIT_PROVIDER, eb);
198                        }
199
200                        openedEditable = CmsJspTagEdit.insertDirectEditStart(
201                            cms,
202                            context,
203                            element.getResource(),
204                            canCreate,
205                            canDelete,
206                            null,
207                            creationSiteMap,
208                            postCreateHandler,
209                            uploadFolder);
210                    }
211                    if (contextBean.getIsEditMode()) {
212                        CmsADESessionCache.getCache(
213                            (HttpServletRequest)(context.getRequest()),
214                            cms).setCacheContainerElement(element.editorHash(), element);
215                    }
216                    try {
217                        CmsJspTagInclude.includeTagAction(
218                            context,
219                            cms.getRequestContext().removeSiteRoot(formatter.getJspRootPath()),
220                            null,
221                            locale,
222                            false,
223                            isOnline && cacheable,
224                            CmsRequestUtil.createParameterMap(element.getSettings()),
225                            CmsRequestUtil.getAtrributeMap(request),
226                            request,
227                            response);
228                    } catch (Exception e) {
229                        if (CmsJspLoader.isJasperCompilerException(e)) {
230                            LOG.error(e.getLocalizedMessage());
231                        } else {
232                            LOG.error(e.getLocalizedMessage(), e);
233                        }
234                    }
235                    if (openedEditable) {
236                        CmsJspTagEdit.insertDirectEditEnd(context);
237                    }
238                }
239            } catch (CmsException e) {
240                LOG.error(e.getLocalizedMessage(), e);
241            }
242            contextBean.setElement(parentElement);
243        }
244
245    }
246
247    /**
248     * Includes the formatter rendering the given element.<p>
249     *
250     * @param element the element
251     * @param formatter the formatter configuration bean
252     * @param context the page context
253     * @param request the request
254     * @param response the response
255     */
256    public static void displayAction(
257        CmsContainerElementBean element,
258        I_CmsFormatterBean formatter,
259        PageContext context,
260        ServletRequest request,
261        ServletResponse response) {
262
263        displayAction(element, formatter, true, false, false, false, null, null, null, context, request, response);
264    }
265
266    /**
267     * Includes the formatter rendering the given element.<p>
268     *
269     * @param elementResource the element resource
270     * @param formatter the formatter configuration bean
271     * @param settings the element settings
272     * @param cacheable true if the flex cache should be used for calling the display formatter
273     * @param editable if editable
274     * @param canCreate if new resources may be created
275     * @param canDelete if the resource may be deleted
276     * @param creationSiteMap the create location sub site
277     * @param postCreateHandler the post create handler
278     * @param uploadFolder the upload folder
279     * @param context the page context
280     * @param request the request
281     * @param response the response
282     */
283    public static void displayAction(
284        CmsResource elementResource,
285        I_CmsFormatterBean formatter,
286        Map<String, String> settings,
287        boolean cacheable,
288        boolean editable,
289        boolean canCreate,
290        boolean canDelete,
291        String creationSiteMap,
292        String postCreateHandler,
293        String uploadFolder,
294        PageContext context,
295        ServletRequest request,
296        ServletResponse response) {
297
298        CmsContainerElementBean element = new CmsContainerElementBean(
299            elementResource.getStructureId(),
300            formatter.getJspStructureId(),
301            settings,
302            false);
303        displayAction(
304            element,
305            formatter,
306            cacheable,
307            editable,
308            canCreate,
309            canDelete,
310            creationSiteMap,
311            postCreateHandler,
312            uploadFolder,
313            context,
314            request,
315            response);
316    }
317
318    /**
319     * If the setting key starts with the key or id of the given formatter, returns the remaining suffix, else null.
320     *
321     * @param config the current sitemap configuration
322     * @param formatter the formatter bean
323     * @param settingKey the setting key
324     *
325     * @return the remaining setting name suffix
326     */
327    public static String getSettingKeyForMatchingFormatterPrefix(
328        CmsADEConfigData config,
329        I_CmsFormatterBean formatter,
330        String settingKey) {
331
332        if (CmsElementUtil.isSystemSetting(settingKey)) {
333            return null;
334        }
335
336        int underscoreIndex = settingKey.indexOf("_");
337        if (underscoreIndex < 0) {
338            return null;
339        }
340        String prefix = settingKey.substring(0, underscoreIndex);
341        String suffix = settingKey.substring(underscoreIndex + 1);
342        I_CmsFormatterBean dynamicFmt = config.findFormatter(prefix, /*noWarn=*/true);
343        if (dynamicFmt == null) {
344            return null;
345        }
346        boolean keyMatch = (dynamicFmt.getKey() != null) && dynamicFmt.getKey().equals(formatter.getKey());
347        boolean idMatch = (dynamicFmt.getId() != null) && dynamicFmt.getId().equals(formatter.getId());
348        if (!keyMatch && !idMatch) {
349            return null;
350        }
351        if (!dynamicFmt.getSettings(config).containsKey(suffix)) {
352            return null;
353        }
354        return suffix;
355    }
356
357    /**
358     * Adds a display formatter.<p>
359     *
360     * @param type the resource type
361     * @param path the path to the formatter configuration file.<p>
362     */
363    public void addDisplayFormatter(String type, String path) {
364
365        m_displayFormatterPaths.put(type, path);
366    }
367
368    /**
369     * Adds a display formatter key for a type.
370     *
371     * @param type the resource type
372     * @param key the display formatter key
373     */
374    public void addDisplayFormatterKey(String type, String key) {
375
376        m_displayFormatterIds.put(type, key);
377    }
378
379    /**
380     * @see org.opencms.jsp.I_CmsJspTagParamParent#addParameter(java.lang.String, java.lang.String)
381     */
382    public void addParameter(String name, String value) {
383
384        // No null values allowed in parameters
385        if ((name == null) || (value == null)) {
386            return;
387        }
388
389        m_parameterMap.put(name, value);
390    }
391
392    /**
393     * @see javax.servlet.jsp.tagext.BodyTagSupport#doEndTag()
394     */
395    @Override
396    public int doEndTag() throws JspException {
397
398        ServletRequest request = pageContext.getRequest();
399        ServletResponse response = pageContext.getResponse();
400        if (CmsFlexController.isCmsRequest(request)) {
401            // this will always be true if the page is called through OpenCms
402            CmsObject cms = CmsFlexController.getCmsObject(request);
403            try {
404                boolean isOnline = cms.getRequestContext().getCurrentProject().isOnlineProject();
405                CmsResource res = null;
406                if (CmsUUID.isValidUUID(m_value)) {
407                    CmsUUID structureId = new CmsUUID(m_value);
408                    res = isOnline
409                    ? cms.readResource(structureId)
410                    : cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
411                } else {
412                    res = isOnline
413                    ? cms.readResource(m_value)
414                    : cms.readResource(m_value, CmsResourceFilter.IGNORE_EXPIRATION);
415                }
416
417                CmsObject cmsForFormatterLookup = cms;
418                if (!CmsStringUtil.isEmptyOrWhitespaceOnly(m_baseUri)) {
419                    cmsForFormatterLookup = OpenCms.initCmsObject(cms);
420                    cmsForFormatterLookup.getRequestContext().setUri(m_baseUri);
421                }
422                I_CmsFormatterBean formatter = getFormatterForType(cmsForFormatterLookup, res, isOnline);
423                CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(
424                    cmsForFormatterLookup,
425                    cms.getRequestContext().getRootUri());
426                if (formatter == null) {
427                    String error = "cms:display - could not find display formatter for " + m_value + "\n";
428                    try {
429                        error += "\n\nTag instance: " + ReflectionToStringBuilder.toString(this);
430                    } catch (Exception e) {
431                        // ignore
432                    }
433                    throw new JspException(error);
434                }
435
436                Map<String, String> settings = prepareSettings(config, formatter);
437
438                displayAction(
439                    res,
440                    formatter,
441                    settings,
442                    isCacheable(),
443                    m_editable,
444                    m_canCreate,
445                    m_canDelete,
446                    m_creationSiteMap,
447                    m_postCreateHandler,
448                    m_uploadFolder,
449                    pageContext,
450                    request,
451                    response);
452            } catch (CmsException e) {
453                LOG.error(e.getLocalizedMessage(), e);
454            }
455        }
456        release();
457        return EVAL_PAGE;
458    }
459
460    /**
461     * @see javax.servlet.jsp.tagext.BodyTagSupport#doStartTag()
462     */
463    @Override
464    public int doStartTag() {
465
466        if (Boolean.valueOf(m_passSettings).booleanValue()) {
467            CmsContainerElementBean element = CmsJspStandardContextBean.getInstance(
468                pageContext.getRequest()).getElement();
469            if (element != null) {
470                m_parameterMap.putAll(element.getSettings());
471            }
472        }
473        if (m_settings != null) {
474            m_parameterMap.putAll(m_settings);
475        }
476
477        return EVAL_BODY_BUFFERED;
478    }
479
480    /**
481     * Returns the editable.<p>
482     *
483     * @return the editable
484     */
485    public boolean getEditable() {
486
487        return m_editable;
488    }
489
490    /**
491     * Returns the passSettings.<p>
492     *
493     * @return the passSettings
494     */
495    public boolean getPassSettings() {
496
497        return m_passSettings;
498    }
499
500    /**
501     * Returns the element settings to be used.<p>
502     *
503     * @return the element settings to be used
504     */
505    public Map<String, String> getSettings() {
506
507        return m_settings;
508    }
509
510    /**
511     * Returns the value.<p>
512     *
513     * @return the value
514     */
515    public String getValue() {
516
517        return m_value;
518    }
519
520    /**
521     * @see javax.servlet.jsp.tagext.BodyTagSupport#release()
522     */
523    @Override
524    public void release() {
525
526        super.release();
527        m_parameterMap.clear();
528        m_displayFormatterPaths.clear();
529        m_displayFormatterIds.clear();
530        m_settings = null;
531        m_passSettings = false;
532        m_editable = false;
533        m_value = null;
534    }
535
536    /**
537     * Sets the base URI to use for finding the 'default' display formatter.
538     *
539     * @param uri the base URI
540     */
541    public void setBaseUri(String uri) {
542
543        m_baseUri = uri;
544    }
545
546    /**
547     * Enables/disables the use of the flex cache for the display formatter include.
548     *
549     * @param cacheable true if the flex cache should be used for the display formatter include
550     */
551    public void setCacheable(boolean cacheable) {
552
553        m_cacheable = Boolean.valueOf(cacheable);
554    }
555
556    /**
557     * Sets the container type used to select a formatter.
558     *
559     * @param containerType the container type
560     */
561    public void setContainerType(String containerType) {
562
563        m_containerType = containerType;
564    }
565
566    /** Setter for the "create" attribute of the tag.
567     * @param canCreate value of the tag's attribute "create".
568     */
569    public void setCreate(boolean canCreate) {
570
571        m_canCreate = canCreate;
572    }
573
574    /** Setter for the "create" attribute of the tag.
575     * @param canCreate value of the tag's attribute "create".
576     */
577    public void setCreate(String canCreate) {
578
579        m_canCreate = Boolean.valueOf(canCreate).booleanValue();
580    }
581
582    /** Setter for the "creationSiteMap" attribute of the tag.
583     * @param sitePath value of the "creationSiteMap" attribute of the tag.
584     */
585    public void setCreationSiteMap(String sitePath) {
586
587        m_creationSiteMap = sitePath;
588    }
589
590    /**Setter for the "delete" attribute of the tag.
591     * @param canDelete value of the "delete" attribute of the tag.
592     */
593    public void setDelete(boolean canDelete) {
594
595        m_canDelete = canDelete;
596    }
597
598    /**Setter for the "delete" attribute of the tag.
599     * @param canDelete value of the "delete" attribute of the tag.
600     */
601    public void setDelete(String canDelete) {
602
603        m_canDelete = Boolean.valueOf(canDelete).booleanValue();
604    }
605
606    /**
607     * Sets the items.<p>
608     *
609     * @param displayFormatters the items to set
610     */
611    public void setDisplayFormatters(Object displayFormatters) {
612
613        if (displayFormatters instanceof List) {
614            for (Object formatterItem : ((List<?>)displayFormatters)) {
615                if (formatterItem instanceof CmsJspContentAccessValueWrapper) {
616                    addFormatter((CmsJspContentAccessValueWrapper)formatterItem);
617                }
618            }
619        } else if (displayFormatters instanceof CmsJspContentAccessValueWrapper) {
620            addFormatter((CmsJspContentAccessValueWrapper)displayFormatters);
621        } else if (displayFormatters instanceof String) {
622            String[] temp = ((String)displayFormatters).split(CmsXmlDisplayFormatterValue.SEPARATOR);
623            if (temp.length == 2) {
624                addDisplayFormatter(temp[0], temp[1]);
625            }
626        }
627    }
628
629    /**
630     * Sets the editable.<p>
631     *
632     * @param editable the editable to set
633     */
634    public void setEditable(boolean editable) {
635
636        m_editable = editable;
637    }
638
639    /**
640     * Sets the editable.<p>
641     *
642     * @param editable the editable to set
643     */
644    public void setEditable(String editable) {
645
646        m_editable = Boolean.valueOf(editable).booleanValue();
647    }
648
649    /**
650     * Sets the passSettings.<p>
651     *
652     * @param passSettings the passSettings to set
653     */
654    public void setPassSettings(boolean passSettings) {
655
656        m_passSettings = passSettings;
657    }
658
659    /**
660     * Sets the passSettings.<p>
661     *
662     * @param passSettings the passSettings to set
663     */
664    public void setPassSettings(String passSettings) {
665
666        m_passSettings = Boolean.valueOf(passSettings).booleanValue();
667    }
668
669    /** Setter for the "postCreateHandler" attribute of the tag.
670     * @param postCreateHandler fully qualified class name of the {@link I_CmsCollectorPostCreateHandler} to use.
671     */
672    public void setPostCreateHandler(final String postCreateHandler) {
673
674        m_postCreateHandler = postCreateHandler;
675    }
676
677    /**
678     * Sets the element settings to be used.<p>
679     *
680     * @param settings the element settings to be used
681     */
682    public void setSettings(Map<String, String> settings) {
683
684        m_settings = settings;
685    }
686
687    /**
688     * Sets the upload folder.
689     *
690     * @param uploadFolder the upload folder
691     */
692    public void setUploadFolder(String uploadFolder) {
693
694        m_uploadFolder = uploadFolder;
695    }
696
697    /**
698     * Sets the value.<p>
699     *
700     * @param value the value to set
701     */
702    public void setValue(String value) {
703
704        m_value = value;
705    }
706
707    /**
708     * Adds a formatter.<p>
709     *
710     * @param formatterItem the formatter value
711     */
712    private void addFormatter(CmsJspContentAccessValueWrapper formatterItem) {
713
714        I_CmsXmlContentValue val = formatterItem.getContentValue();
715        if (val instanceof CmsXmlDisplayFormatterValue) {
716            CmsXmlDisplayFormatterValue value = (CmsXmlDisplayFormatterValue)val;
717            String type = value.getDisplayType();
718            String formatterId = value.getFormatterId();
719            if (formatterId != null) {
720                m_displayFormatterIds.put(type, formatterId);
721            }
722        }
723    }
724
725    /**
726     * Returns the config for the requested resource, or <code>null</code> if not available.<p>
727     *
728     * @param cms the cms context
729     * @param resource the resource
730     * @param isOnline the is online flag
731     *
732     * @return the formatter configuration bean
733     */
734    private I_CmsFormatterBean getFormatterForType(CmsObject cms, CmsResource resource, boolean isOnline) {
735
736        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
737        CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(
738            cms,
739            cms.getRequestContext().getRootUri());
740        I_CmsFormatterBean result = null;
741        if (m_displayFormatterPaths.containsKey(typeName)) {
742            try {
743                CmsResource res = cms.readResource(m_displayFormatterPaths.get(typeName));
744                result = OpenCms.getADEManager().getCachedFormatters(isOnline).getFormatters().get(
745                    res.getStructureId());
746            } catch (CmsException e) {
747                LOG.error(e.getLocalizedMessage(), e);
748            }
749        } else if (m_displayFormatterIds.containsKey(typeName)) {
750            result = config.findFormatter(m_displayFormatterIds.get(typeName));
751        } else {
752            if (config != null) {
753                if (m_containerType != null) {
754                    result = config.getActiveFormattersWithContainerType(m_containerType).stream().filter(
755                        formatter -> formatter.getResourceTypeNames().contains(typeName)).collect(
756                            Collectors.maxBy((a, b) -> Integer.compare(a.getRank(), b.getRank()))).orElse(null);
757                }
758                if (result == null) {
759                    CmsFormatterConfiguration formatters = config.getFormatters(cms, resource);
760                    if (formatters != null) {
761                        result = formatters.getDisplayFormatter();
762                    }
763                }
764            }
765        }
766        return result;
767    }
768
769    /**
770     * Checks if this tag instance should use the flex cache for including the formatter.
771     *
772     * @return true if this tag instance should use the flex cache for including the formatter
773     */
774    private boolean isCacheable() {
775
776        return (m_cacheable == null) || m_cacheable.booleanValue();
777    }
778
779    /**
780     * Prepares the settings before the call to displayAction().
781     *
782     * @param config the sitemap configuration
783     * @param formatter the display formatter
784     *
785     * @return the settings to use
786     */
787    private Map<String, String> prepareSettings(CmsADEConfigData config, I_CmsFormatterBean formatter) {
788
789        Map<String, String> settings = new HashMap<String, String>();
790        for (Entry<String, String> entry : m_parameterMap.entrySet()) {
791            if (CmsContainerElement.ELEMENT_INSTANCE_ID.equals(entry.getKey())) {
792                // remove any instance id to make sure to generate a unique one
793                continue;
794            }
795            String fmtSetting = getSettingKeyForMatchingFormatterPrefix(config, formatter, entry.getKey());
796            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
797                settings.put(entry.getKey(), formatter.getId());
798            } else if (fmtSetting != null) {
799                settings.put(fmtSetting, entry.getValue());
800            } else if (!settings.containsKey(entry.getKey())) {
801                settings.put(entry.getKey(), entry.getValue());
802            }
803        }
804        return settings;
805    }
806}