001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.containerpage;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsADEManager;
032import org.opencms.ade.configuration.CmsElementView;
033import org.opencms.ade.configuration.CmsModelPageConfig;
034import org.opencms.ade.configuration.CmsResourceTypeConfig;
035import org.opencms.ade.containerpage.inherited.CmsInheritanceReference;
036import org.opencms.ade.containerpage.inherited.CmsInheritanceReferenceParser;
037import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState;
038import org.opencms.ade.containerpage.shared.CmsCntPageData;
039import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode;
040import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementReuseMode;
041import org.opencms.ade.containerpage.shared.CmsContainer;
042import org.opencms.ade.containerpage.shared.CmsContainerElement;
043import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
044import org.opencms.ade.containerpage.shared.CmsContainerElementData;
045import org.opencms.ade.containerpage.shared.CmsContainerPageGalleryData;
046import org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext;
047import org.opencms.ade.containerpage.shared.CmsCreateElementData;
048import org.opencms.ade.containerpage.shared.CmsDialogOptions;
049import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo;
050import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
051import org.opencms.ade.containerpage.shared.CmsElementViewInfo;
052import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
053import org.opencms.ade.containerpage.shared.CmsGroupContainer;
054import org.opencms.ade.containerpage.shared.CmsGroupContainerSaveResult;
055import org.opencms.ade.containerpage.shared.CmsInheritanceContainer;
056import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
057import org.opencms.ade.containerpage.shared.CmsLocaleLinkBean;
058import org.opencms.ade.containerpage.shared.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        for (CmsRelation relation : relationsToElement) {
1651            System.out.println("FROM: " + relation.getSourcePath() + " TYPE: " + relation.getType().getName());
1652        }
1653        Iterator<CmsRelation> iter = relationsToElement.iterator();
1654
1655        // ignore XML_STRONG (i.e. container element) relations from the container page, this must be checked on the client side.
1656        while (iter.hasNext()) {
1657            CmsRelation relation = iter.next();
1658            if ((containerpageId != null)
1659                && containerpageId.equals(relation.getSourceId())
1660                && relation.getType().equals(CmsRelationType.XML_STRONG)) {
1661                iter.remove();
1662            }
1663        }
1664        ElementDeleteMode elementDeleteMode = null;
1665        if (contextId != null) {
1666            CmsResource contextResource = cms.readResource(contextId, CmsResourceFilter.IGNORE_EXPIRATION);
1667            CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
1668                cms,
1669                contextResource.getRootPath());
1670            CmsResourceTypeConfig typeConfig = adeConfig.getResourceType(
1671                OpenCms.getResourceManager().getResourceType(elementResource).getTypeName());
1672
1673            if (typeConfig != null) {
1674                elementDeleteMode = typeConfig.getElementDeleteMode();
1675            }
1676        } else {
1677            elementDeleteMode = ElementDeleteMode.askKeep;
1678        }
1679        boolean hasNoRelations = relationsToElement.isEmpty();
1680        boolean deletionCandidate = hasNoRelations && hasWritePermissions && !isSystemResource;
1681        CmsListInfoBean elementInfo = CmsVfsService.getPageInfo(cms, elementResource);
1682        return new CmsRemovedElementStatus(structureId, elementInfo, deletionCandidate, elementDeleteMode);
1683    }
1684
1685    /**
1686     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#loadClipboardTab()
1687     */
1688    public int loadClipboardTab() {
1689
1690        Integer clipboardTab = (Integer)(getRequest().getSession().getAttribute(ATTR_CLIPBOARD_TAB));
1691        if (clipboardTab == null) {
1692            clipboardTab = Integer.valueOf(0);
1693        }
1694        return clipboardTab.intValue();
1695    }
1696
1697    /**
1698     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prefetch()
1699     */
1700    public CmsCntPageData prefetch() throws CmsRpcException {
1701
1702        CmsCntPageData data = null;
1703        CmsObject cms = getCmsObject();
1704        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1705        HttpServletRequest request = getRequest();
1706
1707        try {
1708            Map<String, String> sessionStorageData = new HashMap<>();
1709            CmsTemplateContextInfo info = OpenCms.getTemplateContextManager().getContextInfoBean(cms, request);
1710            CmsResource containerPage = getContainerpage(cms);
1711            Set<String> detailTypes = getDetailTypes(cms, containerPage);
1712            boolean isEditingModelGroup = isEditingModelGroups(cms, containerPage);
1713            boolean isModelPage = isModelPage(cms, containerPage);
1714            if (isModelPage) {
1715                // the model edit confirm dialog should only be shown once per session, disable it after first model editing
1716                getRequest().getSession().setAttribute(
1717                    CmsVfsSitemapService.ATTR_SHOW_MODEL_EDIT_CONFIRM,
1718                    Boolean.FALSE);
1719            }
1720
1721            TemplateBean templateBean = (TemplateBean)getRequest().getAttribute(
1722                CmsTemplateContextManager.ATTR_TEMPLATE_BEAN);
1723            CmsADESessionCache sessionCache = CmsADESessionCache.getCache(getRequest(), cms);
1724            sessionCache.setTemplateBean(containerPage.getRootPath(), templateBean);
1725            long lastModified = containerPage.getDateLastModified();
1726            String editorUri = OpenCms.getWorkplaceManager().getEditorHandler().getEditorUri(
1727                cms,
1728                CmsResourceTypeXmlContent.getStaticTypeName(),
1729                "User agent",
1730                false);
1731            boolean useClassicEditor = (editorUri == null) || !editorUri.contains("acacia");
1732            CmsResource detailResource = CmsDetailPageResourceHandler.getDetailResource(request);
1733            String noEditReason;
1734            String detailContainerPage = null;
1735            CmsQuickLaunchLocationCache locationCache = CmsQuickLaunchLocationCache.getLocationCache(
1736                request.getSession());
1737            CmsUUID detailContainerPageId = null;
1738            if (detailResource != null) {
1739                locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), detailResource);
1740                CmsObject rootCms = OpenCms.initCmsObject(cms);
1741                rootCms.getRequestContext().setSiteRoot("");
1742                String detailResourcePath = detailResource.getRootPath();
1743                String locale = cms.getRequestContext().getLocale().toString();
1744                detailContainerPage = CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
1745                    cms,
1746                    containerPage,
1747                    detailResourcePath,
1748                    locale);
1749
1750                if (rootCms.existsResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION)) {
1751                    detailContainerPageId = rootCms.readResource(
1752                        detailContainerPage,
1753                        CmsResourceFilter.IGNORE_EXPIRATION).getStructureId();
1754                    noEditReason = getNoEditReason(
1755                        rootCms,
1756                        rootCms.readResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION));
1757                } else {
1758                    String permissionFolder = CmsResource.getFolderPath(detailContainerPage);
1759                    while (!rootCms.existsResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION)) {
1760                        permissionFolder = CmsResource.getParentFolder(permissionFolder);
1761                    }
1762                    noEditReason = getNoEditReason(
1763                        rootCms,
1764                        rootCms.readResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION));
1765                }
1766            } else {
1767                if (!isModelPage && !isEditingModelGroup) {
1768                    locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), containerPage);
1769                    sessionStorageData.put(
1770                        CmsGwtConstants.LAST_CONTAINER_PAGE_ID,
1771                        containerPage.getStructureId().toString());
1772                }
1773                noEditReason = getNoEditReason(cms, containerPage);
1774            }
1775
1776            String sitemapPath = "";
1777            boolean sitemapManager = OpenCms.getRoleManager().hasRole(cms, CmsRole.EDITOR);
1778            if (sitemapManager) {
1779                sitemapPath = CmsADEManager.PATH_SITEMAP_EDITOR_JSP;
1780            }
1781            CmsCntPageData.ElementReuseMode reuseMode = ElementReuseMode.reuse;
1782            String reuseModeString = getWorkplaceSettings().getUserSettings().getAdditionalPreference(
1783                "elementReuseMode",
1784                true);
1785
1786            try {
1787                reuseMode = ElementReuseMode.valueOf(reuseModeString);
1788            } catch (Exception e) {
1789                LOG.info("Invalid reuse mode : " + reuseModeString, e);
1790            }
1791            InitialElementViewProvider viewHelper = new InitialElementViewProvider();
1792            viewHelper.init(getSessionCache().getElementView(), containerPage, info);
1793            CmsLocaleGroup group = cms.getLocaleGroupService().readLocaleGroup(containerPage);
1794            Locale mainLocale = null;
1795
1796            if (group.isRealGroup() && !cms.getRequestContext().getLocale().equals(group.getMainLocale())) {
1797                mainLocale = group.getMainLocale();
1798            }
1799            CmsSiteManagerImpl siteManager = OpenCms.getSiteManager();
1800            String ownRoot = siteManager.getSiteRoot(containerPage.getRootPath());
1801            Map<String, CmsLocaleLinkBean> localeLinkBeans = null;
1802            if (group.isRealGroup()) {
1803                localeLinkBeans = Maps.newHashMap();
1804                Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1805                for (Map.Entry<Locale, CmsResource> entry : group.getResourcesByLocale().entrySet()) {
1806                    String otherRoot = siteManager.getSiteRoot(entry.getValue().getRootPath());
1807                    if ((otherRoot != null) && otherRoot.equals(ownRoot)) {
1808                        String theLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1809                            cms,
1810                            cms.getRequestContext().removeSiteRoot(entry.getValue().getRootPath()));
1811                        localeLinkBeans.put(entry.getKey().getDisplayLanguage(locale), CmsLocaleLinkBean.link(theLink));
1812                    } else {
1813                        localeLinkBeans.put(
1814                            entry.getKey().getDisplayLanguage(locale),
1815                            CmsLocaleLinkBean.error(
1816                                Messages.get().getBundle(locale).key(Messages.GUI_SHOWLOCALE_WRONG_SITE_0)));
1817                    }
1818                }
1819            }
1820
1821            String onlineLink = null;
1822            CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(cms.getRequestContext().getSiteRoot());
1823            if ((site != null) && !OpenCms.getSiteManager().getWorkplaceServer().equals(site.getUrl())) {
1824                if (detailResource != null) {
1825                    onlineLink = OpenCms.getLinkManager().getOnlineLink(
1826                        cms,
1827                        cms.getSitePath(detailResource),
1828                        cms.getSitePath(containerPage),
1829                        false);
1830                } else {
1831                    onlineLink = OpenCms.getLinkManager().getOnlineLink(cms, cms.getSitePath(containerPage));
1832                }
1833            }
1834
1835            String modelGroupElementId = null;
1836            if (isEditingModelGroup) {
1837                CmsProperty modelElementProp = cms.readPropertyObject(
1838                    containerPage,
1839                    CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
1840                    false);
1841                if (!modelElementProp.isNullProperty() && CmsUUID.isValidUUID(modelElementProp.getValue())) {
1842                    modelGroupElementId = modelElementProp.getValue();
1843                }
1844            }
1845            String title = null;
1846            if (isModelPage || isEditingModelGroup) {
1847                title = Messages.get().getBundle(wpLocale).key(Messages.GUI_TITLE_MODEL_0);
1848
1849            }
1850            ElementDeleteMode deleteMode = OpenCms.getWorkplaceManager().getElementDeleteMode();
1851            if (deleteMode == null) {
1852                deleteMode = ElementDeleteMode.askDelete;
1853            }
1854            CmsListInfoBean pageInfo = CmsVfsService.getPageInfo(cms, containerPage);
1855            data = new CmsCntPageData(
1856                onlineLink,
1857                noEditReason,
1858                CmsRequestUtil.encodeParams(request),
1859                sitemapPath,
1860                sitemapManager,
1861                detailResource != null ? detailResource.getStructureId() : null,
1862                detailContainerPage,
1863                detailContainerPageId,
1864                detailTypes,
1865                lastModified,
1866                getLockInfo(containerPage),
1867                pageInfo,
1868                cms.getRequestContext().getLocale().toString(),
1869                useClassicEditor,
1870                info,
1871                isEditSmallElements(request, cms),
1872                Lists.newArrayList(viewHelper.getViewMap().values()),
1873                viewHelper.getDefaultView(),
1874                reuseMode,
1875                deleteMode,
1876                isModelPage,
1877                isEditingModelGroup,
1878                modelGroupElementId,
1879                mainLocale != null ? mainLocale.toString() : null,
1880                localeLinkBeans,
1881                title,
1882                System.currentTimeMillis());
1883            boolean allowSettingsInEditor = true;
1884            CmsModule baseModule = OpenCms.getModuleManager().getModule("org.opencms.base");
1885            if (baseModule != null) {
1886                String param = baseModule.getParameter("allowSettingsInEditor");
1887                allowSettingsInEditor = CmsStringUtil.isEmptyOrWhitespaceOnly(param)
1888                    || Boolean.valueOf(param).booleanValue();
1889            }
1890            data.setAllowSettingsInEditor(allowSettingsInEditor);
1891            String placementModeEnabledStr = (String)OpenCms.getRuntimeProperty(
1892                PARAM_PAGE_EDITOR_PLACEMENT_MODE_ENABLED);
1893            boolean placementModeEnabled = (placementModeEnabledStr == null)
1894                || Boolean.parseBoolean(placementModeEnabledStr);
1895            data.setPlacementModeEnabled(placementModeEnabled);
1896            data.setSessionStorageData(sessionStorageData);
1897        } catch (Throwable e) {
1898            error(e);
1899        }
1900        return data;
1901    }
1902
1903    /**
1904     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prepareForEdit(java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1905     */
1906    public CmsUUID prepareForEdit(String clientId, String editOption, CmsUUID pageId, String requestParams)
1907    throws CmsRpcException {
1908
1909        try {
1910            CmsResource pageResource = getCmsObject().readResource(
1911                pageId,
1912                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1913            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1914            element.initResource(getCmsObject());
1915            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1916            if (type instanceof CmsResourceTypeXmlContent) {
1917                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1918                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1919                    CmsEncoder.decode(requestParams),
1920                    true,
1921                    CmsEncoder.ENCODING_UTF_8);
1922                return handler.prepareForEdit(getCmsObject(), element, editOption, pageId, params);
1923            }
1924        } catch (CmsException e) {
1925            error(e);
1926        }
1927        return null;
1928    }
1929
1930    /**
1931     * @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)
1932     */
1933    public CmsContainerElementData replaceElement(
1934        CmsContainerPageRpcContext context,
1935        CmsUUID detailContentId,
1936        String reqParams,
1937        String clientId,
1938        String replaceId,
1939        Collection<CmsContainer> containers,
1940        String locale)
1941    throws CmsRpcException {
1942
1943        CmsContainerElementData element = null;
1944        try {
1945            ensureSession();
1946            CmsObject cms = getCmsObject();
1947            CmsResource pageResource = cms.readResource(
1948                context.getPageStructureId(),
1949                CmsResourceFilter.ignoreExpirationOffline(cms));
1950            initRequestFromRpcContext(context);
1951            String containerpageUri = cms.getSitePath(pageResource);
1952            Locale contentLocale = CmsLocaleManager.getLocale(locale);
1953            CmsElementUtil elemUtil = new CmsElementUtil(
1954                cms,
1955                containerpageUri,
1956                generateContainerPageForContainers(containers, pageResource.getRootPath()),
1957                detailContentId,
1958                getRequest(),
1959                getResponse(),
1960                false,
1961                contentLocale);
1962
1963            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
1964            Map<String, String> settings = new HashMap<String, String>(elementBean.getIndividualSettings());
1965            settings.remove(CmsContainerElement.ELEMENT_INSTANCE_ID);
1966            CmsContainerElementBean replaceBean = new CmsContainerElementBean(
1967                new CmsUUID(replaceId),
1968                elementBean.getFormatterId(),
1969                settings,
1970                elementBean.isCreateNew());
1971            getSessionCache().setCacheContainerElement(replaceBean.editorHash(), replaceBean);
1972            element = elemUtil.getElementData(pageResource, replaceBean, containers);
1973        } catch (Throwable e) {
1974            error(e);
1975        }
1976        return element;
1977    }
1978
1979    /**
1980     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveClipboardTab(int)
1981     */
1982    public void saveClipboardTab(int tabIndex) {
1983
1984        getRequest().getSession().setAttribute(ATTR_CLIPBOARD_TAB, Integer.valueOf(tabIndex));
1985    }
1986
1987    /**
1988     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveContainerpage(org.opencms.util.CmsUUID, java.util.List)
1989     */
1990    public CmsPageSaveStatus saveContainerpage(CmsUUID pageStructureId, List<CmsContainer> containers)
1991    throws CmsRpcException {
1992
1993        CmsObject cms = getCmsObject();
1994        try {
1995            ensureSession();
1996            CmsResource containerpage = cms.readResource(
1997                pageStructureId,
1998                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1999            ensureLock(containerpage);
2000            String containerpageUri = cms.getSitePath(containerpage);
2001            saveContainers(cms, containerpage, containerpageUri, containers);
2002        } catch (Throwable e) {
2003            error(e);
2004        }
2005        return new CmsPageSaveStatus(pageStructureId, System.currentTimeMillis());
2006    }
2007
2008    /**
2009     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveDetailContainers(org.opencms.util.CmsUUID, java.lang.String, java.util.List)
2010     */
2011    public CmsPageSaveStatus saveDetailContainers(
2012        CmsUUID detailId,
2013        String detailContainerResource,
2014        List<CmsContainer> containers)
2015    throws CmsRpcException {
2016
2017        CmsObject cms = getCmsObject();
2018        CmsUUID id = null;
2019        try {
2020            ensureSession();
2021            CmsObject rootCms = OpenCms.initCmsObject(cms);
2022            rootCms.getRequestContext().setSiteRoot("");
2023            CmsResource containerpage;
2024            containerpage = CmsDetailOnlyContainerUtil.readOrCreateDetailOnlyPage(
2025                rootCms,
2026                detailId,
2027                detailContainerResource);
2028            id = containerpage.getStructureId();
2029            saveContainers(rootCms, containerpage, detailContainerResource, containers);
2030        } catch (Throwable e) {
2031            error(e);
2032        }
2033        return new CmsPageSaveStatus(id, System.currentTimeMillis());
2034    }
2035
2036    /**
2037     * @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)
2038     */
2039    public CmsContainerElementData saveElementSettings(
2040        CmsContainerPageRpcContext context,
2041        CmsUUID detailContentId,
2042        String reqParams,
2043        String clientId,
2044        Map<String, String> settings,
2045        List<CmsContainer> containers,
2046        String locale)
2047    throws CmsRpcException {
2048
2049        CmsContainerElementData element = null;
2050        try {
2051            ensureSession();
2052            CmsObject cms = getCmsObject();
2053            CmsResource pageResource = cms.readResource(
2054                context.getPageStructureId(),
2055                CmsResourceFilter.ignoreExpirationOffline(cms));
2056            initRequestFromRpcContext(context);
2057            Locale contentLocale = CmsLocaleManager.getLocale(locale);
2058            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
2059            elementBean.initResource(cms);
2060            storeFormatterSelection(elementBean, settings);
2061            // make sure to keep the element instance id
2062            if (!settings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)
2063                && elementBean.getIndividualSettings().containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) {
2064                settings.put(
2065                    CmsContainerElement.ELEMENT_INSTANCE_ID,
2066                    elementBean.getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID));
2067            }
2068            if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.SETTING_PAGE_ID)) {
2069                settings.put(
2070                    CmsContainerElement.SETTING_PAGE_ID,
2071                    elementBean.getIndividualSettings().get(CmsContainerElement.SETTING_PAGE_ID));
2072            }
2073            if (!isEditingModelGroups(cms, pageResource)) {
2074                // in case of model group state set to 'noGroup', the group will be dissolved and former group id forgotten
2075                if (!(settings.containsKey(CmsContainerElement.MODEL_GROUP_STATE)
2076                    && (ModelGroupState.noGroup == ModelGroupState.evaluate(
2077                        settings.get(CmsContainerElement.MODEL_GROUP_STATE))))) {
2078                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID)) {
2079                        // make sure to keep the model group id
2080                        settings.put(
2081                            CmsContainerElement.MODEL_GROUP_ID,
2082                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID));
2083                    }
2084                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE)) {
2085                        settings.put(
2086                            CmsContainerElement.MODEL_GROUP_STATE,
2087                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE));
2088                    }
2089                }
2090            }
2091            elementBean = CmsContainerElementBean.cloneWithSettings(
2092                elementBean,
2093                convertSettingValues(elementBean.getResource(), settings, contentLocale));
2094            getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
2095
2096            // update client id within container data
2097            for (CmsContainer container : containers) {
2098                for (CmsContainerElement child : container.getElements()) {
2099                    if (child.getClientId().equals(clientId)) {
2100                        child.setClientId(elementBean.editorHash());
2101                    }
2102                }
2103            }
2104            if (detailContentId == null) {
2105                saveContainers(cms, pageResource, cms.getSitePath(pageResource), containers);
2106            } else {
2107                List<CmsContainer> detailContainers = new ArrayList<CmsContainer>();
2108                for (CmsContainer container : containers) {
2109                    if (container.isDetailOnly()) {
2110                        detailContainers.add(container);
2111                    }
2112                }
2113                CmsObject rootCms = OpenCms.initCmsObject(cms);
2114                rootCms.getRequestContext().setSiteRoot("");
2115                CmsResource detailResource = rootCms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2116                String detailRootPath = detailResource.getRootPath();
2117                CmsResource detailContainerPage = rootCms.readResource(
2118                    CmsDetailOnlyContainerUtil.getDetailOnlyPageName(cms, pageResource, detailRootPath, locale));
2119
2120                ensureLock(detailContainerPage);
2121                saveContainers(rootCms, detailContainerPage, detailContainerPage.getRootPath(), detailContainers);
2122            }
2123            String containerpageUri = cms.getSitePath(pageResource);
2124            CmsElementUtil elemUtil = new CmsElementUtil(
2125                cms,
2126                containerpageUri,
2127                generateContainerPageForContainers(containers, pageResource.getRootPath()),
2128                detailContentId,
2129                getRequest(),
2130                getResponse(),
2131                false,
2132                contentLocale);
2133            element = elemUtil.getElementData(pageResource, elementBean, containers);
2134        } catch (Throwable e) {
2135            error(e);
2136        }
2137        return element;
2138    }
2139
2140    /**
2141     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveFavoriteList(java.util.List, java.lang.String)
2142     */
2143    public void saveFavoriteList(List<String> clientIds, String uri) throws CmsRpcException {
2144
2145        try {
2146            ensureSession();
2147            OpenCms.getADEManager().saveFavoriteList(
2148                getCmsObject(),
2149                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2150        } catch (Throwable e) {
2151            error(e);
2152        }
2153    }
2154
2155    /**
2156     * @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)
2157     */
2158    public CmsGroupContainerSaveResult saveGroupContainer(
2159        CmsContainerPageRpcContext context,
2160
2161        CmsUUID detailContentId,
2162        String reqParams,
2163        CmsGroupContainer groupContainer,
2164        Collection<CmsContainer> containers,
2165        String locale)
2166    throws CmsRpcException {
2167
2168        CmsObject cms = getCmsObject();
2169        List<CmsRemovedElementStatus> removedElements = null;
2170        try {
2171            CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> saveResult = internalSaveGroupContainer(
2172                cms,
2173                context.getPageStructureId(),
2174                groupContainer);
2175            removedElements = saveResult.getSecond();
2176        } catch (Throwable e) {
2177            error(e);
2178        }
2179        Collection<String> ids = new ArrayList<String>();
2180        ids.add(groupContainer.getClientId());
2181        // update offline indices
2182        OpenCms.getSearchManager().updateOfflineIndexes();
2183        return new CmsGroupContainerSaveResult(
2184            getElementsData(context, detailContentId, reqParams, ids, containers, false, null, locale),
2185            removedElements);
2186    }
2187
2188    /**
2189     * @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)
2190     */
2191    public Map<String, CmsContainerElementData> saveInheritanceContainer(
2192        CmsUUID pageStructureId,
2193        CmsUUID detailContentId,
2194        CmsInheritanceContainer inheritanceContainer,
2195        Collection<CmsContainer> containers,
2196        String locale)
2197    throws CmsRpcException {
2198
2199        try {
2200            CmsObject cms = getCmsObject();
2201            CmsADEConfigData rpcConfig = OpenCms.getADEManager().lookupConfiguration(
2202                cms,
2203                cms.getRequestContext().getRootUri());
2204            CmsResource containerPage = cms.readResource(
2205                pageStructureId,
2206                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
2207            String sitePath = cms.getSitePath(containerPage);
2208            Locale requestedLocale = CmsLocaleManager.getLocale(locale);
2209            CmsResource referenceResource = null;
2210            if (inheritanceContainer.isNew()) {
2211                CmsADEConfigData config = getConfigData(containerPage.getRootPath());
2212                CmsResourceTypeConfig typeConfig = config.getResourceType(
2213                    CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_TYPE_NAME);
2214                referenceResource = typeConfig.createNewElement(cms, containerPage.getRootPath());
2215                inheritanceContainer.setClientId(referenceResource.getStructureId().toString());
2216            }
2217            if (referenceResource == null) {
2218                CmsUUID id = convertToServerId(inheritanceContainer.getClientId());
2219                referenceResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2220            }
2221            ensureLock(referenceResource);
2222            saveInheritanceGroup(referenceResource, inheritanceContainer);
2223            tryUnlock(referenceResource);
2224            List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2225            for (CmsContainerElement clientElement : inheritanceContainer.getElements()) {
2226                CmsContainerElementBean elementBean = getCachedElement(
2227                    clientElement.getClientId(),
2228                    containerPage.getRootPath());
2229                elementBean = CmsContainerElementBean.cloneWithSettings(
2230                    elementBean,
2231                    elementBean.getIndividualSettings());
2232                CmsInheritanceInfo inheritanceInfo = clientElement.getInheritanceInfo();
2233                // if a local elements misses the key it was newly added
2234                if (inheritanceInfo.isNew() && CmsStringUtil.isEmptyOrWhitespaceOnly(inheritanceInfo.getKey())) {
2235                    // generating new key
2236                    inheritanceInfo.setKey(CmsResource.getFolderPath(sitePath) + new CmsUUID().toString());
2237                }
2238                elementBean.setInheritanceInfo(inheritanceInfo);
2239                elements.add(elementBean);
2240            }
2241            cms.getRequestContext().setLocale(requestedLocale);
2242            if (inheritanceContainer.getElementsChanged()) {
2243                OpenCms.getADEManager().saveInheritedContainer(
2244                    cms,
2245                    containerPage,
2246                    inheritanceContainer.getName(),
2247                    true,
2248                    elements);
2249            }
2250            return getElements(
2251                rpcConfig,
2252                containerPage,
2253                new ArrayList<String>(Collections.singletonList(inheritanceContainer.getClientId())),
2254                sitePath,
2255                detailContentId,
2256                containers,
2257                false,
2258                null,
2259                false,
2260                requestedLocale);
2261        } catch (Exception e) {
2262            error(e);
2263        }
2264        return null;
2265    }
2266
2267    /**
2268     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveRecentList(java.util.List, java.lang.String)
2269     */
2270    public void saveRecentList(List<String> clientIds, String uri) throws CmsRpcException {
2271
2272        try {
2273            ensureSession();
2274            OpenCms.getADEManager().saveRecentList(
2275                getCmsObject(),
2276                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2277        } catch (Throwable e) {
2278            error(e);
2279        }
2280    }
2281
2282    /**
2283     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setEditSmallElements(boolean)
2284     */
2285    public void setEditSmallElements(boolean editSmallElements) throws CmsRpcException {
2286
2287        try {
2288            CmsObject cms = getCmsObject();
2289            CmsUser user = cms.getRequestContext().getCurrentUser();
2290            user.getAdditionalInfo().put(ADDINFO_EDIT_SMALL_ELEMENTS, "" + editSmallElements);
2291            cms.writeUser(user);
2292        } catch (Throwable t) {
2293            error(t);
2294        }
2295    }
2296
2297    /**
2298     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setElementView(org.opencms.util.CmsUUID)
2299     */
2300    public void setElementView(CmsUUID elementView) {
2301
2302        getSessionCache().setElementView(elementView);
2303    }
2304
2305    /**
2306     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setLastPage(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
2307     */
2308    public void setLastPage(CmsUUID pageId, CmsUUID detailId) throws CmsRpcException {
2309
2310        try {
2311            HttpServletRequest req = getRequest();
2312            CmsObject cms = getCmsObject();
2313            CmsADESessionCache cache = CmsADESessionCache.getCache(req, cms);
2314            cache.setLastPage(cms, pageId, detailId);
2315        } catch (Exception e) {
2316            error(e);
2317        }
2318
2319    }
2320
2321    /**
2322     * Sets the session cache.<p>
2323     *
2324     * @param cache the session cache
2325     */
2326    public void setSessionCache(CmsADESessionCache cache) {
2327
2328        m_sessionCache = cache;
2329    }
2330
2331    /**
2332     * Gets the settings which should be updated for an element in the DND case.<p>
2333     *
2334     * @param config the sitemap configuration
2335     * @param originalSettings the original settings
2336     * @param formatterConfig the formatter configuration for the element
2337     * @param containers the containers
2338     * @param dndContainer the id of the DND origin container
2339     *
2340     * @return the map of settings to update
2341     */
2342    Map<String, String> getSettingsToChangeForDnd(
2343        CmsADEConfigData config,
2344        Map<String, String> originalSettings,
2345        CmsFormatterConfiguration formatterConfig,
2346        Collection<CmsContainer> containers,
2347        String dndContainer) {
2348
2349        Map<String, String> result = Maps.newHashMap();
2350
2351        if (dndContainer == null) {
2352            return result;
2353        }
2354        String key = CmsFormatterConfig.getSettingsKeyForContainer(dndContainer);
2355        String formatterId = originalSettings.get(key);
2356        if (formatterId == null) {
2357            return result;
2358        }
2359        for (CmsContainer container : containers) {
2360            if (container.getName().equals(dndContainer)) {
2361                continue;
2362            }
2363
2364            Map<String, I_CmsFormatterBean> formatterSelection = formatterConfig.getFormatterSelection(
2365                container.getType(),
2366                container.getWidth());
2367            I_CmsFormatterBean currentBean = config.findFormatter(formatterId);
2368            if (currentBean != null) {
2369                if (CmsFormatterConfiguration.matchFormatter(currentBean, container.getType(), container.getWidth())) {
2370                    String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2371                    result.put(newKey, currentBean.getKeyOrId());
2372                }
2373            } else if (formatterSelection.containsKey(formatterId)) {
2374                // for backwards compatibility with schema-configured formatters
2375                String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2376                result.put(newKey, formatterId);
2377            }
2378        }
2379        return result;
2380    }
2381
2382    /**
2383     * Creates a new container element bean from an existing one, but changes some of the individual settings in the copy.<p>
2384     *
2385     * @param element the original container element
2386     * @param settingsToOverride the map of settings to change
2387     *
2388     * @return the new container element bean with the changed settings
2389     */
2390    CmsContainerElementBean overrideSettings(CmsContainerElementBean element, Map<String, String> settingsToOverride) {
2391
2392        Map<String, String> settings = Maps.newHashMap(element.getIndividualSettings());
2393        settings.putAll(settingsToOverride);
2394        CmsContainerElementBean result = new CmsContainerElementBean(
2395            element.getId(),
2396            element.getFormatterId(),
2397            settings,
2398            element.isCreateNew());
2399        return result;
2400    }
2401
2402    /**
2403     * Adds the formatter to the recently used formatter list.<p>
2404     *
2405     * @param elementBean the element bean
2406     * @param settings the changed settings
2407     */
2408    void storeFormatterSelection(CmsContainerElementBean elementBean, Map<String, String> settings) {
2409
2410        Entry<String, String> previousFormatterEntry = null;
2411        for (Entry<String, String> entry : elementBean.getIndividualSettings().entrySet()) {
2412            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2413                previousFormatterEntry = entry;
2414                break;
2415            }
2416        }
2417        Entry<String, String> formatterEntry = null;
2418        for (Entry<String, String> entry : settings.entrySet()) {
2419            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2420                formatterEntry = entry;
2421                break;
2422            }
2423        }
2424        if ((formatterEntry != null)
2425            && ((previousFormatterEntry == null)
2426                || !formatterEntry.getKey().equals(previousFormatterEntry.getKey())
2427                || !formatterEntry.getValue().equals(previousFormatterEntry.getValue()))) {
2428            String idString = formatterEntry.getValue();
2429            if (idString != null) {
2430                // the formatter setting has changed
2431                I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(elementBean.getResource());
2432                if (!(resType instanceof CmsResourceTypeFunctionConfig)) {
2433                    getSessionCache().addRecentFormatter(resType.getTypeName(), idString);
2434                }
2435            }
2436        }
2437    }
2438
2439    /**
2440     * Converts the given setting values according to the setting configuration of the given resource.<p>
2441     *
2442     * @param resource the resource
2443     * @param settings the settings to convert
2444     * @param locale the locale used for accessing the element settings
2445     *
2446     * @return the converted settings
2447     * @throws CmsException if something goes wrong
2448     */
2449    private Map<String, String> convertSettingValues(CmsResource resource, Map<String, String> settings, Locale locale)
2450    throws CmsException {
2451
2452        CmsObject cms = getCmsObject();
2453        Locale origLocale = cms.getRequestContext().getLocale();
2454        try {
2455            cms.getRequestContext().setLocale(locale);
2456            Map<String, CmsXmlContentProperty> settingsConf = OpenCms.getADEManager().getElementSettings(cms, resource);
2457            Map<String, String> changedSettings = new HashMap<String, String>();
2458            if (settings != null) {
2459                for (Map.Entry<String, String> entry : settings.entrySet()) {
2460                    String settingName = entry.getKey();
2461                    String settingType = "string";
2462                    if (settingsConf.get(settingName) != null) {
2463                        settingType = settingsConf.get(settingName).getType();
2464                    }
2465                    changedSettings.put(
2466                        settingName,
2467                        CmsXmlContentPropertyHelper.getPropValueIds(getCmsObject(), settingType, entry.getValue()));
2468                }
2469            }
2470            return changedSettings;
2471        } finally {
2472            cms.getRequestContext().setLocale(origLocale);
2473        }
2474    }
2475
2476    /**
2477     * Generates the XML container page bean for the given containers.<p>
2478     *
2479     * @param containers the containers
2480     * @param containerpageRootPath the container page root path
2481     *
2482     * @return the container page bean
2483     * @throws CmsException in case generating the page data fails
2484     */
2485    private CmsContainerPageBean generateContainerPageForContainers(
2486        Collection<CmsContainer> containers,
2487        String containerpageRootPath)
2488    throws CmsException {
2489
2490        List<CmsContainerBean> containerBeans = new ArrayList<CmsContainerBean>();
2491        for (CmsContainer container : containers) {
2492            CmsContainerBean containerBean = getContainerBeanToSave(container, containerpageRootPath);
2493            containerBeans.add(containerBean);
2494        }
2495        CmsContainerPageBean page = new CmsContainerPageBean(containerBeans);
2496        return page;
2497    }
2498
2499    /**
2500     * Returns a list of container elements from a list with client id's.<p>
2501     *
2502     * @param clientIds list of client id's
2503     * @param pageRootPath the container page root path
2504     *
2505     * @return a list of element beans
2506     * @throws CmsException in case reading the element resource fails
2507     */
2508    private List<CmsContainerElementBean> getCachedElements(List<String> clientIds, String pageRootPath)
2509    throws CmsException {
2510
2511        List<CmsContainerElementBean> result = new ArrayList<CmsContainerElementBean>();
2512        for (String id : clientIds) {
2513            try {
2514                result.add(getCachedElement(id, pageRootPath));
2515            } catch (CmsIllegalArgumentException e) {
2516                log(e.getLocalizedMessage(), e);
2517            }
2518        }
2519        return result;
2520    }
2521
2522    /**
2523     * Returns the configuration data of the current container page context.<p>
2524     *
2525     * @param pageRootPath the container page root path
2526     *
2527     * @return the configuration data of the current container page context
2528     */
2529    private CmsADEConfigData getConfigData(String pageRootPath) {
2530
2531        if (m_configData == null) {
2532            m_configData = OpenCms.getADEManager().lookupConfiguration(getCmsObject(), pageRootPath);
2533        }
2534        return m_configData;
2535    }
2536
2537    /**
2538     * Helper method for converting a CmsContainer to a CmsContainerBean when saving a container page.<p>
2539     *
2540     * @param container the container for which the CmsContainerBean should be created
2541     * @param containerpageRootPath the container page root path
2542     *
2543     * @return a container bean
2544     *
2545     * @throws CmsException in case generating the container data fails
2546     */
2547    private CmsContainerBean getContainerBeanToSave(CmsContainer container, String containerpageRootPath)
2548    throws CmsException {
2549
2550        CmsObject cms = getCmsObject();
2551        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2552        for (CmsContainerElement elementData : container.getElements()) {
2553            if (!elementData.isNew()) {
2554                CmsContainerElementBean newElementBean = getContainerElementBeanToSave(
2555                    cms,
2556                    containerpageRootPath,
2557                    container,
2558                    elementData);
2559                if (newElementBean != null) {
2560                    elements.add(newElementBean);
2561                }
2562            }
2563        }
2564        CmsContainerBean result = CmsElementUtil.clientToServerContainer(container, elements);
2565        return result;
2566    }
2567
2568    /**
2569     * Converts container page element data to a bean which can be saved in a container page.<p>
2570     *
2571     * @param cms the current CMS context
2572     * @param containerpageRootPath the container page root path
2573     * @param container the container containing the element
2574     * @param elementData the data for the single element
2575     *
2576     * @return the container element bean
2577     *
2578     * @throws CmsException if something goes wrong
2579     */
2580    private CmsContainerElementBean getContainerElementBeanToSave(
2581        CmsObject cms,
2582        String containerpageRootPath,
2583        CmsContainer container,
2584        CmsContainerElement elementData)
2585    throws CmsException {
2586
2587        String elementClientId = elementData.getClientId();
2588        boolean hasUuidPrefix = (elementClientId != null) && elementClientId.matches(CmsUUID.UUID_REGEX + ".*$");
2589        boolean isCreateNew = elementData.isCreateNew();
2590        if (elementData.isNew() && !hasUuidPrefix) {
2591
2592            // Due to the changed save system without the save button, we need to make sure that new elements
2593            // are only created once. This must happen when the user first edits a new element. But we still
2594            // want to save changes to non-new elements on the page, so we skip new elements while saving.
2595            return null;
2596        }
2597        CmsContainerElementBean element = getCachedElement(elementData.getClientId(), containerpageRootPath);
2598
2599        CmsResource resource;
2600        if (element.getResource() == null) {
2601            element.initResource(cms);
2602            resource = element.getResource();
2603        } else {
2604            // make sure resource is readable, this is necessary for new content elements
2605            if (element.getId().isNullUUID()) {
2606                // in memory only element, can not be read nor saved
2607                return null;
2608            }
2609            resource = cms.readResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION);
2610        }
2611
2612        // check if there is a valid formatter
2613        int containerWidth = container.getWidth();
2614        CmsADEConfigData config = getConfigData(containerpageRootPath);
2615        CmsFormatterConfiguration formatters = config.getFormatters(cms, resource);
2616        String containerType = null;
2617        containerType = container.getType();
2618        I_CmsFormatterBean formatter = null;
2619        String formatterConfigId = null;
2620        if ((element.getIndividualSettings() != null)
2621            && (element.getIndividualSettings().get(
2622                CmsFormatterConfig.getSettingsKeyForContainer(container.getName())) != null)) {
2623            formatterConfigId = element.getIndividualSettings().get(
2624                CmsFormatterConfig.getSettingsKeyForContainer(container.getName()));
2625            I_CmsFormatterBean dynamicFmt = config.findFormatter(formatterConfigId);
2626            if (dynamicFmt != null) {
2627                formatter = dynamicFmt;
2628            } else if (formatterConfigId.startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)
2629                && CmsUUID.isValidUUID(formatterConfigId.substring(CmsFormatterConfig.SCHEMA_FORMATTER_ID.length()))) {
2630                formatter = formatters.getFormatterSelection(containerType, containerWidth).get(formatterConfigId);
2631            }
2632        }
2633        if (formatter == null) {
2634            formatter = CmsElementUtil.getFormatterForContainer(cms, element, container, config, getSessionCache());
2635            if (formatter != null) {
2636                formatterConfigId = formatter.isFromFormatterConfigFile()
2637                ? formatter.getId()
2638                : CmsFormatterConfig.SCHEMA_FORMATTER_ID + formatter.getJspStructureId().toString();
2639            }
2640        }
2641        CmsContainerElementBean newElementBean = null;
2642        if (formatter != null) {
2643            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
2644            String formatterKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2645            settings.put(formatterKey, formatterConfigId);
2646            // remove not used formatter settings
2647            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
2648            while (entries.hasNext()) {
2649                Entry<String, String> entry = entries.next();
2650                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)
2651                    && !entry.getKey().equals(formatterKey)) {
2652                    entries.remove();
2653                }
2654            }
2655
2656            newElementBean = new CmsContainerElementBean(
2657                element.getId(),
2658                formatter.getJspStructureId(),
2659                settings,
2660                isCreateNew);
2661        }
2662        return newElementBean;
2663    }
2664
2665    /**
2666     * Returns the requested container-page resource.<p>
2667     *
2668     * @param cms the current cms object
2669     *
2670     * @return the container-page resource
2671     *
2672     * @throws CmsException if the resource could not be read for any reason
2673     */
2674    private CmsResource getContainerpage(CmsObject cms) throws CmsException {
2675
2676        String currentUri = cms.getRequestContext().getUri();
2677        CmsResource containerPage = cms.readResource(currentUri, CmsResourceFilter.ignoreExpirationOffline(cms));
2678        if (!CmsResourceTypeXmlContainerPage.isContainerPage(containerPage)) {
2679            // container page is used as template
2680            String cntPagePath = cms.readPropertyObject(
2681                containerPage,
2682                CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
2683                true).getValue("");
2684            try {
2685                containerPage = cms.readResource(cntPagePath, CmsResourceFilter.ignoreExpirationOffline(cms));
2686            } catch (CmsException e) {
2687                if (!LOG.isDebugEnabled()) {
2688                    LOG.warn(e.getLocalizedMessage());
2689                }
2690                LOG.debug(e.getLocalizedMessage(), e);
2691            }
2692        }
2693        return containerPage;
2694    }
2695
2696    /**
2697     * Gets the (potentially empty) set of types for which the container page is registered as a detail page.
2698     *
2699     * @param cms the CMS context
2700     * @param containerPage a container page resource
2701     *
2702     * @return the set of names of types for which the container page is a detail page
2703     */
2704    private Set<String> getDetailTypes(CmsObject cms, CmsResource containerPage) {
2705
2706        List<CmsDetailPageInfo> infos = OpenCms.getADEManager().getAllDetailPages(cms);
2707        Set<CmsUUID> ids = new HashSet<>();
2708        ids.add(containerPage.getStructureId());
2709        Set<String> result = new HashSet<>();
2710        if (containerPage.isFile()) {
2711            try {
2712                CmsResource folder = cms.readParentFolder(containerPage.getStructureId());
2713                if (folder != null) {
2714                    ids.add(folder.getStructureId());
2715                }
2716            } catch (CmsException e) {
2717                LOG.error(e.getLocalizedMessage(), e);
2718            }
2719        }
2720        for (CmsDetailPageInfo info : infos) {
2721            if (ids.contains(info.getId())) {
2722                result.add(info.getType());
2723            }
2724        }
2725
2726        return result;
2727
2728    }
2729
2730    /**
2731     * Returns the data of the given elements.<p>
2732     *
2733     * @param config the sitemap configuration
2734     * @param page the current container page
2735     * @param clientIds the list of IDs of the elements to retrieve the data for
2736     * @param uriParam the current URI
2737     * @param detailContentId the detail content structure id
2738     * @param containers the containers for which the element data should be fetched
2739     * @param allwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group
2740     * @param dndOriginContainer the container from which an element was dragged (null if this method is not called for DND)
2741     * @param isDragMode if the page is in drag mode
2742     * @param locale the locale to use
2743     *
2744     * @return the elements data
2745     *
2746     * @throws CmsException if something really bad happens
2747     */
2748    private Map<String, CmsContainerElementData> getElements(
2749        CmsADEConfigData config,
2750        CmsResource page,
2751        Collection<String> clientIds,
2752        String uriParam,
2753        CmsUUID detailContentId,
2754        Collection<CmsContainer> containers,
2755        boolean allwaysCopy,
2756        String dndOriginContainer,
2757        boolean isDragMode,
2758        Locale locale)
2759    throws CmsException {
2760
2761        CmsObject cms = getCmsObject();
2762        CmsContainerPageBean pageBean = generateContainerPageForContainers(
2763            containers,
2764            cms.getRequestContext().addSiteRoot(uriParam));
2765        Map<String, CmsContainerElementBean> idMapping = new HashMap<String, CmsContainerElementBean>();
2766        for (String elemId : clientIds) {
2767            if ((elemId == null)) {
2768                continue;
2769            }
2770            CmsContainerElementBean element = getCachedElement(elemId, cms.getRequestContext().addSiteRoot(uriParam));
2771            if (element.getInstanceId() == null) {
2772                element = element.clone();
2773                getSessionCache().setCacheContainerElement(element.editorHash(), element);
2774            }
2775            element.initResource(cms);
2776            idMapping.put(elemId, element);
2777        }
2778        List<String> foundGroups = new ArrayList<String>();
2779        if (CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2780            // this indicates the element is added to the page and not being repositioned, check for model group data
2781            CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
2782                cms,
2783                getConfigData(uriParam),
2784                getSessionCache(),
2785                isEditingModelGroups(cms, page));
2786            String createElementContext = CmsResource.getParentFolder(page.getRootPath());
2787            if (detailContentId != null) {
2788                try {
2789                    CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2790                    createElementContext = CmsResource.getParentFolder(
2791                        CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
2792                            cms,
2793                            page,
2794                            detailContent.getRootPath(),
2795                            "" + locale));
2796                } catch (Exception e) {
2797                    LOG.error(e.getLocalizedMessage(), e);
2798                }
2799            }
2800            pageBean = modelHelper.prepareforModelGroupContent(
2801                idMapping,
2802                foundGroups,
2803                pageBean,
2804                allwaysCopy,
2805                locale,
2806                createElementContext);
2807        }
2808
2809        CmsElementUtil elemUtil = new CmsElementUtil(
2810            cms,
2811            uriParam,
2812            pageBean,
2813            detailContentId,
2814            getRequest(),
2815            getResponse(),
2816            isDragMode,
2817            locale);
2818        Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>();
2819        Set<String> ids = new HashSet<String>();
2820        for (Entry<String, CmsContainerElementBean> entry : idMapping.entrySet()) {
2821            CmsContainerElementBean element = entry.getValue();
2822            String dndId = null;
2823            if (ids.contains(element.editorHash())) {
2824                continue;
2825            }
2826            if ((dndOriginContainer != null) && !CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2827                CmsFormatterConfiguration formatterConfig = elemUtil.getFormatterConfiguration(element.getResource());
2828                Map<String, String> dndSettings = getSettingsToChangeForDnd(
2829                    config,
2830                    element.getIndividualSettings(),
2831                    formatterConfig,
2832                    containers,
2833                    dndOriginContainer);
2834                if (!dndSettings.isEmpty()) {
2835                    CmsContainerElementBean dndElementBean = overrideSettings(element, dndSettings);
2836                    getSessionCache().setCacheContainerElement(dndElementBean.editorHash(), dndElementBean);
2837                    element = dndElementBean;
2838                    dndId = dndElementBean.editorHash();
2839                    Map<String, CmsContainerElementData> dndResults = getElements(
2840                        config,
2841                        page,
2842                        Arrays.asList(dndId),
2843                        uriParam,
2844                        detailContentId,
2845                        containers,
2846                        false,
2847                        null,
2848                        isDragMode,
2849                        locale);
2850                    result.putAll(dndResults);
2851                }
2852            }
2853
2854            CmsContainerElementData elementData = elemUtil.getElementData(page, element, containers);
2855            if (elementData == null) {
2856                continue;
2857            }
2858            getSessionCache().setCacheContainerElement(element.editorHash(), element);
2859            elementData.setDndId(dndId);
2860            result.put(entry.getKey(), elementData);
2861            if (elementData.isGroupContainer() || elementData.isInheritContainer()) {
2862                // this is a group-container
2863                CmsResource elementRes = cms.readResource(element.getId());
2864                List<CmsContainerElementBean> subElements = elementData.isGroupContainer()
2865                ? getGroupContainerElements(elementRes)
2866                : getInheritedElements(elementRes, locale, uriParam);
2867                // adding all sub-items to the elements data
2868                for (CmsContainerElementBean subElement : subElements) {
2869                    getSessionCache().setCacheContainerElement(subElement.editorHash(), subElement);
2870                    if (!ids.contains(subElement.editorHash())) {
2871                        CmsContainerElementData subItemData = elemUtil.getElementData(page, subElement, containers);
2872                        ids.add(subElement.editorHash());
2873                        result.put(subElement.editorHash(), subItemData);
2874                    }
2875                }
2876            }
2877            ids.add(element.editorHash());
2878        }
2879        for (CmsContainerElementData elementData : result.values()) {
2880            elementData.setGroup(foundGroups.contains(elementData.getClientId()));
2881        }
2882        return result;
2883    }
2884
2885    /**
2886     * Helper method for converting a CmsGroupContainer to a CmsGroupContainerBean when saving a group container.<p>
2887     *
2888     * @param groupContainer the group-container data
2889     * @param containerPage the container page
2890     * @param locale the locale to use
2891     *
2892     * @return the group-container bean
2893     */
2894    private CmsGroupContainerBean getGroupContainerBean(
2895        CmsGroupContainer groupContainer,
2896        CmsResource containerPage,
2897        String locale) {
2898
2899        CmsObject cms = getCmsObject();
2900        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2901        for (CmsContainerElement elementData : groupContainer.getElements()) {
2902            try {
2903                if (elementData.isNew()) {
2904                    elementData = createNewElement(
2905                        containerPage.getStructureId(),
2906                        null,
2907                        elementData.getClientId(),
2908                        elementData.getResourceType(),
2909                        null,
2910                        locale);
2911                }
2912                CmsContainerElementBean element = getCachedElement(
2913                    elementData.getClientId(),
2914                    containerPage.getRootPath());
2915
2916                // make sure resource is readable,
2917                if (cms.existsResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION)) {
2918                    elements.add(element);
2919                }
2920
2921            } catch (Exception e) {
2922                log(e.getLocalizedMessage(), e);
2923            }
2924        }
2925        return new CmsGroupContainerBean(
2926            groupContainer.getTitle(),
2927            groupContainer.getDescription(),
2928            elements,
2929            groupContainer.getTypes());
2930    }
2931
2932    /**
2933     * Returns the sub-elements of this group container resource.<p>
2934     *
2935     * @param resource the group container resource
2936     *
2937     * @return the sub-elements
2938     *
2939     * @throws CmsException if something goes wrong reading the resource
2940     */
2941    private List<CmsContainerElementBean> getGroupContainerElements(CmsResource resource) throws CmsException {
2942
2943        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(
2944            getCmsObject(),
2945            resource,
2946            getRequest());
2947        CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(getCmsObject());
2948        return groupContainer.getElements();
2949    }
2950
2951    /**
2952     * Gets the structure ids of group container elements from an unmarshalled group container for a single locale.<p>
2953     *
2954     * @param groupContainer the group container
2955     * @param locale the locale for which we want the element ids
2956     *
2957     * @return the group container's element ids for the given locale
2958     */
2959    private Set<CmsUUID> getGroupElementIds(CmsXmlGroupContainer groupContainer, Locale locale) {
2960
2961        Set<CmsUUID> idSet = new HashSet<CmsUUID>();
2962        CmsGroupContainerBean groupContainerBean = groupContainer.getGroupContainer(getCmsObject());
2963        if (groupContainerBean != null) {
2964            for (CmsContainerElementBean element : groupContainerBean.getElements()) {
2965                idSet.add(element.getId());
2966            }
2967        }
2968        return idSet;
2969
2970    }
2971
2972    /**
2973     * Returns the sub-elements of this inherit container resource.<p>
2974     *
2975     * @param resource the inherit container resource
2976     * @param locale the requested locale
2977     * @param uriParam the current URI
2978     *
2979     * @return the sub-elements
2980     *
2981     * @throws CmsException if something goes wrong reading the resource
2982     */
2983    private List<CmsContainerElementBean> getInheritedElements(CmsResource resource, Locale locale, String uriParam)
2984    throws CmsException {
2985
2986        CmsObject cms = getCmsObject();
2987        cms.getRequestContext().setLocale(locale);
2988        CmsInheritanceReferenceParser parser = new CmsInheritanceReferenceParser(cms);
2989        parser.parse(resource);
2990        CmsInheritanceReference ref = parser.getReference(locale);
2991        if (ref == null) {
2992            // new inheritance reference, return an empty list
2993            return Collections.emptyList();
2994        }
2995        String name = ref.getName();
2996        CmsADEManager adeManager = OpenCms.getADEManager();
2997        CmsInheritedContainerState result = adeManager.getInheritedContainerState(cms, cms.addSiteRoot(uriParam), name);
2998        return result.getElements(true);
2999    }
3000
3001    /**
3002     * Returns the data of the given elements.<p>
3003     *
3004     * @param listElements the list of element beans to retrieve the data for
3005     * @param containerpageUri the current URI
3006     * @param detailContentId the detail content structure id
3007     * @param containers the containers which exist on the container page
3008     * @param locale the locale to use
3009     *
3010     * @return the elements data
3011     *
3012     * @throws CmsException if something really bad happens
3013     */
3014    private List<CmsContainerElementData> getListElementsData(
3015        List<CmsContainerElementBean> listElements,
3016        String containerpageUri,
3017        CmsUUID detailContentId,
3018        Collection<CmsContainer> containers,
3019        Locale locale)
3020    throws CmsException {
3021
3022        CmsObject cms = getCmsObject();
3023        CmsElementUtil elemUtil = new CmsElementUtil(
3024            cms,
3025            containerpageUri,
3026            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(containerpageUri)),
3027            detailContentId,
3028            getRequest(),
3029            getResponse(),
3030            true,
3031            locale);
3032        CmsADESessionCache cache = getSessionCache();
3033        List<CmsContainerElementData> result = new ArrayList<CmsContainerElementData>();
3034        for (CmsContainerElementBean element : listElements) {
3035            // checking if resource exists
3036            if (cms.existsResource(element.getId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFile())) {
3037                try {
3038                    CmsContainerElementBean clone = element.clone();
3039                    // Because ensureNewInstanceId() just generates a new UUID,
3040                    // the key for the element cache will not collide with anything else, so
3041                    // we do not need to set the SYSTEM::pageId setting for disambiguation here.
3042                    clone.ensureNewInstanceId();
3043                    cache.setCacheContainerElement(clone.editorHash(), clone);
3044                    CmsContainerElementData elementData = elemUtil.getElementData(
3045                        elemUtil.getPage(),
3046                        clone,
3047                        containers);
3048                    result.add(elementData);
3049                } catch (CmsVfsResourceNotFoundException e) {
3050                    // model group id not found, or other resources
3051                    LOG.info(e.getLocalizedMessage(), e);
3052                }
3053            }
3054        }
3055        return result;
3056    }
3057
3058    /**
3059     * Returns the lock information to the given resource.<p>
3060     *
3061     * @param resource the resource
3062     *
3063     * @return lock information, if the page is locked by another user
3064     *
3065     * @throws CmsException if something goes wrong reading the lock owner user
3066     */
3067    private String getLockInfo(CmsResource resource) throws CmsException {
3068
3069        CmsObject cms = getCmsObject();
3070        CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource);
3071        CmsLock lock = resourceUtil.getLock();
3072        String lockInfo = null;
3073        if (!lock.isLockableBy(cms.getRequestContext().getCurrentUser())) {
3074            if (lock.getType() == CmsLockType.PUBLISH) {
3075                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3076                    Messages.GUI_LOCKED_FOR_PUBLISH_0);
3077            } else {
3078                CmsUser lockOwner = cms.readUser(lock.getUserId());
3079                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3080                    Messages.GUI_LOCKED_BY_1,
3081                    lockOwner.getFullName());
3082            }
3083        }
3084        return lockInfo;
3085    }
3086
3087    /**
3088     * Returns the element data for a new element not existing in the VFS yet.<p>
3089     *
3090     * @param resourceTypeName the resource type name
3091     * @param uriParam the request parameters
3092     * @param detailContentId the detail content structure id
3093     * @param containers the containers of the template
3094     * @param locale the current locale
3095     *
3096     * @return the element data
3097     *
3098     * @throws CmsException if something goes wrong
3099     */
3100    private CmsContainerElementData getNewElement(
3101        String resourceTypeName,
3102        String uriParam,
3103        CmsUUID detailContentId,
3104        Collection<CmsContainer> containers,
3105        Locale locale)
3106    throws CmsException {
3107
3108        CmsObject cms = getCmsObject();
3109        CmsElementUtil elemUtil = new CmsElementUtil(
3110            cms,
3111            uriParam,
3112            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(uriParam)),
3113            detailContentId,
3114            getRequest(),
3115            getResponse(),
3116            true,
3117            locale);
3118        CmsADEConfigData configData = getConfigData(cms.getRequestContext().addSiteRoot(uriParam));
3119        CmsResourceTypeConfig typeConfig = configData.getResourceType(resourceTypeName);
3120        CmsContainerElementBean elementBean = CmsContainerElementBean.createElementForResourceType(
3121            cms,
3122            OpenCms.getResourceManager().getResourceType(resourceTypeName),
3123            "/",
3124            Collections.<String, String> emptyMap(),
3125            typeConfig.isCopyInModels(),
3126            locale);
3127        CmsContainerElementData data = elemUtil.getElementData(elemUtil.getPage(), elementBean, containers);
3128        data.setClientId(elementBean.editorHash());
3129        getSessionCache().setCacheContainerElement(resourceTypeName, elementBean);
3130        getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
3131        return data;
3132    }
3133
3134    /**
3135     * Returns the no-edit reason for the given resource.<p>
3136     *
3137     * @param cms the current cms object
3138     * @param containerPage the resource
3139     *
3140     * @return the no-edit reason, empty if editing is allowed
3141     *
3142     * @throws CmsException is something goes wrong
3143     */
3144    private String getNoEditReason(CmsObject cms, CmsResource containerPage) throws CmsException {
3145
3146        return new CmsResourceUtil(cms, containerPage).getNoEditReason(
3147            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms),
3148            !cms.getRequestContext().getCurrentProject().isOnlineProject());
3149    }
3150
3151    /**
3152     * Returns the session cache.<p>
3153     *
3154     * @return the session cache
3155     */
3156    private CmsADESessionCache getSessionCache() {
3157
3158        if (m_sessionCache == null) {
3159            m_sessionCache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3160        }
3161        return m_sessionCache;
3162    }
3163
3164    /**
3165     * Returns the workplace settings of the current user.<p>
3166     *
3167     * @return the workplace settings
3168     */
3169    private CmsWorkplaceSettings getWorkplaceSettings() {
3170
3171        if (m_workplaceSettings == null) {
3172            m_workplaceSettings = CmsWorkplace.getWorkplaceSettings(getCmsObject(), getRequest());
3173        }
3174        return m_workplaceSettings;
3175    }
3176
3177    /**
3178     * Checks if results for the stored gallery data can be restored for the new gallery data.<p>
3179     *
3180     * @param originalGalleryData the original gallery data
3181     * @param data the new gallery data
3182     * @param search the search bean
3183     *
3184     * @return true if the original and new gallery data are compatible, i.e. we can restore the search results
3185     */
3186    private boolean hasCompatibleSearchData(
3187        CmsGalleryDataBean originalGalleryData,
3188        CmsGalleryDataBean data,
3189        CmsGallerySearchBean search) {
3190
3191        Set<String> originalUsableTypes = Sets.newHashSet();
3192        Set<String> usableTypes = Sets.newHashSet();
3193        for (CmsResourceTypeBean type : originalGalleryData.getTypes()) {
3194            if (!type.isDeactivated()) {
3195                originalUsableTypes.add(type.getType());
3196            }
3197        }
3198        for (CmsResourceTypeBean type : data.getTypes()) {
3199            if (!type.isDeactivated()) {
3200                usableTypes.add(type.getType());
3201            }
3202        }
3203        if (!usableTypes.containsAll(originalUsableTypes)) {
3204            return false;
3205        }
3206        return true;
3207    }
3208
3209    /**
3210     * Initializes request attributes using data from the RPC context.<p>
3211     *
3212     * @param context the RPC context
3213     */
3214    private void initRequestFromRpcContext(CmsContainerPageRpcContext context) {
3215
3216        if (context.getTemplateContext() != null) {
3217            getRequest().setAttribute(
3218                CmsTemplateContextManager.ATTR_RPC_CONTEXT_OVERRIDE,
3219                context.getTemplateContext());
3220        }
3221    }
3222
3223    /**
3224     * Internal method for saving a group container.<p>
3225     *
3226     * @param cms the cms context
3227     * @param pageStructureId the container page structure id
3228     * @param groupContainer the group container to save
3229     *
3230     * @return the container element representing the group container
3231     *
3232     * @throws CmsException if something goes wrong
3233     * @throws CmsXmlException if the XML processing goes wrong
3234     */
3235    private CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> internalSaveGroupContainer(
3236        CmsObject cms,
3237        CmsUUID pageStructureId,
3238        CmsGroupContainer groupContainer)
3239    throws CmsException, CmsXmlException {
3240
3241        ensureSession();
3242        CmsResource pageResource = getCmsObject().readResource(pageStructureId, CmsResourceFilter.IGNORE_EXPIRATION);
3243        CmsResource groupContainerResource = null;
3244        if (groupContainer.isNew()) {
3245            CmsADEConfigData config = getConfigData(pageResource.getRootPath());
3246            CmsResourceTypeConfig typeConfig = config.getResourceType(
3247                CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3248            groupContainerResource = typeConfig.createNewElement(getCmsObject(), pageResource.getRootPath());
3249            String resourceName = cms.getSitePath(groupContainerResource);
3250            groupContainer.setSitePath(resourceName);
3251            groupContainer.setClientId(groupContainerResource.getStructureId().toString());
3252        }
3253        if (groupContainerResource == null) {
3254            CmsUUID id = convertToServerId(groupContainer.getClientId());
3255            groupContainerResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3256        }
3257        CmsGroupContainerBean groupContainerBean = getGroupContainerBean(
3258            groupContainer,
3259            pageResource,
3260            Locale.ENGLISH.toString());
3261
3262        cms.lockResourceTemporary(groupContainerResource);
3263        CmsFile groupContainerFile = cms.readFile(groupContainerResource);
3264        Locale locale = Locale.ENGLISH;
3265        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(cms, groupContainerFile);
3266        Set<CmsUUID> oldElementIds = getGroupElementIds(xmlGroupContainer, locale);
3267        xmlGroupContainer.clearLocales();
3268        xmlGroupContainer.save(cms, groupContainerBean, locale);
3269        cms.unlockResource(groupContainerResource);
3270        Set<CmsUUID> newElementIds = getGroupElementIds(xmlGroupContainer, locale);
3271        Set<CmsUUID> removedElementIds = Sets.difference(oldElementIds, newElementIds);
3272        List<CmsRemovedElementStatus> deletionCandidateStatuses = new ArrayList<CmsRemovedElementStatus>();
3273        for (CmsUUID removedId : removedElementIds) {
3274            CmsRemovedElementStatus status = internalGetRemovedElementStatus(removedId, null, null);
3275            if (status.isDeletionCandidate()) {
3276                deletionCandidateStatuses.add(status);
3277            }
3278        }
3279        CmsContainerElement element = new CmsContainerElement();
3280        element.setClientId(groupContainerFile.getStructureId().toString());
3281        element.setSitePath(cms.getSitePath(groupContainerFile));
3282        element.setResourceType(CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3283        return CmsPair.create(element, deletionCandidateStatuses);
3284    }
3285
3286    /**
3287     * Checks if small elements in a container page should be initially editable.<p>
3288     *
3289     * @param request the current request
3290     * @param cms the current CMS context
3291     * @return true if small elements should be initially editable
3292     */
3293    private boolean isEditSmallElements(HttpServletRequest request, CmsObject cms) {
3294
3295        CmsUser user = cms.getRequestContext().getCurrentUser();
3296        String editSmallElementsStr = (String)(user.getAdditionalInfo().get(ADDINFO_EDIT_SMALL_ELEMENTS));
3297        if (editSmallElementsStr == null) {
3298            return true;
3299        } else {
3300            return Boolean.valueOf(editSmallElementsStr).booleanValue();
3301        }
3302    }
3303
3304    /**
3305     * Checks if a page is a model page.<p>
3306     *
3307     * @param cms the CMS context to use
3308     * @param containerPage the page to check
3309     *
3310     * @return true if the resource is a model page
3311     */
3312    private boolean isModelPage(CmsObject cms, CmsResource containerPage) {
3313
3314        CmsADEConfigData config = getConfigData(containerPage.getRootPath());
3315        for (CmsModelPageConfig modelConfig : config.getModelPages()) {
3316            if (modelConfig.getResource().getStructureId().equals(containerPage.getStructureId())) {
3317                return true;
3318            }
3319        }
3320        return false;
3321    }
3322
3323    /**
3324     * Saves the given containers to the container page resource.<p>
3325     *
3326     * @param cms the cms context
3327     * @param containerpage the container page resource
3328     * @param containerpageUri the container page site path
3329     * @param containers the container to save
3330     *
3331     * @throws CmsException if something goes wrong writing the file
3332     */
3333    private void saveContainers(
3334        CmsObject cms,
3335        CmsResource containerpage,
3336        String containerpageUri,
3337        List<CmsContainer> containers)
3338    throws CmsException {
3339
3340        CmsContainerPageBean page = generateContainerPageForContainers(containers, containerpage.getRootPath());
3341
3342        CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
3343            getCmsObject(),
3344            getConfigData(containerpage.getRootPath()),
3345            getSessionCache(),
3346            isEditingModelGroups(cms, containerpage));
3347        if (isEditingModelGroups(cms, containerpage)) {
3348            page = modelHelper.saveModelGroups(page, containerpage);
3349        } else {
3350            page = modelHelper.removeModelGroupContainers(page);
3351        }
3352        CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(
3353            cms,
3354            cms.readFile(containerpageUri, CmsResourceFilter.ignoreExpirationOffline(cms)));
3355        xmlCnt.save(cms, page);
3356    }
3357
3358    /**
3359     * Saves the inheritance group.<p>
3360     *
3361     * @param resource the inheritance group resource
3362     * @param inheritanceContainer the inherited group container data
3363     *
3364     * @throws CmsException if something goes wrong
3365     */
3366    private void saveInheritanceGroup(CmsResource resource, CmsInheritanceContainer inheritanceContainer)
3367    throws CmsException {
3368
3369        CmsObject cms = getCmsObject();
3370        CmsFile file = cms.readFile(resource);
3371        CmsXmlContent document = CmsXmlContentFactory.unmarshal(cms, file);
3372
3373        for (Locale docLocale : document.getLocales()) {
3374            document.removeLocale(docLocale);
3375        }
3376        Locale locale = Locale.ENGLISH;
3377        document.addLocale(cms, locale);
3378        document.getValue("Title", locale).setStringValue(cms, inheritanceContainer.getTitle());
3379        document.getValue("Description", locale).setStringValue(cms, inheritanceContainer.getDescription());
3380        document.getValue("ConfigName", locale).setStringValue(cms, inheritanceContainer.getName());
3381        byte[] content = document.marshal();
3382        file.setContents(content);
3383        cms.writeFile(file);
3384    }
3385
3386    /**
3387     * Update favorite or recent list with the given element.<p>
3388     *
3389     * @param containerPage the edited container page
3390     * @param clientId the elements client id
3391     * @param list the list to update
3392     *
3393     * @return the updated list
3394     *
3395     * @throws CmsException in case reading the element resource fails
3396     */
3397    private List<CmsContainerElementBean> updateFavoriteRecentList(
3398        CmsResource containerPage,
3399        String clientId,
3400        List<CmsContainerElementBean> list)
3401    throws CmsException {
3402
3403        try {
3404            CmsContainerElementBean element = getCachedElement(clientId, containerPage.getRootPath());
3405            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
3406            String formatterID = null;
3407            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
3408            while (entries.hasNext()) {
3409                Entry<String, String> entry = entries.next();
3410                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
3411                    formatterID = entry.getValue();
3412                    entries.remove();
3413                }
3414            }
3415            settings.put(CmsFormatterConfig.FORMATTER_SETTINGS_KEY, formatterID);
3416            settings.put(SOURCE_CONTAINERPAGE_ID_SETTING, containerPage.getStructureId().toString());
3417            settings.remove(CmsContainerElement.SETTING_PAGE_ID);
3418            element = CmsContainerElementBean.cloneWithSettings(element, settings);
3419            Iterator<CmsContainerElementBean> listIt = list.iterator();
3420            while (listIt.hasNext()) {
3421                CmsContainerElementBean listElem = listIt.next();
3422                if (element.getInstanceId().equals(listElem.getInstanceId())) {
3423                    listIt.remove();
3424                }
3425            }
3426            list.add(0, element);
3427            return list;
3428        } catch (CmsVfsResourceNotFoundException e) {
3429            LOG.warn(e.getLocalizedMessage(), e);
3430            return list;
3431        }
3432    }
3433
3434}