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.CmsADEManager;
032import org.opencms.ade.configuration.CmsElementView;
033import org.opencms.ade.configuration.CmsModelPageConfig;
034import org.opencms.ade.configuration.CmsResourceTypeConfig;
035import org.opencms.ade.containerpage.inherited.CmsInheritanceReference;
036import org.opencms.ade.containerpage.inherited.CmsInheritanceReferenceParser;
037import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState;
038import org.opencms.ade.containerpage.shared.CmsCntPageData;
039import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode;
040import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementReuseMode;
041import org.opencms.ade.containerpage.shared.CmsContainer;
042import org.opencms.ade.containerpage.shared.CmsContainerElement;
043import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
044import org.opencms.ade.containerpage.shared.CmsContainerElementData;
045import org.opencms.ade.containerpage.shared.CmsContainerPageGalleryData;
046import org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext;
047import org.opencms.ade.containerpage.shared.CmsCreateElementData;
048import org.opencms.ade.containerpage.shared.CmsDialogOptions;
049import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo;
050import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
051import org.opencms.ade.containerpage.shared.CmsElementViewInfo;
052import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
053import org.opencms.ade.containerpage.shared.CmsGroupContainer;
054import org.opencms.ade.containerpage.shared.CmsGroupContainerSaveResult;
055import org.opencms.ade.containerpage.shared.CmsInheritanceContainer;
056import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
057import org.opencms.ade.containerpage.shared.CmsLocaleLinkBean;
058import org.opencms.ade.containerpage.shared.CmsRemovedElementStatus;
059import org.opencms.ade.containerpage.shared.CmsReuseInfo;
060import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService;
061import org.opencms.ade.detailpage.CmsDetailPageInfo;
062import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
063import org.opencms.ade.galleries.CmsGalleryService;
064import org.opencms.ade.galleries.shared.CmsGalleryDataBean;
065import org.opencms.ade.galleries.shared.CmsGallerySearchBean;
066import org.opencms.ade.galleries.shared.CmsResourceTypeBean;
067import org.opencms.ade.galleries.shared.CmsVfsEntryBean;
068import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryTabId;
069import org.opencms.ade.sitemap.CmsVfsSitemapService;
070import org.opencms.file.CmsFile;
071import org.opencms.file.CmsObject;
072import org.opencms.file.CmsProperty;
073import org.opencms.file.CmsPropertyDefinition;
074import org.opencms.file.CmsResource;
075import org.opencms.file.CmsResourceFilter;
076import org.opencms.file.CmsUser;
077import org.opencms.file.CmsVfsResourceNotFoundException;
078import org.opencms.file.types.CmsResourceTypeBinary;
079import org.opencms.file.types.CmsResourceTypeFunctionConfig;
080import org.opencms.file.types.CmsResourceTypeImage;
081import org.opencms.file.types.CmsResourceTypePlain;
082import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
083import org.opencms.file.types.CmsResourceTypeXmlContent;
084import org.opencms.file.types.I_CmsResourceType;
085import org.opencms.flex.CmsFlexController;
086import org.opencms.gwt.CmsDefaultResourceStatusProvider;
087import org.opencms.gwt.CmsGwtActionElement;
088import org.opencms.gwt.CmsGwtService;
089import org.opencms.gwt.CmsIconUtil;
090import org.opencms.gwt.CmsRpcException;
091import org.opencms.gwt.CmsVfsService;
092import org.opencms.gwt.shared.CmsGwtConstants;
093import org.opencms.gwt.shared.CmsListElementCreationDialogData;
094import org.opencms.gwt.shared.CmsListElementCreationOption;
095import org.opencms.gwt.shared.CmsListInfoBean;
096import org.opencms.gwt.shared.CmsModelResourceInfo;
097import org.opencms.gwt.shared.CmsResourceListInfo;
098import org.opencms.gwt.shared.CmsTemplateContextInfo;
099import org.opencms.gwt.shared.I_CmsAutoBeanFactory;
100import org.opencms.gwt.shared.I_CmsListAddMetadata;
101import org.opencms.gwt.shared.I_CmsUnlockData;
102import org.opencms.i18n.CmsEncoder;
103import org.opencms.i18n.CmsLocaleGroup;
104import org.opencms.i18n.CmsLocaleManager;
105import org.opencms.i18n.CmsMessages;
106import org.opencms.jsp.CmsJspTagEdit;
107import org.opencms.jsp.util.CmsJspStandardContextBean.TemplateBean;
108import org.opencms.loader.CmsTemplateContextManager;
109import org.opencms.loader.I_CmsTemplateContextProvider;
110import org.opencms.lock.CmsLock;
111import org.opencms.lock.CmsLockType;
112import org.opencms.main.CmsException;
113import org.opencms.main.CmsIllegalArgumentException;
114import org.opencms.main.CmsLog;
115import org.opencms.main.OpenCms;
116import org.opencms.module.CmsModule;
117import org.opencms.relations.CmsRelation;
118import org.opencms.relations.CmsRelationFilter;
119import org.opencms.relations.CmsRelationType;
120import org.opencms.search.galleries.CmsGallerySearch;
121import org.opencms.search.galleries.CmsGallerySearchResult;
122import org.opencms.security.CmsPermissionSet;
123import org.opencms.security.CmsPermissionViolationException;
124import org.opencms.security.CmsRole;
125import org.opencms.site.CmsSite;
126import org.opencms.site.CmsSiteManagerImpl;
127import org.opencms.ui.apps.CmsQuickLaunchLocationCache;
128import org.opencms.util.CmsFileUtil;
129import org.opencms.util.CmsPair;
130import org.opencms.util.CmsRequestUtil;
131import org.opencms.util.CmsStringUtil;
132import org.opencms.util.CmsUUID;
133import org.opencms.workplace.CmsWorkplace;
134import org.opencms.workplace.CmsWorkplaceMessages;
135import org.opencms.workplace.CmsWorkplaceSettings;
136import org.opencms.workplace.editors.CmsWorkplaceEditorManager;
137import org.opencms.workplace.editors.directedit.I_CmsEditHandler;
138import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
139import org.opencms.workplace.explorer.CmsResourceUtil;
140import org.opencms.xml.CmsXmlException;
141import org.opencms.xml.containerpage.CmsADESessionCache;
142import org.opencms.xml.containerpage.CmsContainerBean;
143import org.opencms.xml.containerpage.CmsContainerElementBean;
144import org.opencms.xml.containerpage.CmsContainerPageBean;
145import org.opencms.xml.containerpage.CmsFormatterConfiguration;
146import org.opencms.xml.containerpage.CmsGroupContainerBean;
147import org.opencms.xml.containerpage.CmsMacroFormatterBean;
148import org.opencms.xml.containerpage.CmsXmlContainerPage;
149import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
150import org.opencms.xml.containerpage.CmsXmlGroupContainer;
151import org.opencms.xml.containerpage.CmsXmlGroupContainerFactory;
152import org.opencms.xml.containerpage.I_CmsFormatterBean;
153import org.opencms.xml.content.CmsXmlContent;
154import org.opencms.xml.content.CmsXmlContentFactory;
155import org.opencms.xml.content.CmsXmlContentProperty;
156import org.opencms.xml.content.CmsXmlContentPropertyHelper;
157
158import java.nio.charset.StandardCharsets;
159import java.security.MessageDigest;
160import java.security.NoSuchAlgorithmException;
161import java.util.ArrayList;
162import java.util.Arrays;
163import java.util.Collection;
164import java.util.Collections;
165import java.util.HashMap;
166import java.util.HashSet;
167import java.util.Iterator;
168import java.util.LinkedHashMap;
169import java.util.List;
170import java.util.Locale;
171import java.util.Map;
172import java.util.Map.Entry;
173import java.util.Set;
174import java.util.stream.Collectors;
175
176import javax.servlet.http.HttpServletRequest;
177import javax.servlet.http.HttpServletResponse;
178
179import org.apache.commons.codec.binary.Hex;
180import org.apache.commons.logging.Log;
181
182import com.google.common.base.Optional;
183import com.google.common.collect.Lists;
184import com.google.common.collect.Maps;
185import com.google.common.collect.Sets;
186import com.google.web.bindery.autobean.shared.AutoBean;
187import com.google.web.bindery.autobean.shared.AutoBeanCodex;
188import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
189
190/**
191 * The RPC service used by the container-page editor.<p>
192 *
193 * @since 8.0.0
194 */
195public class CmsContainerpageService extends CmsGwtService implements I_CmsContainerpageService {
196
197    /**
198     * Helper class used to determine both the available views and the active start view when loading a container page.<p>
199     */
200    private class InitialElementViewProvider {
201
202        /** Start view id. */
203        private CmsUUID m_defaultView;
204
205        /** Map of available views. */
206        private Map<CmsUUID, CmsElementViewInfo> m_viewMap;
207
208        /**
209         * Empty default constructor.<p>
210         */
211        public InitialElementViewProvider() {
212
213            // do nothing
214        }
215
216        /**
217         * Returns the default view info.<p>
218         *
219         * @return the default view info
220         */
221        public CmsElementViewInfo getDefaultView() {
222
223            return getViewMap().get(getDefaultViewId());
224        }
225
226        /**
227         * Gets the start view id.<p>
228         *
229         * @return the start view id
230         */
231        public CmsUUID getDefaultViewId() {
232
233            return m_defaultView;
234        }
235
236        /**
237         * Gets the map of available views.<p>
238         *
239         * @return the map of available views
240         */
241        public Map<CmsUUID, CmsElementViewInfo> getViewMap() {
242
243            return m_viewMap;
244        }
245
246        /**
247         * Initializes this object.<p>
248         *
249         * @param defaultValue the default view id from the session cache
250         * @param checkRes the resource used to check permissions
251         * @param templateContextInfo the template context information
252         */
253        @SuppressWarnings("synthetic-access")
254        public void init(CmsUUID defaultValue, CmsResource checkRes, CmsTemplateContextInfo templateContextInfo) {
255
256            Map<CmsUUID, CmsElementViewInfo> result = new LinkedHashMap<CmsUUID, CmsElementViewInfo>();
257            CmsObject cms = getCmsObject();
258            String templateKey = templateContextInfo != null ? templateContextInfo.getCurrentContext() : null;
259
260            // collect the actually used element view ids
261            CmsADEConfigData config = getConfigData(
262                cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri()));
263            Set<CmsUUID> usedIds = new HashSet<CmsUUID>();
264            for (CmsResourceTypeConfig typeConfig : config.getResourceTypes()) {
265                if (typeConfig.isAvailableInTemplate(templateKey)) {
266                    usedIds.add(typeConfig.getElementView());
267                }
268            }
269
270            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
271            Map<CmsUUID, CmsElementView> realViewMap = OpenCms.getADEManager().getElementViews(cms);
272
273            Set<CmsUUID> parentIds = Sets.newHashSet();
274            for (CmsElementView view : realViewMap.values()) {
275                if (view.getParentViewId() != null) {
276                    parentIds.add(view.getParentViewId());
277                }
278                // add only element view that are used within the type configuration and the user has sufficient permissions for
279                if (usedIds.contains(view.getId()) && view.hasPermission(cms, checkRes) && !view.isOther()) {
280                    result.put(view.getId(), new CmsElementViewInfo(view.getTitle(cms, wpLocale), view.getId()));
281                }
282
283            }
284            m_viewMap = result;
285            for (Map.Entry<CmsUUID, CmsElementViewInfo> viewEntry : m_viewMap.entrySet()) {
286                CmsElementView realView = realViewMap.get(viewEntry.getKey());
287                CmsUUID parentViewId = realView.getParentViewId();
288                if ((parentViewId != null) && !parentIds.contains(viewEntry.getKey())) {
289                    CmsElementViewInfo parentBean = m_viewMap.get(parentViewId);
290                    if (parentBean != null) {
291                        viewEntry.getValue().setParent(parentBean);
292                    }
293                }
294            }
295            if (m_viewMap.containsKey(defaultValue)) {
296                m_defaultView = defaultValue;
297            } else if (m_viewMap.containsKey(CmsElementView.DEFAULT_ELEMENT_VIEW.getId())) {
298                m_defaultView = CmsElementView.DEFAULT_ELEMENT_VIEW.getId();
299            } else if (!m_viewMap.isEmpty()) {
300                m_defaultView = m_viewMap.values().iterator().next().getElementViewId();
301            } else {
302                m_defaultView = defaultValue;
303                LOG.error(
304                    "Initial view not available and no suitable replacement view found: user="
305                        + getCmsObject().getRequestContext().getCurrentUser().getName()
306                        + " view="
307                        + defaultValue
308                        + " path="
309                        + checkRes.getRootPath());
310            }
311
312        }
313    }
314
315    /** Runtime property key to enable / disable placement mode. */
316    public static final String PARAM_PAGE_EDITOR_PLACEMENT_MODE_ENABLED = "pageEditor.placementMode.enabled";
317
318    /** Additional info key for storing the "edit small elements" setting on the user. */
319    public static final String ADDINFO_EDIT_SMALL_ELEMENTS = "EDIT_SMALL_ELEMENTS";
320
321    /** Session attribute name used to store the selected clipboard tab. */
322    public static final String ATTR_CLIPBOARD_TAB = "clipboardtab";
323
324    /** The model group pages path fragment. */
325    public static final String MODEL_GROUP_PATH_FRAGMENT = "/.content/.modelgroups/";
326
327    /** The source container page id settings key. */
328    public static final String SOURCE_CONTAINERPAGE_ID_SETTING = "source_containerpage_id";
329
330    /** Static reference to the log. */
331    static final Log LOG = CmsLog.getLog(CmsContainerpageService.class);
332
333    /** Serial version UID. */
334    private static final long serialVersionUID = -6188370638303594280L;
335
336    /** Maximum number of reuse locations to display in the reuse warning dialog. */
337    public static final int MAX_VISIBLE_ELEMENT_USES = 100;
338
339    /** The configuration data of the current container page context. */
340    private CmsADEConfigData m_configData;
341
342    /** The session cache. */
343    private CmsADESessionCache m_sessionCache;
344
345    /** The workplace settings. */
346    private CmsWorkplaceSettings m_workplaceSettings;
347
348    /**
349     * Generates the model resource data list.<p>
350     *
351     * @param cms the cms context
352     * @param resourceType the resource type name
353     * @param modelResources the model resource
354     * @param contentLocale the content locale
355     *
356     * @return the model resources data
357     *
358     * @throws CmsException if something goes wrong reading the resource information
359     */
360    public static List<CmsModelResourceInfo> generateModelResourceList(
361        CmsObject cms,
362        String resourceType,
363        List<CmsResource> modelResources,
364        Locale contentLocale)
365    throws CmsException {
366
367        List<CmsModelResourceInfo> result = new ArrayList<CmsModelResourceInfo>();
368        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
369        CmsModelResourceInfo defaultInfo = new CmsModelResourceInfo(
370            Messages.get().getBundle(wpLocale).key(Messages.GUI_TITLE_DEFAULT_RESOURCE_CONTENT_0),
371            Messages.get().getBundle(wpLocale).key(Messages.GUI_DESCRIPTION_DEFAULT_RESOURCE_CONTENT_0),
372            null);
373        defaultInfo.setResourceType(resourceType);
374        result.add(defaultInfo);
375        for (CmsResource model : modelResources) {
376            CmsGallerySearchResult searchInfo = CmsGallerySearch.searchById(cms, model.getStructureId(), contentLocale);
377            CmsModelResourceInfo modelInfo = new CmsModelResourceInfo(
378                searchInfo.getTitle(),
379                searchInfo.getDescription(),
380                null);
381            modelInfo.addAdditionalInfo(
382                Messages.get().getBundle(wpLocale).key(Messages.GUI_LABEL_PATH_0),
383                cms.getSitePath(model));
384            modelInfo.setResourceType(resourceType);
385            modelInfo.setStructureId(model.getStructureId());
386            result.add(modelInfo);
387        }
388        return result;
389    }
390
391    /**
392     * Returns serialized container data.<p>
393     *
394     * @param container the container
395     *
396     * @return the serialized data
397     *
398     * @throws Exception if serialization fails
399     */
400    public static String getSerializedContainerInfo(CmsContainer container) throws Exception {
401
402        return CmsGwtActionElement.serialize(I_CmsContainerpageService.class.getMethod("getContainerInfo"), container);
403    }
404
405    /**
406     * Returns the serialized element data.<p>
407     *
408     * @param cms the cms context
409     * @param request the servlet request
410     * @param response the servlet response
411     * @param elementBean the element to serialize
412     * @param page the container page
413     *
414     * @return the serialized element data
415     *
416     * @throws Exception if something goes wrong
417     */
418    public static String getSerializedElementInfo(
419        CmsObject cms,
420        HttpServletRequest request,
421        HttpServletResponse response,
422        CmsContainerElementBean elementBean,
423        CmsContainerPageBean page)
424    throws Exception {
425
426        CmsContainerElement result = new CmsContainerElement();
427        CmsElementUtil util = new CmsElementUtil(
428            cms,
429            cms.getRequestContext().getUri(),
430            page,
431            null,
432            request,
433            response,
434            false,
435            cms.getRequestContext().getLocale());
436        util.setElementInfo(elementBean, result);
437        return CmsGwtActionElement.serialize(I_CmsContainerpageService.class.getMethod("getElementInfo"), result);
438    }
439
440    /**
441     * Checks whether the current page is a model group page.<p>
442     *
443     * @param cms the CMS context
444     * @param containerPage the current page
445     *
446     * @return <code>true</code> if the current page is a model group page
447     */
448    public static boolean isEditingModelGroups(CmsObject cms, CmsResource containerPage) {
449
450        return (OpenCms.getResourceManager().getResourceType(containerPage).getTypeName().equals(
451            CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME)
452            && OpenCms.getRoleManager().hasRole(cms, CmsRole.DEVELOPER));
453    }
454
455    /**
456     * Fetches the container page data.<p>
457     *
458     * @param request the current request
459     *
460     * @return the container page data
461     *
462     * @throws CmsRpcException if something goes wrong
463     */
464    public static CmsCntPageData prefetch(HttpServletRequest request) throws CmsRpcException {
465
466        CmsContainerpageService srv = new CmsContainerpageService();
467        srv.setCms(CmsFlexController.getCmsObject(request));
468        srv.setRequest(request);
469        CmsCntPageData result = null;
470        try {
471            result = srv.prefetch();
472        } finally {
473            srv.clearThreadStorage();
474        }
475        return result;
476    }
477
478    /**
479     * Unlocks a page or set of pages if they are locked by the current user.
480     *
481     * <p>This is not called via the normal GWT-RPC mechanism, but with the browser's sendBeacon function.
482     *
483     * @param cms the CMS context
484     * @param request the current request
485     * @param response the current response
486     * @throws Exception if something goes wrong
487     */
488    @SuppressWarnings("resource")
489    public static void unlockPage(CmsObject cms, HttpServletRequest request, HttpServletResponse response)
490    throws Exception {
491
492        // don't bother doing anything unless we have a session and are offline
493
494        if (request.getSession(false) == null) {
495            LOG.debug("no session found");
496            return;
497        }
498        if (cms.getRequestContext().getCurrentProject().isOnlineProject()) {
499            LOG.debug("can't unlock page in online project");
500            return;
501        }
502
503        byte[] byteData = CmsFileUtil.readFully(request.getInputStream(), false);
504
505        String encoding = request.getCharacterEncoding();
506        if (encoding == null) {
507            encoding = "UTF-8";
508        }
509        String strData = new String(byteData, encoding);
510        LOG.debug("Unlock request received: " + strData);
511
512        AutoBean<I_CmsUnlockData> data = AutoBeanCodex.decode(
513            AutoBeanFactorySource.create(I_CmsAutoBeanFactory.class),
514            I_CmsUnlockData.class,
515            strData);
516
517        I_CmsUnlockData unlockData = data.as();
518        List<CmsUUID> ids = new ArrayList<>();
519        if (CmsUUID.isValidUUID(unlockData.getPageId())) {
520            ids.add(new CmsUUID(unlockData.getPageId()));
521        }
522        CmsUUID detailId = null;
523        if (CmsUUID.isValidUUID(unlockData.getDetailId())) {
524            detailId = new CmsUUID(unlockData.getDetailId());
525            try {
526                CmsResource detailResource = cms.readResource(detailId, CmsResourceFilter.ALL);
527                Optional<CmsResource> detailOnlyPage = CmsDetailOnlyContainerUtil.getDetailOnlyPage(
528                    cms,
529                    detailResource,
530                    unlockData.getLocale());
531                if (detailOnlyPage.isPresent()) {
532                    ids.add(detailOnlyPage.get().getStructureId());
533                }
534            } catch (CmsVfsResourceNotFoundException e) {
535                LOG.info(e.getLocalizedMessage(), e);
536            } catch (Exception e) {
537                LOG.error(e.getLocalizedMessage(), e);
538            }
539        }
540
541        for (CmsUUID id : ids) {
542            try {
543                CmsResource page = cms.readResource(id, CmsResourceFilter.IGNORE_EXPIRATION);
544                CmsLock lock = cms.getLock(page);
545                if (!lock.isUnlocked() && lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) {
546                    LOG.debug("Unlocking " + page.getRootPath());
547                    cms.unlockResource(page);
548                } else {
549                    LOG.debug("Can't unlock " + page.getRootPath() + " because it's not locked for the current user.");
550                }
551            } catch (Exception e) {
552                LOG.error(e.getLocalizedMessage(), e);
553            }
554        }
555    }
556
557    /**
558     * Returns the server id part of the given client id.<p>
559     *
560     * @param id the id
561     *
562     * @return the server id
563     */
564    private static String getServerIdString(String id) {
565
566        if (id.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) {
567            id = id.substring(0, id.indexOf(CmsADEManager.CLIENT_ID_SEPERATOR));
568        }
569        return id;
570    }
571
572    /**
573     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#addToFavoriteList(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, java.lang.String)
574     */
575    public void addToFavoriteList(CmsContainerPageRpcContext context, String clientId) throws CmsRpcException {
576
577        try {
578            ensureSession();
579            List<CmsContainerElementBean> list = OpenCms.getADEManager().getFavoriteList(getCmsObject());
580            CmsResource containerPage = getCmsObject().readResource(
581                context.getPageStructureId(),
582                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
583            updateFavoriteRecentList(containerPage, clientId, list);
584            OpenCms.getADEManager().saveFavoriteList(getCmsObject(), list);
585        } catch (Throwable e) {
586            error(e);
587        }
588    }
589
590    /**
591     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#addToRecentList(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, java.lang.String)
592     */
593    public void addToRecentList(CmsContainerPageRpcContext context, String clientId) throws CmsRpcException {
594
595        try {
596            ensureSession();
597            List<CmsContainerElementBean> list = OpenCms.getADEManager().getRecentList(getCmsObject());
598            CmsResource containerPage = getCmsObject().readResource(
599                context.getPageStructureId(),
600                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
601            updateFavoriteRecentList(containerPage, clientId, list);
602            OpenCms.getADEManager().saveRecentList(getCmsObject(), list);
603        } catch (Throwable e) {
604            error(e);
605        }
606    }
607
608    /**
609     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#checkContainerpageOrElementsChanged(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.lang.String)
610     */
611    public boolean checkContainerpageOrElementsChanged(
612        CmsUUID structureId,
613        CmsUUID detailContentId,
614        String contentLocale)
615    throws CmsRpcException {
616
617        try {
618            List<CmsUUID> additionalIds = new ArrayList<CmsUUID>();
619            additionalIds.add(structureId);
620            boolean detailOnlyChanged = false;
621            if (detailContentId != null) {
622                additionalIds.add(detailContentId);
623                try {
624
625                    CmsObject cms = getCmsObject();
626                    CmsResource detailContentRes = cms.readResource(detailContentId, CmsResourceFilter.ALL);
627                    OpenCms.getLocaleManager();
628                    CmsResource page = cms.readResource(structureId, CmsResourceFilter.ignoreExpirationOffline(cms));
629                    Optional<CmsResource> detailOnlyRes = CmsDetailOnlyContainerUtil.getDetailOnlyResource(
630                        cms,
631                        contentLocale,
632                        detailContentRes,
633                        page);
634                    if (detailOnlyRes.isPresent()) {
635                        detailOnlyChanged = CmsDefaultResourceStatusProvider.getContainerpageRelationTargets(
636                            getCmsObject(),
637                            detailOnlyRes.get().getStructureId(),
638                            Arrays.asList(detailOnlyRes.get().getStructureId()),
639                            true).isChanged();
640                    }
641                } catch (CmsException e) {
642                    LOG.error(e.getLocalizedMessage(), e);
643                }
644            }
645            return detailOnlyChanged
646                || CmsDefaultResourceStatusProvider.getContainerpageRelationTargets(
647                    getCmsObject(),
648                    structureId,
649                    additionalIds,
650                    true /*stop looking if we find a changed resource.*/).isChanged();
651        } catch (Throwable e) {
652            error(e);
653            return false; // will never be reached
654        }
655
656    }
657
658    /**
659     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#checkCreateNewElement(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, org.opencms.ade.containerpage.shared.CmsContainer, java.lang.String)
660     */
661    public CmsCreateElementData checkCreateNewElement(
662        CmsUUID pageStructureId,
663        CmsUUID detailContentId,
664        String clientId,
665        String resourceType,
666        CmsContainer container,
667        String locale)
668    throws CmsRpcException {
669
670        CmsObject cms = getCmsObject();
671        CmsCreateElementData result = new CmsCreateElementData();
672        try {
673            CmsResource currentPage = cms.readResource(pageStructureId, CmsResourceFilter.ignoreExpirationOffline(cms));
674
675            List<CmsResource> modelResources = CmsResourceTypeXmlContent.getModelFiles(
676                getCmsObject(),
677                CmsResource.getFolderPath(cms.getSitePath(currentPage)),
678                resourceType);
679            if (modelResources.isEmpty()) {
680                CmsContainerElementBean bean = getCachedElement(clientId, currentPage.getRootPath());
681                I_CmsFormatterBean formatter = CmsElementUtil.getFormatterForContainer(
682                    cms,
683                    bean,
684                    container,
685                    getConfigData(currentPage.getRootPath()),
686                    getSessionCache());
687                CmsUUID modelResId = null;
688                if (formatter instanceof CmsMacroFormatterBean) {
689                    modelResId = ((CmsMacroFormatterBean)formatter).getDefaultContentStructureId();
690                }
691                result.setCreatedElement(
692                    createNewElement(pageStructureId, detailContentId, clientId, resourceType, modelResId, locale));
693            } else {
694                result.setModelResources(
695                    generateModelResourceList(
696                        getCmsObject(),
697                        resourceType,
698                        modelResources,
699                        CmsLocaleManager.getLocale(locale)));
700            }
701        } catch (CmsException e) {
702            error(e);
703        }
704        return result;
705    }
706
707    /**
708     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#checkNewWidgetsAvailable(org.opencms.util.CmsUUID)
709     */
710    public boolean checkNewWidgetsAvailable(CmsUUID structureId) throws CmsRpcException {
711
712        try {
713            CmsObject cms = getCmsObject();
714            CmsResource resource = cms.readResource(structureId);
715            return CmsWorkplaceEditorManager.checkAcaciaEditorAvailable(cms, resource);
716        } catch (Throwable t) {
717            error(t);
718        }
719        return false;
720    }
721
722    /**
723     * Parses an element id.<p>
724     *
725     * @param id the element id
726     *
727     * @return the corresponding structure id
728     *
729     * @throws CmsIllegalArgumentException if the id has not the right format
730     */
731    public CmsUUID convertToServerId(String id) throws CmsIllegalArgumentException {
732
733        if (id == null) {
734            throw new CmsIllegalArgumentException(
735                org.opencms.xml.containerpage.Messages.get().container(
736                    org.opencms.xml.containerpage.Messages.ERR_INVALID_ID_1,
737                    id));
738        }
739        String serverId = getServerIdString(id);
740        try {
741            return new CmsUUID(serverId);
742        } catch (NumberFormatException e) {
743            throw new CmsIllegalArgumentException(
744                org.opencms.xml.containerpage.Messages.get().container(
745                    org.opencms.xml.containerpage.Messages.ERR_INVALID_ID_1,
746                    id),
747                e);
748        }
749    }
750
751    /**
752     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#copyElement(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.lang.String)
753     */
754    public CmsUUID copyElement(CmsUUID pageId, CmsUUID originalElementId, String locale) throws CmsRpcException {
755
756        try {
757            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
758            cms.getRequestContext().setLocale(CmsLocaleManager.getLocale(locale));
759            CmsResource page = cms.readResource(pageId, CmsResourceFilter.IGNORE_EXPIRATION);
760            CmsResource element = cms.readResource(originalElementId, CmsResourceFilter.IGNORE_EXPIRATION);
761            CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, page.getRootPath());
762            String typeName = OpenCms.getResourceManager().getResourceType(element.getTypeId()).getTypeName();
763            CmsResourceTypeConfig typeConfig = config.getResourceType(typeName);
764            if (typeConfig == null) {
765                LOG.error("copyElement: Type not configured in ADE configuration: " + typeName);
766                return originalElementId;
767            } else {
768                CmsResource newResource = typeConfig.createNewElement(
769                    cms,
770                    element,
771                    CmsResource.getParentFolder(page.getRootPath()));
772                return newResource.getStructureId();
773            }
774        } catch (Throwable e) {
775            error(e);
776            return null; // will never be reached
777        }
778    }
779
780    /**
781     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#createNewElement(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
782     */
783    public CmsContainerElement createNewElement(
784        CmsUUID pageStructureId,
785        CmsUUID detailContentId,
786        String clientId,
787        String resourceType,
788        CmsUUID modelResourceStructureId,
789        String locale)
790    throws CmsRpcException {
791
792        CmsContainerElement element = null;
793        try {
794            ensureSession();
795            CmsObject cms = getCmsObject();
796            CmsResource pageResource = cms.readResource(
797                pageStructureId,
798                CmsResourceFilter.ignoreExpirationOffline(cms));
799            CmsADEConfigData configData = getConfigData(pageResource.getRootPath());
800            CmsResourceTypeConfig typeConfig = configData.getResourceType(resourceType);
801            CmsObject cloneCms = OpenCms.initCmsObject(cms);
802            cloneCms.getRequestContext().setLocale(CmsLocaleManager.getLocale(locale));
803
804            CmsResource modelResource = null;
805            if (modelResourceStructureId != null) {
806                modelResource = cms.readResource(modelResourceStructureId);
807            }
808            String pageFolderForElementCreation = CmsResource.getParentFolder(pageResource.getRootPath());
809            if (detailContentId != null) {
810                try {
811                    CmsResource detailResource = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
812                    pageFolderForElementCreation = CmsResource.getParentFolder(
813                        CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
814                            cloneCms,
815                            pageResource,
816                            detailResource.getRootPath(),
817                            locale));
818                } catch (Exception e) {
819                    // pageFolderForElementCreation remains the folder of the detail page in this case
820                    LOG.info(e.getLocalizedMessage(), e);
821                }
822            }
823            CmsResource newResource = typeConfig.createNewElement(
824                cloneCms,
825                modelResource,
826                pageFolderForElementCreation);
827            CmsContainerElementBean bean = getCachedElement(clientId, pageResource.getRootPath());
828            Map<String, String> settings = new HashMap<String, String>();
829
830            settings = bean.getIndividualSettings();
831
832            CmsContainerElementBean newBean = new CmsContainerElementBean(
833                newResource.getStructureId(),
834                null,
835                settings,
836                typeConfig.isCopyInModels());
837            String newClientId = newBean.editorHash();
838            getSessionCache().setCacheContainerElement(newClientId, newBean);
839            element = new CmsContainerElement();
840            element.setNewEditorDisabled(!CmsWorkplaceEditorManager.checkAcaciaEditorAvailable(cms, newResource));
841            element.setClientId(newClientId);
842            element.setSitePath(cms.getSitePath(newResource));
843            element.setResourceType(resourceType);
844            element.setIconClasses(
845                CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, newResource), null, false));
846            element.setCreateNew(newBean.isCreateNew());
847        } catch (CmsException e) {
848            error(e);
849        }
850        return element;
851    }
852
853    /**
854     * Reads the cached element-bean for the given client-side-id from cache.<p>
855     *
856     * @param clientId the client-side-id
857     * @param pageRootPath the container page root path
858     *
859     * @return the cached container element bean
860     *
861     * @throws CmsException in case reading the element resource fails
862     */
863    public CmsContainerElementBean getCachedElement(String clientId, String pageRootPath) throws CmsException {
864
865        String id = clientId;
866        CmsContainerElementBean element = null;
867        element = getSessionCache().getCacheContainerElement(id);
868        if (element != null) {
869            return element;
870        }
871        if (id.contains(CmsADEManager.CLIENT_ID_SEPERATOR)) {
872            throw new CmsException(Messages.get().container(Messages.ERR_MISSING_CACHED_ELEMENT_0));
873        }
874        // this is necessary if the element has not been cached yet
875        CmsResource resource = getCmsObject().readResource(convertToServerId(id), CmsResourceFilter.IGNORE_EXPIRATION);
876        CmsADEConfigData configData = getConfigData(pageRootPath);
877        CmsResourceTypeConfig typeConfig = configData.getResourceType(
878            OpenCms.getResourceManager().getResourceType(resource).getTypeName());
879        element = new CmsContainerElementBean(
880            convertToServerId(id),
881            null,
882            null,
883            (typeConfig != null) && typeConfig.isCopyInModels());
884        getSessionCache().setCacheContainerElement(element.editorHash(), element);
885        return element;
886    }
887
888    /**
889     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getContainerInfo()
890     */
891    public CmsContainer getContainerInfo() {
892
893        throw new UnsupportedOperationException("This method is used for serialization only.");
894    }
895
896    /**
897     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getDeleteOptions(java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
898     */
899    public CmsDialogOptionsAndInfo getDeleteOptions(String clientId, CmsUUID pageId, String requestParams)
900    throws CmsRpcException {
901
902        try {
903            CmsResource pageResource = getCmsObject().readResource(
904                pageId,
905                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
906            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
907            element.initResource(getCmsObject());
908            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
909            if (type instanceof CmsResourceTypeXmlContent) {
910                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
911                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
912                    CmsEncoder.decode(requestParams),
913                    true,
914                    CmsEncoder.ENCODING_UTF_8);
915                CmsDialogOptions options = handler.getDeleteOptions(getCmsObject(), element, pageId, params);
916                if (options != null) {
917                    return new CmsDialogOptionsAndInfo(
918                        options,
919                        CmsVfsService.getPageInfo(getCmsObject(), element.getResource()));
920                }
921            }
922        } catch (CmsException e) {
923            error(e);
924        }
925        return null;
926    }
927
928    /**
929     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getEditOptions(java.lang.String, org.opencms.util.CmsUUID, java.lang.String, boolean)
930     */
931    public CmsDialogOptionsAndInfo getEditOptions(
932        String clientId,
933        CmsUUID pageId,
934        String requestParams,
935        boolean isListElement)
936    throws CmsRpcException {
937
938        try {
939            CmsResource pageResource = getCmsObject().readResource(
940                pageId,
941                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
942            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
943            element.initResource(getCmsObject());
944            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
945            if (type instanceof CmsResourceTypeXmlContent) {
946                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
947                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
948                    CmsEncoder.decode(requestParams),
949                    true,
950                    CmsEncoder.ENCODING_UTF_8);
951                CmsDialogOptions options = handler.getEditOptions(
952                    getCmsObject(),
953                    element,
954                    pageId,
955                    params,
956                    isListElement);
957                if (options != null) {
958                    return new CmsDialogOptionsAndInfo(
959                        options,
960                        CmsVfsService.getPageInfo(getCmsObject(), element.getResource()));
961                }
962            }
963        } catch (CmsException e) {
964            error(e);
965        }
966        return null;
967    }
968
969    /**
970     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getElementInfo()
971     */
972    public CmsContainerElement getElementInfo() {
973
974        throw new UnsupportedOperationException("This method is used for serialization only.");
975    }
976
977    /**
978     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getElementsData(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, java.util.Collection, java.util.Collection, boolean, java.lang.String, java.lang.String)
979     */
980    public Map<String, CmsContainerElementData> getElementsData(
981        CmsContainerPageRpcContext context,
982        CmsUUID detailContentId,
983        String reqParams,
984        Collection<String> clientIds,
985        Collection<CmsContainer> containers,
986        boolean allwaysCopy,
987        String dndSource,
988        String locale)
989    throws CmsRpcException {
990
991        Map<String, CmsContainerElementData> result = null;
992        try {
993            ensureSession();
994            CmsResource pageResource = getCmsObject().readResource(
995                context.getPageStructureId(),
996                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
997            CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
998                getCmsObject(),
999                pageResource.getRootPath());
1000            initRequestFromRpcContext(context);
1001            String containerpageUri = getCmsObject().getSitePath(pageResource);
1002            result = getElements(
1003                config,
1004                pageResource,
1005                clientIds,
1006                containerpageUri,
1007                detailContentId,
1008                containers,
1009                allwaysCopy,
1010                dndSource,
1011                CmsStringUtil.isNotEmptyOrWhitespaceOnly(dndSource),
1012                CmsLocaleManager.getLocale(locale));
1013        } catch (Throwable e) {
1014            error(e);
1015        }
1016        return result;
1017    }
1018
1019    /**
1020     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getElementSettingsConfig(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, java.lang.String, java.lang.String, java.util.Collection, java.lang.String)
1021     */
1022    public CmsElementSettingsConfig getElementSettingsConfig(
1023        CmsContainerPageRpcContext context,
1024        String clientId,
1025        String containerId,
1026        Collection<CmsContainer> containers,
1027        String locale)
1028    throws CmsRpcException {
1029
1030        try {
1031            ensureSession();
1032            CmsObject cms = getCmsObject();
1033            CmsResource pageResource = cms.readResource(
1034                context.getPageStructureId(),
1035                CmsResourceFilter.ignoreExpirationOffline(cms));
1036            initRequestFromRpcContext(context);
1037            String containerpageUri = cms.getSitePath(pageResource);
1038
1039            CmsContainerPageBean pageBean = generateContainerPageForContainers(
1040                containers,
1041                cms.getRequestContext().addSiteRoot(containerpageUri));
1042
1043            CmsElementUtil elemUtil = new CmsElementUtil(
1044                cms,
1045                containerpageUri,
1046                pageBean,
1047                null,
1048                getRequest(),
1049                getResponse(),
1050                false,
1051                CmsLocaleManager.getLocale(locale));
1052            CmsContainerElementBean element = getCachedElement(
1053                clientId,
1054                cms.getRequestContext().addSiteRoot(containerpageUri));
1055            if (element.getInstanceId() == null) {
1056                element = element.clone();
1057                getSessionCache().setCacheContainerElement(element.editorHash(), element);
1058            }
1059            element.initResource(cms);
1060            return elemUtil.getElementSettingsConfig(pageResource, element, containerId, containers);
1061        } catch (Throwable e) {
1062            error(e);
1063        }
1064        return null;
1065    }
1066
1067    /**
1068     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getElementsLockedForPublishing(java.util.Set)
1069     */
1070    public Set<CmsUUID> getElementsLockedForPublishing(Set<CmsUUID> idsToCheck) throws CmsRpcException {
1071
1072        try {
1073            CmsObject cms = getCmsObject();
1074            Set<CmsUUID> result = new HashSet<>();
1075            for (CmsUUID id : idsToCheck) {
1076                try {
1077                    CmsResource resource = cms.readResource(id, CmsResourceFilter.ALL);
1078                    CmsLock lock = cms.getLock(resource);
1079                    if (!lock.getSystemLock().isUnlocked()
1080                        && lock.getUserId().equals(cms.getRequestContext().getCurrentUser().getId())) {
1081                        result.add(resource.getStructureId());
1082                    }
1083                } catch (CmsVfsResourceNotFoundException e) {
1084                    LOG.debug(e.getLocalizedMessage(), e);
1085                }
1086            }
1087            return result;
1088        } catch (Exception e) {
1089            error(e);
1090            return null;
1091        }
1092    }
1093
1094    /**
1095     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getElementWithSettings(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.util.Map, java.util.Collection, java.lang.String)
1096     */
1097    public CmsContainerElementData getElementWithSettings(
1098        CmsContainerPageRpcContext context,
1099        CmsUUID detailContentId,
1100        String uriParams,
1101        String clientId,
1102        Map<String, String> settings,
1103        Collection<CmsContainer> containers,
1104        String locale)
1105    throws CmsRpcException {
1106
1107        CmsContainerElementData element = null;
1108        try {
1109            ensureSession();
1110            CmsObject cms = getCmsObject();
1111            CmsResource pageResource = cms.readResource(
1112                context.getPageStructureId(),
1113                CmsResourceFilter.ignoreExpirationOffline(cms));
1114            initRequestFromRpcContext(context);
1115            String containerpageUri = cms.getSitePath(pageResource);
1116            Locale contentLocale = CmsLocaleManager.getLocale(locale);
1117            CmsElementUtil elemUtil = new CmsElementUtil(
1118                cms,
1119                containerpageUri,
1120                generateContainerPageForContainers(containers, pageResource.getRootPath()),
1121                detailContentId,
1122                getRequest(),
1123                getResponse(),
1124                false,
1125                contentLocale);
1126
1127            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
1128            elementBean.initResource(cms);
1129            storeFormatterSelection(elementBean, settings);
1130            // make sure to keep the element instance id
1131            if (!settings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)
1132                && elementBean.getIndividualSettings().containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) {
1133                settings.put(
1134                    CmsContainerElement.ELEMENT_INSTANCE_ID,
1135                    elementBean.getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID));
1136            }
1137
1138            elementBean = CmsContainerElementBean.cloneWithSettings(
1139                elementBean,
1140                convertSettingValues(elementBean.getResource(), settings, contentLocale));
1141            getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
1142            element = elemUtil.getElementData(pageResource, elementBean, containers);
1143        } catch (Throwable e) {
1144            error(e);
1145        }
1146        return element;
1147    }
1148
1149    /**
1150     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getFavoriteList(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.util.Collection, java.lang.String)
1151     */
1152    public List<CmsContainerElementData> getFavoriteList(
1153        CmsUUID pageStructureId,
1154        CmsUUID detailContentId,
1155        Collection<CmsContainer> containers,
1156        String locale)
1157    throws CmsRpcException {
1158
1159        List<CmsContainerElementData> result = null;
1160        try {
1161            ensureSession();
1162            CmsResource containerpage = getCmsObject().readResource(
1163                pageStructureId,
1164                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1165            String containerpageUri = getCmsObject().getSitePath(containerpage);
1166            result = getListElementsData(
1167                OpenCms.getADEManager().getFavoriteList(getCmsObject()),
1168                containerpageUri,
1169                detailContentId,
1170                containers,
1171                CmsLocaleManager.getLocale(locale));
1172        } catch (Throwable e) {
1173            error(e);
1174        }
1175        return result;
1176    }
1177
1178    /**
1179     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getGalleryDataForPage(java.util.List, org.opencms.util.CmsUUID, java.lang.String, org.opencms.util.CmsUUID, java.lang.String, org.opencms.gwt.shared.CmsTemplateContextInfo)
1180     */
1181    public CmsContainerPageGalleryData getGalleryDataForPage(
1182        final List<CmsContainer> containers,
1183        CmsUUID elementView,
1184        String uri,
1185        CmsUUID detailContentId,
1186        String locale,
1187        CmsTemplateContextInfo templateContextInfo)
1188    throws CmsRpcException {
1189
1190        CmsGalleryDataBean data = null;
1191        try {
1192            CmsObject cms = getCmsObject();
1193            String pageFolderRootPath = cms.getRequestContext().addSiteRoot(uri);
1194            CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, pageFolderRootPath);
1195            Map<String, CmsResourceTypeConfig> typesByName = config.getTypesByName();
1196            final String templateContextStr = (templateContextInfo != null)
1197                && (templateContextInfo.getCurrentContext() != null) ? templateContextInfo.getCurrentContext() : null;
1198            CmsAddDialogTypeHelper typeHelper = new CmsAddDialogTypeHelper(CmsResourceTypeConfig.AddMenuType.ade) {
1199
1200                @Override
1201                protected boolean exclude(CmsResourceTypeBean type) {
1202
1203                    CmsResourceTypeConfig typeConfig = typesByName.get(type.getType());
1204                    if ((typeConfig != null)
1205                        && (templateContextStr != null)
1206                        && !typeConfig.isAvailableInTemplate(templateContextStr)) {
1207                        return true;
1208                    }
1209                    return false;
1210
1211                }
1212            };
1213            if (detailContentId != null) {
1214                try {
1215                    CmsResource page = cms.readResource(uri, CmsResourceFilter.IGNORE_EXPIRATION);
1216                    CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
1217                    pageFolderRootPath = CmsResource.getParentFolder(
1218                        CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
1219                            cms,
1220                            page,
1221                            detailContent.getRootPath(),
1222                            "" + locale));
1223                } catch (Exception e) {
1224                    LOG.error(e.getLocalizedMessage(), e);
1225                }
1226            }
1227            List<CmsResourceTypeBean> resTypeBeans = typeHelper.getResourceTypes(
1228                cms,
1229                cms.getRequestContext().addSiteRoot(uri),
1230                pageFolderRootPath,
1231                uri,
1232                OpenCms.getADEManager().getElementViews(cms).get(elementView),
1233                new I_CmsResourceTypeEnabledCheck() {
1234
1235                    public boolean checkEnabled(
1236                        CmsObject paramCms,
1237                        CmsADEConfigData config2,
1238                        I_CmsResourceType resType) {
1239
1240                        boolean isModelGroup = CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME.equals(
1241                            resType.getTypeName());
1242                        return isModelGroup || config2.hasFormatters(paramCms, resType, containers);
1243                    }
1244                });
1245            CmsGalleryService srv = new CmsGalleryService();
1246            srv.setCms(cms);
1247            srv.setRequest(getRequest());
1248            data = srv.getInitialSettingsForContainerPage(resTypeBeans, uri, locale);
1249            CmsContainerPageGalleryData result = new CmsContainerPageGalleryData();
1250
1251            CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), cms);
1252            CmsGallerySearchBean search = cache.getLastPageEditorGallerySearch();
1253            String subsite = OpenCms.getADEManager().getSubSiteRoot(cms, cms.addSiteRoot(uri));
1254
1255            // The template context now influences the gallery search results, so use checksum of the template context provider and context as part of the cache key
1256            String providerSuffix = "null";
1257            if (templateContextInfo != null) {
1258                String providerKey = templateContextInfo.getContextProvider();
1259                I_CmsTemplateContextProvider provider = OpenCms.getTemplateContextManager().getTemplateContextProvider(
1260                    providerKey);
1261                if (provider != null) {
1262                    try {
1263                        MessageDigest md5 = MessageDigest.getInstance("md5");
1264                        md5.update(providerKey.getBytes(StandardCharsets.UTF_8));
1265                        if (templateContextInfo.getCurrentContext() != null) {
1266                            md5.update((byte)0); // 0 byte as separator
1267                            md5.update(templateContextInfo.getCurrentContext().getBytes(StandardCharsets.UTF_8));
1268                            providerSuffix = Hex.encodeHexString(md5.digest());
1269                        }
1270                    } catch (NoSuchAlgorithmException e) {
1271                        // MD5 must be in standard library
1272                    }
1273                }
1274            }
1275
1276            String searchStoreKey = elementView + "|" + subsite + "|" + locale + "|" + providerSuffix;
1277            data.getContextParameters().put("searchStoreKey", searchStoreKey);
1278            if ((search != null) && !search.getServerSearchTypes().contains(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
1279                if (searchStoreKey.equals(
1280                    search.getOriginalGalleryData().getContextParameters().get("searchStoreKey"))) {
1281                    if (hasCompatibleSearchData(search.getOriginalGalleryData(), data, search)) {
1282
1283                        CmsVfsEntryBean preloadData = null;
1284                        if (search.getFolders() != null) {
1285                            preloadData = CmsGalleryService.generateVfsPreloadData(
1286                                getCmsObject(),
1287                                CmsGalleryService.getVfsTreeState(getRequest(), data.getTreeToken()),
1288                                search.getFolders());
1289                        }
1290
1291                        // only restore last result list if the search was performed in a 'similar' context
1292                        search.setTabId(GalleryTabId.cms_tab_results.toString());
1293                        search.setPage(1);
1294                        search.setLastPage(0);
1295                        data.setStartTab(GalleryTabId.cms_tab_results);
1296                        search = srv.getSearch(search);
1297                        data.setVfsPreloadData(preloadData);
1298                        data.setIncludeExpiredDefault(search.isIncludeExpired());
1299                        result.setGallerySearch(search);
1300                    }
1301                }
1302            }
1303            result.setGalleryData(data);
1304            return result;
1305
1306        } catch (Exception e) {
1307            error(e);
1308            return null;
1309        }
1310    }
1311
1312    /**
1313     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getListElementCreationOptions(org.opencms.util.CmsUUID, java.lang.String)
1314     */
1315    public CmsListElementCreationDialogData getListElementCreationOptions(CmsUUID structureId, String jsonListAddData)
1316    throws CmsRpcException {
1317
1318        CmsObject cms = getCmsObject();
1319        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1320        CmsMessages msg = Messages.get().getBundle(locale);
1321        try {
1322            CmsUUID listId = structureId;
1323
1324            String jsonConfig = jsonListAddData;
1325            I_CmsAutoBeanFactory beanFactory = AutoBeanFactorySource.create(I_CmsAutoBeanFactory.class);
1326            AutoBean<I_CmsListAddMetadata> listAddData = AutoBeanCodex.decode(
1327                beanFactory,
1328                I_CmsListAddMetadata.class,
1329                jsonConfig);
1330            CmsListElementCreationDialogData result = new CmsListElementCreationDialogData();
1331            result.setCaption(msg.key(Messages.GUI_LISTADD_CAPTION_0));
1332            result.setPostCreateHandler(listAddData.as().getPostCreateHandler());
1333            String uploadFolder = listAddData.as().getUploadFolder();
1334            boolean isUpload = false;
1335            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(uploadFolder) && !"none".equals(uploadFolder)) {
1336                if (listAddData.as().getTypes().stream().anyMatch(
1337                    type -> CmsResourceTypeBinary.getStaticTypeName().equals(type)
1338                        || CmsResourceTypePlain.getStaticTypeName().equals(type)
1339                        || CmsResourceTypeImage.getStaticTypeName().equals(type))) {
1340
1341                    CmsResource uploadFolderResource = null;
1342                    try {
1343                        uploadFolderResource = cms.readResource(uploadFolder, CmsResourceFilter.IGNORE_EXPIRATION);
1344                        if (cms.hasPermissions(
1345                            uploadFolderResource,
1346                            CmsPermissionSet.ACCESS_WRITE,
1347                            false,
1348                            CmsResourceFilter.IGNORE_EXPIRATION)) {
1349                            isUpload = true;
1350                        }
1351                    } catch (CmsVfsResourceNotFoundException | CmsPermissionViolationException e) {
1352                        LOG.debug(e.getLocalizedMessage(), e);
1353                    } catch (Exception e) {
1354                        LOG.error(e.getLocalizedMessage(), e);
1355                    }
1356                }
1357            }
1358            if (isUpload) {
1359                result.setUploadFolder(uploadFolder);
1360                CmsListInfoBean listResourceInfo = CmsVfsService.getPageInfo(
1361                    cms,
1362                    cms.readResource(uploadFolder, CmsResourceFilter.IGNORE_EXPIRATION));
1363                result.setListInfo(listResourceInfo);
1364            } else {
1365                CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
1366                    cms,
1367                    cms.getRequestContext().getRootUri());
1368                CmsResource listResource = cms.readResource(listId, CmsResourceFilter.IGNORE_EXPIRATION);
1369                CmsListInfoBean listResourceInfo = CmsVfsService.getPageInfo(cms, listResource);
1370                result.setListInfo(listResourceInfo);
1371                List<String> createTypes = listAddData.as().getTypes();
1372                Map<String, CmsResourceTypeConfig> typeMap = adeConfig.getTypesByName();
1373                for (String type : createTypes) {
1374                    try {
1375                        CmsResourceTypeConfig currentType = typeMap.get(type);
1376                        if (currentType != null) {
1377                            if (adeConfig.getDirectEditPermissions(type).canCreate()
1378                                && currentType.checkCreatable(cms, null)) {
1379                                CmsListInfoBean typeInfo = new CmsListInfoBean();
1380                                CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
1381                                    type);
1382                                String title = CmsWorkplaceMessages.getResourceTypeName(locale, type);
1383                                typeInfo.setTitle(title);
1384                                String description = CmsWorkplaceMessages.getResourceTypeDescription(locale, type);
1385                                typeInfo.setSubTitle(description);
1386                                typeInfo.setResourceType(type);
1387                                typeInfo.setBigIconClasses(CmsIconUtil.getIconClasses(explorerType, null, false));
1388                                String newLink = CmsJspTagEdit.getNewLink(
1389                                    cms,
1390                                    OpenCms.getResourceManager().getResourceType(type),
1391                                    cms.getRequestContext().getUri());
1392                                CmsListElementCreationOption option = new CmsListElementCreationOption(
1393                                    type,
1394                                    typeInfo,
1395                                    newLink);
1396                                result.add(option);
1397                            }
1398                        }
1399                    } catch (Exception e) {
1400                        LOG.error(e.getLocalizedMessage(), e);
1401                    }
1402                }
1403                if (result.getOptions().size() == 0) {
1404                    result.setMessage(msg.key(Messages.GUI_LISTADD_NO_TYPES_0));
1405                }
1406            }
1407
1408            return result;
1409        } catch (Exception e) {
1410            error(e);
1411            return null;
1412        }
1413    }
1414
1415    /**
1416     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getNewElementData(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.util.Collection, java.lang.String)
1417     */
1418    public CmsContainerElementData getNewElementData(
1419        CmsContainerPageRpcContext context,
1420        CmsUUID detailContentId,
1421        String reqParams,
1422        String resourceType,
1423        Collection<CmsContainer> containers,
1424        String localeName)
1425    throws CmsRpcException {
1426
1427        CmsContainerElementData result = null;
1428        try {
1429            ensureSession();
1430            CmsResource pageResource = getCmsObject().readResource(
1431                context.getPageStructureId(),
1432                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1433            initRequestFromRpcContext(context);
1434            String containerpageUri = getCmsObject().getSitePath(pageResource);
1435            Locale locale = CmsLocaleManager.getLocale(localeName);
1436            result = getNewElement(
1437                getServerIdString(resourceType),
1438                containerpageUri,
1439                detailContentId,
1440                containers,
1441                locale);
1442
1443            CmsListInfoBean info = new CmsListInfoBean();
1444            // type title and subtitle
1445            String realType = getServerIdString(resourceType);
1446            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1447            info.setTitle(CmsWorkplaceMessages.getResourceTypeName(wpLocale, realType));
1448            info.setSubTitle(CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, realType));
1449            info.setBigIconClasses(CmsIconUtil.getIconClasses(realType, null, false));
1450            result.setListInfo(info);
1451        } catch (Throwable e) {
1452            error(e);
1453        }
1454        return result;
1455    }
1456
1457    /**
1458     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getNewOptions(java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1459     */
1460    public CmsDialogOptionsAndInfo getNewOptions(String clientId, CmsUUID pageStructureId, String requestParams)
1461    throws CmsRpcException {
1462
1463        try {
1464            CmsResource pageResource = getCmsObject().readResource(
1465                pageStructureId,
1466                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1467            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1468            element.initResource(getCmsObject());
1469            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1470            if (type instanceof CmsResourceTypeXmlContent) {
1471                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1472                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1473                    CmsEncoder.decode(requestParams),
1474                    true,
1475                    CmsEncoder.ENCODING_UTF_8);
1476                CmsDialogOptions options = handler.getNewOptions(getCmsObject(), element, pageStructureId, params);
1477                if (options != null) {
1478                    return new CmsDialogOptionsAndInfo(
1479                        options,
1480                        CmsVfsService.getPageInfo(getCmsObject(), element.getResource()));
1481                }
1482            }
1483        } catch (CmsException e) {
1484            error(e);
1485        }
1486        return null;
1487
1488    }
1489
1490    /**
1491     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getRecentList(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.util.Collection, java.lang.String)
1492     */
1493    public List<CmsContainerElementData> getRecentList(
1494        CmsUUID pageStructureId,
1495        CmsUUID detailContentId,
1496        Collection<CmsContainer> containers,
1497        String locale)
1498    throws CmsRpcException {
1499
1500        List<CmsContainerElementData> result = null;
1501        try {
1502            ensureSession();
1503            CmsResource containerpage = getCmsObject().readResource(
1504                pageStructureId,
1505                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1506            String containerpageUri = getCmsObject().getSitePath(containerpage);
1507            result = getListElementsData(
1508                OpenCms.getADEManager().getRecentList(getCmsObject()),
1509                containerpageUri,
1510                detailContentId,
1511                containers,
1512                CmsLocaleManager.getLocale(locale));
1513        } catch (Throwable e) {
1514            error(e);
1515        }
1516        return result;
1517    }
1518
1519    /**
1520     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getRemovedElementStatus(java.lang.String, org.opencms.util.CmsUUID)
1521     */
1522    public CmsRemovedElementStatus getRemovedElementStatus(String id, CmsUUID containerpageId) throws CmsRpcException {
1523
1524        if ((id == null) || !id.matches(CmsUUID.UUID_REGEX + ".*$")) {
1525            return new CmsRemovedElementStatus(null, null, false, null);
1526        }
1527        try {
1528            CmsUUID structureId = convertToServerId(id);
1529            return internalGetRemovedElementStatus(structureId, containerpageId);
1530        } catch (CmsException e) {
1531            error(e);
1532            return null;
1533        }
1534    }
1535
1536    /**
1537     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getReuseInfo(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1538     */
1539    public CmsReuseInfo getReuseInfo(CmsUUID pageId, CmsUUID detailId, CmsUUID elementId) throws CmsRpcException {
1540
1541        try {
1542            CmsObject cms = getCmsObject();
1543            Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1544            CmsResource detailResource = null;
1545            CmsResource element = cms.readResource(elementId, CmsResourceFilter.IGNORE_EXPIRATION);
1546            if (detailId != null) {
1547                detailResource = cms.readResource(detailId, CmsResourceFilter.IGNORE_EXPIRATION);
1548            }
1549            Set<CmsUUID> idsForCurrentPage = CmsElementUtil.getPageAndDetailOnlyIds(
1550                getCmsObject(),
1551                pageId,
1552                detailResource);
1553            List<CmsResource> allUses = OpenCms.getADEManager().getOfflineElementUses(element).filter(
1554                res -> !idsForCurrentPage.contains(res.getStructureId())).collect(Collectors.toList());
1555            List<CmsResourceListInfo> infos = new ArrayList<>();
1556            int visibleCount = 0;
1557            for (CmsResource use : allUses) {
1558                try {
1559                    // make sure resource is visible to current user, otherwise continue with next resource
1560                    cms.readResource(use.getStructureId(), CmsResourceFilter.IGNORE_EXPIRATION.addRequireVisible());
1561                    visibleCount += 1;
1562                    CmsResourceListInfo info = new CmsResourceListInfo();
1563                    CmsVfsService.addPageInfo(cms, use, info);
1564                    info.setStructureId(use.getStructureId());
1565                    infos.add(info);
1566                    if (visibleCount >= MAX_VISIBLE_ELEMENT_USES) {
1567                        break;
1568                    }
1569                } catch (CmsVfsResourceNotFoundException | CmsPermissionViolationException e) {
1570                    // ignore
1571                } catch (Exception e) {
1572                    LOG.error(e.getLocalizedMessage(), e);
1573                }
1574            }
1575            CmsListInfoBean elementInfo = CmsVfsService.getPageInfo(cms, element);
1576            String message;
1577            CmsMessages messages = Messages.get().getBundle(locale);
1578            if (allUses.size() > 0) {
1579                message = messages.key(Messages.GUI_REUSE_CHECK_WARNING_TEXT_1, "" + allUses.size());
1580            } else {
1581                message = "";
1582            }
1583            String title = messages.key(Messages.GUI_REUSE_CHECK_TITLE_0);
1584            if (allUses.size() > infos.size()) {
1585                message = message + "\n" + messages.key(Messages.GUI_REUSE_CHECK_ONLY_SHOW_N_1, infos.size());
1586            }
1587            CmsReuseInfo result = new CmsReuseInfo(elementInfo, infos, message, title, allUses.size());
1588            return result;
1589        } catch (Exception e) {
1590            error(e);
1591            return null;
1592        }
1593    }
1594
1595    /**
1596     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#handleDelete(java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1597     */
1598    public void handleDelete(String clientId, String deleteOption, CmsUUID pageId, String requestParams)
1599    throws CmsRpcException {
1600
1601        try {
1602            CmsResource pageResource = getCmsObject().readResource(
1603                pageId,
1604                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1605            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1606            element.initResource(getCmsObject());
1607            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1608            if (type instanceof CmsResourceTypeXmlContent) {
1609                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1610                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1611                    CmsEncoder.decode(requestParams),
1612                    true,
1613                    CmsEncoder.ENCODING_UTF_8);
1614                handler.handleDelete(getCmsObject(), element, deleteOption, pageId, params);
1615            }
1616        } catch (CmsException e) {
1617            error(e);
1618        }
1619    }
1620
1621    /**
1622     * Internal helper method to get the status of a removed element.<p>
1623     *
1624     * @param structureId the structure id of the removed element
1625     * @param containerpageId the id of the page to exclude from the relation check, or null if no page should be excluded
1626     *
1627     * @return the status of the removed element
1628     *
1629     * @throws CmsException in case reading the resource fails
1630     */
1631    public CmsRemovedElementStatus internalGetRemovedElementStatus(CmsUUID structureId, CmsUUID containerpageId)
1632    throws CmsException {
1633
1634        CmsObject cms = getCmsObject();
1635        CmsResource elementResource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1636        boolean hasWritePermissions = cms.hasPermissions(
1637            elementResource,
1638            CmsPermissionSet.ACCESS_WRITE,
1639            false,
1640            CmsResourceFilter.ALL);
1641        boolean isSystemResource = elementResource.getRootPath().startsWith(CmsResource.VFS_FOLDER_SYSTEM + "/");
1642        CmsRelationFilter relationFilter = CmsRelationFilter.relationsToStructureId(structureId);
1643        List<CmsRelation> relationsToElement = cms.readRelations(relationFilter);
1644        Iterator<CmsRelation> iter = relationsToElement.iterator();
1645
1646        // ignore XML_STRONG (i.e. container element) relations from the container page, this must be checked on the client side.
1647        while (iter.hasNext()) {
1648            CmsRelation relation = iter.next();
1649            if ((containerpageId != null)
1650                && containerpageId.equals(relation.getSourceId())
1651                && relation.getType().equals(CmsRelationType.XML_STRONG)) {
1652                iter.remove();
1653            }
1654        }
1655        ElementDeleteMode elementDeleteMode = null;
1656        CmsResource pageResource = cms.readResource(containerpageId, CmsResourceFilter.IGNORE_EXPIRATION);
1657        CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(cms, pageResource.getRootPath());
1658        CmsResourceTypeConfig typeConfig = adeConfig.getResourceType(
1659            OpenCms.getResourceManager().getResourceType(elementResource).getTypeName());
1660
1661        if (typeConfig != null) {
1662            elementDeleteMode = typeConfig.getElementDeleteMode();
1663        }
1664
1665        boolean hasNoRelations = relationsToElement.isEmpty();
1666        boolean deletionCandidate = hasNoRelations && hasWritePermissions && !isSystemResource;
1667        CmsListInfoBean elementInfo = CmsVfsService.getPageInfo(cms, elementResource);
1668        return new CmsRemovedElementStatus(structureId, elementInfo, deletionCandidate, elementDeleteMode);
1669    }
1670
1671    /**
1672     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#loadClipboardTab()
1673     */
1674    public int loadClipboardTab() {
1675
1676        Integer clipboardTab = (Integer)(getRequest().getSession().getAttribute(ATTR_CLIPBOARD_TAB));
1677        if (clipboardTab == null) {
1678            clipboardTab = Integer.valueOf(0);
1679        }
1680        return clipboardTab.intValue();
1681    }
1682
1683    /**
1684     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prefetch()
1685     */
1686    public CmsCntPageData prefetch() throws CmsRpcException {
1687
1688        CmsCntPageData data = null;
1689        CmsObject cms = getCmsObject();
1690        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1691        HttpServletRequest request = getRequest();
1692
1693        try {
1694            Map<String, String> sessionStorageData = new HashMap<>();
1695            CmsTemplateContextInfo info = OpenCms.getTemplateContextManager().getContextInfoBean(cms, request);
1696            CmsResource containerPage = getContainerpage(cms);
1697            Set<String> detailTypes = getDetailTypes(cms, containerPage);
1698            boolean isEditingModelGroup = isEditingModelGroups(cms, containerPage);
1699            boolean isModelPage = isModelPage(cms, containerPage);
1700            if (isModelPage) {
1701                // the model edit confirm dialog should only be shown once per session, disable it after first model editing
1702                getRequest().getSession().setAttribute(
1703                    CmsVfsSitemapService.ATTR_SHOW_MODEL_EDIT_CONFIRM,
1704                    Boolean.FALSE);
1705            }
1706
1707            TemplateBean templateBean = (TemplateBean)getRequest().getAttribute(
1708                CmsTemplateContextManager.ATTR_TEMPLATE_BEAN);
1709            CmsADESessionCache sessionCache = CmsADESessionCache.getCache(getRequest(), cms);
1710            sessionCache.setTemplateBean(containerPage.getRootPath(), templateBean);
1711            long lastModified = containerPage.getDateLastModified();
1712            String editorUri = OpenCms.getWorkplaceManager().getEditorHandler().getEditorUri(
1713                cms,
1714                CmsResourceTypeXmlContent.getStaticTypeName(),
1715                "User agent",
1716                false);
1717            boolean useClassicEditor = (editorUri == null) || !editorUri.contains("acacia");
1718            CmsResource detailResource = CmsDetailPageResourceHandler.getDetailResource(request);
1719            String noEditReason;
1720            String detailContainerPage = null;
1721            CmsQuickLaunchLocationCache locationCache = CmsQuickLaunchLocationCache.getLocationCache(
1722                request.getSession());
1723            CmsUUID detailContainerPageId = null;
1724            if (detailResource != null) {
1725                locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), detailResource);
1726                CmsObject rootCms = OpenCms.initCmsObject(cms);
1727                rootCms.getRequestContext().setSiteRoot("");
1728                String detailResourcePath = detailResource.getRootPath();
1729                String locale = cms.getRequestContext().getLocale().toString();
1730                detailContainerPage = CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
1731                    cms,
1732                    containerPage,
1733                    detailResourcePath,
1734                    locale);
1735
1736                if (rootCms.existsResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION)) {
1737                    detailContainerPageId = rootCms.readResource(
1738                        detailContainerPage,
1739                        CmsResourceFilter.IGNORE_EXPIRATION).getStructureId();
1740                    noEditReason = getNoEditReason(
1741                        rootCms,
1742                        rootCms.readResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION));
1743                } else {
1744                    String permissionFolder = CmsResource.getFolderPath(detailContainerPage);
1745                    while (!rootCms.existsResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION)) {
1746                        permissionFolder = CmsResource.getParentFolder(permissionFolder);
1747                    }
1748                    noEditReason = getNoEditReason(
1749                        rootCms,
1750                        rootCms.readResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION));
1751                }
1752            } else {
1753                if (!isModelPage && !isEditingModelGroup) {
1754                    locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), containerPage);
1755                    sessionStorageData.put(
1756                        CmsGwtConstants.LAST_CONTAINER_PAGE_ID,
1757                        containerPage.getStructureId().toString());
1758                }
1759                noEditReason = getNoEditReason(cms, containerPage);
1760            }
1761
1762            String sitemapPath = "";
1763            boolean sitemapManager = OpenCms.getRoleManager().hasRole(cms, CmsRole.EDITOR);
1764            if (sitemapManager) {
1765                sitemapPath = CmsADEManager.PATH_SITEMAP_EDITOR_JSP;
1766            }
1767            CmsCntPageData.ElementReuseMode reuseMode = ElementReuseMode.reuse;
1768            String reuseModeString = getWorkplaceSettings().getUserSettings().getAdditionalPreference(
1769                "elementReuseMode",
1770                true);
1771
1772            try {
1773                reuseMode = ElementReuseMode.valueOf(reuseModeString);
1774            } catch (Exception e) {
1775                LOG.info("Invalid reuse mode : " + reuseModeString, e);
1776            }
1777            InitialElementViewProvider viewHelper = new InitialElementViewProvider();
1778            viewHelper.init(getSessionCache().getElementView(), containerPage, info);
1779            CmsLocaleGroup group = cms.getLocaleGroupService().readLocaleGroup(containerPage);
1780            Locale mainLocale = null;
1781
1782            if (group.isRealGroup() && !cms.getRequestContext().getLocale().equals(group.getMainLocale())) {
1783                mainLocale = group.getMainLocale();
1784            }
1785            CmsSiteManagerImpl siteManager = OpenCms.getSiteManager();
1786            String ownRoot = siteManager.getSiteRoot(containerPage.getRootPath());
1787            Map<String, CmsLocaleLinkBean> localeLinkBeans = null;
1788            if (group.isRealGroup()) {
1789                localeLinkBeans = Maps.newHashMap();
1790                Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1791                for (Map.Entry<Locale, CmsResource> entry : group.getResourcesByLocale().entrySet()) {
1792                    String otherRoot = siteManager.getSiteRoot(entry.getValue().getRootPath());
1793                    if ((otherRoot != null) && otherRoot.equals(ownRoot)) {
1794                        String theLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1795                            cms,
1796                            cms.getRequestContext().removeSiteRoot(entry.getValue().getRootPath()));
1797                        localeLinkBeans.put(entry.getKey().getDisplayLanguage(locale), CmsLocaleLinkBean.link(theLink));
1798                    } else {
1799                        localeLinkBeans.put(
1800                            entry.getKey().getDisplayLanguage(locale),
1801                            CmsLocaleLinkBean.error(
1802                                Messages.get().getBundle(locale).key(Messages.GUI_SHOWLOCALE_WRONG_SITE_0)));
1803                    }
1804                }
1805            }
1806
1807            String onlineLink = null;
1808            CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(cms.getRequestContext().getSiteRoot());
1809            if ((site != null) && !OpenCms.getSiteManager().getWorkplaceServer().equals(site.getUrl())) {
1810                if (detailResource != null) {
1811                    onlineLink = OpenCms.getLinkManager().getOnlineLink(
1812                        cms,
1813                        cms.getSitePath(detailResource),
1814                        cms.getSitePath(containerPage),
1815                        false);
1816                } else {
1817                    onlineLink = OpenCms.getLinkManager().getOnlineLink(cms, cms.getSitePath(containerPage));
1818                }
1819            }
1820
1821            String modelGroupElementId = null;
1822            if (isEditingModelGroup) {
1823                CmsProperty modelElementProp = cms.readPropertyObject(
1824                    containerPage,
1825                    CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
1826                    false);
1827                if (!modelElementProp.isNullProperty() && CmsUUID.isValidUUID(modelElementProp.getValue())) {
1828                    modelGroupElementId = modelElementProp.getValue();
1829                }
1830            }
1831            String title = null;
1832            if (isModelPage || isEditingModelGroup) {
1833                title = Messages.get().getBundle(wpLocale).key(Messages.GUI_TITLE_MODEL_0);
1834
1835            }
1836            ElementDeleteMode deleteMode = OpenCms.getWorkplaceManager().getElementDeleteMode();
1837            if (deleteMode == null) {
1838                deleteMode = ElementDeleteMode.askDelete;
1839            }
1840            CmsListInfoBean pageInfo = CmsVfsService.getPageInfo(cms, containerPage);
1841            data = new CmsCntPageData(
1842                onlineLink,
1843                noEditReason,
1844                CmsRequestUtil.encodeParams(request),
1845                sitemapPath,
1846                sitemapManager,
1847                detailResource != null ? detailResource.getStructureId() : null,
1848                detailContainerPage,
1849                detailContainerPageId,
1850                detailTypes,
1851                lastModified,
1852                getLockInfo(containerPage),
1853                pageInfo,
1854                cms.getRequestContext().getLocale().toString(),
1855                useClassicEditor,
1856                info,
1857                isEditSmallElements(request, cms),
1858                Lists.newArrayList(viewHelper.getViewMap().values()),
1859                viewHelper.getDefaultView(),
1860                reuseMode,
1861                deleteMode,
1862                isModelPage,
1863                isEditingModelGroup,
1864                modelGroupElementId,
1865                mainLocale != null ? mainLocale.toString() : null,
1866                localeLinkBeans,
1867                title,
1868                System.currentTimeMillis());
1869            boolean allowSettingsInEditor = true;
1870            CmsModule baseModule = OpenCms.getModuleManager().getModule("org.opencms.base");
1871            if (baseModule != null) {
1872                String param = baseModule.getParameter("allowSettingsInEditor");
1873                allowSettingsInEditor = CmsStringUtil.isEmptyOrWhitespaceOnly(param)
1874                    || Boolean.valueOf(param).booleanValue();
1875            }
1876            data.setAllowSettingsInEditor(allowSettingsInEditor);
1877            String placementModeEnabledStr = (String)OpenCms.getRuntimeProperty(PARAM_PAGE_EDITOR_PLACEMENT_MODE_ENABLED);
1878            boolean placementModeEnabled = (placementModeEnabledStr == null) || Boolean.parseBoolean(placementModeEnabledStr);
1879            data.setPlacementModeEnabled(placementModeEnabled);
1880            data.setSessionStorageData(sessionStorageData);
1881        } catch (Throwable e) {
1882            error(e);
1883        }
1884        return data;
1885    }
1886
1887    /**
1888     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prepareForEdit(java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1889     */
1890    public CmsUUID prepareForEdit(String clientId, String editOption, CmsUUID pageId, String requestParams)
1891    throws CmsRpcException {
1892
1893        try {
1894            CmsResource pageResource = getCmsObject().readResource(
1895                pageId,
1896                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1897            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1898            element.initResource(getCmsObject());
1899            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1900            if (type instanceof CmsResourceTypeXmlContent) {
1901                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1902                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1903                    CmsEncoder.decode(requestParams),
1904                    true,
1905                    CmsEncoder.ENCODING_UTF_8);
1906                return handler.prepareForEdit(getCmsObject(), element, editOption, pageId, params);
1907            }
1908        } catch (CmsException e) {
1909            error(e);
1910        }
1911        return null;
1912    }
1913
1914    /**
1915     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#replaceElement(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.lang.String, java.util.Collection, java.lang.String)
1916     */
1917    public CmsContainerElementData replaceElement(
1918        CmsContainerPageRpcContext context,
1919        CmsUUID detailContentId,
1920        String reqParams,
1921        String clientId,
1922        String replaceId,
1923        Collection<CmsContainer> containers,
1924        String locale)
1925    throws CmsRpcException {
1926
1927        CmsContainerElementData element = null;
1928        try {
1929            ensureSession();
1930            CmsObject cms = getCmsObject();
1931            CmsResource pageResource = cms.readResource(
1932                context.getPageStructureId(),
1933                CmsResourceFilter.ignoreExpirationOffline(cms));
1934            initRequestFromRpcContext(context);
1935            String containerpageUri = cms.getSitePath(pageResource);
1936            Locale contentLocale = CmsLocaleManager.getLocale(locale);
1937            CmsElementUtil elemUtil = new CmsElementUtil(
1938                cms,
1939                containerpageUri,
1940                generateContainerPageForContainers(containers, pageResource.getRootPath()),
1941                detailContentId,
1942                getRequest(),
1943                getResponse(),
1944                false,
1945                contentLocale);
1946
1947            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
1948            Map<String, String> settings = new HashMap<String, String>(elementBean.getIndividualSettings());
1949            settings.remove(CmsContainerElement.ELEMENT_INSTANCE_ID);
1950            CmsContainerElementBean replaceBean = new CmsContainerElementBean(
1951                new CmsUUID(replaceId),
1952                elementBean.getFormatterId(),
1953                settings,
1954                elementBean.isCreateNew());
1955            getSessionCache().setCacheContainerElement(replaceBean.editorHash(), replaceBean);
1956            element = elemUtil.getElementData(pageResource, replaceBean, containers);
1957        } catch (Throwable e) {
1958            error(e);
1959        }
1960        return element;
1961    }
1962
1963    /**
1964     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveClipboardTab(int)
1965     */
1966    public void saveClipboardTab(int tabIndex) {
1967
1968        getRequest().getSession().setAttribute(ATTR_CLIPBOARD_TAB, Integer.valueOf(tabIndex));
1969    }
1970
1971    /**
1972     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveContainerpage(org.opencms.util.CmsUUID, java.util.List)
1973     */
1974    public long saveContainerpage(CmsUUID pageStructureId, List<CmsContainer> containers) throws CmsRpcException {
1975
1976        CmsObject cms = getCmsObject();
1977        try {
1978            ensureSession();
1979            CmsResource containerpage = cms.readResource(
1980                pageStructureId,
1981                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1982            ensureLock(containerpage);
1983            String containerpageUri = cms.getSitePath(containerpage);
1984            saveContainers(cms, containerpage, containerpageUri, containers);
1985        } catch (Throwable e) {
1986            error(e);
1987        }
1988        return System.currentTimeMillis();
1989    }
1990
1991    /**
1992     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveDetailContainers(org.opencms.util.CmsUUID, java.lang.String, java.util.List)
1993     */
1994    public long saveDetailContainers(CmsUUID detailId, String detailContainerResource, List<CmsContainer> containers)
1995    throws CmsRpcException {
1996
1997        CmsObject cms = getCmsObject();
1998        try {
1999            ensureSession();
2000            CmsObject rootCms = OpenCms.initCmsObject(cms);
2001            rootCms.getRequestContext().setSiteRoot("");
2002            CmsResource containerpage;
2003            containerpage = CmsDetailOnlyContainerUtil.readOrCreateDetailOnlyPage(
2004                rootCms,
2005                detailId,
2006                detailContainerResource);
2007            saveContainers(rootCms, containerpage, detailContainerResource, containers);
2008        } catch (Throwable e) {
2009            error(e);
2010        }
2011        return System.currentTimeMillis();
2012    }
2013
2014    /**
2015     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveElementSettings(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.util.Map, java.util.List, java.lang.String)
2016     */
2017    public CmsContainerElementData saveElementSettings(
2018        CmsContainerPageRpcContext context,
2019        CmsUUID detailContentId,
2020        String reqParams,
2021        String clientId,
2022        Map<String, String> settings,
2023        List<CmsContainer> containers,
2024        String locale)
2025    throws CmsRpcException {
2026
2027        CmsContainerElementData element = null;
2028        try {
2029            ensureSession();
2030            CmsObject cms = getCmsObject();
2031            CmsResource pageResource = cms.readResource(
2032                context.getPageStructureId(),
2033                CmsResourceFilter.ignoreExpirationOffline(cms));
2034            initRequestFromRpcContext(context);
2035            Locale contentLocale = CmsLocaleManager.getLocale(locale);
2036            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
2037            elementBean.initResource(cms);
2038            storeFormatterSelection(elementBean, settings);
2039            // make sure to keep the element instance id
2040            if (!settings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)
2041                && elementBean.getIndividualSettings().containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) {
2042                settings.put(
2043                    CmsContainerElement.ELEMENT_INSTANCE_ID,
2044                    elementBean.getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID));
2045            }
2046            if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.SETTING_PAGE_ID)) {
2047                settings.put(
2048                    CmsContainerElement.SETTING_PAGE_ID,
2049                    elementBean.getIndividualSettings().get(CmsContainerElement.SETTING_PAGE_ID));
2050            }
2051            if (!isEditingModelGroups(cms, pageResource)) {
2052                // in case of model group state set to 'noGroup', the group will be dissolved and former group id forgotten
2053                if (!(settings.containsKey(CmsContainerElement.MODEL_GROUP_STATE)
2054                    && (ModelGroupState.noGroup == ModelGroupState.evaluate(
2055                        settings.get(CmsContainerElement.MODEL_GROUP_STATE))))) {
2056                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID)) {
2057                        // make sure to keep the model group id
2058                        settings.put(
2059                            CmsContainerElement.MODEL_GROUP_ID,
2060                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID));
2061                    }
2062                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE)) {
2063                        settings.put(
2064                            CmsContainerElement.MODEL_GROUP_STATE,
2065                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE));
2066                    }
2067                }
2068            }
2069            elementBean = CmsContainerElementBean.cloneWithSettings(
2070                elementBean,
2071                convertSettingValues(elementBean.getResource(), settings, contentLocale));
2072            getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
2073
2074            // update client id within container data
2075            for (CmsContainer container : containers) {
2076                for (CmsContainerElement child : container.getElements()) {
2077                    if (child.getClientId().equals(clientId)) {
2078                        child.setClientId(elementBean.editorHash());
2079                    }
2080                }
2081            }
2082            if (detailContentId == null) {
2083                saveContainers(cms, pageResource, cms.getSitePath(pageResource), containers);
2084            } else {
2085                List<CmsContainer> detailContainers = new ArrayList<CmsContainer>();
2086                for (CmsContainer container : containers) {
2087                    if (container.isDetailOnly()) {
2088                        detailContainers.add(container);
2089                    }
2090                }
2091                CmsObject rootCms = OpenCms.initCmsObject(cms);
2092                rootCms.getRequestContext().setSiteRoot("");
2093                CmsResource detailResource = rootCms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2094                String detailRootPath = detailResource.getRootPath();
2095                CmsResource detailContainerPage = rootCms.readResource(
2096                    CmsDetailOnlyContainerUtil.getDetailOnlyPageName(cms, pageResource, detailRootPath, locale));
2097
2098                ensureLock(detailContainerPage);
2099                saveContainers(rootCms, detailContainerPage, detailContainerPage.getRootPath(), detailContainers);
2100            }
2101            String containerpageUri = cms.getSitePath(pageResource);
2102            CmsElementUtil elemUtil = new CmsElementUtil(
2103                cms,
2104                containerpageUri,
2105                generateContainerPageForContainers(containers, pageResource.getRootPath()),
2106                detailContentId,
2107                getRequest(),
2108                getResponse(),
2109                false,
2110                contentLocale);
2111            element = elemUtil.getElementData(pageResource, elementBean, containers);
2112        } catch (Throwable e) {
2113            error(e);
2114        }
2115        return element;
2116    }
2117
2118    /**
2119     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveFavoriteList(java.util.List, java.lang.String)
2120     */
2121    public void saveFavoriteList(List<String> clientIds, String uri) throws CmsRpcException {
2122
2123        try {
2124            ensureSession();
2125            OpenCms.getADEManager().saveFavoriteList(
2126                getCmsObject(),
2127                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2128        } catch (Throwable e) {
2129            error(e);
2130        }
2131    }
2132
2133    /**
2134     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveGroupContainer(org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext, org.opencms.util.CmsUUID, java.lang.String, org.opencms.ade.containerpage.shared.CmsGroupContainer, java.util.Collection, java.lang.String)
2135     */
2136    public CmsGroupContainerSaveResult saveGroupContainer(
2137        CmsContainerPageRpcContext context,
2138
2139        CmsUUID detailContentId,
2140        String reqParams,
2141        CmsGroupContainer groupContainer,
2142        Collection<CmsContainer> containers,
2143        String locale)
2144    throws CmsRpcException {
2145
2146        CmsObject cms = getCmsObject();
2147        List<CmsRemovedElementStatus> removedElements = null;
2148        try {
2149            CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> saveResult = internalSaveGroupContainer(
2150                cms,
2151                context.getPageStructureId(),
2152                groupContainer);
2153            removedElements = saveResult.getSecond();
2154        } catch (Throwable e) {
2155            error(e);
2156        }
2157        Collection<String> ids = new ArrayList<String>();
2158        ids.add(groupContainer.getClientId());
2159        // update offline indices
2160        OpenCms.getSearchManager().updateOfflineIndexes();
2161        return new CmsGroupContainerSaveResult(
2162            getElementsData(context, detailContentId, reqParams, ids, containers, false, null, locale),
2163            removedElements);
2164    }
2165
2166    /**
2167     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveInheritanceContainer(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, org.opencms.ade.containerpage.shared.CmsInheritanceContainer, java.util.Collection, java.lang.String)
2168     */
2169    public Map<String, CmsContainerElementData> saveInheritanceContainer(
2170        CmsUUID pageStructureId,
2171        CmsUUID detailContentId,
2172        CmsInheritanceContainer inheritanceContainer,
2173        Collection<CmsContainer> containers,
2174        String locale)
2175    throws CmsRpcException {
2176
2177        try {
2178            CmsObject cms = getCmsObject();
2179            CmsADEConfigData rpcConfig = OpenCms.getADEManager().lookupConfiguration(
2180                cms,
2181                cms.getRequestContext().getRootUri());
2182            CmsResource containerPage = cms.readResource(
2183                pageStructureId,
2184                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
2185            String sitePath = cms.getSitePath(containerPage);
2186            Locale requestedLocale = CmsLocaleManager.getLocale(locale);
2187            CmsResource referenceResource = null;
2188            if (inheritanceContainer.isNew()) {
2189                CmsADEConfigData config = getConfigData(containerPage.getRootPath());
2190                CmsResourceTypeConfig typeConfig = config.getResourceType(
2191                    CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_TYPE_NAME);
2192                referenceResource = typeConfig.createNewElement(cms, containerPage.getRootPath());
2193                inheritanceContainer.setClientId(referenceResource.getStructureId().toString());
2194            }
2195            if (referenceResource == null) {
2196                CmsUUID id = convertToServerId(inheritanceContainer.getClientId());
2197                referenceResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2198            }
2199            ensureLock(referenceResource);
2200            saveInheritanceGroup(referenceResource, inheritanceContainer);
2201            tryUnlock(referenceResource);
2202            List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2203            for (CmsContainerElement clientElement : inheritanceContainer.getElements()) {
2204                CmsContainerElementBean elementBean = getCachedElement(
2205                    clientElement.getClientId(),
2206                    containerPage.getRootPath());
2207                elementBean = CmsContainerElementBean.cloneWithSettings(
2208                    elementBean,
2209                    elementBean.getIndividualSettings());
2210                CmsInheritanceInfo inheritanceInfo = clientElement.getInheritanceInfo();
2211                // if a local elements misses the key it was newly added
2212                if (inheritanceInfo.isNew() && CmsStringUtil.isEmptyOrWhitespaceOnly(inheritanceInfo.getKey())) {
2213                    // generating new key
2214                    inheritanceInfo.setKey(CmsResource.getFolderPath(sitePath) + new CmsUUID().toString());
2215                }
2216                elementBean.setInheritanceInfo(inheritanceInfo);
2217                elements.add(elementBean);
2218            }
2219            cms.getRequestContext().setLocale(requestedLocale);
2220            if (inheritanceContainer.getElementsChanged()) {
2221                OpenCms.getADEManager().saveInheritedContainer(
2222                    cms,
2223                    containerPage,
2224                    inheritanceContainer.getName(),
2225                    true,
2226                    elements);
2227            }
2228            return getElements(
2229                rpcConfig,
2230                containerPage,
2231                new ArrayList<String>(Collections.singletonList(inheritanceContainer.getClientId())),
2232                sitePath,
2233                detailContentId,
2234                containers,
2235                false,
2236                null,
2237                false,
2238                requestedLocale);
2239        } catch (Exception e) {
2240            error(e);
2241        }
2242        return null;
2243    }
2244
2245    /**
2246     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveRecentList(java.util.List, java.lang.String)
2247     */
2248    public void saveRecentList(List<String> clientIds, String uri) throws CmsRpcException {
2249
2250        try {
2251            ensureSession();
2252            OpenCms.getADEManager().saveRecentList(
2253                getCmsObject(),
2254                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2255        } catch (Throwable e) {
2256            error(e);
2257        }
2258    }
2259
2260    /**
2261     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setEditSmallElements(boolean)
2262     */
2263    public void setEditSmallElements(boolean editSmallElements) throws CmsRpcException {
2264
2265        try {
2266            CmsObject cms = getCmsObject();
2267            CmsUser user = cms.getRequestContext().getCurrentUser();
2268            user.getAdditionalInfo().put(ADDINFO_EDIT_SMALL_ELEMENTS, "" + editSmallElements);
2269            cms.writeUser(user);
2270        } catch (Throwable t) {
2271            error(t);
2272        }
2273    }
2274
2275    /**
2276     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setElementView(org.opencms.util.CmsUUID)
2277     */
2278    public void setElementView(CmsUUID elementView) {
2279
2280        getSessionCache().setElementView(elementView);
2281    }
2282
2283    /**
2284     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setLastPage(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
2285     */
2286    public void setLastPage(CmsUUID pageId, CmsUUID detailId) throws CmsRpcException {
2287
2288        try {
2289            HttpServletRequest req = getRequest();
2290            CmsObject cms = getCmsObject();
2291            CmsADESessionCache cache = CmsADESessionCache.getCache(req, cms);
2292            cache.setLastPage(cms, pageId, detailId);
2293        } catch (Exception e) {
2294            error(e);
2295        }
2296
2297    }
2298
2299    /**
2300     * Sets the session cache.<p>
2301     *
2302     * @param cache the session cache
2303     */
2304    public void setSessionCache(CmsADESessionCache cache) {
2305
2306        m_sessionCache = cache;
2307    }
2308
2309    /**
2310     * Gets the settings which should be updated for an element in the DND case.<p>
2311     *
2312     * @param config the sitemap configuration
2313     * @param originalSettings the original settings
2314     * @param formatterConfig the formatter configuration for the element
2315     * @param containers the containers
2316     * @param dndContainer the id of the DND origin container
2317     *
2318     * @return the map of settings to update
2319     */
2320    Map<String, String> getSettingsToChangeForDnd(
2321        CmsADEConfigData config,
2322        Map<String, String> originalSettings,
2323        CmsFormatterConfiguration formatterConfig,
2324        Collection<CmsContainer> containers,
2325        String dndContainer) {
2326
2327        Map<String, String> result = Maps.newHashMap();
2328
2329        if (dndContainer == null) {
2330            return result;
2331        }
2332        String key = CmsFormatterConfig.getSettingsKeyForContainer(dndContainer);
2333        String formatterId = originalSettings.get(key);
2334        if (formatterId == null) {
2335            return result;
2336        }
2337        for (CmsContainer container : containers) {
2338            if (container.getName().equals(dndContainer)) {
2339                continue;
2340            }
2341
2342            Map<String, I_CmsFormatterBean> formatterSelection = formatterConfig.getFormatterSelection(
2343                container.getType(),
2344                container.getWidth());
2345            I_CmsFormatterBean currentBean = config.findFormatter(formatterId);
2346            if (currentBean != null) {
2347                if (CmsFormatterConfiguration.matchFormatter(currentBean, container.getType(), container.getWidth())) {
2348                    String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2349                    result.put(newKey, currentBean.getKeyOrId());
2350                }
2351            } else if (formatterSelection.containsKey(formatterId)) {
2352                // for backwards compatibility with schema-configured formatters
2353                String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2354                result.put(newKey, formatterId);
2355            }
2356        }
2357        return result;
2358    }
2359
2360    /**
2361     * Creates a new container element bean from an existing one, but changes some of the individual settings in the copy.<p>
2362     *
2363     * @param element the original container element
2364     * @param settingsToOverride the map of settings to change
2365     *
2366     * @return the new container element bean with the changed settings
2367     */
2368    CmsContainerElementBean overrideSettings(CmsContainerElementBean element, Map<String, String> settingsToOverride) {
2369
2370        Map<String, String> settings = Maps.newHashMap(element.getIndividualSettings());
2371        settings.putAll(settingsToOverride);
2372        CmsContainerElementBean result = new CmsContainerElementBean(
2373            element.getId(),
2374            element.getFormatterId(),
2375            settings,
2376            element.isCreateNew());
2377        return result;
2378    }
2379
2380    /**
2381     * Adds the formatter to the recently used formatter list.<p>
2382     *
2383     * @param elementBean the element bean
2384     * @param settings the changed settings
2385     */
2386    void storeFormatterSelection(CmsContainerElementBean elementBean, Map<String, String> settings) {
2387
2388        Entry<String, String> previousFormatterEntry = null;
2389        for (Entry<String, String> entry : elementBean.getIndividualSettings().entrySet()) {
2390            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2391                previousFormatterEntry = entry;
2392                break;
2393            }
2394        }
2395        Entry<String, String> formatterEntry = null;
2396        for (Entry<String, String> entry : settings.entrySet()) {
2397            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2398                formatterEntry = entry;
2399                break;
2400            }
2401        }
2402        if ((formatterEntry != null)
2403            && ((previousFormatterEntry == null)
2404                || !formatterEntry.getKey().equals(previousFormatterEntry.getKey())
2405                || !formatterEntry.getValue().equals(previousFormatterEntry.getValue()))) {
2406            String idString = formatterEntry.getValue();
2407            if (idString != null) {
2408                // the formatter setting has changed
2409                I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(elementBean.getResource());
2410                if (!(resType instanceof CmsResourceTypeFunctionConfig)) {
2411                    getSessionCache().addRecentFormatter(resType.getTypeName(), idString);
2412                }
2413            }
2414        }
2415    }
2416
2417    /**
2418     * Converts the given setting values according to the setting configuration of the given resource.<p>
2419     *
2420     * @param resource the resource
2421     * @param settings the settings to convert
2422     * @param locale the locale used for accessing the element settings
2423     *
2424     * @return the converted settings
2425     * @throws CmsException if something goes wrong
2426     */
2427    private Map<String, String> convertSettingValues(CmsResource resource, Map<String, String> settings, Locale locale)
2428    throws CmsException {
2429
2430        CmsObject cms = getCmsObject();
2431        Locale origLocale = cms.getRequestContext().getLocale();
2432        try {
2433            cms.getRequestContext().setLocale(locale);
2434            Map<String, CmsXmlContentProperty> settingsConf = OpenCms.getADEManager().getElementSettings(cms, resource);
2435            Map<String, String> changedSettings = new HashMap<String, String>();
2436            if (settings != null) {
2437                for (Map.Entry<String, String> entry : settings.entrySet()) {
2438                    String settingName = entry.getKey();
2439                    String settingType = "string";
2440                    if (settingsConf.get(settingName) != null) {
2441                        settingType = settingsConf.get(settingName).getType();
2442                    }
2443                    changedSettings.put(
2444                        settingName,
2445                        CmsXmlContentPropertyHelper.getPropValueIds(getCmsObject(), settingType, entry.getValue()));
2446                }
2447            }
2448            return changedSettings;
2449        } finally {
2450            cms.getRequestContext().setLocale(origLocale);
2451        }
2452    }
2453
2454    /**
2455     * Generates the XML container page bean for the given containers.<p>
2456     *
2457     * @param containers the containers
2458     * @param containerpageRootPath the container page root path
2459     *
2460     * @return the container page bean
2461     * @throws CmsException in case generating the page data fails
2462     */
2463    private CmsContainerPageBean generateContainerPageForContainers(
2464        Collection<CmsContainer> containers,
2465        String containerpageRootPath)
2466    throws CmsException {
2467
2468        List<CmsContainerBean> containerBeans = new ArrayList<CmsContainerBean>();
2469        for (CmsContainer container : containers) {
2470            CmsContainerBean containerBean = getContainerBeanToSave(container, containerpageRootPath);
2471            containerBeans.add(containerBean);
2472        }
2473        CmsContainerPageBean page = new CmsContainerPageBean(containerBeans);
2474        return page;
2475    }
2476
2477    /**
2478     * Returns a list of container elements from a list with client id's.<p>
2479     *
2480     * @param clientIds list of client id's
2481     * @param pageRootPath the container page root path
2482     *
2483     * @return a list of element beans
2484     * @throws CmsException in case reading the element resource fails
2485     */
2486    private List<CmsContainerElementBean> getCachedElements(List<String> clientIds, String pageRootPath)
2487    throws CmsException {
2488
2489        List<CmsContainerElementBean> result = new ArrayList<CmsContainerElementBean>();
2490        for (String id : clientIds) {
2491            try {
2492                result.add(getCachedElement(id, pageRootPath));
2493            } catch (CmsIllegalArgumentException e) {
2494                log(e.getLocalizedMessage(), e);
2495            }
2496        }
2497        return result;
2498    }
2499
2500    /**
2501     * Returns the configuration data of the current container page context.<p>
2502     *
2503     * @param pageRootPath the container page root path
2504     *
2505     * @return the configuration data of the current container page context
2506     */
2507    private CmsADEConfigData getConfigData(String pageRootPath) {
2508
2509        if (m_configData == null) {
2510            m_configData = OpenCms.getADEManager().lookupConfiguration(getCmsObject(), pageRootPath);
2511        }
2512        return m_configData;
2513    }
2514
2515    /**
2516     * Helper method for converting a CmsContainer to a CmsContainerBean when saving a container page.<p>
2517     *
2518     * @param container the container for which the CmsContainerBean should be created
2519     * @param containerpageRootPath the container page root path
2520     *
2521     * @return a container bean
2522     *
2523     * @throws CmsException in case generating the container data fails
2524     */
2525    private CmsContainerBean getContainerBeanToSave(CmsContainer container, String containerpageRootPath)
2526    throws CmsException {
2527
2528        CmsObject cms = getCmsObject();
2529        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2530        for (CmsContainerElement elementData : container.getElements()) {
2531            if (!elementData.isNew()) {
2532                CmsContainerElementBean newElementBean = getContainerElementBeanToSave(
2533                    cms,
2534                    containerpageRootPath,
2535                    container,
2536                    elementData);
2537                if (newElementBean != null) {
2538                    elements.add(newElementBean);
2539                }
2540            }
2541        }
2542        CmsContainerBean result = CmsElementUtil.clientToServerContainer(container, elements);
2543        return result;
2544    }
2545
2546    /**
2547     * Converts container page element data to a bean which can be saved in a container page.<p>
2548     *
2549     * @param cms the current CMS context
2550     * @param containerpageRootPath the container page root path
2551     * @param container the container containing the element
2552     * @param elementData the data for the single element
2553     *
2554     * @return the container element bean
2555     *
2556     * @throws CmsException if something goes wrong
2557     */
2558    private CmsContainerElementBean getContainerElementBeanToSave(
2559        CmsObject cms,
2560        String containerpageRootPath,
2561        CmsContainer container,
2562        CmsContainerElement elementData)
2563    throws CmsException {
2564
2565        String elementClientId = elementData.getClientId();
2566        boolean hasUuidPrefix = (elementClientId != null) && elementClientId.matches(CmsUUID.UUID_REGEX + ".*$");
2567        boolean isCreateNew = elementData.isCreateNew();
2568        if (elementData.isNew() && !hasUuidPrefix) {
2569
2570            // Due to the changed save system without the save button, we need to make sure that new elements
2571            // are only created once. This must happen when the user first edits a new element. But we still
2572            // want to save changes to non-new elements on the page, so we skip new elements while saving.
2573            return null;
2574        }
2575        CmsContainerElementBean element = getCachedElement(elementData.getClientId(), containerpageRootPath);
2576
2577        CmsResource resource;
2578        if (element.getResource() == null) {
2579            element.initResource(cms);
2580            resource = element.getResource();
2581        } else {
2582            // make sure resource is readable, this is necessary for new content elements
2583            if (element.getId().isNullUUID()) {
2584                // in memory only element, can not be read nor saved
2585                return null;
2586            }
2587            resource = cms.readResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION);
2588        }
2589
2590        // check if there is a valid formatter
2591        int containerWidth = container.getWidth();
2592        CmsADEConfigData config = getConfigData(containerpageRootPath);
2593        CmsFormatterConfiguration formatters = config.getFormatters(cms, resource);
2594        String containerType = null;
2595        containerType = container.getType();
2596        I_CmsFormatterBean formatter = null;
2597        String formatterConfigId = null;
2598        if ((element.getIndividualSettings() != null)
2599            && (element.getIndividualSettings().get(
2600                CmsFormatterConfig.getSettingsKeyForContainer(container.getName())) != null)) {
2601            formatterConfigId = element.getIndividualSettings().get(
2602                CmsFormatterConfig.getSettingsKeyForContainer(container.getName()));
2603            I_CmsFormatterBean dynamicFmt = config.findFormatter(formatterConfigId);
2604            if (dynamicFmt != null) {
2605                formatter = dynamicFmt;
2606            } else if (formatterConfigId.startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)
2607                && CmsUUID.isValidUUID(formatterConfigId.substring(CmsFormatterConfig.SCHEMA_FORMATTER_ID.length()))) {
2608                formatter = formatters.getFormatterSelection(containerType, containerWidth).get(formatterConfigId);
2609            }
2610        }
2611        if (formatter == null) {
2612            formatter = CmsElementUtil.getFormatterForContainer(cms, element, container, config, getSessionCache());
2613            if (formatter != null) {
2614                formatterConfigId = formatter.isFromFormatterConfigFile()
2615                ? formatter.getId()
2616                : CmsFormatterConfig.SCHEMA_FORMATTER_ID + formatter.getJspStructureId().toString();
2617            }
2618        }
2619        CmsContainerElementBean newElementBean = null;
2620        if (formatter != null) {
2621            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
2622            String formatterKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2623            settings.put(formatterKey, formatterConfigId);
2624            // remove not used formatter settings
2625            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
2626            while (entries.hasNext()) {
2627                Entry<String, String> entry = entries.next();
2628                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)
2629                    && !entry.getKey().equals(formatterKey)) {
2630                    entries.remove();
2631                }
2632            }
2633
2634            newElementBean = new CmsContainerElementBean(
2635                element.getId(),
2636                formatter.getJspStructureId(),
2637                settings,
2638                isCreateNew);
2639        }
2640        return newElementBean;
2641    }
2642
2643    /**
2644     * Returns the requested container-page resource.<p>
2645     *
2646     * @param cms the current cms object
2647     *
2648     * @return the container-page resource
2649     *
2650     * @throws CmsException if the resource could not be read for any reason
2651     */
2652    private CmsResource getContainerpage(CmsObject cms) throws CmsException {
2653
2654        String currentUri = cms.getRequestContext().getUri();
2655        CmsResource containerPage = cms.readResource(currentUri, CmsResourceFilter.ignoreExpirationOffline(cms));
2656        if (!CmsResourceTypeXmlContainerPage.isContainerPage(containerPage)) {
2657            // container page is used as template
2658            String cntPagePath = cms.readPropertyObject(
2659                containerPage,
2660                CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
2661                true).getValue("");
2662            try {
2663                containerPage = cms.readResource(cntPagePath, CmsResourceFilter.ignoreExpirationOffline(cms));
2664            } catch (CmsException e) {
2665                if (!LOG.isDebugEnabled()) {
2666                    LOG.warn(e.getLocalizedMessage());
2667                }
2668                LOG.debug(e.getLocalizedMessage(), e);
2669            }
2670        }
2671        return containerPage;
2672    }
2673
2674    /**
2675     * Gets the (potentially empty) set of types for which the container page is registered as a detail page.
2676     *
2677     * @param cms the CMS context
2678     * @param containerPage a container page resource
2679     *
2680     * @return the set of names of types for which the container page is a detail page
2681     */
2682    private Set<String> getDetailTypes(CmsObject cms, CmsResource containerPage) {
2683
2684        List<CmsDetailPageInfo> infos = OpenCms.getADEManager().getAllDetailPages(cms);
2685        Set<CmsUUID> ids = new HashSet<>();
2686        ids.add(containerPage.getStructureId());
2687        Set<String> result = new HashSet<>();
2688        if (containerPage.isFile()) {
2689            try {
2690                CmsResource folder = cms.readParentFolder(containerPage.getStructureId());
2691                if (folder != null) {
2692                    ids.add(folder.getStructureId());
2693                }
2694            } catch (CmsException e) {
2695                LOG.error(e.getLocalizedMessage(), e);
2696            }
2697        }
2698        for (CmsDetailPageInfo info : infos) {
2699            if (ids.contains(info.getId())) {
2700                result.add(info.getType());
2701            }
2702        }
2703
2704        return result;
2705
2706    }
2707
2708    /**
2709     * Returns the data of the given elements.<p>
2710     *
2711     * @param config the sitemap configuration
2712     * @param page the current container page
2713     * @param clientIds the list of IDs of the elements to retrieve the data for
2714     * @param uriParam the current URI
2715     * @param detailContentId the detail content structure id
2716     * @param containers the containers for which the element data should be fetched
2717     * @param allwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group
2718     * @param dndOriginContainer the container from which an element was dragged (null if this method is not called for DND)
2719     * @param isDragMode if the page is in drag mode
2720     * @param locale the locale to use
2721     *
2722     * @return the elements data
2723     *
2724     * @throws CmsException if something really bad happens
2725     */
2726    private Map<String, CmsContainerElementData> getElements(
2727        CmsADEConfigData config,
2728        CmsResource page,
2729        Collection<String> clientIds,
2730        String uriParam,
2731        CmsUUID detailContentId,
2732        Collection<CmsContainer> containers,
2733        boolean allwaysCopy,
2734        String dndOriginContainer,
2735        boolean isDragMode,
2736        Locale locale)
2737    throws CmsException {
2738
2739        CmsObject cms = getCmsObject();
2740        CmsContainerPageBean pageBean = generateContainerPageForContainers(
2741            containers,
2742            cms.getRequestContext().addSiteRoot(uriParam));
2743        Map<String, CmsContainerElementBean> idMapping = new HashMap<String, CmsContainerElementBean>();
2744        for (String elemId : clientIds) {
2745            if ((elemId == null)) {
2746                continue;
2747            }
2748            CmsContainerElementBean element = getCachedElement(elemId, cms.getRequestContext().addSiteRoot(uriParam));
2749            if (element.getInstanceId() == null) {
2750                element = element.clone();
2751                getSessionCache().setCacheContainerElement(element.editorHash(), element);
2752            }
2753            element.initResource(cms);
2754            idMapping.put(elemId, element);
2755        }
2756        List<String> foundGroups = new ArrayList<String>();
2757        if (CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2758            // this indicates the element is added to the page and not being repositioned, check for model group data
2759            CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
2760                cms,
2761                getConfigData(uriParam),
2762                getSessionCache(),
2763                isEditingModelGroups(cms, page));
2764            String createElementContext = CmsResource.getParentFolder(page.getRootPath());
2765            if (detailContentId != null) {
2766                try {
2767                    CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2768                    createElementContext = CmsResource.getParentFolder(
2769                        CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
2770                            cms,
2771                            page,
2772                            detailContent.getRootPath(),
2773                            "" + locale));
2774                } catch (Exception e) {
2775                    LOG.error(e.getLocalizedMessage(), e);
2776                }
2777            }
2778            pageBean = modelHelper.prepareforModelGroupContent(
2779                idMapping,
2780                foundGroups,
2781                pageBean,
2782                allwaysCopy,
2783                locale,
2784                createElementContext);
2785        }
2786
2787        CmsElementUtil elemUtil = new CmsElementUtil(
2788            cms,
2789            uriParam,
2790            pageBean,
2791            detailContentId,
2792            getRequest(),
2793            getResponse(),
2794            isDragMode,
2795            locale);
2796        Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>();
2797        Set<String> ids = new HashSet<String>();
2798        for (Entry<String, CmsContainerElementBean> entry : idMapping.entrySet()) {
2799            CmsContainerElementBean element = entry.getValue();
2800            String dndId = null;
2801            if (ids.contains(element.editorHash())) {
2802                continue;
2803            }
2804            if ((dndOriginContainer != null) && !CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2805                CmsFormatterConfiguration formatterConfig = elemUtil.getFormatterConfiguration(element.getResource());
2806                Map<String, String> dndSettings = getSettingsToChangeForDnd(
2807                    config,
2808                    element.getIndividualSettings(),
2809                    formatterConfig,
2810                    containers,
2811                    dndOriginContainer);
2812                if (!dndSettings.isEmpty()) {
2813                    CmsContainerElementBean dndElementBean = overrideSettings(element, dndSettings);
2814                    getSessionCache().setCacheContainerElement(dndElementBean.editorHash(), dndElementBean);
2815                    element = dndElementBean;
2816                    dndId = dndElementBean.editorHash();
2817                    Map<String, CmsContainerElementData> dndResults = getElements(
2818                        config,
2819                        page,
2820                        Arrays.asList(dndId),
2821                        uriParam,
2822                        detailContentId,
2823                        containers,
2824                        false,
2825                        null,
2826                        isDragMode,
2827                        locale);
2828                    result.putAll(dndResults);
2829                }
2830            }
2831
2832            CmsContainerElementData elementData = elemUtil.getElementData(page, element, containers);
2833            if (elementData == null) {
2834                continue;
2835            }
2836            getSessionCache().setCacheContainerElement(element.editorHash(), element);
2837            elementData.setDndId(dndId);
2838            result.put(entry.getKey(), elementData);
2839            if (elementData.isGroupContainer() || elementData.isInheritContainer()) {
2840                // this is a group-container
2841                CmsResource elementRes = cms.readResource(element.getId());
2842                List<CmsContainerElementBean> subElements = elementData.isGroupContainer()
2843                ? getGroupContainerElements(elementRes)
2844                : getInheritedElements(elementRes, locale, uriParam);
2845                // adding all sub-items to the elements data
2846                for (CmsContainerElementBean subElement : subElements) {
2847                    getSessionCache().setCacheContainerElement(subElement.editorHash(), subElement);
2848                    if (!ids.contains(subElement.editorHash())) {
2849                        CmsContainerElementData subItemData = elemUtil.getElementData(page, subElement, containers);
2850                        ids.add(subElement.editorHash());
2851                        result.put(subElement.editorHash(), subItemData);
2852                    }
2853                }
2854            }
2855            ids.add(element.editorHash());
2856        }
2857        for (CmsContainerElementData elementData : result.values()) {
2858            elementData.setGroup(foundGroups.contains(elementData.getClientId()));
2859        }
2860        return result;
2861    }
2862
2863    /**
2864     * Helper method for converting a CmsGroupContainer to a CmsGroupContainerBean when saving a group container.<p>
2865     *
2866     * @param groupContainer the group-container data
2867     * @param containerPage the container page
2868     * @param locale the locale to use
2869     *
2870     * @return the group-container bean
2871     */
2872    private CmsGroupContainerBean getGroupContainerBean(
2873        CmsGroupContainer groupContainer,
2874        CmsResource containerPage,
2875        String locale) {
2876
2877        CmsObject cms = getCmsObject();
2878        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2879        for (CmsContainerElement elementData : groupContainer.getElements()) {
2880            try {
2881                if (elementData.isNew()) {
2882                    elementData = createNewElement(
2883                        containerPage.getStructureId(),
2884                        null,
2885                        elementData.getClientId(),
2886                        elementData.getResourceType(),
2887                        null,
2888                        locale);
2889                }
2890                CmsContainerElementBean element = getCachedElement(
2891                    elementData.getClientId(),
2892                    containerPage.getRootPath());
2893
2894                // make sure resource is readable,
2895                if (cms.existsResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION)) {
2896                    elements.add(element);
2897                }
2898
2899            } catch (Exception e) {
2900                log(e.getLocalizedMessage(), e);
2901            }
2902        }
2903        return new CmsGroupContainerBean(
2904            groupContainer.getTitle(),
2905            groupContainer.getDescription(),
2906            elements,
2907            groupContainer.getTypes());
2908    }
2909
2910    /**
2911     * Returns the sub-elements of this group container resource.<p>
2912     *
2913     * @param resource the group container resource
2914     *
2915     * @return the sub-elements
2916     *
2917     * @throws CmsException if something goes wrong reading the resource
2918     */
2919    private List<CmsContainerElementBean> getGroupContainerElements(CmsResource resource) throws CmsException {
2920
2921        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(
2922            getCmsObject(),
2923            resource,
2924            getRequest());
2925        CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(getCmsObject());
2926        return groupContainer.getElements();
2927    }
2928
2929    /**
2930     * Gets the structure ids of group container elements from an unmarshalled group container for a single locale.<p>
2931     *
2932     * @param groupContainer the group container
2933     * @param locale the locale for which we want the element ids
2934     *
2935     * @return the group container's element ids for the given locale
2936     */
2937    private Set<CmsUUID> getGroupElementIds(CmsXmlGroupContainer groupContainer, Locale locale) {
2938
2939        Set<CmsUUID> idSet = new HashSet<CmsUUID>();
2940        CmsGroupContainerBean groupContainerBean = groupContainer.getGroupContainer(getCmsObject());
2941        if (groupContainerBean != null) {
2942            for (CmsContainerElementBean element : groupContainerBean.getElements()) {
2943                idSet.add(element.getId());
2944            }
2945        }
2946        return idSet;
2947
2948    }
2949
2950    /**
2951     * Returns the sub-elements of this inherit container resource.<p>
2952     *
2953     * @param resource the inherit container resource
2954     * @param locale the requested locale
2955     * @param uriParam the current URI
2956     *
2957     * @return the sub-elements
2958     *
2959     * @throws CmsException if something goes wrong reading the resource
2960     */
2961    private List<CmsContainerElementBean> getInheritedElements(CmsResource resource, Locale locale, String uriParam)
2962    throws CmsException {
2963
2964        CmsObject cms = getCmsObject();
2965        cms.getRequestContext().setLocale(locale);
2966        CmsInheritanceReferenceParser parser = new CmsInheritanceReferenceParser(cms);
2967        parser.parse(resource);
2968        CmsInheritanceReference ref = parser.getReference(locale);
2969        if (ref == null) {
2970            // new inheritance reference, return an empty list
2971            return Collections.emptyList();
2972        }
2973        String name = ref.getName();
2974        CmsADEManager adeManager = OpenCms.getADEManager();
2975        CmsInheritedContainerState result = adeManager.getInheritedContainerState(cms, cms.addSiteRoot(uriParam), name);
2976        return result.getElements(true);
2977    }
2978
2979    /**
2980     * Returns the data of the given elements.<p>
2981     *
2982     * @param listElements the list of element beans to retrieve the data for
2983     * @param containerpageUri the current URI
2984     * @param detailContentId the detail content structure id
2985     * @param containers the containers which exist on the container page
2986     * @param locale the locale to use
2987     *
2988     * @return the elements data
2989     *
2990     * @throws CmsException if something really bad happens
2991     */
2992    private List<CmsContainerElementData> getListElementsData(
2993        List<CmsContainerElementBean> listElements,
2994        String containerpageUri,
2995        CmsUUID detailContentId,
2996        Collection<CmsContainer> containers,
2997        Locale locale)
2998    throws CmsException {
2999
3000        CmsObject cms = getCmsObject();
3001        CmsElementUtil elemUtil = new CmsElementUtil(
3002            cms,
3003            containerpageUri,
3004            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(containerpageUri)),
3005            detailContentId,
3006            getRequest(),
3007            getResponse(),
3008            true,
3009            locale);
3010        CmsADESessionCache cache = getSessionCache();
3011        List<CmsContainerElementData> result = new ArrayList<CmsContainerElementData>();
3012        for (CmsContainerElementBean element : listElements) {
3013            // checking if resource exists
3014            if (cms.existsResource(element.getId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFile())) {
3015                try {
3016                    CmsContainerElementBean clone = element.clone();
3017                    // Because ensureNewInstanceId() just generates a new UUID,
3018                    // the key for the element cache will not collide with anything else, so
3019                    // we do not need to set the SYSTEM::pageId setting for disambiguation here.
3020                    clone.ensureNewInstanceId();
3021                    cache.setCacheContainerElement(clone.editorHash(), clone);
3022                    CmsContainerElementData elementData = elemUtil.getElementData(
3023                        elemUtil.getPage(),
3024                        clone,
3025                        containers);
3026                    result.add(elementData);
3027                } catch (CmsVfsResourceNotFoundException e) {
3028                    // model group id not found, or other resources
3029                    LOG.info(e.getLocalizedMessage(), e);
3030                }
3031            }
3032        }
3033        return result;
3034    }
3035
3036    /**
3037     * Returns the lock information to the given resource.<p>
3038     *
3039     * @param resource the resource
3040     *
3041     * @return lock information, if the page is locked by another user
3042     *
3043     * @throws CmsException if something goes wrong reading the lock owner user
3044     */
3045    private String getLockInfo(CmsResource resource) throws CmsException {
3046
3047        CmsObject cms = getCmsObject();
3048        CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource);
3049        CmsLock lock = resourceUtil.getLock();
3050        String lockInfo = null;
3051        if (!lock.isLockableBy(cms.getRequestContext().getCurrentUser())) {
3052            if (lock.getType() == CmsLockType.PUBLISH) {
3053                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3054                    Messages.GUI_LOCKED_FOR_PUBLISH_0);
3055            } else {
3056                CmsUser lockOwner = cms.readUser(lock.getUserId());
3057                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3058                    Messages.GUI_LOCKED_BY_1,
3059                    lockOwner.getFullName());
3060            }
3061        }
3062        return lockInfo;
3063    }
3064
3065    /**
3066     * Returns the element data for a new element not existing in the VFS yet.<p>
3067     *
3068     * @param resourceTypeName the resource type name
3069     * @param uriParam the request parameters
3070     * @param detailContentId the detail content structure id
3071     * @param containers the containers of the template
3072     * @param locale the current locale
3073     *
3074     * @return the element data
3075     *
3076     * @throws CmsException if something goes wrong
3077     */
3078    private CmsContainerElementData getNewElement(
3079        String resourceTypeName,
3080        String uriParam,
3081        CmsUUID detailContentId,
3082        Collection<CmsContainer> containers,
3083        Locale locale)
3084    throws CmsException {
3085
3086        CmsObject cms = getCmsObject();
3087        CmsElementUtil elemUtil = new CmsElementUtil(
3088            cms,
3089            uriParam,
3090            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(uriParam)),
3091            detailContentId,
3092            getRequest(),
3093            getResponse(),
3094            true,
3095            locale);
3096        CmsADEConfigData configData = getConfigData(cms.getRequestContext().addSiteRoot(uriParam));
3097        CmsResourceTypeConfig typeConfig = configData.getResourceType(resourceTypeName);
3098        CmsContainerElementBean elementBean = CmsContainerElementBean.createElementForResourceType(
3099            cms,
3100            OpenCms.getResourceManager().getResourceType(resourceTypeName),
3101            "/",
3102            Collections.<String, String> emptyMap(),
3103            typeConfig.isCopyInModels(),
3104            locale);
3105        CmsContainerElementData data = elemUtil.getElementData(elemUtil.getPage(), elementBean, containers);
3106        data.setClientId(elementBean.editorHash());
3107        getSessionCache().setCacheContainerElement(resourceTypeName, elementBean);
3108        getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
3109        return data;
3110    }
3111
3112    /**
3113     * Returns the no-edit reason for the given resource.<p>
3114     *
3115     * @param cms the current cms object
3116     * @param containerPage the resource
3117     *
3118     * @return the no-edit reason, empty if editing is allowed
3119     *
3120     * @throws CmsException is something goes wrong
3121     */
3122    private String getNoEditReason(CmsObject cms, CmsResource containerPage) throws CmsException {
3123
3124        return new CmsResourceUtil(cms, containerPage).getNoEditReason(
3125            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms),
3126            !cms.getRequestContext().getCurrentProject().isOnlineProject());
3127    }
3128
3129    /**
3130     * Returns the session cache.<p>
3131     *
3132     * @return the session cache
3133     */
3134    private CmsADESessionCache getSessionCache() {
3135
3136        if (m_sessionCache == null) {
3137            m_sessionCache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3138        }
3139        return m_sessionCache;
3140    }
3141
3142    /**
3143     * Returns the workplace settings of the current user.<p>
3144     *
3145     * @return the workplace settings
3146     */
3147    private CmsWorkplaceSettings getWorkplaceSettings() {
3148
3149        if (m_workplaceSettings == null) {
3150            m_workplaceSettings = CmsWorkplace.getWorkplaceSettings(getCmsObject(), getRequest());
3151        }
3152        return m_workplaceSettings;
3153    }
3154
3155    /**
3156     * Checks if results for the stored gallery data can be restored for the new gallery data.<p>
3157     *
3158     * @param originalGalleryData the original gallery data
3159     * @param data the new gallery data
3160     * @param search the search bean
3161     *
3162     * @return true if the original and new gallery data are compatible, i.e. we can restore the search results
3163     */
3164    private boolean hasCompatibleSearchData(
3165        CmsGalleryDataBean originalGalleryData,
3166        CmsGalleryDataBean data,
3167        CmsGallerySearchBean search) {
3168
3169        Set<String> originalUsableTypes = Sets.newHashSet();
3170        Set<String> usableTypes = Sets.newHashSet();
3171        for (CmsResourceTypeBean type : originalGalleryData.getTypes()) {
3172            if (!type.isDeactivated()) {
3173                originalUsableTypes.add(type.getType());
3174            }
3175        }
3176        for (CmsResourceTypeBean type : data.getTypes()) {
3177            if (!type.isDeactivated()) {
3178                usableTypes.add(type.getType());
3179            }
3180        }
3181        if (!usableTypes.containsAll(originalUsableTypes)) {
3182            return false;
3183        }
3184        return true;
3185    }
3186
3187    /**
3188     * Initializes request attributes using data from the RPC context.<p>
3189     *
3190     * @param context the RPC context
3191     */
3192    private void initRequestFromRpcContext(CmsContainerPageRpcContext context) {
3193
3194        if (context.getTemplateContext() != null) {
3195            getRequest().setAttribute(
3196                CmsTemplateContextManager.ATTR_RPC_CONTEXT_OVERRIDE,
3197                context.getTemplateContext());
3198        }
3199    }
3200
3201    /**
3202     * Internal method for saving a group container.<p>
3203     *
3204     * @param cms the cms context
3205     * @param pageStructureId the container page structure id
3206     * @param groupContainer the group container to save
3207     *
3208     * @return the container element representing the group container
3209     *
3210     * @throws CmsException if something goes wrong
3211     * @throws CmsXmlException if the XML processing goes wrong
3212     */
3213    private CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> internalSaveGroupContainer(
3214        CmsObject cms,
3215        CmsUUID pageStructureId,
3216        CmsGroupContainer groupContainer)
3217    throws CmsException, CmsXmlException {
3218
3219        ensureSession();
3220        CmsResource pageResource = getCmsObject().readResource(pageStructureId, CmsResourceFilter.IGNORE_EXPIRATION);
3221        CmsResource groupContainerResource = null;
3222        if (groupContainer.isNew()) {
3223            CmsADEConfigData config = getConfigData(pageResource.getRootPath());
3224            CmsResourceTypeConfig typeConfig = config.getResourceType(
3225                CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3226            groupContainerResource = typeConfig.createNewElement(getCmsObject(), pageResource.getRootPath());
3227            String resourceName = cms.getSitePath(groupContainerResource);
3228            groupContainer.setSitePath(resourceName);
3229            groupContainer.setClientId(groupContainerResource.getStructureId().toString());
3230        }
3231        if (groupContainerResource == null) {
3232            CmsUUID id = convertToServerId(groupContainer.getClientId());
3233            groupContainerResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3234        }
3235        CmsGroupContainerBean groupContainerBean = getGroupContainerBean(
3236            groupContainer,
3237            pageResource,
3238            Locale.ENGLISH.toString());
3239
3240        cms.lockResourceTemporary(groupContainerResource);
3241        CmsFile groupContainerFile = cms.readFile(groupContainerResource);
3242        Locale locale = Locale.ENGLISH;
3243        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(cms, groupContainerFile);
3244        Set<CmsUUID> oldElementIds = getGroupElementIds(xmlGroupContainer, locale);
3245        xmlGroupContainer.clearLocales();
3246        xmlGroupContainer.save(cms, groupContainerBean, locale);
3247        cms.unlockResource(groupContainerResource);
3248        Set<CmsUUID> newElementIds = getGroupElementIds(xmlGroupContainer, locale);
3249        Set<CmsUUID> removedElementIds = Sets.difference(oldElementIds, newElementIds);
3250        List<CmsRemovedElementStatus> deletionCandidateStatuses = new ArrayList<CmsRemovedElementStatus>();
3251        for (CmsUUID removedId : removedElementIds) {
3252            CmsRemovedElementStatus status = internalGetRemovedElementStatus(removedId, null);
3253            if (status.isDeletionCandidate()) {
3254                deletionCandidateStatuses.add(status);
3255            }
3256        }
3257        CmsContainerElement element = new CmsContainerElement();
3258        element.setClientId(groupContainerFile.getStructureId().toString());
3259        element.setSitePath(cms.getSitePath(groupContainerFile));
3260        element.setResourceType(CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3261        return CmsPair.create(element, deletionCandidateStatuses);
3262    }
3263
3264    /**
3265     * Checks if small elements in a container page should be initially editable.<p>
3266     *
3267     * @param request the current request
3268     * @param cms the current CMS context
3269     * @return true if small elements should be initially editable
3270     */
3271    private boolean isEditSmallElements(HttpServletRequest request, CmsObject cms) {
3272
3273        CmsUser user = cms.getRequestContext().getCurrentUser();
3274        String editSmallElementsStr = (String)(user.getAdditionalInfo().get(ADDINFO_EDIT_SMALL_ELEMENTS));
3275        if (editSmallElementsStr == null) {
3276            return true;
3277        } else {
3278            return Boolean.valueOf(editSmallElementsStr).booleanValue();
3279        }
3280    }
3281
3282    /**
3283     * Checks if a page is a model page.<p>
3284     *
3285     * @param cms the CMS context to use
3286     * @param containerPage the page to check
3287     *
3288     * @return true if the resource is a model page
3289     */
3290    private boolean isModelPage(CmsObject cms, CmsResource containerPage) {
3291
3292        CmsADEConfigData config = getConfigData(containerPage.getRootPath());
3293        for (CmsModelPageConfig modelConfig : config.getModelPages()) {
3294            if (modelConfig.getResource().getStructureId().equals(containerPage.getStructureId())) {
3295                return true;
3296            }
3297        }
3298        return false;
3299    }
3300
3301    /**
3302     * Saves the given containers to the container page resource.<p>
3303     *
3304     * @param cms the cms context
3305     * @param containerpage the container page resource
3306     * @param containerpageUri the container page site path
3307     * @param containers the container to save
3308     *
3309     * @throws CmsException if something goes wrong writing the file
3310     */
3311    private void saveContainers(
3312        CmsObject cms,
3313        CmsResource containerpage,
3314        String containerpageUri,
3315        List<CmsContainer> containers)
3316    throws CmsException {
3317
3318        CmsContainerPageBean page = generateContainerPageForContainers(containers, containerpage.getRootPath());
3319
3320        CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
3321            getCmsObject(),
3322            getConfigData(containerpage.getRootPath()),
3323            getSessionCache(),
3324            isEditingModelGroups(cms, containerpage));
3325        if (isEditingModelGroups(cms, containerpage)) {
3326            page = modelHelper.saveModelGroups(page, containerpage);
3327        } else {
3328            page = modelHelper.removeModelGroupContainers(page);
3329        }
3330        CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(
3331            cms,
3332            cms.readFile(containerpageUri, CmsResourceFilter.ignoreExpirationOffline(cms)));
3333        xmlCnt.save(cms, page);
3334    }
3335
3336    /**
3337     * Saves the inheritance group.<p>
3338     *
3339     * @param resource the inheritance group resource
3340     * @param inheritanceContainer the inherited group container data
3341     *
3342     * @throws CmsException if something goes wrong
3343     */
3344    private void saveInheritanceGroup(CmsResource resource, CmsInheritanceContainer inheritanceContainer)
3345    throws CmsException {
3346
3347        CmsObject cms = getCmsObject();
3348        CmsFile file = cms.readFile(resource);
3349        CmsXmlContent document = CmsXmlContentFactory.unmarshal(cms, file);
3350
3351        for (Locale docLocale : document.getLocales()) {
3352            document.removeLocale(docLocale);
3353        }
3354        Locale locale = Locale.ENGLISH;
3355        document.addLocale(cms, locale);
3356        document.getValue("Title", locale).setStringValue(cms, inheritanceContainer.getTitle());
3357        document.getValue("Description", locale).setStringValue(cms, inheritanceContainer.getDescription());
3358        document.getValue("ConfigName", locale).setStringValue(cms, inheritanceContainer.getName());
3359        byte[] content = document.marshal();
3360        file.setContents(content);
3361        cms.writeFile(file);
3362    }
3363
3364    /**
3365     * Update favorite or recent list with the given element.<p>
3366     *
3367     * @param containerPage the edited container page
3368     * @param clientId the elements client id
3369     * @param list the list to update
3370     *
3371     * @return the updated list
3372     *
3373     * @throws CmsException in case reading the element resource fails
3374     */
3375    private List<CmsContainerElementBean> updateFavoriteRecentList(
3376        CmsResource containerPage,
3377        String clientId,
3378        List<CmsContainerElementBean> list)
3379    throws CmsException {
3380
3381        try {
3382            CmsContainerElementBean element = getCachedElement(clientId, containerPage.getRootPath());
3383            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
3384            String formatterID = null;
3385            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
3386            while (entries.hasNext()) {
3387                Entry<String, String> entry = entries.next();
3388                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
3389                    formatterID = entry.getValue();
3390                    entries.remove();
3391                }
3392            }
3393            settings.put(CmsFormatterConfig.FORMATTER_SETTINGS_KEY, formatterID);
3394            settings.put(SOURCE_CONTAINERPAGE_ID_SETTING, containerPage.getStructureId().toString());
3395            settings.remove(CmsContainerElement.SETTING_PAGE_ID);
3396            element = CmsContainerElementBean.cloneWithSettings(element, settings);
3397            Iterator<CmsContainerElementBean> listIt = list.iterator();
3398            while (listIt.hasNext()) {
3399                CmsContainerElementBean listElem = listIt.next();
3400                if (element.getInstanceId().equals(listElem.getInstanceId())) {
3401                    listIt.remove();
3402                }
3403            }
3404            list.add(0, element);
3405            return list;
3406        } catch (CmsVfsResourceNotFoundException e) {
3407            LOG.warn(e.getLocalizedMessage(), e);
3408            return list;
3409        }
3410    }
3411
3412}