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.jsp.util;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsADEManager;
032import org.opencms.ade.configuration.CmsFunctionReference;
033import org.opencms.ade.containerpage.CmsContainerpageService;
034import org.opencms.ade.containerpage.CmsModelGroupHelper;
035import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
036import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
037import org.opencms.ade.detailpage.CmsDetailPageInfo;
038import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
039import org.opencms.file.CmsFile;
040import org.opencms.file.CmsObject;
041import org.opencms.file.CmsPropertyDefinition;
042import org.opencms.file.CmsRequestContext;
043import org.opencms.file.CmsResource;
044import org.opencms.file.CmsResourceFilter;
045import org.opencms.file.history.CmsHistoryResourceHandler;
046import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
047import org.opencms.flex.CmsFlexController;
048import org.opencms.flex.CmsFlexRequest;
049import org.opencms.gwt.shared.CmsGwtConstants;
050import org.opencms.i18n.CmsLocaleGroupService;
051import org.opencms.jsp.CmsJspBean;
052import org.opencms.jsp.CmsJspResourceWrapper;
053import org.opencms.jsp.CmsJspTagContainer;
054import org.opencms.jsp.CmsJspTagEditable;
055import org.opencms.jsp.Messages;
056import org.opencms.jsp.jsonpart.CmsJsonPartFilter;
057import org.opencms.loader.CmsTemplateContextManager;
058import org.opencms.main.CmsException;
059import org.opencms.main.CmsLog;
060import org.opencms.main.CmsRuntimeException;
061import org.opencms.main.CmsSystemInfo;
062import org.opencms.main.OpenCms;
063import org.opencms.relations.CmsCategory;
064import org.opencms.relations.CmsCategoryService;
065import org.opencms.search.galleries.CmsGalleryNameMacroResolver;
066import org.opencms.site.CmsSite;
067import org.opencms.util.CmsCollectionsGenericWrapper;
068import org.opencms.util.CmsMacroResolver;
069import org.opencms.util.CmsStringUtil;
070import org.opencms.util.CmsUUID;
071import org.opencms.xml.containerpage.CmsADESessionCache;
072import org.opencms.xml.containerpage.CmsContainerBean;
073import org.opencms.xml.containerpage.CmsContainerElementBean;
074import org.opencms.xml.containerpage.CmsContainerPageBean;
075import org.opencms.xml.containerpage.CmsDynamicFunctionBean;
076import org.opencms.xml.containerpage.CmsDynamicFunctionParser;
077import org.opencms.xml.containerpage.CmsFormatterConfiguration;
078import org.opencms.xml.containerpage.CmsMetaMapping;
079import org.opencms.xml.containerpage.CmsXmlContainerPage;
080import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
081import org.opencms.xml.containerpage.I_CmsFormatterBean;
082import org.opencms.xml.content.CmsXmlContent;
083import org.opencms.xml.content.CmsXmlContentFactory;
084import org.opencms.xml.content.CmsXmlContentProperty;
085import org.opencms.xml.templatemapper.CmsTemplateMapper;
086import org.opencms.xml.types.I_CmsXmlContentValue;
087
088import java.lang.reflect.Constructor;
089import java.lang.reflect.Method;
090import java.util.ArrayList;
091import java.util.Arrays;
092import java.util.Collections;
093import java.util.HashMap;
094import java.util.List;
095import java.util.Locale;
096import java.util.Map;
097
098import javax.servlet.ServletRequest;
099import javax.servlet.http.HttpServletRequest;
100
101import org.apache.commons.collections.Transformer;
102import org.apache.commons.lang3.LocaleUtils;
103import org.apache.commons.logging.Log;
104
105/**
106 * Allows convenient access to the most important OpenCms functions on a JSP page,
107 * indented to be used from a JSP with the JSTL or EL.<p>
108 *
109 * This bean is available by default in the context of an OpenCms managed JSP.<p>
110 *
111 * @since 8.0
112 */
113public final class CmsJspStandardContextBean {
114
115    /**
116     * Container element wrapper to add some API methods.<p>
117     */
118    public class CmsContainerElementWrapper extends CmsContainerElementBean {
119
120        /** Cache for the wrapped element parent. */
121        private CmsContainerElementWrapper m_parent;
122
123        /** Cache for the wrapped element type name. */
124        private String m_resourceTypeName;
125
126        /** The wrapped element instance. */
127        private CmsContainerElementBean m_wrappedElement;
128
129        /** Cache for the wrapped element settings. */
130        private Map<String, CmsJspElementSettingValueWrapper> m_wrappedSettings;
131
132        /**
133         * Constructor.<p>
134         *
135         * @param element the element to wrap
136         */
137        protected CmsContainerElementWrapper(CmsContainerElementBean element) {
138
139            m_wrappedElement = element;
140
141        }
142
143        /**
144         * @see org.opencms.xml.containerpage.CmsContainerElementBean#clone()
145         */
146        @Override
147        public CmsContainerElementBean clone() {
148
149            return m_wrappedElement.clone();
150        }
151
152        /**
153         * @see org.opencms.xml.containerpage.CmsContainerElementBean#editorHash()
154         */
155        @Override
156        public String editorHash() {
157
158            return m_wrappedElement.editorHash();
159        }
160
161        /**
162         * @see org.opencms.xml.containerpage.CmsContainerElementBean#equals(java.lang.Object)
163         */
164        @Override
165        public boolean equals(Object obj) {
166
167            return m_wrappedElement.equals(obj);
168        }
169
170        /**
171         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getFormatterId()
172         */
173        @Override
174        public CmsUUID getFormatterId() {
175
176            return m_wrappedElement.getFormatterId();
177        }
178
179        /**
180         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getId()
181         */
182        @Override
183        public CmsUUID getId() {
184
185            return m_wrappedElement.getId();
186        }
187
188        /**
189         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getIndividualSettings()
190         */
191        @Override
192        public Map<String, String> getIndividualSettings() {
193
194            return m_wrappedElement.getIndividualSettings();
195        }
196
197        /**
198         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getInheritanceInfo()
199         */
200        @Override
201        public CmsInheritanceInfo getInheritanceInfo() {
202
203            return m_wrappedElement.getInheritanceInfo();
204        }
205
206        /**
207         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getInstanceId()
208         */
209        @Override
210        public String getInstanceId() {
211
212            return m_wrappedElement.getInstanceId();
213        }
214
215        /**
216         * Returns the parent element if present.<p>
217         *
218         * @return the parent element or <code>null</code> if not available
219         */
220        public CmsContainerElementWrapper getParent() {
221
222            if (m_parent == null) {
223                CmsContainerElementBean parent = getParentElement(m_wrappedElement);
224                m_parent = (parent != null) ? new CmsContainerElementWrapper(getParentElement(m_wrappedElement)) : null;
225            }
226            return m_parent;
227        }
228
229        /**
230         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getResource()
231         */
232        @Override
233        public CmsResource getResource() {
234
235            return m_wrappedElement.getResource();
236        }
237
238        /**
239         * Returns the resource type name of the element resource.<p>
240         *
241         * @return the resource type name
242         */
243        public String getResourceTypeName() {
244
245            if (m_resourceTypeName == null) {
246                m_resourceTypeName = "";
247                try {
248                    m_resourceTypeName = OpenCms.getResourceManager().getResourceType(
249                        m_wrappedElement.getResource()).getTypeName();
250                } catch (Exception e) {
251                    CmsJspStandardContextBean.LOG.error(e.getLocalizedMessage(), e);
252                }
253            }
254            return m_resourceTypeName;
255        }
256
257        /**
258         * Returns a lazy initialized setting map.<p>
259         *
260         * The values returned in the map are instances of {@link A_CmsJspValueWrapper}.
261         *
262         * @return the wrapped settings
263         */
264        public Map<String, CmsJspElementSettingValueWrapper> getSetting() {
265
266            if (m_wrappedSettings == null) {
267                m_wrappedSettings = CmsCollectionsGenericWrapper.createLazyMap(
268                    new SettingsTransformer(m_wrappedElement));
269            }
270            return m_wrappedSettings;
271        }
272
273        /**
274         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getSettings()
275         */
276        @Override
277        public Map<String, String> getSettings() {
278
279            return m_wrappedElement.getSettings();
280        }
281
282        /**
283         * @see org.opencms.xml.containerpage.CmsContainerElementBean#getSitePath()
284         */
285        @Override
286        public String getSitePath() {
287
288            return m_wrappedElement.getSitePath();
289        }
290
291        /**
292         * @see org.opencms.xml.containerpage.CmsContainerElementBean#hashCode()
293         */
294        @Override
295        public int hashCode() {
296
297            return m_wrappedElement.hashCode();
298        }
299
300        /**
301         * @see org.opencms.xml.containerpage.CmsContainerElementBean#initResource(org.opencms.file.CmsObject)
302         */
303        @Override
304        public void initResource(CmsObject cms) throws CmsException {
305
306            m_wrappedElement.initResource(cms);
307        }
308
309        /**
310         * @see org.opencms.xml.containerpage.CmsContainerElementBean#initSettings(org.opencms.file.CmsObject, org.opencms.xml.containerpage.I_CmsFormatterBean, java.util.Locale, javax.servlet.ServletRequest, java.util.Map)
311         */
312        @Override
313        public void initSettings(
314            CmsObject cms,
315            I_CmsFormatterBean formatterBean,
316            Locale locale,
317            ServletRequest request,
318            Map<String, String> settingPresets) {
319
320            m_wrappedElement.initSettings(cms, formatterBean, locale, request, settingPresets);
321        }
322
323        /**
324         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isCreateNew()
325         */
326        @Override
327        public boolean isCreateNew() {
328
329            return m_wrappedElement.isCreateNew();
330        }
331
332        /**
333         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isGroupContainer(org.opencms.file.CmsObject)
334         */
335        @Override
336        public boolean isGroupContainer(CmsObject cms) throws CmsException {
337
338            return m_wrappedElement.isGroupContainer(cms);
339        }
340
341        /**
342         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isHistoryContent()
343         */
344        @Override
345        public boolean isHistoryContent() {
346
347            return m_wrappedElement.isHistoryContent();
348        }
349
350        /**
351         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isInheritedContainer(org.opencms.file.CmsObject)
352         */
353        @Override
354        public boolean isInheritedContainer(CmsObject cms) throws CmsException {
355
356            return m_wrappedElement.isInheritedContainer(cms);
357        }
358
359        /**
360         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isInMemoryOnly()
361         */
362        @Override
363        public boolean isInMemoryOnly() {
364
365            return m_wrappedElement.isInMemoryOnly();
366        }
367
368        /**
369         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isReleasedAndNotExpired()
370         */
371        @Override
372        public boolean isReleasedAndNotExpired() {
373
374            return m_wrappedElement.isReleasedAndNotExpired();
375        }
376
377        /**
378         * @see org.opencms.xml.containerpage.CmsContainerElementBean#isTemporaryContent()
379         */
380        @Override
381        public boolean isTemporaryContent() {
382
383            return m_wrappedElement.isTemporaryContent();
384        }
385
386        /**
387         * @see org.opencms.xml.containerpage.CmsContainerElementBean#removeInstanceId()
388         */
389        @Override
390        public void removeInstanceId() {
391
392            m_wrappedElement.removeInstanceId();
393        }
394
395        /**
396         * @see org.opencms.xml.containerpage.CmsContainerElementBean#setFormatterId(org.opencms.util.CmsUUID)
397         */
398        @Override
399        public void setFormatterId(CmsUUID formatterId) {
400
401            m_wrappedElement.setFormatterId(formatterId);
402        }
403
404        /**
405         * @see org.opencms.xml.containerpage.CmsContainerElementBean#setHistoryFile(org.opencms.file.CmsFile)
406         */
407        @Override
408        public void setHistoryFile(CmsFile file) {
409
410            m_wrappedElement.setHistoryFile(file);
411        }
412
413        /**
414         * @see org.opencms.xml.containerpage.CmsContainerElementBean#setInheritanceInfo(org.opencms.ade.containerpage.shared.CmsInheritanceInfo)
415         */
416        @Override
417        public void setInheritanceInfo(CmsInheritanceInfo inheritanceInfo) {
418
419            m_wrappedElement.setInheritanceInfo(inheritanceInfo);
420        }
421
422        /**
423         * @see org.opencms.xml.containerpage.CmsContainerElementBean#setTemporaryFile(org.opencms.file.CmsFile)
424         */
425        @Override
426        public void setTemporaryFile(CmsFile elementFile) {
427
428            m_wrappedElement.setTemporaryFile(elementFile);
429        }
430
431        /**
432         * @see org.opencms.xml.containerpage.CmsContainerElementBean#toString()
433         */
434        @Override
435        public String toString() {
436
437            return m_wrappedElement.toString();
438        }
439    }
440
441    /**
442     * Provides a lazy initialized Map that provides the detail page link as a value when given the name of a
443     * (named) dynamic function or resource type as a key.<p>
444     */
445    public class CmsDetailLookupTransformer implements Transformer {
446
447        /** The selected prefix. */
448        private String m_prefix;
449
450        /**
451         * Constructor with a prefix.<p>
452         *
453         * The prefix is used to distinguish between type detail pages and function detail pages.<p>
454         *
455         * @param prefix the prefix to use
456         */
457        public CmsDetailLookupTransformer(String prefix) {
458
459            m_prefix = prefix;
460        }
461
462        /**
463         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
464         */
465        @Override
466        public Object transform(Object input) {
467
468            String type = m_prefix + String.valueOf(input);
469            CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
470                m_cms,
471                m_cms.addSiteRoot(m_cms.getRequestContext().getUri()));
472            List<CmsDetailPageInfo> detailPages = config.getDetailPagesForType(type);
473            CmsDetailPageInfo detailPage = null;
474            boolean usingDefault = false;
475            if ((detailPages == null) || (detailPages.size() == 0)) {
476                detailPage = config.getDefaultDetailPage();
477                usingDefault = true;
478            } else {
479                detailPage = detailPages.get(0);
480            }
481            if (detailPage == null) {
482                return "[No detail page configured for type =" + type + "=]";
483            }
484
485            CmsUUID id = detailPage.getId();
486            try {
487                CmsResource r = m_cms.readResource(id);
488                String link = OpenCms.getLinkManager().substituteLink(m_cms, r);
489                if (usingDefault) {
490                    link = CmsStringUtil.joinPaths(link, (String)input);
491                }
492                return link;
493            } catch (CmsException e) {
494                LOG.warn(e.getLocalizedMessage(), e);
495                return "[Error reading detail page for type =" + type + "=]";
496            }
497        }
498    }
499
500    /**
501     * The element setting transformer.<p>
502     */
503    public class SettingsTransformer implements Transformer {
504
505        /** The element formatter config. */
506        private I_CmsFormatterBean m_formatter;
507
508        /** The configured formatter settings. */
509        private Map<String, CmsXmlContentProperty> m_formatterSettingsConfig;
510
511        /** The element. */
512        private CmsContainerElementBean m_transformElement;
513
514        /**
515         * Constructor.<p>
516         *
517         * @param element the element
518         */
519        SettingsTransformer(CmsContainerElementBean element) {
520
521            m_transformElement = element;
522            m_formatter = getElementFormatter(element);
523        }
524
525        /**
526         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
527         */
528        @Override
529        public Object transform(Object settingName) {
530
531            boolean exists;
532            if (m_formatter != null) {
533                if (m_formatterSettingsConfig == null) {
534                    m_formatterSettingsConfig = OpenCms.getADEManager().getFormatterSettings(
535                        m_cms,
536                        m_formatter,
537                        m_transformElement.getResource(),
538                        getLocale(),
539                        m_request);
540                }
541                exists = m_formatterSettingsConfig.get(settingName) != null;
542            } else {
543                exists = m_transformElement.getSettings().get(settingName) != null;
544            }
545            return new CmsJspElementSettingValueWrapper(
546                CmsJspStandardContextBean.this,
547                m_transformElement.getSettings().get(settingName),
548                exists);
549        }
550    }
551
552    /**
553     * Bean containing a template name and URI.<p>
554     */
555    public static class TemplateBean {
556
557        /** True if the template context was manually selected. */
558        private boolean m_forced;
559
560        /** The template name. */
561        private String m_name;
562
563        /** The template resource. */
564        private CmsResource m_resource;
565
566        /** The template uri, if no resource is set. */
567        private String m_uri;
568
569        /**
570         * Creates a new instance.<p>
571         *
572         * @param name the template name
573         * @param resource the template resource
574         */
575        public TemplateBean(String name, CmsResource resource) {
576
577            m_resource = resource;
578            m_name = name;
579        }
580
581        /**
582         * Creates a new instance with an URI instead of a resoure.<p>
583         *
584         * @param name the template name
585         * @param uri the template uri
586         */
587        public TemplateBean(String name, String uri) {
588
589            m_name = name;
590            m_uri = uri;
591        }
592
593        /**
594         * Gets the template name.<p>
595         *
596         * @return the template name
597         */
598        public String getName() {
599
600            return m_name;
601        }
602
603        /**
604         * Gets the template resource.<p>
605         *
606         * @return the template resource
607         */
608        public CmsResource getResource() {
609
610            return m_resource;
611        }
612
613        /**
614         * Gets the template uri.<p>
615         *
616         * @return the template URI.
617         */
618        public String getUri() {
619
620            if (m_resource != null) {
621                return m_resource.getRootPath();
622            } else {
623                return m_uri;
624            }
625        }
626
627        /**
628         * Returns true if the template context was manually selected.<p>
629         *
630         * @return true if the template context was manually selected
631         */
632        public boolean isForced() {
633
634            return m_forced;
635        }
636
637        /**
638         * Sets the 'forced' flag to a new value.<p>
639         *
640         * @param forced the new value
641         */
642        public void setForced(boolean forced) {
643
644            m_forced = forced;
645        }
646
647    }
648
649    /**
650     * The meta mappings transformer.<p>
651     */
652    class MetaLookupTranformer implements Transformer {
653
654        /**
655         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
656         */
657        public Object transform(Object arg0) {
658
659            String result = null;
660            if ((m_metaMappings != null) && m_metaMappings.containsKey(arg0)) {
661                MetaMapping mapping = m_metaMappings.get(arg0);
662                CmsGalleryNameMacroResolver resolver = null;
663                try {
664                    CmsResourceFilter filter = getIsEditMode()
665                    ? CmsResourceFilter.IGNORE_EXPIRATION
666                    : CmsResourceFilter.DEFAULT;
667                    CmsResource res = m_cms.readResource(mapping.m_contentId, filter);
668                    CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, res, m_request);
669                    resolver = new CmsGalleryNameMacroResolver(m_cms, content, getLocale());
670                    if (content.hasLocale(getLocale())) {
671                        I_CmsXmlContentValue val = content.getValue(mapping.m_elementXPath, getLocale());
672                        if (val != null) {
673                            result = val.getStringValue(m_cms);
674                        }
675                    }
676
677                } catch (CmsException e) {
678                    LOG.error(e.getLocalizedMessage(), e);
679                }
680                if (result == null) {
681                    result = mapping.m_defaultValue;
682                }
683                if ((resolver != null) && (result != null)) {
684                    result = resolver.resolveMacros(result);
685                }
686            }
687            return result;
688        }
689
690    }
691
692    /** The meta mapping data. */
693    class MetaMapping {
694
695        /** The mapping content structure id. */
696        CmsUUID m_contentId;
697
698        /** The default value. */
699        String m_defaultValue;
700
701        /** The mapping value xpath. */
702        String m_elementXPath;
703
704        /** The mapping key. */
705        String m_key;
706
707        /** The mapping order. */
708        int m_order;
709    }
710
711    /** The attribute name of the cms object.*/
712    public static final String ATTRIBUTE_CMS_OBJECT = "__cmsObject";
713
714    /** The attribute name of the standard JSP context bean. */
715    public static final String ATTRIBUTE_NAME = "cms";
716
717    /** The logger instance for this class. */
718    protected static final Log LOG = CmsLog.getLog(CmsJspStandardContextBean.class);
719
720    /** OpenCms user context. */
721    protected CmsObject m_cms;
722
723    /** The meta mapping configuration. */
724    Map<String, MetaMapping> m_metaMappings;
725
726    /** The current request. */
727    ServletRequest m_request;
728
729    /** Lazily initialized map from a category path to all sub-categories of that category. */
730    private Map<String, CmsJspCategoryAccessBean> m_allSubCategories;
731
732    /** Lazily initialized map from a category path to the path's category object. */
733    private Map<String, CmsCategory> m_categories;
734
735    /** The container the currently rendered element is part of. */
736    private CmsContainerBean m_container;
737
738    /** The current detail content resource if available. */
739    private CmsResource m_detailContentResource;
740
741    /** The detail function page. */
742    private CmsResource m_detailFunctionPage;
743
744    /** The detail only page references containers that are only displayed in detail view. */
745    private CmsContainerPageBean m_detailOnlyPage;
746
747    /** Flag to indicate if element was just edited. */
748    private boolean m_edited;
749
750    /** The currently rendered element. */
751    private CmsContainerElementBean m_element;
752
753    /** The elements of the current page. */
754    private Map<String, CmsContainerElementBean> m_elementInstances;
755
756    /** The lazy initialized map which allows access to the dynamic function beans. */
757    private Map<String, CmsDynamicFunctionBeanWrapper> m_function;
758
759    /** The lazy initialized map for the function detail pages. */
760    private Map<String, String> m_functionDetailPage;
761
762    /** Indicates if in drag mode. */
763    private boolean m_isDragMode;
764
765    /** Stores the edit mode info. */
766    private Boolean m_isEditMode;
767
768    /** Lazily initialized map from the locale to the localized title property. */
769    private Map<String, String> m_localeTitles;
770
771    /** The currently displayed container page. */
772    private CmsContainerPageBean m_page;
773
774    /** The current container page resource, lazy initialized. */
775    private CmsJspResourceWrapper m_pageResource;
776
777    /** The parent containers to the given element instance ids. */
778    private Map<String, CmsContainerBean> m_parentContainers;
779
780    /** Lazily initialized map from a category path to all categories on that path. */
781    private Map<String, List<CmsCategory>> m_pathCategories;
782
783    /** Lazily initialized map from the root path of a resource to all categories assigned to the resource. */
784    private Map<String, CmsJspCategoryAccessBean> m_resourceCategories;
785
786    /** Map from root paths to site relative paths. */
787    private Map<String, String> m_sitePaths;
788
789    /** The lazy initialized map for the detail pages. */
790    private Map<String, String> m_typeDetailPage;
791
792    /** The VFS content access bean. */
793    private CmsJspVfsAccessBean m_vfsBean;
794
795    /**
796     * Creates an empty instance.<p>
797     */
798    private CmsJspStandardContextBean() {
799
800        // NOOP
801    }
802
803    /**
804     * Creates a new standard JSP context bean.
805     *
806     * @param req the current servlet request
807     */
808    private CmsJspStandardContextBean(ServletRequest req) {
809
810        CmsFlexController controller = CmsFlexController.getController(req);
811        m_request = req;
812        CmsObject cms;
813        if (controller != null) {
814            cms = controller.getCmsObject();
815        } else {
816            cms = (CmsObject)req.getAttribute(ATTRIBUTE_CMS_OBJECT);
817        }
818        if (cms == null) {
819            // cms object unavailable - this request was not initialized properly
820            throw new CmsRuntimeException(
821                Messages.get().container(Messages.ERR_MISSING_CMS_CONTROLLER_1, CmsJspBean.class.getName()));
822        }
823        updateCmsObject(cms);
824
825        m_detailContentResource = CmsDetailPageResourceHandler.getDetailResource(req);
826        m_detailFunctionPage = CmsDetailPageResourceHandler.getDetailFunctionPage(req);
827    }
828
829    /**
830     * Creates a new instance of the standard JSP context bean.<p>
831     *
832     * To prevent multiple creations of the bean during a request, the OpenCms request context
833     * attributes are used to cache the created VFS access utility bean.<p>
834     *
835     * @param req the current servlet request
836     *
837     * @return a new instance of the standard JSP context bean
838     */
839    public static CmsJspStandardContextBean getInstance(ServletRequest req) {
840
841        Object attribute = req.getAttribute(ATTRIBUTE_NAME);
842        CmsJspStandardContextBean result;
843        if ((attribute != null) && (attribute instanceof CmsJspStandardContextBean)) {
844            result = (CmsJspStandardContextBean)attribute;
845        } else {
846            result = new CmsJspStandardContextBean(req);
847            req.setAttribute(ATTRIBUTE_NAME, result);
848        }
849        return result;
850    }
851
852    /**
853     * Returns a copy of this JSP context bean.<p>
854     *
855     * @return a copy of this JSP context bean
856     */
857    public CmsJspStandardContextBean createCopy() {
858
859        CmsJspStandardContextBean result = new CmsJspStandardContextBean();
860        result.m_container = m_container;
861        if (m_detailContentResource != null) {
862            result.m_detailContentResource = m_detailContentResource.getCopy();
863        }
864        result.m_element = m_element;
865        result.setPage(m_page);
866        return result;
867    }
868
869    /**
870     * Returns a caching hash specific to the element, it's properties and the current container width.<p>
871     *
872     * @return the caching hash
873     */
874    public String elementCachingHash() {
875
876        String result = "";
877        if (m_element != null) {
878            result = m_element.editorHash();
879            if (m_container != null) {
880                result += "w:"
881                    + m_container.getWidth()
882                    + "cName:"
883                    + m_container.getName()
884                    + "cType:"
885                    + m_container.getType();
886            }
887        }
888        return result;
889    }
890
891    /**
892     * Returns the locales available for the currently requested URI.
893     *
894     * @return the locales available for the currently requested URI.
895     */
896    public List<Locale> getAvailableLocales() {
897
898        return OpenCms.getLocaleManager().getAvailableLocales(m_cms, getRequestContext().getUri());
899    }
900
901    /**
902     * Helper for easy instantiation and initialization of custom context beans that returns
903     * an instance of the class specified via <code>className</code>, with the current context already set.
904     *
905     * @param className name of the class to instantiate. Must be a subclass of {@link A_CmsJspCustomContextBean}.
906     * @return an instance of the provided class with the current context already set.
907     */
908    public Object getBean(String className) {
909
910        try {
911            Class<?> clazz = Class.forName(className);
912            if (A_CmsJspCustomContextBean.class.isAssignableFrom(clazz)) {
913                Constructor<?> constructor = clazz.getConstructor();
914                Object instance = constructor.newInstance();
915                Method setContextMethod = clazz.getMethod("setContext", CmsJspStandardContextBean.class);
916                setContextMethod.invoke(instance, this);
917                return instance;
918            } else {
919                throw new Exception();
920            }
921        } catch (Exception e) {
922            LOG.error(Messages.get().container(Messages.ERR_NO_CUSTOM_BEAN_1, className));
923        }
924        return null;
925
926    }
927
928    /**
929     * Returns the container the currently rendered element is part of.<p>
930     *
931     * @return the currently the currently rendered element is part of
932     */
933    public CmsContainerBean getContainer() {
934
935        return m_container;
936    }
937
938    /**
939     * Returns the current detail content, or <code>null</code> if no detail content is requested.<p>
940     *
941     * @return the current detail content, or <code>null</code> if no detail content is requested.<p>
942     */
943    public CmsJspResourceWrapper getDetailContent() {
944
945        return CmsJspResourceWrapper.wrap(m_cms, m_detailContentResource);
946    }
947
948    /**
949     * Returns the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p>
950     *
951     * @return the structure id of the current detail content, or <code>null</code> if no detail content is requested.<p>
952     */
953    public CmsUUID getDetailContentId() {
954
955        return m_detailContentResource == null ? null : m_detailContentResource.getStructureId();
956    }
957
958    /**
959     * Returns the detail content site path, or <code>null</code> if not available.<p>
960     *
961     * @return the detail content site path
962     */
963    public String getDetailContentSitePath() {
964
965        return ((m_cms == null) || (m_detailContentResource == null))
966        ? null
967        : m_cms.getSitePath(m_detailContentResource);
968    }
969
970    /**
971     * Returns the detail function page.<p>
972     *
973     * @return the detai function page
974     */
975    public CmsJspResourceWrapper getDetailFunctionPage() {
976
977        return CmsJspResourceWrapper.wrap(m_cms, m_detailFunctionPage);
978    }
979
980    /**
981     * Returns the detail only page.<p>
982     *
983     * @return the detail only page
984     */
985    public CmsContainerPageBean getDetailOnlyPage() {
986
987        return m_detailOnlyPage;
988    }
989
990    /**
991     * Returns the currently rendered element.<p>
992     *
993     * @return the currently rendered element
994     */
995    public CmsContainerElementWrapper getElement() {
996
997        return m_element != null ? new CmsContainerElementWrapper(m_element) : null;
998    }
999
1000    /**
1001     * Returns a lazy initialized map of wrapped container elements beans by container name suffix.<p>
1002     *
1003     * So in case there is more than one container where the name end with the given suffix,
1004     * a joined list of container elements beans is returned.<p>
1005     *
1006     * @return a lazy initialized map of wrapped container elements beans by container name suffix
1007     *
1008     * @see #getElementsInContainer()
1009     */
1010    public Map<String, List<CmsContainerElementWrapper>> getElementBeansInContainers() {
1011
1012        return CmsCollectionsGenericWrapper.createLazyMap(obj -> {
1013            if (obj instanceof String) {
1014                List<CmsContainerElementBean> containerElements = new ArrayList<>();
1015                for (CmsContainerBean container : getPage().getContainers().values()) {
1016                    if (container.getName().endsWith("-" + obj)) {
1017                        for (CmsContainerElementBean element : container.getElements()) {
1018                            try {
1019                                element.initResource(m_cms);
1020                                containerElements.add(new CmsContainerElementWrapper(element));
1021                            } catch (Exception e) {
1022                                LOG.error(e.getLocalizedMessage(), e);
1023                            }
1024                        }
1025                    }
1026                }
1027                return containerElements;
1028            } else {
1029                return null;
1030            }
1031        });
1032
1033    }
1034
1035    /**
1036     * Returns a lazy initialized map of wrapped element resources by container name.<p>
1037     *
1038     * @return the lazy map of element resource wrappers
1039     */
1040    public Map<String, List<CmsJspResourceWrapper>> getElementsInContainer() {
1041
1042        return CmsCollectionsGenericWrapper.createLazyMap(obj -> {
1043            if (obj instanceof String) {
1044                List<CmsJspResourceWrapper> elements = new ArrayList<>();
1045                CmsContainerBean container = getPage().getContainers().get(obj);
1046                if (container != null) {
1047                    for (CmsContainerElementBean element : container.getElements()) {
1048                        try {
1049                            element.initResource(m_cms);
1050                            elements.add(CmsJspResourceWrapper.wrap(m_cms, element.getResource()));
1051                        } catch (Exception e) {
1052                            LOG.error(e.getLocalizedMessage(), e);
1053                        }
1054                    }
1055                }
1056                return elements;
1057            } else {
1058                return null;
1059            }
1060        });
1061
1062    }
1063
1064    /**
1065     * Returns a lazy initialized map of wrapped element resources by container name suffix.<p>
1066     *
1067     * So in case there is more than one container where the name end with the given suffix,
1068     * a joined list of elements is returned.<p>
1069     *
1070     * @return the lazy map of element resource wrappers
1071     *
1072     * @see #getElementBeansInContainers()
1073     */
1074    public Map<String, List<CmsJspResourceWrapper>> getElementsInContainers() {
1075
1076        return CmsCollectionsGenericWrapper.createLazyMap(obj -> {
1077            if (obj instanceof String) {
1078                List<CmsJspResourceWrapper> elements = new ArrayList<>();
1079                for (CmsContainerBean container : getPage().getContainers().values()) {
1080                    if (container.getName().endsWith("-" + obj)) {
1081                        for (CmsContainerElementBean element : container.getElements()) {
1082                            try {
1083                                element.initResource(m_cms);
1084                                elements.add(CmsJspResourceWrapper.wrap(m_cms, element.getResource()));
1085                            } catch (Exception e) {
1086                                LOG.error(e.getLocalizedMessage(), e);
1087                            }
1088                        }
1089                    }
1090                }
1091                return elements;
1092            } else {
1093                return null;
1094            }
1095        });
1096
1097    }
1098
1099    /**
1100     * Alternative method name for getReloadMarker().
1101     *
1102     * @see org.opencms.jsp.util.CmsJspStandardContextBean#getReloadMarker()
1103     *
1104     * @return the reload marker
1105     */
1106    public String getEnableReload() {
1107
1108        return getReloadMarker();
1109    }
1110
1111    /**
1112     * Returns a lazy initialized Map which allows access to the dynamic function beans using the JSP EL.<p>
1113     *
1114     * When given a key, the returned map will look up the corresponding dynamic function bean in the module configuration.<p>
1115     *
1116     * @return a lazy initialized Map which allows access to the dynamic function beans using the JSP EL
1117     */
1118    public Map<String, CmsDynamicFunctionBeanWrapper> getFunction() {
1119
1120        if (m_function == null) {
1121
1122            Transformer transformer = new Transformer() {
1123
1124                @Override
1125                public Object transform(Object input) {
1126
1127                    try {
1128                        CmsDynamicFunctionBean dynamicFunction = readDynamicFunctionBean((String)input);
1129                        CmsDynamicFunctionBeanWrapper wrapper = new CmsDynamicFunctionBeanWrapper(
1130                            m_cms,
1131                            dynamicFunction);
1132                        return wrapper;
1133
1134                    } catch (CmsException e) {
1135                        LOG.debug(e.getLocalizedMessage(), e);
1136                        return new CmsDynamicFunctionBeanWrapper(m_cms, null);
1137                    }
1138                }
1139            };
1140            m_function = CmsCollectionsGenericWrapper.createLazyMap(transformer);
1141        }
1142        return m_function;
1143
1144    }
1145
1146    /**
1147     * Deprecated method to access function detail pages using the EL.<p>
1148     *
1149     * @return a lazy initialized Map that provides the detail page link as a value when given the name of a
1150     * (named) dynamic function as a key
1151     *
1152     * @deprecated use {@link #getFunctionDetailPage()} instead
1153     */
1154    @Deprecated
1155    public Map<String, String> getFunctionDetail() {
1156
1157        return getFunctionDetailPage();
1158    }
1159
1160    /**
1161     * Returns a lazy initialized Map that provides the detail page link as a value when given the name of a
1162     * (named) dynamic function as a key.<p>
1163     *
1164     * The provided Map key is assumed to be a String that represents a named dynamic function.<p>
1165     *
1166     * Usage example on a JSP with the JSTL:<pre>
1167     * &lt;a href=${cms.functionDetailPage['search']} /&gt
1168     * </pre>
1169     *
1170     * @return a lazy initialized Map that provides the detail page link as a value when given the name of a
1171     * (named) dynamic function as a key
1172     *
1173     * @see #getTypeDetailPage()
1174     */
1175    public Map<String, String> getFunctionDetailPage() {
1176
1177        if (m_functionDetailPage == null) {
1178            m_functionDetailPage = CmsCollectionsGenericWrapper.createLazyMap(
1179                new CmsDetailLookupTransformer(CmsDetailPageInfo.FUNCTION_PREFIX));
1180        }
1181        return m_functionDetailPage;
1182    }
1183
1184    /**
1185     * Returns a lazy map which creates a wrapper object for a dynamic function format when given an XML content
1186     * as a key.<p>
1187     *
1188     * @return a lazy map for accessing function formats for a content
1189     */
1190    public Map<CmsJspContentAccessBean, CmsDynamicFunctionFormatWrapper> getFunctionFormatFromContent() {
1191
1192        Transformer transformer = new Transformer() {
1193
1194            @Override
1195            public Object transform(Object contentAccess) {
1196
1197                CmsXmlContent content = (CmsXmlContent)(((CmsJspContentAccessBean)contentAccess).getRawContent());
1198                CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser();
1199                CmsDynamicFunctionBean functionBean = null;
1200                try {
1201                    functionBean = parser.parseFunctionBean(m_cms, content);
1202                } catch (CmsException e) {
1203                    LOG.debug(e.getLocalizedMessage(), e);
1204                    return new CmsDynamicFunctionFormatWrapper(m_cms, null);
1205                }
1206                String type = getContainer().getType();
1207                String width = getContainer().getWidth();
1208                int widthNum = -1;
1209                try {
1210                    widthNum = Integer.parseInt(width);
1211                } catch (NumberFormatException e) {
1212                    LOG.debug(e.getLocalizedMessage(), e);
1213                }
1214                CmsDynamicFunctionBean.Format format = functionBean.getFormatForContainer(m_cms, type, widthNum);
1215                CmsDynamicFunctionFormatWrapper wrapper = new CmsDynamicFunctionFormatWrapper(m_cms, format);
1216                return wrapper;
1217            }
1218        };
1219        return CmsCollectionsGenericWrapper.createLazyMap(transformer);
1220    }
1221
1222    /**
1223     * Checks if the current request should be direct edit enabled.
1224     * Online-, history-requests, previews and temporary files will not be editable.<p>
1225     *
1226     * @return <code>true</code> if the current request should be direct edit enabled
1227     */
1228    public boolean getIsEditMode() {
1229
1230        if (m_isEditMode == null) {
1231            m_isEditMode = Boolean.valueOf(CmsJspTagEditable.isEditableRequest(m_request));
1232        }
1233        return m_isEditMode.booleanValue();
1234    }
1235
1236    /**
1237     * Returns true if the current request is a JSON request.<p>
1238     *
1239     * @return true if we are in a JSON request
1240     */
1241    public boolean getIsJSONRequest() {
1242
1243        return CmsJsonPartFilter.isJsonRequest(m_request);
1244    }
1245
1246    /**
1247     * Returns if the current project is the online project.<p>
1248     *
1249     * @return <code>true</code> if the current project is the online project
1250     */
1251    public boolean getIsOnlineProject() {
1252
1253        return m_cms.getRequestContext().getCurrentProject().isOnlineProject();
1254    }
1255
1256    /**
1257     * Returns the current locale.<p>
1258     *
1259     * @return the current locale
1260     */
1261    public Locale getLocale() {
1262
1263        return getRequestContext().getLocale();
1264    }
1265
1266    /**
1267     * Gets a map providing access to the locale variants of the current page.<p>
1268     *
1269     * Note that all available locales for the site / subsite are used as keys, not just the ones for which a locale
1270     * variant actually exists.
1271     *
1272     * Usage in JSPs: ${cms.localeResource['de']]
1273     *
1274     * @return the map from locale strings to locale variant resources
1275     */
1276    public Map<String, CmsJspResourceWrapper> getLocaleResource() {
1277
1278        Map<String, CmsJspResourceWrapper> result = getPageResource().getLocaleResource();
1279        List<Locale> locales = CmsLocaleGroupService.getPossibleLocales(m_cms, getPageResource());
1280        for (Locale locale : locales) {
1281            if (!result.containsKey(locale.toString())) {
1282                result.put(locale.toString(), null);
1283            }
1284        }
1285        return result;
1286    }
1287
1288    /**
1289     * Gets the main locale for the current page's locale group.<p>
1290     *
1291     * @return the main locale for the current page's locale group
1292     */
1293    public Locale getMainLocale() {
1294
1295        return getPageResource().getMainLocale();
1296    }
1297
1298    /**
1299     * Returns the meta mappings map.<p>
1300     *
1301     * @return the meta mappings
1302     */
1303    public Map<String, String> getMeta() {
1304
1305        initMetaMappings();
1306        return CmsCollectionsGenericWrapper.createLazyMap(new MetaLookupTranformer());
1307    }
1308
1309    /**
1310     * Returns the currently displayed container page.<p>
1311     *
1312     * @return the currently displayed container page
1313     */
1314    public CmsContainerPageBean getPage() {
1315
1316        return m_page;
1317    }
1318
1319    /**
1320     * Returns the container page bean for the give page and locale.<p>
1321     *
1322     * @param page the container page resource as id, path or already as resource
1323     * @param locale the content locale as locale or string
1324     *
1325     * @return the container page bean
1326     */
1327    public CmsContainerPageBean getPage(Object page, Object locale) {
1328
1329        CmsResource pageResource = null;
1330        CmsContainerPageBean result = null;
1331        if (m_cms != null) {
1332            try {
1333                pageResource = CmsJspElFunctions.convertRawResource(m_cms, page);
1334                Locale l = CmsJspElFunctions.convertLocale(locale);
1335                result = getPage(pageResource);
1336                if (result != null) {
1337                    CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
1338                        m_cms,
1339                        pageResource.getRootPath());
1340                    for (CmsContainerBean container : result.getContainers().values()) {
1341                        for (CmsContainerElementBean element : container.getElements()) {
1342                            boolean isGroupContainer = element.isGroupContainer(m_cms);
1343                            boolean isInheritedContainer = element.isInheritedContainer(m_cms);
1344                            I_CmsFormatterBean formatterConfig = null;
1345                            if (!isGroupContainer && !isInheritedContainer) {
1346                                element.initResource(m_cms);
1347                                // ensure that the formatter configuration id is added to the element settings, so it will be persisted on save
1348                                formatterConfig = CmsJspTagContainer.getFormatterConfigurationForElement(
1349                                    m_cms,
1350                                    element,
1351                                    adeConfig,
1352                                    container.getName(),
1353                                    "",
1354                                    0);
1355                                if (formatterConfig != null) {
1356                                    element.initSettings(m_cms, formatterConfig, l, m_request, null);
1357                                }
1358                            }
1359                        }
1360                    }
1361                }
1362            } catch (Exception e) {
1363                LOG.warn(e.getLocalizedMessage(), e);
1364            }
1365
1366        }
1367        return result;
1368    }
1369
1370    /**
1371     * Returns the current container page resource.<p>
1372     *
1373     * @return the current container page resource
1374     */
1375    public CmsJspResourceWrapper getPageResource() {
1376
1377        try {
1378            if (m_pageResource == null) {
1379                // get the container page itself, checking the history first
1380                m_pageResource = CmsJspResourceWrapper.wrap(
1381                    m_cms,
1382                    (CmsResource)CmsHistoryResourceHandler.getHistoryResource(m_request));
1383                if (m_pageResource == null) {
1384                    m_pageResource = CmsJspResourceWrapper.wrap(
1385                        m_cms,
1386                        m_cms.readResource(m_cms.getRequestContext().getUri()));
1387                }
1388            }
1389        } catch (CmsException e) {
1390            LOG.error(e.getLocalizedMessage(), e);
1391        }
1392        return m_pageResource;
1393    }
1394
1395    /**
1396     * Returns the parent container to the current container if available.<p>
1397     *
1398     * @return the parent container
1399     */
1400    public CmsContainerBean getParentContainer() {
1401
1402        CmsContainerBean result = null;
1403        if ((getContainer() != null) && (getContainer().getParentInstanceId() != null)) {
1404            result = m_parentContainers.get(getContainer().getParentInstanceId());
1405        }
1406        return result;
1407    }
1408
1409    /**
1410     * Returns the instance id parent container mapping.<p>
1411     *
1412     * @return the instance id parent container mapping
1413     */
1414    public Map<String, CmsContainerBean> getParentContainers() {
1415
1416        if (m_parentContainers == null) {
1417            initPageData();
1418        }
1419        return Collections.unmodifiableMap(m_parentContainers);
1420    }
1421
1422    /**
1423     * Returns the parent element to the current element if available.<p>
1424     *
1425     * @return the parent element or null
1426     */
1427    public CmsContainerElementBean getParentElement() {
1428
1429        return getParentElement(getElement());
1430    }
1431
1432    /**
1433     * JSP EL accessor method for retrieving the preview formatters.<p>
1434     *
1435     * @return a lazy map for accessing preview formatters
1436     */
1437    public Map<String, String> getPreviewFormatter() {
1438
1439        Transformer transformer = new Transformer() {
1440
1441            @Override
1442            public Object transform(Object uri) {
1443
1444                try {
1445                    String rootPath = m_cms.getRequestContext().addSiteRoot((String)uri);
1446                    CmsResource resource = m_cms.readResource((String)uri);
1447                    CmsADEManager adeManager = OpenCms.getADEManager();
1448                    CmsADEConfigData configData = adeManager.lookupConfiguration(m_cms, rootPath);
1449                    CmsFormatterConfiguration formatterConfig = configData.getFormatters(m_cms, resource);
1450                    if (formatterConfig == null) {
1451                        return "";
1452                    }
1453                    I_CmsFormatterBean previewFormatter = formatterConfig.getPreviewFormatter();
1454                    if (previewFormatter == null) {
1455                        return "";
1456                    }
1457                    CmsUUID structureId = previewFormatter.getJspStructureId();
1458                    m_cms.readResource(structureId);
1459                    CmsResource formatterResource = m_cms.readResource(structureId);
1460                    String formatterSitePath = m_cms.getRequestContext().removeSiteRoot(
1461                        formatterResource.getRootPath());
1462                    return formatterSitePath;
1463                } catch (CmsException e) {
1464                    LOG.warn(e.getLocalizedMessage(), e);
1465                    return "";
1466                }
1467            }
1468        };
1469        return CmsCollectionsGenericWrapper.createLazyMap(transformer);
1470    }
1471
1472    /**
1473     * Reads all sub-categories below the provided category.
1474     * @return The map from the provided category to it's sub-categories in a {@link CmsJspCategoryAccessBean}.
1475     */
1476    public Map<String, CmsJspCategoryAccessBean> getReadAllSubCategories() {
1477
1478        if (null == m_allSubCategories) {
1479            m_allSubCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1480
1481                @Override
1482                public Object transform(Object categoryPath) {
1483
1484                    try {
1485                        List<CmsCategory> categories = CmsCategoryService.getInstance().readCategories(
1486                            m_cms,
1487                            (String)categoryPath,
1488                            true,
1489                            m_cms.getRequestContext().getUri());
1490                        CmsJspCategoryAccessBean result = new CmsJspCategoryAccessBean(
1491                            m_cms,
1492                            categories,
1493                            (String)categoryPath);
1494                        return result;
1495                    } catch (CmsException e) {
1496                        LOG.warn(e.getLocalizedMessage(), e);
1497                        return null;
1498                    }
1499                }
1500
1501            });
1502        }
1503        return m_allSubCategories;
1504    }
1505
1506    /**
1507     * Reads the categories assigned to the currently requested URI.
1508     * @return the categories assigned to the currently requested URI.
1509     */
1510    public CmsJspCategoryAccessBean getReadCategories() {
1511
1512        return getReadResourceCategories().get(getRequestContext().getRootUri());
1513    }
1514
1515    /**
1516     * Transforms the category path of a category to the category.
1517     * @return a map from root or site path to category.
1518     */
1519    public Map<String, CmsCategory> getReadCategory() {
1520
1521        if (null == m_categories) {
1522            m_categories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1523
1524                public Object transform(Object categoryPath) {
1525
1526                    try {
1527                        CmsCategoryService catService = CmsCategoryService.getInstance();
1528                        return catService.localizeCategory(
1529                            m_cms,
1530                            catService.readCategory(m_cms, (String)categoryPath, getRequestContext().getUri()),
1531                            m_cms.getRequestContext().getLocale());
1532                    } catch (CmsException e) {
1533                        LOG.warn(e.getLocalizedMessage(), e);
1534                        return null;
1535                    }
1536                }
1537
1538            });
1539        }
1540        return m_categories;
1541    }
1542
1543    /**
1544     * Transforms the category path to the list of all categories on that path.<p>
1545     *
1546     * Example: For path <code>"location/europe/"</code>
1547     *          the list <code>[getReadCategory.get("location/"),getReadCategory.get("location/europe/")]</code>
1548     *          is returned.
1549     * @return a map from a category path to list of categories on that path.
1550     */
1551    public Map<String, List<CmsCategory>> getReadPathCategories() {
1552
1553        if (null == m_pathCategories) {
1554            m_pathCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1555
1556                public Object transform(Object categoryPath) {
1557
1558                    List<CmsCategory> result = new ArrayList<CmsCategory>();
1559
1560                    String path = (String)categoryPath;
1561
1562                    if ((null == path) || (path.length() <= 1)) {
1563                        return result;
1564                    }
1565
1566                    //cut last slash
1567                    path = path.substring(0, path.length() - 1);
1568
1569                    List<String> pathParts = Arrays.asList(path.split("/"));
1570
1571                    String currentPath = "";
1572                    for (String part : pathParts) {
1573                        currentPath += part + "/";
1574                        CmsCategory category = getReadCategory().get(currentPath);
1575                        if (null != category) {
1576                            result.add(category);
1577                        }
1578                    }
1579                    return CmsCategoryService.getInstance().localizeCategories(
1580                        m_cms,
1581                        result,
1582                        m_cms.getRequestContext().getLocale());
1583                }
1584
1585            });
1586        }
1587        return m_pathCategories;
1588    }
1589
1590    /**
1591     * Reads the categories assigned to a resource.
1592     *
1593     * @return map from the resource path (root path) to the assigned categories
1594     */
1595    public Map<String, CmsJspCategoryAccessBean> getReadResourceCategories() {
1596
1597        if (null == m_resourceCategories) {
1598            m_resourceCategories = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1599
1600                public Object transform(Object resourceName) {
1601
1602                    try {
1603                        CmsResource resource = m_cms.readResource(
1604                            getRequestContext().removeSiteRoot((String)resourceName));
1605                        return new CmsJspCategoryAccessBean(m_cms, resource);
1606                    } catch (CmsException e) {
1607                        LOG.warn(e.getLocalizedMessage(), e);
1608                        return null;
1609                    }
1610                }
1611            });
1612        }
1613        return m_resourceCategories;
1614    }
1615
1616    /**
1617     * Returns a HTML comment string that will cause the container page editor to reload the page if the element or its settings
1618     * were edited.<p>
1619     *
1620     * @return the reload marker
1621     */
1622    public String getReloadMarker() {
1623
1624        if (m_cms.getRequestContext().getCurrentProject().isOnlineProject()) {
1625            return ""; // reload marker is not needed in Online mode
1626        } else {
1627            return CmsGwtConstants.FORMATTER_RELOAD_MARKER;
1628        }
1629    }
1630
1631    /**
1632     * Returns the request context.<p>
1633     *
1634     * @return the request context
1635     */
1636    public CmsRequestContext getRequestContext() {
1637
1638        return m_cms.getRequestContext();
1639    }
1640
1641    /**
1642     * Returns the current site.<p>
1643     *
1644     * @return the current site
1645     */
1646    public CmsSite getSite() {
1647
1648        return OpenCms.getSiteManager().getSiteForSiteRoot(m_cms.getRequestContext().getSiteRoot());
1649    }
1650
1651    /**
1652     * Transforms root paths to site paths.
1653     *
1654     * @return lazy map from root paths to site paths.
1655     *
1656     * @see CmsRequestContext#removeSiteRoot(String)
1657     */
1658    public Map<String, String> getSitePath() {
1659
1660        if (m_sitePaths == null) {
1661            m_sitePaths = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1662
1663                public Object transform(Object rootPath) {
1664
1665                    if (rootPath instanceof String) {
1666                        return getRequestContext().removeSiteRoot((String)rootPath);
1667                    }
1668                    return null;
1669                }
1670            });
1671        }
1672        return m_sitePaths;
1673    }
1674
1675    /**
1676     * Returns the subsite path for the currently requested URI.<p>
1677     *
1678     * @return the subsite path
1679     */
1680    public String getSubSitePath() {
1681
1682        return m_cms.getRequestContext().removeSiteRoot(
1683            OpenCms.getADEManager().getSubSiteRoot(m_cms, m_cms.getRequestContext().getRootUri()));
1684    }
1685
1686    /**
1687     * Returns the system information.<p>
1688     *
1689     * @return the system information
1690     */
1691    public CmsSystemInfo getSystemInfo() {
1692
1693        return OpenCms.getSystemInfo();
1694    }
1695
1696    /**
1697     * Gets a bean containing information about the current template.<p>
1698     *
1699     * @return the template information bean
1700     */
1701    public TemplateBean getTemplate() {
1702
1703        TemplateBean templateBean = getRequestAttribute(CmsTemplateContextManager.ATTR_TEMPLATE_BEAN);
1704        if (templateBean == null) {
1705            templateBean = new TemplateBean("", "");
1706        }
1707        return templateBean;
1708    }
1709
1710    /**
1711     * Returns the title of a page delivered from OpenCms, usually used for the <code>&lt;title&gt;</code> tag of
1712     * a HTML page.<p>
1713     *
1714     * If no title information has been found, the empty String "" is returned.<p>
1715     *
1716     * @return the title of the current page
1717     */
1718    public String getTitle() {
1719
1720        return getLocaleSpecificTitle(null);
1721
1722    }
1723
1724    /**
1725     * Get the title and read the Title property according the provided locale.
1726     * @return The map from locales to the locale specific titles.
1727     */
1728    public Map<String, String> getTitleLocale() {
1729
1730        if (m_localeTitles == null) {
1731            m_localeTitles = CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
1732
1733                public Object transform(Object inputLocale) {
1734
1735                    Locale locale = null;
1736                    if (null != inputLocale) {
1737                        if (inputLocale instanceof Locale) {
1738                            locale = (Locale)inputLocale;
1739                        } else if (inputLocale instanceof String) {
1740                            try {
1741                                locale = LocaleUtils.toLocale((String)inputLocale);
1742                            } catch (IllegalArgumentException | NullPointerException e) {
1743                                // do nothing, just go on without locale
1744                            }
1745                        }
1746                    }
1747                    return getLocaleSpecificTitle(locale);
1748                }
1749
1750            });
1751        }
1752        return m_localeTitles;
1753    }
1754
1755    /**
1756     * Returns a lazy initialized Map that provides the detail page link as a value when given the name of a
1757     * resource type as a key.<p>
1758     *
1759     * The provided Map key is assumed to be the name of a resource type that has a detail page configured.<p>
1760     *
1761     * Usage example on a JSP with the JSTL:<pre>
1762     * &lt;a href=${cms.typeDetailPage['bs-blog']} /&gt
1763     * </pre>
1764     *
1765     * @return a lazy initialized Map that provides the detail page link as a value when given the name of a
1766     * resource type as a key
1767     *
1768     * @see #getFunctionDetailPage()
1769     */
1770    public Map<String, String> getTypeDetailPage() {
1771
1772        if (m_typeDetailPage == null) {
1773            m_typeDetailPage = CmsCollectionsGenericWrapper.createLazyMap(new CmsDetailLookupTransformer(""));
1774        }
1775        return m_typeDetailPage;
1776    }
1777
1778    /**
1779     * Returns an initialized VFS access bean.<p>
1780     *
1781     * @return an initialized VFS access bean
1782     */
1783    public CmsJspVfsAccessBean getVfs() {
1784
1785        if (m_vfsBean == null) {
1786            // create a new VVFS access bean
1787            m_vfsBean = CmsJspVfsAccessBean.create(m_cms);
1788        }
1789        return m_vfsBean;
1790    }
1791
1792    /**
1793     * Returns the workplace locale from the current user's settings.<p>
1794     *
1795     * @return returns the workplace locale from the current user's settings
1796     */
1797    public Locale getWorkplaceLocale() {
1798
1799        return OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
1800    }
1801
1802    /**
1803     * Returns an EL access wrapper map for the given object.<p>
1804     *
1805     * If the object is a {@link CmsResource}, then a {@link CmsJspResourceWrapper} is returned.
1806     * Otherwise the object is wrapped in a {@link CmsJspObjectValueWrapper}.<p>
1807     *
1808     * If the object is already is a wrapper, it is returned unchanged.<p>
1809     *
1810     * @return an EL access wrapper map for the given object
1811     */
1812    public Map<Object, Object> getWrap() {
1813
1814        return CmsCollectionsGenericWrapper.createLazyMap(obj -> {
1815
1816            if ((obj instanceof A_CmsJspValueWrapper) || (obj instanceof CmsJspResourceWrapper)) {
1817                return obj;
1818            } else if (obj instanceof CmsResource) {
1819                return CmsJspResourceWrapper.wrap(m_cms, (CmsResource)obj);
1820            } else {
1821                return CmsJspObjectValueWrapper.createWrapper(m_cms, obj);
1822            }
1823        });
1824    }
1825
1826    /**
1827     * Initializes the requested container page.<p>
1828     *
1829     * @throws CmsException in case reading the requested resource fails
1830     */
1831    public void initPage() throws CmsException {
1832
1833        if ((m_page == null) && (m_cms != null)) {
1834            String requestUri = m_cms.getRequestContext().getUri();
1835            // get the container page itself, checking the history first
1836            CmsResource pageResource = (CmsResource)CmsHistoryResourceHandler.getHistoryResource(m_request);
1837            if (pageResource == null) {
1838                pageResource = m_cms.readResource(requestUri);
1839            }
1840            m_page = getPage(pageResource);
1841            m_page = CmsTemplateMapper.get(m_request).transformContainerpageBean(
1842                m_cms,
1843                m_page,
1844                pageResource.getRootPath());
1845
1846        }
1847    }
1848
1849    /**
1850     * Returns <code>true</code in case a detail page is available for the current element.<p>
1851     *
1852     * @return <code>true</code in case a detail page is available for the current element
1853     */
1854    public boolean isDetailPageAvailable() {
1855
1856        boolean result = false;
1857        if ((m_cms != null)
1858            && (m_element != null)
1859            && !m_element.isInMemoryOnly()
1860            && (m_element.getResource() != null)) {
1861            try {
1862                String detailPage = OpenCms.getADEManager().getDetailPageHandler().getDetailPage(
1863                    m_cms,
1864                    m_element.getResource().getRootPath(),
1865                    m_cms.getRequestContext().getUri(),
1866                    null);
1867                result = detailPage != null;
1868            } catch (Exception e) {
1869                LOG.warn(e.getLocalizedMessage(), e);
1870            }
1871        }
1872        return result;
1873    }
1874
1875    /**
1876     * Returns <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise.<p>
1877     *
1878     * Same as to check if {@link #getDetailContent()} is <code>null</code>.<p>
1879     *
1880     * @return <code>true</code> if this is a request to a detail resource, <code>false</code> otherwise
1881     */
1882    public boolean isDetailRequest() {
1883
1884        return m_detailContentResource != null;
1885    }
1886
1887    /**
1888     * Returns if the page is in drag mode.<p>
1889     *
1890     * @return if the page is in drag mode
1891     */
1892    public boolean isDragMode() {
1893
1894        return m_isDragMode;
1895    }
1896
1897    /**
1898     * Returns the flag to indicate if in drag and drop mode.<p>
1899     *
1900     * @return <code>true</code> if in drag and drop mode
1901     */
1902    public boolean isEdited() {
1903
1904        return m_edited;
1905    }
1906
1907    /**
1908     * Returns if the current element is a model group.<p>
1909     *
1910     * @return <code>true</code> if the current element is a model group
1911     */
1912    public boolean isModelGroupElement() {
1913
1914        return (m_element != null) && !m_element.isInMemoryOnly() && isModelGroupPage() && m_element.isModelGroup();
1915    }
1916
1917    /**
1918     * Returns if the current page is used to manage model groups.<p>
1919     *
1920     * @return <code>true</code> if the current page is used to manage model groups
1921     */
1922    public boolean isModelGroupPage() {
1923
1924        CmsResource page = getPageResource();
1925        return (page != null) && CmsContainerpageService.isEditingModelGroups(m_cms, page);
1926
1927    }
1928
1929    /**
1930     * Sets the container the currently rendered element is part of.<p>
1931     *
1932     * @param container the container the currently rendered element is part of
1933     */
1934    public void setContainer(CmsContainerBean container) {
1935
1936        m_container = container;
1937    }
1938
1939    /**
1940     * Sets the detail only page.<p>
1941     *
1942     * @param detailOnlyPage the detail only page to set
1943     */
1944    public void setDetailOnlyPage(CmsContainerPageBean detailOnlyPage) {
1945
1946        m_detailOnlyPage = detailOnlyPage;
1947        clearPageData();
1948    }
1949
1950    /**
1951     * Sets if the page is in drag mode.<p>
1952     *
1953     * @param isDragMode if the page is in drag mode
1954     */
1955    public void setDragMode(boolean isDragMode) {
1956
1957        m_isDragMode = isDragMode;
1958    }
1959
1960    /**
1961     * Sets the flag to indicate if in drag and drop mode.<p>
1962     *
1963     * @param edited <code>true</code> if in drag and drop mode
1964     */
1965    public void setEdited(boolean edited) {
1966
1967        m_edited = edited;
1968    }
1969
1970    /**
1971     * Sets the currently rendered element.<p>
1972     *
1973     * @param element the currently rendered element to set
1974     */
1975    public void setElement(CmsContainerElementBean element) {
1976
1977        m_element = element;
1978    }
1979
1980    /**
1981     * Sets the currently displayed container page.<p>
1982     *
1983     * @param page the currently displayed container page to set
1984     */
1985    public void setPage(CmsContainerPageBean page) {
1986
1987        m_page = page;
1988        clearPageData();
1989    }
1990
1991    /**
1992     * Updates the internally stored OpenCms user context.<p>
1993     *
1994     * @param cms the new OpenCms user context
1995     */
1996    public void updateCmsObject(CmsObject cms) {
1997
1998        try {
1999            m_cms = OpenCms.initCmsObject(cms);
2000        } catch (CmsException e) {
2001            LOG.error(e.getLocalizedMessage(), e);
2002            m_cms = cms;
2003        }
2004    }
2005
2006    /**
2007     * Updates the standard context bean from the request.<p>
2008     *
2009     * @param cmsFlexRequest the request from which to update the data
2010     */
2011    public void updateRequestData(CmsFlexRequest cmsFlexRequest) {
2012
2013        CmsResource detailRes = CmsDetailPageResourceHandler.getDetailResource(cmsFlexRequest);
2014        m_detailContentResource = detailRes;
2015        m_request = cmsFlexRequest;
2016
2017    }
2018
2019    /**
2020     * Returns the formatter configuration to the given element.<p>
2021     *
2022     * @param element the element
2023     *
2024     * @return the formatter configuration
2025     */
2026    protected I_CmsFormatterBean getElementFormatter(CmsContainerElementBean element) {
2027
2028        if (m_elementInstances == null) {
2029            initPageData();
2030        }
2031        I_CmsFormatterBean formatter = null;
2032        CmsContainerBean container = m_parentContainers.get(element.getInstanceId());
2033        if (container == null) {
2034            // use the current container
2035            container = getContainer();
2036        }
2037        if (container != null) {
2038            String containerName = container.getName();
2039            Map<String, String> settings = element.getSettings();
2040            if (settings != null) {
2041                String formatterConfigId = settings.get(CmsFormatterConfig.getSettingsKeyForContainer(containerName));
2042                if (CmsUUID.isValidUUID(formatterConfigId)) {
2043                    formatter = OpenCms.getADEManager().getCachedFormatters(false).getFormatters().get(
2044                        new CmsUUID(formatterConfigId));
2045                }
2046            }
2047            if (formatter == null) {
2048                try {
2049                    CmsResource resource = m_cms.readResource(m_cms.getRequestContext().getUri());
2050
2051                    CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
2052                        m_cms,
2053                        resource.getRootPath());
2054                    CmsFormatterConfiguration formatters = config.getFormatters(m_cms, resource);
2055                    int width = -2;
2056                    try {
2057                        width = Integer.parseInt(container.getWidth());
2058                    } catch (Exception e) {
2059                        LOG.debug(e.getLocalizedMessage(), e);
2060                    }
2061                    formatter = formatters.getDefaultSchemaFormatter(container.getType(), width);
2062                } catch (CmsException e1) {
2063                    if (LOG.isWarnEnabled()) {
2064                        LOG.warn(e1.getLocalizedMessage(), e1);
2065                    }
2066                }
2067            }
2068        }
2069        return formatter;
2070    }
2071
2072    /**
2073     * Returns the title according to the given locale.
2074     * @param locale the locale for which the title should be read.
2075     * @return the title according to the given locale
2076     */
2077    protected String getLocaleSpecificTitle(Locale locale) {
2078
2079        String result = null;
2080
2081        try {
2082
2083            if (isDetailRequest()) {
2084                // this is a request to a detail page
2085                CmsResource res = getDetailContent();
2086                CmsFile file = m_cms.readFile(res);
2087                CmsXmlContent content = CmsXmlContentFactory.unmarshal(m_cms, file);
2088                result = content.getHandler().getTitleMapping(m_cms, content, m_cms.getRequestContext().getLocale());
2089                if (result == null) {
2090                    // title not found, maybe no mapping OR not available in the current locale
2091                    // read the title of the detail resource as fall back (may contain mapping from another locale)
2092                    result = m_cms.readPropertyObject(
2093                        res,
2094                        CmsPropertyDefinition.PROPERTY_TITLE,
2095                        false,
2096                        locale).getValue();
2097                }
2098            }
2099            if (result == null) {
2100                // read the title of the requested resource as fall back
2101                result = m_cms.readPropertyObject(
2102                    m_cms.getRequestContext().getUri(),
2103                    CmsPropertyDefinition.PROPERTY_TITLE,
2104                    true,
2105                    locale).getValue();
2106            }
2107        } catch (CmsException e) {
2108            LOG.debug(e.getLocalizedMessage(), e);
2109        }
2110        if (CmsStringUtil.isEmptyOrWhitespaceOnly(result)) {
2111            result = "";
2112        }
2113
2114        return result;
2115    }
2116
2117    /**
2118     * Returns the parent element if available.<p>
2119     *
2120     * @param element the element
2121     *
2122     * @return the parent element or null
2123     */
2124    protected CmsContainerElementBean getParentElement(CmsContainerElementBean element) {
2125
2126        if (m_elementInstances == null) {
2127            initPageData();
2128        }
2129        CmsContainerElementBean parent = null;
2130        CmsContainerBean cont = m_parentContainers.get(element.getInstanceId());
2131        if ((cont != null) && cont.isNestedContainer()) {
2132            parent = m_elementInstances.get(cont.getParentInstanceId());
2133        }
2134        return parent;
2135    }
2136
2137    /**
2138     * Reads a dynamic function bean, given its name in the module configuration.<p>
2139     *
2140     * @param configuredName the name of the dynamic function in the module configuration
2141     * @return the dynamic function bean for the dynamic function configured under that name
2142     *
2143     * @throws CmsException if something goes wrong
2144     */
2145    protected CmsDynamicFunctionBean readDynamicFunctionBean(String configuredName) throws CmsException {
2146
2147        CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
2148            m_cms,
2149            m_cms.addSiteRoot(m_cms.getRequestContext().getUri()));
2150        CmsFunctionReference functionRef = config.getFunctionReference(configuredName);
2151        if (functionRef == null) {
2152            return null;
2153        }
2154        CmsDynamicFunctionParser parser = new CmsDynamicFunctionParser();
2155        CmsResource functionResource = m_cms.readResource(functionRef.getStructureId());
2156        CmsDynamicFunctionBean result = parser.parseFunctionBean(m_cms, functionResource);
2157        return result;
2158    }
2159
2160    /**
2161     * Adds the mappings of the given formatter configuration.<p>
2162     *
2163     * @param formatterBean the formatter bean
2164     * @param elementId the element content structure id
2165     * @param resolver The macro resolver used on key and default value of the mappings
2166     * @param isDetailContent in case of a detail content
2167     */
2168    private void addMappingsForFormatter(
2169        I_CmsFormatterBean formatterBean,
2170        CmsUUID elementId,
2171        CmsMacroResolver resolver,
2172        boolean isDetailContent) {
2173
2174        if ((formatterBean != null) && (formatterBean.getMetaMappings() != null)) {
2175            for (CmsMetaMapping map : formatterBean.getMetaMappings()) {
2176                String key = map.getKey();
2177                key = resolver.resolveMacros(key);
2178                // the detail content mapping overrides other mappings
2179                if (isDetailContent
2180                    || !m_metaMappings.containsKey(key)
2181                    || (m_metaMappings.get(key).m_order <= map.getOrder())) {
2182                    MetaMapping mapping = new MetaMapping();
2183                    mapping.m_key = key;
2184                    mapping.m_elementXPath = map.getElement();
2185                    mapping.m_defaultValue = resolver.resolveMacros(map.getDefaultValue());
2186                    mapping.m_order = map.getOrder();
2187                    mapping.m_contentId = elementId;
2188                    m_metaMappings.put(key, mapping);
2189                }
2190            }
2191        }
2192    }
2193
2194    /**
2195     * Clears the page element data.<p>
2196     */
2197    private void clearPageData() {
2198
2199        m_elementInstances = null;
2200        m_parentContainers = null;
2201    }
2202
2203    /**
2204     * Returns the container page bean for the give resource.<p>
2205     *
2206     * @param pageResource the resource
2207     *
2208     * @return the container page bean
2209     *
2210     * @throws CmsException in case reading the page bean fails
2211     */
2212    private CmsContainerPageBean getPage(CmsResource pageResource) throws CmsException {
2213
2214        CmsContainerPageBean result = null;
2215        if ((pageResource != null) && CmsResourceTypeXmlContainerPage.isContainerPage(pageResource)) {
2216            CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(m_cms, pageResource, m_request);
2217            result = xmlContainerPage.getContainerPage(m_cms);
2218            CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
2219                m_cms,
2220                OpenCms.getADEManager().lookupConfiguration(m_cms, pageResource.getRootPath()),
2221                CmsJspTagEditable.isEditableRequest(m_request) && (m_request instanceof HttpServletRequest)
2222                ? CmsADESessionCache.getCache((HttpServletRequest)m_request, m_cms)
2223                : null,
2224                CmsContainerpageService.isEditingModelGroups(m_cms, pageResource));
2225            result = modelHelper.readModelGroups(xmlContainerPage.getContainerPage(m_cms));
2226        }
2227        return result;
2228    }
2229
2230    /**
2231     * Convenience method for getting a request attribute without an explicit cast.<p>
2232     *
2233     * @param name the attribute name
2234     * @return the request attribute
2235     */
2236    @SuppressWarnings("unchecked")
2237    private <A> A getRequestAttribute(String name) {
2238
2239        Object attribute = m_request.getAttribute(name);
2240
2241        return attribute != null ? (A)attribute : null;
2242    }
2243
2244    /**
2245     * Initializes the mapping configuration.<p>
2246     */
2247    private void initMetaMappings() {
2248
2249        if (m_metaMappings == null) {
2250            m_metaMappings = new HashMap<String, MetaMapping>();
2251            try {
2252                initPage();
2253                CmsMacroResolver resolver = new CmsMacroResolver();
2254                resolver.setKeepEmptyMacros(true);
2255                resolver.setCmsObject(m_cms);
2256                resolver.setMessages(OpenCms.getWorkplaceManager().getMessages(getLocale()));
2257                CmsResourceFilter filter = getIsEditMode()
2258                ? CmsResourceFilter.IGNORE_EXPIRATION
2259                : CmsResourceFilter.DEFAULT;
2260                for (CmsContainerBean container : m_page.getContainers().values()) {
2261                    for (CmsContainerElementBean element : container.getElements()) {
2262                        String settingsKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2263                        String formatterConfigId = element.getSettings() != null
2264                        ? element.getSettings().get(settingsKey)
2265                        : null;
2266                        I_CmsFormatterBean formatterBean = null;
2267                        if (CmsUUID.isValidUUID(formatterConfigId)) {
2268                            formatterBean = OpenCms.getADEManager().getCachedFormatters(
2269                                m_cms.getRequestContext().getCurrentProject().isOnlineProject()).getFormatters().get(
2270                                    new CmsUUID(formatterConfigId));
2271                        }
2272                        if ((formatterBean != null)
2273                            && formatterBean.useMetaMappingsForNormalElements()
2274                            && m_cms.existsResource(element.getId(), filter)) {
2275                            addMappingsForFormatter(formatterBean, element.getId(), resolver, false);
2276                        }
2277
2278                    }
2279                }
2280                if (getDetailContentId() != null) {
2281                    try {
2282                        CmsResource detailContent = m_cms.readResource(
2283                            getDetailContentId(),
2284                            CmsResourceFilter.ignoreExpirationOffline(m_cms));
2285                        CmsFormatterConfiguration config = OpenCms.getADEManager().lookupConfiguration(
2286                            m_cms,
2287                            m_cms.getRequestContext().getRootUri()).getFormatters(m_cms, detailContent);
2288                        for (I_CmsFormatterBean formatter : config.getDetailFormatters()) {
2289                            addMappingsForFormatter(formatter, getDetailContentId(), resolver, true);
2290                        }
2291                    } catch (CmsException e) {
2292                        LOG.error(
2293                            Messages.get().getBundle().key(
2294                                Messages.ERR_READING_REQUIRED_RESOURCE_1,
2295                                getDetailContentId()),
2296                            e);
2297                    }
2298                }
2299            } catch (Exception e) {
2300                LOG.error(e.getLocalizedMessage(), e);
2301            }
2302        }
2303    }
2304
2305    /**
2306     * Initializes the page element data.<p>
2307     */
2308    private void initPageData() {
2309
2310        m_elementInstances = new HashMap<String, CmsContainerElementBean>();
2311        m_parentContainers = new HashMap<String, CmsContainerBean>();
2312        if (m_page != null) {
2313            for (CmsContainerBean container : m_page.getContainers().values()) {
2314                for (CmsContainerElementBean element : container.getElements()) {
2315                    m_elementInstances.put(element.getInstanceId(), element);
2316                    m_parentContainers.put(element.getInstanceId(), container);
2317                    try {
2318                        if (element.isGroupContainer(m_cms) || element.isInheritedContainer(m_cms)) {
2319                            List<CmsContainerElementBean> children;
2320                            if (element.isGroupContainer(m_cms)) {
2321                                children = CmsJspTagContainer.getGroupContainerElements(
2322                                    m_cms,
2323                                    element,
2324                                    m_request,
2325                                    container.getType());
2326                            } else {
2327                                children = CmsJspTagContainer.getInheritedContainerElements(m_cms, element);
2328                            }
2329                            for (CmsContainerElementBean childElement : children) {
2330                                m_elementInstances.put(childElement.getInstanceId(), childElement);
2331                                m_parentContainers.put(childElement.getInstanceId(), container);
2332                            }
2333                        }
2334                    } catch (CmsException e) {
2335                        LOG.error(e.getLocalizedMessage(), e);
2336                    }
2337                }
2338            }
2339            // also add detail only data
2340            if (m_detailOnlyPage != null) {
2341                for (CmsContainerBean container : m_detailOnlyPage.getContainers().values()) {
2342                    for (CmsContainerElementBean element : container.getElements()) {
2343                        m_elementInstances.put(element.getInstanceId(), element);
2344                        m_parentContainers.put(element.getInstanceId(), container);
2345                    }
2346                }
2347            }
2348        }
2349    }
2350
2351}