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.ade.containerpage;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsElementView;
032import org.opencms.ade.configuration.CmsResourceTypeConfig;
033import org.opencms.ade.containerpage.inherited.CmsContainerConfigurationCache;
034import org.opencms.ade.containerpage.inherited.CmsInheritanceReference;
035import org.opencms.ade.containerpage.inherited.CmsInheritanceReferenceParser;
036import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState;
037import org.opencms.ade.containerpage.shared.CmsContainer;
038import org.opencms.ade.containerpage.shared.CmsContainerElement;
039import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
040import org.opencms.ade.containerpage.shared.CmsContainerElementData;
041import org.opencms.ade.containerpage.shared.CmsElementLockInfo;
042import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
043import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
044import org.opencms.ade.containerpage.shared.CmsFormatterConfigCollection;
045import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
046import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
047import org.opencms.configuration.CmsConfigurationException;
048import org.opencms.db.CmsResourceState;
049import org.opencms.file.CmsFile;
050import org.opencms.file.CmsObject;
051import org.opencms.file.CmsProperty;
052import org.opencms.file.CmsPropertyDefinition;
053import org.opencms.file.CmsRequestContext;
054import org.opencms.file.CmsResource;
055import org.opencms.file.CmsResourceFilter;
056import org.opencms.file.CmsUser;
057import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
058import org.opencms.file.types.CmsResourceTypeXmlContent;
059import org.opencms.file.types.I_CmsResourceType;
060import org.opencms.gwt.CmsDefaultResourceStatusProvider;
061import org.opencms.gwt.CmsIconUtil;
062import org.opencms.gwt.CmsVfsService;
063import org.opencms.gwt.shared.CmsAdditionalInfoBean;
064import org.opencms.gwt.shared.CmsListInfoBean;
065import org.opencms.gwt.shared.CmsPermissionInfo;
066import org.opencms.i18n.CmsMessageContainer;
067import org.opencms.i18n.CmsMessages;
068import org.opencms.jsp.util.CmsJspStandardContextBean;
069import org.opencms.jsp.util.CmsJspStandardContextBean.TemplateBean;
070import org.opencms.loader.CmsTemplateContextManager;
071import org.opencms.lock.CmsLock;
072import org.opencms.main.CmsException;
073import org.opencms.main.CmsLog;
074import org.opencms.main.OpenCms;
075import org.opencms.relations.CmsRelation;
076import org.opencms.relations.CmsRelationFilter;
077import org.opencms.relations.CmsRelationType;
078import org.opencms.search.galleries.CmsGallerySearch;
079import org.opencms.search.galleries.CmsGallerySearchResult;
080import org.opencms.util.CmsDateUtil;
081import org.opencms.util.CmsStringUtil;
082import org.opencms.util.CmsUUID;
083import org.opencms.workplace.CmsWorkplaceMessages;
084import org.opencms.workplace.editors.CmsWorkplaceEditorManager;
085import org.opencms.workplace.editors.directedit.CmsAdvancedDirectEditProvider;
086import org.opencms.workplace.editors.directedit.CmsDirectEditMode;
087import org.opencms.workplace.editors.directedit.I_CmsDirectEditProvider;
088import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
089import org.opencms.workplace.explorer.CmsResourceUtil;
090import org.opencms.xml.containerpage.CmsADESessionCache;
091import org.opencms.xml.containerpage.CmsContainerBean;
092import org.opencms.xml.containerpage.CmsContainerElementBean;
093import org.opencms.xml.containerpage.CmsContainerPageBean;
094import org.opencms.xml.containerpage.CmsFormatterConfiguration;
095import org.opencms.xml.containerpage.CmsGroupContainerBean;
096import org.opencms.xml.containerpage.CmsXmlContainerPage;
097import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
098import org.opencms.xml.containerpage.CmsXmlGroupContainer;
099import org.opencms.xml.containerpage.CmsXmlGroupContainerFactory;
100import org.opencms.xml.containerpage.I_CmsFormatterBean;
101import org.opencms.xml.content.CmsXmlContent;
102import org.opencms.xml.content.CmsXmlContentFactory;
103import org.opencms.xml.content.CmsXmlContentProperty;
104import org.opencms.xml.content.CmsXmlContentPropertyHelper;
105
106import java.io.IOException;
107import java.text.DateFormat;
108import java.util.ArrayList;
109import java.util.Collection;
110import java.util.Collections;
111import java.util.Date;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.LinkedHashMap;
115import java.util.LinkedHashSet;
116import java.util.List;
117import java.util.Locale;
118import java.util.Map;
119import java.util.Map.Entry;
120import java.util.Set;
121import java.util.function.Function;
122
123import javax.servlet.ServletException;
124import javax.servlet.http.HttpServletRequest;
125import javax.servlet.http.HttpServletResponse;
126
127import org.apache.commons.logging.Log;
128
129import org.jsoup.Jsoup;
130import org.jsoup.nodes.Document;
131import org.jsoup.select.Elements;
132
133import com.google.common.base.Supplier;
134import com.google.common.base.Suppliers;
135import com.google.common.collect.Sets;
136
137/**
138 * Utility class to generate the element data objects used within the container-page editor.<p>
139 *
140 * @since 8.0.0
141 */
142public class CmsElementUtil {
143
144    /** The maximum number of nested container levels. */
145    public static final int MAX_NESTING_LEVEL = 7;
146
147    /** Static reference to the log. */
148    private static final Log LOG = CmsLog.getLog(org.opencms.ade.containerpage.CmsElementUtil.class);
149
150    /** The ADE configuration data for the current page URI. */
151    private CmsADEConfigData m_adeConfig;
152
153    /** The cms context. */
154    private CmsObject m_cms;
155
156    /** The current page uri. */
157    private String m_currentPageUri;
158
159    /** The content locale. */
160    private Locale m_locale;
161
162    /** The current container page. */
163    private CmsResource m_page;
164
165    /** The request parameters to use while rendering the elements. */
166    @SuppressWarnings("unused")
167    private Map<String, Object> m_parameterMap;
168
169    /** The http request. */
170    private HttpServletRequest m_req;
171
172    /** The http response. */
173    private HttpServletResponse m_res;
174
175    /** The standard context bean. */
176    private CmsJspStandardContextBean m_standardContext;
177
178    /**
179     * Creates a new instance.<p>
180     * Use this constructor to set the current container page state.<p>
181     *
182     * @param cms the cms context
183     * @param currentPageUri the current page uri
184     * @param containerPage the container page bean with the current container state
185     * @param detailContentId the detail content structure id
186     * @param req the http request
187     * @param res the http response
188     * @param isDragMode if the page is in drag mode
189     * @param locale the content locale
190     *
191     * @throws CmsException if something goes wrong
192     */
193    public CmsElementUtil(
194        CmsObject cms,
195        String currentPageUri,
196        CmsContainerPageBean containerPage,
197        CmsUUID detailContentId,
198        HttpServletRequest req,
199        HttpServletResponse res,
200        boolean isDragMode,
201        Locale locale)
202    throws CmsException {
203
204        m_cms = OpenCms.initCmsObject(cms);
205        String contextPath = (String)cms.getRequestContext().getAttribute(CmsRequestContext.ATTRIBUTE_ADE_CONTEXT_PATH);
206        if (contextPath != null) {
207            m_cms.getRequestContext().setAttribute(CmsRequestContext.ATTRIBUTE_ADE_CONTEXT_PATH, contextPath);
208        }
209        m_req = req;
210        m_res = res;
211        m_currentPageUri = currentPageUri;
212        m_locale = locale;
213        // initializing request for standard context bean
214        req.setAttribute(CmsJspStandardContextBean.ATTRIBUTE_CMS_OBJECT, m_cms);
215        if (detailContentId != null) {
216            CmsResource detailRes = m_cms.readResource(
217                detailContentId,
218                CmsResourceFilter.ignoreExpirationOffline(m_cms));
219            req.setAttribute(CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE, detailRes);
220        }
221        m_standardContext = CmsJspStandardContextBean.getInstance(req);
222        m_page = m_cms.readResource(currentPageUri, CmsResourceFilter.ignoreExpirationOffline(cms));
223        m_standardContext.setPage(containerPage);
224        m_standardContext.setDragMode(isDragMode);
225    }
226
227    /**
228     * Creates a new instance.<p>
229     *
230     * @param cms the cms context
231     * @param currentPageUri the current page uri
232     * @param detailContentId the detail content structure id
233     * @param req the http request
234     * @param res the http response
235     * @param locale the content locale
236     *
237     * @throws CmsException if something goes wrong
238     */
239    public CmsElementUtil(
240        CmsObject cms,
241        String currentPageUri,
242        CmsUUID detailContentId,
243        HttpServletRequest req,
244        HttpServletResponse res,
245        Locale locale)
246    throws CmsException {
247
248        m_cms = OpenCms.initCmsObject(cms);
249        m_req = req;
250        m_res = res;
251        m_currentPageUri = currentPageUri;
252        m_locale = locale;
253        // initializing request for standard context bean
254        req.setAttribute(CmsJspStandardContextBean.ATTRIBUTE_CMS_OBJECT, m_cms);
255        if (detailContentId != null) {
256            CmsResource detailRes = m_cms.readResource(detailContentId, CmsResourceFilter.ignoreExpirationOffline(cms));
257            req.setAttribute(CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE, detailRes);
258        }
259        m_standardContext = CmsJspStandardContextBean.getInstance(req);
260        m_page = m_cms.readResource(currentPageUri);
261        CmsXmlContainerPage xmlContainerPage = CmsXmlContainerPageFactory.unmarshal(cms, m_page, req);
262        CmsContainerPageBean containerPage = xmlContainerPage.getContainerPage(cms);
263        m_standardContext.setPage(containerPage);
264    }
265
266    /**
267     * Creates a new instance.<p>
268     *
269     * @param cms the cms context
270     * @param currentPageUri the current page uri
271     * @param detailContentId the detail content structure id
272     * @param requestParameters the request parameters to use while rendering the elements
273     * @param req the http request
274     * @param res the http response
275     * @param locale the content locale
276     *
277     * @throws CmsException if something goes wrong
278     */
279    public CmsElementUtil(
280        CmsObject cms,
281        String currentPageUri,
282        CmsUUID detailContentId,
283        String requestParameters,
284        HttpServletRequest req,
285        HttpServletResponse res,
286        Locale locale)
287    throws CmsException {
288
289        this(cms, currentPageUri, detailContentId, req, res, locale);
290        m_parameterMap = parseRequestParameters(requestParameters);
291    }
292
293    /**
294     * Checks if a group element is allowed in a container with a given type.<p>
295     *
296     * @param containerType the container type spec (comma separated)
297     * @param groupContainer the group
298     *
299     * @return true if the group is allowed in the container
300     */
301    public static boolean checkGroupAllowed(String containerType, CmsGroupContainerBean groupContainer) {
302
303        return !Sets.intersection(CmsContainer.splitType(containerType), groupContainer.getTypes()).isEmpty();
304    }
305
306    /**
307     * Converts a client container bean to a server container bean.
308     *
309     * @param container the client container
310     * @param elements the elements of the container
311     * @return the server container bean
312     */
313    public static CmsContainerBean clientToServerContainer(
314        CmsContainer container,
315        List<CmsContainerElementBean> elements) {
316
317        return new CmsContainerBean(
318            container.getName(),
319            container.getType(),
320            container.getParentInstanceId(),
321            container.isRootContainer(),
322            container.getMaxElements(),
323            elements);
324
325    }
326
327    /**
328     * Helper method to create a string template source for a given formatter and content.
329     *
330     * @param formatter the formatter
331     * @param contentSupplier the content supplier
332     *
333     * @return the string template provider
334     */
335    public static Function<String, String> createStringTemplateSource(
336        I_CmsFormatterBean formatter,
337        Supplier<CmsXmlContent> contentSupplier) {
338
339        return key -> {
340            String result = null;
341            if (formatter != null) {
342                result = formatter.getAttributes().get(key);
343            }
344            if (result == null) {
345                CmsXmlContent content = contentSupplier.get();
346                if (content != null) {
347                    result = content.getHandler().getParameter(key);
348                }
349            }
350            return result;
351        };
352    }
353
354    /**
355     * Returns the formatter bean for the given element and container.<p>
356     *
357     * @param cms the cms context
358     * @param element the element to render
359     * @param container the container
360     * @param config the configuration data
361     * @param cache the session cache
362     *
363     * @return the formatter bean
364     */
365    public static I_CmsFormatterBean getFormatterForContainer(
366        CmsObject cms,
367        CmsContainerElementBean element,
368        CmsContainer container,
369        CmsADEConfigData config,
370        CmsADESessionCache cache) {
371
372        I_CmsFormatterBean formatter = null;
373        CmsFormatterConfiguration formatterSet = config.getFormatters(cms, element.getResource());
374        Map<String, I_CmsFormatterBean> formatters = formatterSet.getFormatterSelectionByKeyOrId(
375            container.getType(),
376            container.getWidth());
377        String formatterId = element.getIndividualSettings().get(
378            CmsFormatterConfig.getSettingsKeyForContainer(container.getName()));
379        if (formatterId != null) {
380            I_CmsFormatterBean dynamicFmt = config.findFormatter(formatterId);
381            if (dynamicFmt != null) {
382                formatter = dynamicFmt;
383            } else {
384                formatter = formatters.get(formatterId);
385            }
386        }
387        if (formatter == null) {
388            formatterId = element.getIndividualSettings().get(CmsFormatterConfig.FORMATTER_SETTINGS_KEY);
389            if (formatterId != null) {
390                formatter = lookupFormatter(config, formatterId, formatters);
391            }
392        }
393        if (formatter == null) {
394            // check for formatter config id stored for other containers matching the current container
395            for (Entry<String, String> settingsEntry : element.getIndividualSettings().entrySet()) {
396                if (settingsEntry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
397                    formatter = lookupFormatter(config, settingsEntry.getValue(), formatters);
398                    if (formatter != null) {
399                        break;
400                    }
401                }
402            }
403        }
404        if ((formatter == null) && (element.getFormatterId() != null)) {
405            for (I_CmsFormatterBean currentFormatter : formatters.values()) {
406                if ((currentFormatter.getJspStructureId() != null)
407                    && currentFormatter.getJspStructureId().equals(element.getFormatterId())) {
408                    formatter = currentFormatter;
409                    break;
410                }
411            }
412        }
413        if (formatter == null) {
414            formatter = getStartFormatter(cms, container, config, element, cache);
415        }
416        return formatter;
417    }
418
419    /**
420     * Gets the ids for the current page and potentially detail-only containers.
421     * @param cms the CMS context
422     * @param pageId the id for the current page
423     * @param detailContent the current detail content
424     * @return the set of ids for the current page and detail-only containers
425     */
426    public static Set<CmsUUID> getPageAndDetailOnlyIds(CmsObject cms, CmsUUID pageId, CmsResource detailContent) {
427
428        Set<CmsUUID> result = new HashSet<>();
429        result.add(pageId);
430        if (detailContent != null) {
431            for (CmsResource detailOnlyRes : CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, detailContent)) {
432                result.add(detailOnlyRes.getStructureId());
433            }
434        }
435        return result;
436    }
437
438    /**
439     * Checks if the given setting name is a system setting.
440     *
441     * @param name the setting name
442     * @return true if the name corresponds to a system setting
443     */
444    public static final boolean isSystemSetting(String name) {
445
446        if (CmsXmlContainerPage.LEGACY_SYSTEM_SETTING_NAMES.contains(name)
447            || CmsContainerElement.ELEMENT_INSTANCE_ID.equals(name)
448            || name.startsWith(CmsXmlContainerPage.SYSTEM_SETTING_PREFIX)
449            || name.startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
450            return true;
451        }
452        return false;
453    }
454
455    /**
456     * Returns the start formatter for a newly dropped element.<p>
457     * This will be either the least recently used matching formatter or the default formatter.<p>
458     *
459     * @param cms the cms context
460     * @param cnt the container
461     * @param configData the configuration data
462     * @param element the container element
463     * @param cache the session cache
464     *
465     * @return the formatter bean
466     */
467    private static I_CmsFormatterBean getStartFormatter(
468        CmsObject cms,
469        CmsContainer cnt,
470        CmsADEConfigData configData,
471        CmsContainerElementBean element,
472        CmsADESessionCache cache) {
473
474        I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
475        I_CmsFormatterBean formatter = cache.getRecentFormatter(type.getTypeName(), cnt, configData);
476        if (formatter == null) {
477            formatter = configData.getFormatters(cms, element.getResource()).getDefaultFormatter(
478                cnt.getType(),
479                cnt.getWidth());
480        }
481        return formatter;
482    }
483
484    /**
485     * Helper method for looking up the correct formatter for an element.
486     *
487     * @param config the sitemap config
488     * @param keyOrId the key or id of the formatter stored with the container element
489     * @param active map of active formatters by key or id
490     *
491     * @return the formatter with the given key or id
492     */
493    private static I_CmsFormatterBean lookupFormatter(
494        CmsADEConfigData config,
495        String keyOrId,
496        Map<String, I_CmsFormatterBean> active) {
497
498        I_CmsFormatterBean dynamicFmt = config.findFormatter(keyOrId);
499        if (dynamicFmt != null) {
500            for (String key : new String[] {dynamicFmt.getKey(), dynamicFmt.getId(), keyOrId}) {
501                if ((key != null) && (active.get(key) != null)) {
502                    return active.get(key);
503                }
504            }
505            return null;
506        } else {
507            // schema formatters
508            return active.get(keyOrId);
509        }
510    }
511
512    /**
513     * Returns the HTML content for the given resource and container.<p>
514     *
515     * @param elementFile the element resource file
516     * @param elementId the element id
517     * @param container the container
518     *
519     * @return the HTML content
520     */
521    public String getContentByContainer(CmsFile elementFile, String elementId, CmsContainer container) {
522
523        CmsContainerElementBean element = CmsADESessionCache.getCache(m_req, m_cms).getCacheContainerElement(elementId);
524        element = element.clone();
525        element.setTemporaryFile(elementFile);
526        CmsFormatterConfiguration configs = getFormatterConfiguration(element.getResource());
527        return getContentByContainer(element, container, configs);
528    }
529
530    /**
531     * Returns the data for an element.<p>
532     *
533     * @param page the current container page
534     * @param element the resource
535     * @param containers the containers on the current container page
536     *
537     * @return the data for an element
538     *
539     * @throws CmsException if something goes wrong
540     */
541    public CmsContainerElementData getElementData(
542        CmsResource page,
543        CmsContainerElementBean element,
544        Collection<CmsContainer> containers)
545    throws CmsException {
546
547        Locale requestLocale = m_cms.getRequestContext().getLocale();
548        m_cms.getRequestContext().setLocale(m_locale);
549        element.initResource(m_cms);
550        if (element.getResource().isFolder()) {
551            return null;
552        }
553        boolean typeDisabled = false;
554        boolean createDisabled = false;
555        if (page != null) {
556
557            CmsADEConfigData config = OpenCms.getADEManager().lookupConfigurationWithCache(m_cms, page.getRootPath());
558            String typeName = OpenCms.getResourceManager().getResourceType(element.getResource()).getTypeName();
559            if (!config.getAddableTypeNames().contains(typeName)) {
560                typeDisabled = true;
561            }
562            CmsResourceTypeConfig typeConfig = config.getTypesByName().get(typeName);
563            if ((typeConfig == null) || typeConfig.isCreateDisabled()) {
564                createDisabled = true;
565            }
566        }
567
568        CmsContainerElementData elementData = getBaseElementData(page, element);
569        elementData.setAddDisabled(typeDisabled);
570        elementData.setCopyDisabled(createDisabled);
571        CmsFormatterConfiguration formatterConfiguraton = getFormatterConfiguration(element.getResource());
572        Map<String, String> contents = new HashMap<String, String>();
573        if (element.isGroupContainer(m_cms)) {
574            Map<String, CmsContainer> containersByName = new HashMap<String, CmsContainer>();
575            for (CmsContainer container : containers) {
576                containersByName.put(container.getName(), container);
577            }
578            CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(
579                m_cms,
580                element.getResource(),
581                m_req);
582            CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(m_cms);
583            // make sure to use the content title and not the property title
584            elementData.setTitle(groupContainer.getTitle());
585            elementData.setTypes(groupContainer.getTypes());
586            elementData.setDescription(groupContainer.getDescription());
587            if (groupContainer.getTypes().isEmpty()) {
588                if (groupContainer.getElements().isEmpty()) {
589                    String emptySub = "<div>NEW AND EMPTY</div>";
590                    for (CmsContainer cont : containersByName.values()) {
591                        if (formatterConfiguraton.hasFormatter(cont.getType(), cont.getWidth())) {
592                            contents.put(cont.getName(), emptySub);
593                        }
594                    }
595                } else {
596                    // TODO: throw appropriate exception
597                    return null;
598                }
599            } else {
600
601                // add formatter and content entries for the supported types
602                for (CmsContainer cnt : containersByName.values()) {
603
604                    String type = cnt.getType();
605                    if (checkGroupAllowed(type, groupContainer)) {
606                        contents.put(cnt.getName(), "<div>should not be used</div>");
607                    }
608                }
609            }
610            // add subitems
611            List<String> subItems = new ArrayList<String>();
612
613            for (CmsContainerElementBean subElement : groupContainer.getElements()) {
614                // collect ids
615                subItems.add(subElement.editorHash());
616            }
617            elementData.setSubItems(subItems);
618        } else if (element.isInheritedContainer(m_cms)) {
619            CmsInheritanceReferenceParser parser = new CmsInheritanceReferenceParser(m_cms);
620            parser.parse(element.getResource());
621            CmsInheritanceReference ref = parser.getReference(m_locale);
622            String name = null;
623            // check for new inheritance reference
624            if (ref != null) {
625                name = ref.getName();
626                elementData.setDescription(ref.getDescription());
627                elementData.setTitle(ref.getTitle());
628            }
629            for (CmsContainer container : containers) {
630                if (formatterConfiguraton.hasFormatter(container.getType(), container.getWidth())) {
631                    contents.put(container.getName(), "<div>should not be used</div>");
632                }
633            }
634
635            List<CmsInheritanceInfo> inheritanceInfos = new ArrayList<CmsInheritanceInfo>();
636            if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(name)) {
637                CmsInheritedContainerState result = OpenCms.getADEManager().getInheritedContainerState(
638                    m_cms,
639                    m_cms.addSiteRoot(m_currentPageUri),
640                    name);
641                for (CmsContainerElementBean subElement : result.getElements(true)) {
642                    CmsInheritanceInfo inheritanceInfo = subElement.getInheritanceInfo();
643                    inheritanceInfo.setClientId(subElement.editorHash());
644                    inheritanceInfos.add(inheritanceInfo);
645                }
646            } else {
647                // setting a new id for name, will be persisted once the inheritance reference is edited and saved.
648                // use the structure id so it will always be the same for the resource
649                name = element.getResource().getStructureId().toString();
650            }
651            elementData.setInheritanceInfos(inheritanceInfos);
652            elementData.setInheritanceName(name);
653        } else {
654            for (CmsContainer cnt : containers) {
655                boolean missesFormatterSetting = !elementData.getSettings().containsKey(
656                    CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()));
657                if (missesFormatterSetting) {
658                    if (element.getFormatterId() == null) {
659                        I_CmsFormatterBean formatter = getStartFormatter(
660                            m_cms,
661                            cnt,
662                            m_adeConfig,
663                            element,
664                            CmsADESessionCache.getCache(m_req, m_cms));
665                        if (formatter != null) {
666                            elementData.getSettings().put(
667                                CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()),
668                                formatter.getId());
669                            element.addFormatterSetting(cnt.getName(), formatter.getKeyOrId());
670                        }
671                    } else {
672                        Map<String, I_CmsFormatterBean> formatterSelection = formatterConfiguraton.getFormatterSelection(
673                            cnt.getType(),
674                            cnt.getWidth());
675                        for (Entry<String, I_CmsFormatterBean> formatterEntry : formatterSelection.entrySet()) {
676                            I_CmsFormatterBean formatter = formatterEntry.getValue();
677                            if (element.getFormatterId().equals(formatter.getJspStructureId())) {
678                                elementData.getSettings().put(
679                                    CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()),
680                                    formatter.getKeyOrId());
681                                break;
682                            }
683                        }
684                    }
685                }
686            }
687            // get the formatter configuration
688            Map<String, String> contentsByName = getContentsByContainerName(element, containers);
689            contents = contentsByName;
690        }
691        CmsListInfoBean listInfo = CmsVfsService.getPageInfo(m_cms, element.getResource());
692        elementData.setListInfo(listInfo);
693        elementData.setContents(contents);
694        m_cms.getRequestContext().setLocale(requestLocale);
695        return elementData;
696    }
697
698    /**
699     * Returns the formatter and settings config data for an element.<p>
700     *
701     * @param page the current container page
702     * @param element the resource
703     * @param containerId the parent container id
704     * @param containers the containers on the current container page
705     *
706     * @return the data for an element
707     *
708     * @throws CmsException if something goes wrong
709     */
710    public CmsElementSettingsConfig getElementSettingsConfig(
711        CmsResource page,
712        CmsContainerElementBean element,
713        String containerId,
714        Collection<CmsContainer> containers)
715    throws CmsException {
716
717        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
718        CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache(m_cms, page.getRootPath());
719        boolean isCopyGroup = CmsResourceTypeXmlContainerPage.isModelCopyGroup(m_cms, page);
720        Locale requestLocale = m_cms.getRequestContext().getLocale();
721        m_cms.getRequestContext().setLocale(m_locale);
722        element.initResource(m_cms);
723        if (element.getResource().isFolder()) {
724            return null;
725        }
726        String schema = null;
727        try {
728            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
729            schema = type.getConfiguration().getString("schema", null);
730        } catch (Exception e) {
731            LOG.error(e.getLocalizedMessage(), e);
732        }
733        CmsContainerElementData elementData = getBaseElementData(page, element);
734
735        Map<String, String> settingUpdates = new HashMap<>();
736        for (Map.Entry<String, String> entry : elementData.getSettings().entrySet()) {
737            int underscorePos = entry.getKey().indexOf("_");
738            if ((underscorePos >= 0) && !isSystemSetting(entry.getKey())) {
739                String prefix = entry.getKey().substring(0, underscorePos);
740                I_CmsFormatterBean dynamicFmt = adeConfig.findFormatter(prefix, true);
741
742                if (CmsUUID.isValidUUID(prefix)) {
743                    // If we already have a formatter referenced by name, we don't need to do anything
744                    if ((dynamicFmt != null) && (dynamicFmt.getKey() != null)) {
745                        // Replace setting prefix with formatter key
746                        String newSettingName = dynamicFmt.getKey() + entry.getKey().substring(underscorePos);
747                        settingUpdates.put(newSettingName, entry.getValue());
748                        settingUpdates.put(entry.getKey(), null);
749                    }
750                }
751            }
752
753            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
754                String value = entry.getValue();
755                if (CmsUUID.isValidUUID(value)) {
756                    I_CmsFormatterBean dynamicFmt = adeConfig.findFormatter(value);
757                    if ((dynamicFmt != null) && (dynamicFmt.getKey() != null)) {
758                        settingUpdates.put(entry.getKey(), dynamicFmt.getKey());
759                    }
760                }
761            }
762        }
763        for (String key : settingUpdates.keySet()) {
764            String value = settingUpdates.get(key);
765            if (value == null) {
766                elementData.getSettings().remove(key);
767            } else {
768                elementData.getSettings().put(key, value);
769            }
770        }
771        Supplier<CmsXmlContent> contentSupplier = Suppliers.memoize(() -> {
772            try {
773                return CmsXmlContentFactory.unmarshal(m_cms, m_cms.readFile(element.getResource()));
774            } catch (CmsException e) {
775                LOG.error(e.getLocalizedMessage(), e);
776                return null;
777            }
778        });
779        I_CmsFormatterBean foundFormatter = null;
780
781        if (!element.isGroupContainer(m_cms) && !element.isInheritedContainer(m_cms)) {
782            CmsFormatterConfiguration formatterConfiguraton = getFormatterConfiguration(element.getResource());
783            Map<String, CmsFormatterConfigCollection> formatters = new HashMap<String, CmsFormatterConfigCollection>();
784            for (CmsContainer cnt : containers) {
785                if (cnt.getName().equals(containerId)) {
786                    CmsFormatterConfigCollection containerFormatters = new CmsFormatterConfigCollection();
787                    String foundFormatterKey = null;
788                    for (String containerName : new String[] {cnt.getName(), ""}) {
789                        foundFormatterKey = elementData.getSettings().get(
790                            CmsFormatterConfig.getSettingsKeyForContainer(containerName));
791                        if (foundFormatterKey != null) {
792                            break;
793                        }
794                    }
795                    boolean missesFormatterSetting = (foundFormatterKey == null);
796                    if (!missesFormatterSetting) {
797                        foundFormatter = adeConfig.findFormatter(foundFormatterKey);
798                    }
799                    Map<String, I_CmsFormatterBean> formatterSelection = formatterConfiguraton.getFormatterSelection(
800                        cnt.getType(),
801                        cnt.getWidth());
802                    for (Entry<String, I_CmsFormatterBean> formatterEntry : formatterSelection.entrySet()) {
803                        I_CmsFormatterBean formatter = formatterEntry.getValue();
804                        String id = formatterEntry.getValue().getId();
805                        if (missesFormatterSetting
806                            && ((element.getFormatterId() == null)
807                                || element.getFormatterId().equals(formatter.getJspStructureId()))) {
808                            elementData.getSettings().put(
809                                CmsFormatterConfig.getSettingsKeyForContainer(cnt.getName()),
810                                id);
811                            missesFormatterSetting = false;
812                        }
813                        String label = formatter.getNiceName(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms));
814                        if (formatterEntry.getKey().startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)) {
815                            label = Messages.get().getBundle().key(Messages.GUI_SCHEMA_FORMATTER_LABEL_0)
816                                + " ["
817                                + CmsResource.getName(formatter.getJspRootPath())
818                                + "]";
819                        }
820                        if (CmsStringUtil.isEmptyOrWhitespaceOnly(label)) {
821                            label = id;
822                        }
823                        CmsFormatterConfig config = new CmsFormatterConfig(id);
824                        Set<String> cssResources = new LinkedHashSet<String>();
825                        for (String cssSitePath : formatter.getCssHeadIncludes()) {
826                            cssResources.add(OpenCms.getLinkManager().getOnlineLink(m_cms, cssSitePath));
827                        }
828                        config.setCssResources(cssResources);
829                        config.setInlineCss(formatter.getInlineCss());
830                        config.setKey(formatter.getKey());
831                        config.setLabel(label);
832                        config.setDescription(
833                            formatter.getDescription(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms)));
834                        Map<String, CmsXmlContentProperty> settingsConfig = OpenCms.getADEManager().getFormatterSettings(
835                            m_cms,
836                            adeConfig,
837                            formatter,
838                            element.getResource(),
839                            m_locale,
840                            m_req);
841                        Function<String, String> templateSource = createStringTemplateSource(
842                            formatter,
843                            contentSupplier);
844                        settingsConfig = CmsXmlContentPropertyHelper.resolveMacrosForPropertyInfo(
845                            m_cms,
846                            page,
847                            element.getResource(),
848                            contentSupplier,
849                            templateSource,
850                            settingsConfig);
851                        config.setSettingConfig(settingsConfig);
852                        List<I_CmsFormatterBean> nestedFormatters = OpenCms.getADEManager().getNestedFormatters(
853                            m_cms,
854                            adeConfig,
855                            element.getResource(),
856                            m_locale,
857                            m_req);
858                        if ((nestedFormatters != null) && !nestedFormatters.isEmpty()) {
859                            Map<String, String> settingPrefixes = new LinkedHashMap<String, String>();
860                            for (I_CmsFormatterBean nested : nestedFormatters) {
861                                String sectionLabel = nested.getNiceName(
862                                    OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms));
863                                settingPrefixes.put(nested.getId(), sectionLabel);
864                                if (nested.getKey() != null) {
865                                    settingPrefixes.put(nested.getKey() + "_", sectionLabel);
866                                }
867                            }
868                            config.setNestedFormatterPrefixes(settingPrefixes);
869                        }
870
871                        config.setJspRootPath(formatter.getJspRootPath());
872                        containerFormatters.add(config);
873                    }
874                    formatters.put(cnt.getName(), containerFormatters);
875                }
876            }
877            elementData.setFormatters(formatters);
878        }
879
880        m_cms.getRequestContext().setLocale(requestLocale);
881        ArrayList<CmsAdditionalInfoBean> infos = new ArrayList<>();
882
883        CmsResource resource = element.getResource();
884        String resTypeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
885        CmsExplorerTypeSettings cmsExplorerTypeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
886            resTypeName);
887        if (null == cmsExplorerTypeSettings) {
888            CmsMessageContainer errMsg = org.opencms.gwt.Messages.get().container(
889                org.opencms.gwt.Messages.ERR_EXPLORER_TYPE_SETTINGS_FOR_RESOURCE_TYPE_NOT_FOUND_3,
890                resource.getRootPath(),
891                resTypeName,
892                Integer.valueOf(resource.getTypeId()));
893            throw new CmsConfigurationException(errMsg);
894        }
895        String key = cmsExplorerTypeSettings.getKey();
896        Locale currentLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
897        CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(currentLocale);
898        String resTypeNiceName = messages.key(key);
899        infos.add(
900            new CmsAdditionalInfoBean(
901                messages.key(org.opencms.workplace.commons.Messages.GUI_LABEL_TYPE_0),
902                resTypeNiceName,
903                null));
904
905        try {
906            CmsRelationFilter filter = CmsRelationFilter.relationsFromStructureId(
907                element.getResource().getStructureId()).filterType(CmsRelationType.XSD);
908            for (CmsRelation relation : m_cms.readRelations(filter)) {
909                CmsResource target = relation.getTarget(m_cms, CmsResourceFilter.IGNORE_EXPIRATION);
910                String label = Messages.get().getBundle(wpLocale).key(Messages.GUI_ADDINFO_SCHEMA_0);
911                infos.add(new CmsAdditionalInfoBean(label, target.getRootPath(), null));
912                break;
913            }
914        } catch (CmsException e) {
915            LOG.error(e.getLocalizedMessage(), e);
916        }
917        if (foundFormatter != null) {
918            Map<String, String> formatterInfo = CmsDefaultResourceStatusProvider.getFormatterInfo(
919                m_cms,
920                foundFormatter);
921            for (Map.Entry<String, String> entry : formatterInfo.entrySet()) {
922                infos.add(new CmsAdditionalInfoBean(entry.getKey(), entry.getValue(), null));
923            }
924        }
925
926        CmsResourceState state = element.getResource().getState();
927        return new CmsElementSettingsConfig(elementData, state, infos, schema, isCopyGroup);
928    }
929
930    /**
931     * Gets the container page.<p>
932     *
933     * @return the container page resource
934     */
935    public CmsResource getPage() {
936
937        return m_page;
938    }
939
940    /**
941     * Sets the data to the given container element.<p>
942     *
943     * @param elementBean the element bean
944     * @param result the container element to set the data to
945     *
946     * @return the container element
947     *
948     * @throws CmsException if something goes wrong
949     */
950    public CmsContainerElement setElementInfo(CmsContainerElementBean elementBean, CmsContainerElement result)
951    throws CmsException {
952
953        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms);
954        // reinitializing resource to avoid caching issues
955        elementBean.initResource(m_cms);
956        CmsResource resource = elementBean.getResource();
957        boolean isModelGroup = elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID);
958        if (isModelGroup) {
959            CmsUUID groupId = new CmsUUID(elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID));
960            resource = m_cms.readResource(groupId, CmsResourceFilter.IGNORE_EXPIRATION);
961        }
962
963        boolean newEditorDisabled = !CmsWorkplaceEditorManager.checkAcaciaEditorAvailable(
964            m_cms,
965            elementBean.getResource());
966        result.setNewEditorDisabled(newEditorDisabled);
967        I_CmsResourceType resourceType = OpenCms.getResourceManager().getResourceType(resource);
968        String typeName = resourceType.getTypeName();
969        result.setHasEditHandler(
970            (resourceType instanceof CmsResourceTypeXmlContent)
971                && (((CmsResourceTypeXmlContent)resourceType).getEditHandler(m_cms) != null));
972        result.setResourceType(typeName);
973        result.setIconClasses(
974            CmsIconUtil.getIconClasses(
975                CmsIconUtil.getDisplayType(m_cms, resource),
976                elementBean.getResource().getName(),
977                false));
978        CmsPermissionInfo permissionInfo;
979        String title;
980        String subTitle;
981        if (!elementBean.isInMemoryOnly()) {
982            CmsElementLockInfo lockInfo = getLockInfo(m_cms, resource);
983            result.setLockInfo(lockInfo);
984            permissionInfo = OpenCms.getADEManager().getPermissionInfo(m_cms, resource, m_page.getRootPath());
985            if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
986                if (CmsStringUtil.isEmptyOrWhitespaceOnly(permissionInfo.getNoEditReason())
987                    && elementBean.isInheritedContainer(m_cms)) {
988                    String requestUri = m_cms.getRequestContext().getUri();
989                    String folderPath = CmsResource.getFolderPath(requestUri);
990                    String configPath = CmsStringUtil.joinPaths(
991                        folderPath,
992                        CmsContainerConfigurationCache.INHERITANCE_CONFIG_FILE_NAME);
993                    if (m_cms.existsResource(configPath)) {
994                        permissionInfo.setNoEditReason(
995                            new CmsResourceUtil(m_cms, m_cms.readResource(configPath)).getNoEditReason(wpLocale, true));
996                    } else {
997                        if (!m_cms.getLock(folderPath).isLockableBy(m_cms.getRequestContext().getCurrentUser())) {
998                            permissionInfo.setNoEditReason(
999                                org.opencms.workplace.explorer.Messages.get().getBundle(wpLocale).key(
1000                                    org.opencms.workplace.explorer.Messages.GUI_NO_EDIT_REASON_LOCK_1,
1001                                    new CmsResourceUtil(m_cms, m_cms.readResource(folderPath)).getLockedByName()));
1002                        }
1003                    }
1004                }
1005            } else {
1006                permissionInfo.setNoEditReason(
1007                    Messages.get().getBundle(wpLocale).key(Messages.GUI_ELEMENT_RESOURCE_CAN_NOT_BE_EDITED_0));
1008            }
1009
1010            try {
1011                CmsProperty namePatternProp = m_cms.readPropertyObject(
1012                    resource,
1013                    CmsPropertyDefinition.PROPERTY_CONTENT_NAME_PATTERN,
1014                    true);
1015                String namePattern = namePatternProp.getValue();
1016                if ((namePattern != null) && !"none".equals(namePattern)) {
1017                    result.setHasNamePatternProperty(true);
1018                }
1019            } catch (CmsException e) {
1020                LOG.error(e.getLocalizedMessage(), e);
1021            }
1022
1023            CmsGallerySearchResult searchResult = CmsGallerySearch.searchById(
1024                m_cms,
1025                resource.getStructureId(),
1026                m_locale);
1027            title = searchResult.getTitle();
1028            if (CmsStringUtil.isEmptyOrWhitespaceOnly(title)) {
1029                resource.getName();
1030            }
1031            subTitle = searchResult.getUserLastModified();
1032            Date lastModDate = searchResult.getDateLastModified();
1033            if (lastModDate != null) {
1034                subTitle += " / " + CmsDateUtil.getDateTime(lastModDate, DateFormat.MEDIUM, wpLocale);
1035            }
1036        } else {
1037            permissionInfo = new CmsPermissionInfo(true, true, "");
1038            title = CmsWorkplaceMessages.getResourceTypeName(wpLocale, typeName);
1039            subTitle = CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, typeName);
1040        }
1041        result.setTitle(title);
1042        result.setSubTitle(subTitle);
1043        result.setClientId(elementBean.editorHash());
1044        result.setSitePath(m_cms.getSitePath(resource));
1045
1046        result.setCreateNew(elementBean.isCreateNew());
1047        CmsResourceTypeConfig typeConfig = getConfigData().getResourceType(typeName);
1048        if (!elementBean.isInMemoryOnly() && (typeConfig != null)) {
1049            result.setCopyInModels(typeConfig.isCopyInModels());
1050            if (typeConfig.isCheckReuse()) {
1051                final Set<CmsUUID> pageAndAttachments = getPageAndDetailOnlyIds();
1052                boolean reused = OpenCms.getADEManager().isElementReused(
1053                    resource,
1054                    res -> pageAndAttachments.contains(res.getStructureId()));
1055                result.setReused(reused);
1056            }
1057        }
1058
1059        Map<CmsUUID, CmsElementView> viewMap = OpenCms.getADEManager().getElementViews(m_cms);
1060
1061        boolean isModelGroupEditing = CmsModelGroupHelper.isModelGroupResource(m_page);
1062        if (!isModelGroup
1063            && isModelGroupEditing
1064            && elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE)
1065            && (ModelGroupState.isModelGroup == ModelGroupState.evaluate(
1066                elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE)))) {
1067            isModelGroup = true;
1068        }
1069        if (!isModelGroupEditing && isModelGroup) {
1070            CmsResourceTypeConfig modelGroupConfig = getConfigData().getResourceType(
1071                CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME);
1072            if (modelGroupConfig != null) {
1073                CmsUUID elementView = modelGroupConfig.getElementView();
1074                CmsElementView viewObject = viewMap.get(elementView);
1075                if ((viewObject != null) && (viewObject.getParentViewId() != null)) {
1076                    elementView = viewObject.getParentViewId();
1077                }
1078                result.setElementView(elementView);
1079            }
1080        } else if (typeConfig != null) {
1081            CmsUUID elementView = typeConfig.getElementView();
1082            CmsElementView viewObject = viewMap.get(elementView);
1083            if ((viewObject != null) && (viewObject.getParentViewId() != null)) {
1084                elementView = viewObject.getParentViewId();
1085            }
1086            result.setElementView(elementView);
1087        }
1088        if (CmsStringUtil.isEmptyOrWhitespaceOnly(permissionInfo.getNoEditReason())
1089            && ((typeConfig == null) || typeConfig.isEditDisabled())) {
1090            String message = Messages.get().getBundle(wpLocale).key(
1091                Messages.GUI_CONTAINERPAGE_EDIT_DISABLED_BY_SITEMAP_CONFIG_0);
1092            permissionInfo.setNoEditReason(message);
1093        }
1094        result.setHasSettings(hasSettings(m_cms, elementBean.getResource()));
1095        result.setPermissionInfo(permissionInfo);
1096        result.setReleasedAndNotExpired(elementBean.isReleasedAndNotExpired());
1097        if (elementBean.isModelGroup()) {
1098            String modelId = elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID);
1099            result.setModelGroupId(modelId != null ? new CmsUUID(modelId) : CmsUUID.getNullUUID());
1100        }
1101        result.setWasModelGroup(
1102            elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE)
1103                && (ModelGroupState.evaluate(
1104                    elementBean.getIndividualSettings().get(
1105                        CmsContainerElement.MODEL_GROUP_STATE)) == ModelGroupState.wasModelGroup));
1106        return result;
1107    }
1108
1109    /**
1110     * Returns the formatter configuration for the given element resource.<p>
1111     *
1112     * @param resource the element resource
1113     *
1114     * @return the formatter configuration
1115     */
1116    CmsFormatterConfiguration getFormatterConfiguration(CmsResource resource) {
1117
1118        return getConfigData().getFormatters(m_cms, resource);
1119    }
1120
1121    /**
1122     * Returns the base element data for the given element bean, without content or formatter info.<p>
1123     *
1124     * @param page the current container page
1125     * @param element the resource
1126     *
1127     * @return base element data
1128     *
1129     * @throws CmsException in case reading the data fails
1130     */
1131    private CmsContainerElementData getBaseElementData(CmsResource page, CmsContainerElementBean element)
1132    throws CmsException {
1133
1134        CmsResourceUtil resUtil = new CmsResourceUtil(m_cms, element.getResource());
1135        CmsContainerElementData elementData = new CmsContainerElementData();
1136        setElementInfo(element, elementData);
1137        elementData.setLoadTime(System.currentTimeMillis());
1138        elementData.setLastModifiedDate(element.getResource().getDateLastModified());
1139        String userName = null;
1140        try {
1141            CmsUser user = m_cms.readUser(element.getResource().getUserLastModified());
1142            userName = user.getName();
1143        } catch (CmsException e) {
1144            userName = "" + element.getResource().getUserLastModified();
1145            LOG.debug(e.getLocalizedMessage(), e);
1146        }
1147        elementData.setLastModifiedByUser(userName);
1148        elementData.setNavText(resUtil.getNavText());
1149        Map<String, CmsXmlContentProperty> settingConfig = CmsXmlContentPropertyHelper.getPropertyInfo(
1150            m_cms,
1151            page,
1152            element.getResource());
1153        elementData.setSettings(
1154            CmsXmlContentPropertyHelper.convertPropertiesToClientFormat(
1155                m_cms,
1156                element.getIndividualSettings(),
1157                settingConfig));
1158        return elementData;
1159    }
1160
1161    /**
1162     * Returns the ADE configuration data for the current URI.<p>
1163     *
1164     * @return the ADE configuration data
1165     */
1166    private CmsADEConfigData getConfigData() {
1167
1168        if (m_adeConfig == null) {
1169            m_adeConfig = OpenCms.getADEManager().lookupConfigurationWithCache(
1170                m_cms,
1171                m_cms.addSiteRoot(m_currentPageUri));
1172        }
1173        return m_adeConfig;
1174    }
1175
1176    /**
1177     * Returns the HTML content of the given element and container.<p>
1178     *
1179     * @param element the element
1180     * @param container the container
1181     * @param configs the formatter configurations
1182     *
1183     * @return the HTML content
1184     */
1185    private String getContentByContainer(
1186        CmsContainerElementBean element,
1187        CmsContainer container,
1188        CmsFormatterConfiguration configs) {
1189
1190        String content = null;
1191
1192        I_CmsFormatterBean formatter = getFormatterForContainer(
1193            m_cms,
1194            element,
1195            container,
1196            m_adeConfig,
1197            CmsADESessionCache.getCache(m_req, m_cms));
1198        if (formatter != null) {
1199            element = element.clone(); // clone element because presets for different containers may be different
1200            element.initSettings(m_cms, m_adeConfig, formatter, m_locale, m_req, container.getSettingPresets());
1201            try {
1202                content = getElementContent(element, m_cms.readResource(formatter.getJspStructureId()), container);
1203                //                }
1204            } catch (Exception e) {
1205                LOG.error(e.getLocalizedMessage(), e);
1206            }
1207            if (content != null) {
1208                content = removeScriptTags(content);
1209            }
1210        }
1211        return content;
1212    }
1213
1214    /**
1215     * Returns the rendered element content for all the given containers.
1216     *
1217     * @param element the element to render
1218     * @param containers the containers the element appears in
1219     *
1220     * @return a map from container names to rendered page contents
1221     */
1222    private Map<String, String> getContentsByContainerName(
1223        CmsContainerElementBean element,
1224        Collection<CmsContainer> containers) {
1225
1226        CmsFormatterConfiguration configs = getFormatterConfiguration(element.getResource());
1227        Map<String, String> result = new HashMap<String, String>();
1228        for (CmsContainer container : containers) {
1229            String content = getContentByContainer(element, container, configs);
1230            if (content != null) {
1231                content = removeScriptTags(content);
1232            }
1233            result.put(container.getName(), content);
1234        }
1235        return result;
1236    }
1237
1238    /**
1239     * Returns the content of an element when rendered with the given formatter.<p>
1240     *
1241     * @param element the element bean
1242     * @param formatter the formatter uri
1243     * @param container the container for which the element content should be retrieved
1244     *
1245     * @return generated html code
1246     *
1247     * @throws CmsException if an cms related error occurs
1248     * @throws ServletException if a jsp related error occurs
1249     *
1250     * @throws IOException if a jsp related error occurs
1251     */
1252    private String getElementContent(CmsContainerElementBean element, CmsResource formatter, CmsContainer container)
1253    throws CmsException, ServletException, IOException {
1254
1255        element.initResource(m_cms);
1256        TemplateBean templateBean = CmsADESessionCache.getCache(m_req, m_cms).getTemplateBean(
1257            m_cms.addSiteRoot(m_currentPageUri),
1258            true);
1259        String oldUri = m_cms.getRequestContext().getUri();
1260        try {
1261            m_cms.getRequestContext().setUri(m_currentPageUri);
1262            CmsContainerBean containerBean = null;
1263            if ((m_standardContext.getPage() != null)
1264                && m_standardContext.getPage().getContainers().containsKey(container.getName())) {
1265                containerBean = m_standardContext.getPage().getContainers().get(container.getName());
1266            } else {
1267                containerBean = CmsElementUtil.clientToServerContainer(
1268                    container,
1269                    Collections.<CmsContainerElementBean> emptyList());
1270            }
1271            if (containerBean.getWidth() == null) {
1272                containerBean.setWidth(String.valueOf(container.getWidth()));
1273            }
1274            containerBean.setDetailOnly(container.isDetailOnly());
1275            m_standardContext.setContainer(containerBean);
1276            m_standardContext.setElement(element);
1277            m_standardContext.setEdited(true);
1278            // to enable 'old' direct edit features for content-collector-elements,
1279            // set the direct-edit-provider-attribute in the request
1280            I_CmsDirectEditProvider eb = new CmsAdvancedDirectEditProvider();
1281            eb.init(m_cms, CmsDirectEditMode.TRUE, element.getSitePath());
1282            m_req.setAttribute(I_CmsDirectEditProvider.ATTRIBUTE_DIRECT_EDIT_PROVIDER, eb);
1283            m_req.setAttribute(CmsTemplateContextManager.ATTR_TEMPLATE_BEAN, templateBean);
1284            String encoding = m_res.getCharacterEncoding();
1285            return (new String(
1286                OpenCms.getResourceManager().getLoader(formatter).dump(m_cms, formatter, null, m_locale, m_req, m_res),
1287                encoding)).trim();
1288        } finally {
1289            m_cms.getRequestContext().setUri(oldUri);
1290        }
1291    }
1292
1293    /**
1294     * Gets the lock information.
1295     *
1296     * @param cms the current CMS context
1297     * @param resource the resource for which to get lock information
1298     * @return the lock information
1299     */
1300    private CmsElementLockInfo getLockInfo(CmsObject cms, CmsResource resource) {
1301
1302        try {
1303            CmsLock lock = cms.getLock(resource);
1304            CmsUUID owner = lock.getUserId();
1305            boolean isPublish = lock.isPublish();
1306            return new CmsElementLockInfo(owner, isPublish);
1307        } catch (Exception e) {
1308            LOG.error(e.getLocalizedMessage(), e);
1309            return new CmsElementLockInfo(null, false);
1310        }
1311    }
1312
1313    /**
1314     * Gets the ids for the current page and potentially detail-only containers.
1315     *
1316     * @return the set of ids for the current page and detail-only containers
1317     */
1318    private Set<CmsUUID> getPageAndDetailOnlyIds() {
1319
1320        Set<CmsUUID> result = new HashSet<>();
1321        result.add(m_page.getStructureId());
1322        CmsResource detailContent = (CmsResource)m_req.getAttribute(
1323            CmsDetailPageResourceHandler.ATTR_DETAIL_CONTENT_RESOURCE);
1324        if (detailContent != null) {
1325            for (CmsResource detailOnlyRes : CmsDetailOnlyContainerUtil.getDetailOnlyResources(m_cms, detailContent)) {
1326                result.add(detailOnlyRes.getStructureId());
1327            }
1328        }
1329        return result;
1330    }
1331
1332    /**
1333     * Helper method for checking whether there are properties defined for a given content element.<p>
1334     *
1335     * @param cms the CmsObject to use for VFS operations
1336     * @param resource the resource for which it should be checked whether it has properties
1337     *
1338     * @return true if the resource has properties defined
1339     *
1340     * @throws CmsException if something goes wrong
1341     */
1342    private boolean hasSettings(CmsObject cms, CmsResource resource) throws CmsException {
1343
1344        if (!CmsResourceTypeXmlContent.isXmlContent(resource)) {
1345            return false;
1346        }
1347
1348        CmsADEConfigData config = getConfigData();
1349        CmsFormatterConfiguration formatters = config.getFormatters(m_cms, resource);
1350        boolean result = (formatters.getAllFormatters().size() > 1)
1351            || !CmsXmlContentPropertyHelper.getPropertyInfo(m_cms, null, resource).isEmpty();
1352        if (!result && (formatters.getAllFormatters().size() == 1)) {
1353            result = (formatters.getAllFormatters().get(0).getSettings(config).size() > 0);
1354        }
1355        return result;
1356    }
1357
1358    /**
1359     * Parses the given request parameters string into a parameter map.<p>
1360     *
1361     * @param requestParameters the request parameters to parse
1362     *
1363     * @return the parameter map
1364     */
1365    private Map<String, Object> parseRequestParameters(String requestParameters) {
1366
1367        Map<String, Object> parameterMap;
1368        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(requestParameters)) {
1369            parameterMap = new HashMap<String, Object>();
1370            String[] params = requestParameters.split("&");
1371            for (int i = 0; i < params.length; i++) {
1372                int position = params[i].indexOf("=");
1373                if (position >= 0) {
1374                    String key = params[i].substring(0, position);
1375                    String value = params[i].substring(position + 1);
1376                    if (value.contains(",")) {
1377                        parameterMap.put(key, value.split(","));
1378                    } else {
1379                        parameterMap.put(key, value);
1380                    }
1381                }
1382            }
1383        } else {
1384            parameterMap = Collections.<String, Object> emptyMap();
1385        }
1386        return parameterMap;
1387    }
1388
1389    /**
1390     * Removes all script tags from given input.<p>
1391     *
1392     * @param input the input to remove script tags from
1393     *
1394     * @return the cleaned input
1395     */
1396    private String removeScriptTags(String input) {
1397
1398        Document doc = Jsoup.parseBodyFragment(input);
1399        Elements scriptTags = doc.select("script");
1400        String output = input;
1401        if (scriptTags.size() > 0) {
1402            scriptTags.remove();
1403            doc.outputSettings().prettyPrint(false);
1404            output = doc.body().html();
1405        }
1406        return output;
1407    }
1408}