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