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