001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.containerpage;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsADEManager;
032import org.opencms.ade.configuration.CmsElementView;
033import org.opencms.ade.configuration.CmsModelPageConfig;
034import org.opencms.ade.configuration.CmsResourceTypeConfig;
035import org.opencms.ade.containerpage.inherited.CmsInheritanceReference;
036import org.opencms.ade.containerpage.inherited.CmsInheritanceReferenceParser;
037import org.opencms.ade.containerpage.inherited.CmsInheritedContainerState;
038import org.opencms.ade.containerpage.shared.CmsCntPageData;
039import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementDeleteMode;
040import org.opencms.ade.containerpage.shared.CmsCntPageData.ElementReuseMode;
041import org.opencms.ade.containerpage.shared.CmsContainer;
042import org.opencms.ade.containerpage.shared.CmsContainerElement;
043import org.opencms.ade.containerpage.shared.CmsContainerElement.ModelGroupState;
044import org.opencms.ade.containerpage.shared.CmsContainerElementData;
045import org.opencms.ade.containerpage.shared.CmsContainerPageGalleryData;
046import org.opencms.ade.containerpage.shared.CmsContainerPageRpcContext;
047import org.opencms.ade.containerpage.shared.CmsCreateElementData;
048import org.opencms.ade.containerpage.shared.CmsDialogOptions;
049import org.opencms.ade.containerpage.shared.CmsDialogOptionsAndInfo;
050import org.opencms.ade.containerpage.shared.CmsElementSettingsConfig;
051import org.opencms.ade.containerpage.shared.CmsElementViewInfo;
052import org.opencms.ade.containerpage.shared.CmsFormatterConfig;
053import org.opencms.ade.containerpage.shared.CmsGroupContainer;
054import org.opencms.ade.containerpage.shared.CmsGroupContainerSaveResult;
055import org.opencms.ade.containerpage.shared.CmsInheritanceContainer;
056import org.opencms.ade.containerpage.shared.CmsInheritanceInfo;
057import org.opencms.ade.containerpage.shared.CmsLocaleLinkBean;
058import org.opencms.ade.containerpage.shared.CmsPageSaveStatus;
059import org.opencms.ade.containerpage.shared.CmsRemovedElementStatus;
060import org.opencms.ade.containerpage.shared.CmsReuseInfo;
061import org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService;
062import org.opencms.ade.detailpage.CmsDetailPageInfo;
063import org.opencms.ade.detailpage.CmsDetailPageResourceHandler;
064import org.opencms.ade.galleries.CmsGalleryService;
065import org.opencms.ade.galleries.shared.CmsGalleryDataBean;
066import org.opencms.ade.galleries.shared.CmsGallerySearchBean;
067import org.opencms.ade.galleries.shared.CmsResourceTypeBean;
068import org.opencms.ade.galleries.shared.CmsVfsEntryBean;
069import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryTabId;
070import org.opencms.ade.sitemap.CmsVfsSitemapService;
071import org.opencms.file.CmsFile;
072import org.opencms.file.CmsObject;
073import org.opencms.file.CmsProperty;
074import org.opencms.file.CmsPropertyDefinition;
075import org.opencms.file.CmsResource;
076import org.opencms.file.CmsResourceFilter;
077import org.opencms.file.CmsUser;
078import org.opencms.file.CmsVfsResourceNotFoundException;
079import org.opencms.file.types.CmsResourceTypeBinary;
080import org.opencms.file.types.CmsResourceTypeFunctionConfig;
081import org.opencms.file.types.CmsResourceTypeImage;
082import org.opencms.file.types.CmsResourceTypePlain;
083import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
084import org.opencms.file.types.CmsResourceTypeXmlContent;
085import org.opencms.file.types.I_CmsResourceType;
086import org.opencms.flex.CmsFlexController;
087import org.opencms.gwt.CmsDefaultResourceStatusProvider;
088import org.opencms.gwt.CmsGwtActionElement;
089import org.opencms.gwt.CmsGwtService;
090import org.opencms.gwt.CmsIconUtil;
091import org.opencms.gwt.CmsRpcException;
092import org.opencms.gwt.CmsVfsService;
093import org.opencms.gwt.shared.CmsGwtConstants;
094import org.opencms.gwt.shared.CmsListElementCreationDialogData;
095import org.opencms.gwt.shared.CmsListElementCreationOption;
096import org.opencms.gwt.shared.CmsListInfoBean;
097import org.opencms.gwt.shared.CmsModelResourceInfo;
098import org.opencms.gwt.shared.CmsResourceListInfo;
099import org.opencms.gwt.shared.CmsTemplateContextInfo;
100import org.opencms.gwt.shared.I_CmsAutoBeanFactory;
101import org.opencms.gwt.shared.I_CmsListAddMetadata;
102import org.opencms.gwt.shared.I_CmsUnlockData;
103import org.opencms.i18n.CmsEncoder;
104import org.opencms.i18n.CmsLocaleGroup;
105import org.opencms.i18n.CmsLocaleManager;
106import org.opencms.i18n.CmsMessages;
107import org.opencms.jsp.CmsJspTagEdit;
108import org.opencms.jsp.util.CmsJspStandardContextBean.TemplateBean;
109import org.opencms.loader.CmsTemplateContextManager;
110import org.opencms.loader.I_CmsTemplateContextProvider;
111import org.opencms.lock.CmsLock;
112import org.opencms.lock.CmsLockType;
113import org.opencms.main.CmsException;
114import org.opencms.main.CmsIllegalArgumentException;
115import org.opencms.main.CmsLog;
116import org.opencms.main.OpenCms;
117import org.opencms.module.CmsModule;
118import org.opencms.relations.CmsRelation;
119import org.opencms.relations.CmsRelationFilter;
120import org.opencms.relations.CmsRelationType;
121import org.opencms.search.galleries.CmsGallerySearch;
122import org.opencms.search.galleries.CmsGallerySearchResult;
123import org.opencms.security.CmsPermissionSet;
124import org.opencms.security.CmsPermissionViolationException;
125import org.opencms.security.CmsRole;
126import org.opencms.site.CmsSite;
127import org.opencms.site.CmsSiteManagerImpl;
128import org.opencms.ui.apps.CmsQuickLaunchLocationCache;
129import org.opencms.util.CmsFileUtil;
130import org.opencms.util.CmsPair;
131import org.opencms.util.CmsRequestUtil;
132import org.opencms.util.CmsStringUtil;
133import org.opencms.util.CmsUUID;
134import org.opencms.workplace.CmsWorkplace;
135import org.opencms.workplace.CmsWorkplaceMessages;
136import org.opencms.workplace.CmsWorkplaceSettings;
137import org.opencms.workplace.editors.CmsWorkplaceEditorManager;
138import org.opencms.workplace.editors.directedit.I_CmsEditHandler;
139import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
140import org.opencms.workplace.explorer.CmsResourceUtil;
141import org.opencms.xml.CmsXmlException;
142import org.opencms.xml.containerpage.CmsADESessionCache;
143import org.opencms.xml.containerpage.CmsContainerBean;
144import org.opencms.xml.containerpage.CmsContainerElementBean;
145import org.opencms.xml.containerpage.CmsContainerPageBean;
146import org.opencms.xml.containerpage.CmsFormatterConfiguration;
147import org.opencms.xml.containerpage.CmsGroupContainerBean;
148import org.opencms.xml.containerpage.CmsMacroFormatterBean;
149import org.opencms.xml.containerpage.CmsXmlContainerPage;
150import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
151import org.opencms.xml.containerpage.CmsXmlGroupContainer;
152import org.opencms.xml.containerpage.CmsXmlGroupContainerFactory;
153import org.opencms.xml.containerpage.I_CmsFormatterBean;
154import org.opencms.xml.content.CmsXmlContent;
155import org.opencms.xml.content.CmsXmlContentFactory;
156import org.opencms.xml.content.CmsXmlContentProperty;
157import org.opencms.xml.content.CmsXmlContentPropertyHelper;
158
159import java.nio.charset.StandardCharsets;
160import java.security.MessageDigest;
161import java.security.NoSuchAlgorithmException;
162import java.util.ArrayList;
163import java.util.Arrays;
164import java.util.Collection;
165import java.util.Collections;
166import java.util.HashMap;
167import java.util.HashSet;
168import java.util.Iterator;
169import java.util.LinkedHashMap;
170import java.util.List;
171import java.util.Locale;
172import java.util.Map;
173import java.util.Map.Entry;
174import java.util.Set;
175import java.util.stream.Collectors;
176
177import javax.servlet.http.HttpServletRequest;
178import javax.servlet.http.HttpServletResponse;
179
180import org.apache.commons.codec.binary.Hex;
181import org.apache.commons.logging.Log;
182
183import com.google.common.base.Optional;
184import com.google.common.collect.Lists;
185import com.google.common.collect.Maps;
186import com.google.common.collect.Sets;
187import com.google.web.bindery.autobean.shared.AutoBean;
188import com.google.web.bindery.autobean.shared.AutoBeanCodex;
189import com.google.web.bindery.autobean.vm.AutoBeanFactorySource;
190
191/**
192 * The RPC service used by the container-page editor.<p>
193 *
194 * @since 8.0.0
195 */
196public class CmsContainerpageService extends CmsGwtService implements I_CmsContainerpageService {
197
198    /**
199     * Helper class used to determine both the available views and the active start view when loading a container page.<p>
200     */
201    private class InitialElementViewProvider {
202
203        /** Start view id. */
204        private CmsUUID m_defaultView;
205
206        /** Map of available views. */
207        private Map<CmsUUID, CmsElementViewInfo> m_viewMap;
208
209        /**
210         * Empty default constructor.<p>
211         */
212        public InitialElementViewProvider() {
213
214            // do nothing
215        }
216
217        /**
218         * Returns the default view info.<p>
219         *
220         * @return the default view info
221         */
222        public CmsElementViewInfo getDefaultView() {
223
224            return getViewMap().get(getDefaultViewId());
225        }
226
227        /**
228         * Gets the start view id.<p>
229         *
230         * @return the start view id
231         */
232        public CmsUUID getDefaultViewId() {
233
234            return m_defaultView;
235        }
236
237        /**
238         * Gets the map of available views.<p>
239         *
240         * @return the map of available views
241         */
242        public Map<CmsUUID, CmsElementViewInfo> getViewMap() {
243
244            return m_viewMap;
245        }
246
247        /**
248         * Initializes this object.<p>
249         *
250         * @param defaultValue the default view id from the session cache
251         * @param checkRes the resource used to check permissions
252         * @param templateContextInfo the template context information
253         */
254        @SuppressWarnings("synthetic-access")
255        public void init(CmsUUID defaultValue, CmsResource checkRes, CmsTemplateContextInfo templateContextInfo) {
256
257            Map<CmsUUID, CmsElementViewInfo> result = new LinkedHashMap<CmsUUID, CmsElementViewInfo>();
258            CmsObject cms = getCmsObject();
259            String templateKey = templateContextInfo != null ? templateContextInfo.getCurrentContext() : null;
260
261            // collect the actually used element view ids
262            CmsADEConfigData config = getConfigData(
263                cms.getRequestContext().addSiteRoot(cms.getRequestContext().getUri()));
264            Set<CmsUUID> usedIds = new HashSet<CmsUUID>();
265            for (CmsResourceTypeConfig typeConfig : config.getResourceTypes()) {
266                if (typeConfig.isAvailableInTemplate(templateKey)) {
267                    usedIds.add(typeConfig.getElementView());
268                }
269            }
270
271            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
272            Map<CmsUUID, CmsElementView> realViewMap = OpenCms.getADEManager().getElementViews(cms);
273
274            Set<CmsUUID> parentIds = Sets.newHashSet();
275            for (CmsElementView view : realViewMap.values()) {
276                if (view.getParentViewId() != null) {
277                    parentIds.add(view.getParentViewId());
278                }
279                // add only element view that are used within the type configuration and the user has sufficient permissions for
280                if (usedIds.contains(view.getId()) && view.hasPermission(cms, checkRes) && !view.isOther()) {
281                    result.put(view.getId(), new CmsElementViewInfo(view.getTitle(cms, wpLocale), view.getId()));
282                }
283
284            }
285            m_viewMap = result;
286            for (Map.Entry<CmsUUID, CmsElementViewInfo> viewEntry : m_viewMap.entrySet()) {
287                CmsElementView realView = realViewMap.get(viewEntry.getKey());
288                CmsUUID parentViewId = realView.getParentViewId();
289                if ((parentViewId != null) && !parentIds.contains(viewEntry.getKey())) {
290                    CmsElementViewInfo parentBean = m_viewMap.get(parentViewId);
291                    if (parentBean != null) {
292                        viewEntry.getValue().setParent(parentBean);
293                    }
294                }
295            }
296            if (m_viewMap.containsKey(defaultValue)) {
297                m_defaultView = defaultValue;
298            } else if (m_viewMap.containsKey(CmsElementView.DEFAULT_ELEMENT_VIEW.getId())) {
299                m_defaultView = CmsElementView.DEFAULT_ELEMENT_VIEW.getId();
300            } else if (!m_viewMap.isEmpty()) {
301                m_defaultView = m_viewMap.values().iterator().next().getElementViewId();
302            } else {
303                m_defaultView = defaultValue;
304                LOG.error(
305                    "Initial view not available and no suitable replacement view found: user="
306                        + getCmsObject().getRequestContext().getCurrentUser().getName()
307                        + " view="
308                        + defaultValue
309                        + " path="
310                        + checkRes.getRootPath());
311            }
312
313        }
314    }
315
316    /** Additional info key for storing the "edit small elements" setting on the user. */
317    public static final String ADDINFO_EDIT_SMALL_ELEMENTS = "EDIT_SMALL_ELEMENTS";
318
319    /** Session attribute name used to store the selected clipboard tab. */
320    public static final String ATTR_CLIPBOARD_TAB = "clipboardtab";
321
322    /** Maximum number of reuse locations to display in the reuse warning dialog. */
323    public static final int MAX_VISIBLE_ELEMENT_USES = 100;
324
325    /** The model group pages path fragment. */
326    public static final String MODEL_GROUP_PATH_FRAGMENT = "/.content/.modelgroups/";
327
328    /** Runtime property key to enable / disable placement mode. */
329    public static final String PARAM_PAGE_EDITOR_PLACEMENT_MODE_ENABLED = "pageEditor.placementMode.enabled";
330
331    /** The source container page id settings key. */
332    public static final String SOURCE_CONTAINERPAGE_ID_SETTING = "source_containerpage_id";
333
334    /** Static reference to the log. */
335    static final Log LOG = CmsLog.getLog(CmsContainerpageService.class);
336
337    /** Serial version UID. */
338    private static final long serialVersionUID = -6188370638303594280L;
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            List<CmsResourceTypeBean> resTypeBeans = getGalleryTypesForView(
1195                cms,
1196                containers,
1197                elementView,
1198                uri,
1199                detailContentId,
1200                locale,
1201                templateContextInfo);
1202            CmsGalleryService srv = new CmsGalleryService();
1203            srv.setCms(cms);
1204            srv.setRequest(getRequest());
1205            data = srv.getInitialSettingsForContainerPage(resTypeBeans, uri, locale);
1206            CmsContainerPageGalleryData result = new CmsContainerPageGalleryData();
1207
1208            CmsADESessionCache cache = CmsADESessionCache.getCache(getRequest(), cms);
1209            CmsGallerySearchBean search = cache.getLastPageEditorGallerySearch();
1210            String subsite = OpenCms.getADEManager().getSubSiteRoot(cms, cms.addSiteRoot(uri));
1211
1212            // 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
1213            String providerSuffix = "null";
1214            if (templateContextInfo != null) {
1215                String providerKey = templateContextInfo.getContextProvider();
1216                I_CmsTemplateContextProvider provider = OpenCms.getTemplateContextManager().getTemplateContextProvider(
1217                    providerKey);
1218                if (provider != null) {
1219                    try {
1220                        MessageDigest md5 = MessageDigest.getInstance("md5");
1221                        md5.update(providerKey.getBytes(StandardCharsets.UTF_8));
1222                        if (templateContextInfo.getCurrentContext() != null) {
1223                            md5.update((byte)0); // 0 byte as separator
1224                            md5.update(templateContextInfo.getCurrentContext().getBytes(StandardCharsets.UTF_8));
1225                            providerSuffix = Hex.encodeHexString(md5.digest());
1226                        }
1227                    } catch (NoSuchAlgorithmException e) {
1228                        // MD5 must be in standard library
1229                    }
1230                }
1231            }
1232
1233            String searchStoreKey = elementView + "|" + subsite + "|" + locale + "|" + providerSuffix;
1234            data.getContextParameters().put("searchStoreKey", searchStoreKey);
1235            if ((search != null) && !search.getServerSearchTypes().contains(CmsResourceTypeFunctionConfig.TYPE_NAME)) {
1236                if (searchStoreKey.equals(
1237                    search.getOriginalGalleryData().getContextParameters().get("searchStoreKey"))) {
1238                    if (hasCompatibleSearchData(search.getOriginalGalleryData(), data, search)) {
1239
1240                        CmsVfsEntryBean preloadData = null;
1241                        if (search.getFolders() != null) {
1242                            preloadData = CmsGalleryService.generateVfsPreloadData(
1243                                getCmsObject(),
1244                                CmsGalleryService.getVfsTreeState(getRequest(), data.getTreeToken()),
1245                                search.getFolders());
1246                        }
1247
1248                        // only restore last result list if the search was performed in a 'similar' context
1249                        search.setTabId(GalleryTabId.cms_tab_results.toString());
1250                        search.setPage(1);
1251                        search.setLastPage(0);
1252                        data.setStartTab(GalleryTabId.cms_tab_results);
1253                        search = srv.getSearch(search);
1254                        data.setVfsPreloadData(preloadData);
1255                        data.setIncludeExpiredDefault(search.isIncludeExpired());
1256                        result.setGallerySearch(search);
1257                    }
1258                }
1259            }
1260            result.setGalleryData(data);
1261            return result;
1262
1263        } catch (Exception e) {
1264            error(e);
1265            return null;
1266        }
1267    }
1268
1269    /**
1270     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getGalleryTypesForMultipleViews(java.util.List, java.util.List, java.lang.String, org.opencms.util.CmsUUID, java.lang.String, org.opencms.gwt.shared.CmsTemplateContextInfo)
1271     */
1272    public Map<CmsUUID, List<CmsResourceTypeBean>> getGalleryTypesForMultipleViews(
1273        final List<CmsContainer> containers,
1274        List<CmsUUID> views,
1275        String uri,
1276        CmsUUID detailContentId,
1277        String locale,
1278        CmsTemplateContextInfo templateContextInfo)
1279    throws CmsRpcException {
1280
1281        try {
1282            Map<CmsUUID, List<CmsResourceTypeBean>> result = new HashMap<>();
1283            CmsObject cms = getCmsObject();
1284            for (CmsUUID view : views) {
1285                List<CmsResourceTypeBean> typesForView = getGalleryTypesForView(
1286                    cms,
1287                    containers,
1288                    view,
1289                    uri,
1290                    detailContentId,
1291                    locale,
1292                    templateContextInfo);
1293                result.put(view, typesForView);
1294            }
1295            return result;
1296        } catch (Exception e) {
1297            error(e);
1298            return null;
1299        }
1300    }
1301
1302    /**
1303     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getListElementCreationOptions(org.opencms.util.CmsUUID, java.lang.String)
1304     */
1305    public CmsListElementCreationDialogData getListElementCreationOptions(CmsUUID structureId, String jsonListAddData)
1306    throws CmsRpcException {
1307
1308        CmsObject cms = getCmsObject();
1309        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1310        CmsMessages msg = Messages.get().getBundle(locale);
1311        try {
1312            CmsUUID listId = structureId;
1313
1314            String jsonConfig = jsonListAddData;
1315            I_CmsAutoBeanFactory beanFactory = AutoBeanFactorySource.create(I_CmsAutoBeanFactory.class);
1316            AutoBean<I_CmsListAddMetadata> listAddData = AutoBeanCodex.decode(
1317                beanFactory,
1318                I_CmsListAddMetadata.class,
1319                jsonConfig);
1320            CmsListElementCreationDialogData result = new CmsListElementCreationDialogData();
1321            result.setCaption(msg.key(Messages.GUI_LISTADD_CAPTION_0));
1322            result.setPostCreateHandler(listAddData.as().getPostCreateHandler());
1323            String uploadFolder = listAddData.as().getUploadFolder();
1324            boolean isUpload = false;
1325            if (!CmsStringUtil.isEmptyOrWhitespaceOnly(uploadFolder) && !"none".equals(uploadFolder)) {
1326                if (listAddData.as().getTypes().stream().anyMatch(
1327                    type -> CmsResourceTypeBinary.getStaticTypeName().equals(type)
1328                        || CmsResourceTypePlain.getStaticTypeName().equals(type)
1329                        || CmsResourceTypeImage.getStaticTypeName().equals(type))) {
1330
1331                    CmsResource uploadFolderResource = null;
1332                    try {
1333                        uploadFolderResource = cms.readResource(uploadFolder, CmsResourceFilter.IGNORE_EXPIRATION);
1334                        if (cms.hasPermissions(
1335                            uploadFolderResource,
1336                            CmsPermissionSet.ACCESS_WRITE,
1337                            false,
1338                            CmsResourceFilter.IGNORE_EXPIRATION)) {
1339                            isUpload = true;
1340                        }
1341                    } catch (CmsVfsResourceNotFoundException | CmsPermissionViolationException e) {
1342                        LOG.debug(e.getLocalizedMessage(), e);
1343                    } catch (Exception e) {
1344                        LOG.error(e.getLocalizedMessage(), e);
1345                    }
1346                }
1347            }
1348            if (isUpload) {
1349                result.setUploadFolder(uploadFolder);
1350                CmsListInfoBean listResourceInfo = CmsVfsService.getPageInfo(
1351                    cms,
1352                    cms.readResource(uploadFolder, CmsResourceFilter.IGNORE_EXPIRATION));
1353                result.setListInfo(listResourceInfo);
1354            } else {
1355                CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
1356                    cms,
1357                    cms.getRequestContext().getRootUri());
1358                CmsResource listResource = cms.readResource(listId, CmsResourceFilter.IGNORE_EXPIRATION);
1359                CmsListInfoBean listResourceInfo = CmsVfsService.getPageInfo(cms, listResource);
1360                result.setListInfo(listResourceInfo);
1361                List<String> createTypes = listAddData.as().getTypes();
1362                Map<String, CmsResourceTypeConfig> typeMap = adeConfig.getTypesByName();
1363                for (String type : createTypes) {
1364                    try {
1365                        CmsResourceTypeConfig currentType = typeMap.get(type);
1366                        if (currentType != null) {
1367                            if (adeConfig.getDirectEditPermissions(type).canCreate()
1368                                && currentType.checkCreatable(cms, null)) {
1369                                CmsListInfoBean typeInfo = new CmsListInfoBean();
1370                                CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
1371                                    type);
1372                                String title = CmsWorkplaceMessages.getResourceTypeName(locale, type);
1373                                typeInfo.setTitle(title);
1374                                String description = CmsWorkplaceMessages.getResourceTypeDescription(locale, type);
1375                                typeInfo.setSubTitle(description);
1376                                typeInfo.setResourceType(type);
1377                                typeInfo.setBigIconClasses(CmsIconUtil.getIconClasses(explorerType, null, false));
1378                                String newLink = CmsJspTagEdit.getNewLink(
1379                                    cms,
1380                                    OpenCms.getResourceManager().getResourceType(type),
1381                                    cms.getRequestContext().getUri());
1382                                CmsListElementCreationOption option = new CmsListElementCreationOption(
1383                                    type,
1384                                    typeInfo,
1385                                    newLink);
1386                                result.add(option);
1387                            }
1388                        }
1389                    } catch (Exception e) {
1390                        LOG.error(e.getLocalizedMessage(), e);
1391                    }
1392                }
1393                if (result.getOptions().size() == 0) {
1394                    result.setMessage(msg.key(Messages.GUI_LISTADD_NO_TYPES_0));
1395                }
1396            }
1397
1398            return result;
1399        } catch (Exception e) {
1400            error(e);
1401            return null;
1402        }
1403    }
1404
1405    /**
1406     * @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)
1407     */
1408    public CmsContainerElementData getNewElementData(
1409        CmsContainerPageRpcContext context,
1410        CmsUUID detailContentId,
1411        String reqParams,
1412        String resourceType,
1413        Collection<CmsContainer> containers,
1414        String localeName)
1415    throws CmsRpcException {
1416
1417        CmsContainerElementData result = null;
1418        try {
1419            ensureSession();
1420            CmsResource pageResource = getCmsObject().readResource(
1421                context.getPageStructureId(),
1422                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1423            initRequestFromRpcContext(context);
1424            String containerpageUri = getCmsObject().getSitePath(pageResource);
1425            Locale locale = CmsLocaleManager.getLocale(localeName);
1426            result = getNewElement(
1427                getServerIdString(resourceType),
1428                containerpageUri,
1429                detailContentId,
1430                containers,
1431                locale);
1432
1433            CmsListInfoBean info = new CmsListInfoBean();
1434            // type title and subtitle
1435            String realType = getServerIdString(resourceType);
1436            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1437            info.setTitle(CmsWorkplaceMessages.getResourceTypeName(wpLocale, realType));
1438            info.setSubTitle(CmsWorkplaceMessages.getResourceTypeDescription(wpLocale, realType));
1439            info.setBigIconClasses(CmsIconUtil.getIconClasses(realType, null, false));
1440            result.setListInfo(info);
1441        } catch (Throwable e) {
1442            error(e);
1443        }
1444        return result;
1445    }
1446
1447    /**
1448     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getNewOptions(java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1449     */
1450    public CmsDialogOptionsAndInfo getNewOptions(String clientId, CmsUUID pageStructureId, String requestParams)
1451    throws CmsRpcException {
1452
1453        try {
1454            CmsResource pageResource = getCmsObject().readResource(
1455                pageStructureId,
1456                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1457            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1458            element.initResource(getCmsObject());
1459            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1460            if (type instanceof CmsResourceTypeXmlContent) {
1461                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1462                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1463                    CmsEncoder.decode(requestParams),
1464                    true,
1465                    CmsEncoder.ENCODING_UTF_8);
1466                CmsDialogOptions options = handler.getNewOptions(getCmsObject(), element, pageStructureId, params);
1467                if (options != null) {
1468                    return new CmsDialogOptionsAndInfo(
1469                        options,
1470                        CmsVfsService.getPageInfo(getCmsObject(), element.getResource()));
1471                }
1472            }
1473        } catch (CmsException e) {
1474            error(e);
1475        }
1476        return null;
1477
1478    }
1479
1480    /**
1481     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getRecentList(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, java.util.Collection, java.lang.String)
1482     */
1483    public List<CmsContainerElementData> getRecentList(
1484        CmsUUID pageStructureId,
1485        CmsUUID detailContentId,
1486        Collection<CmsContainer> containers,
1487        String locale)
1488    throws CmsRpcException {
1489
1490        List<CmsContainerElementData> result = null;
1491        try {
1492            ensureSession();
1493            CmsResource containerpage = getCmsObject().readResource(
1494                pageStructureId,
1495                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1496            String containerpageUri = getCmsObject().getSitePath(containerpage);
1497            result = getListElementsData(
1498                OpenCms.getADEManager().getRecentList(getCmsObject()),
1499                containerpageUri,
1500                detailContentId,
1501                containers,
1502                CmsLocaleManager.getLocale(locale));
1503        } catch (Throwable e) {
1504            error(e);
1505        }
1506        return result;
1507    }
1508
1509    /**
1510     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getRemovedElementStatus(java.lang.String, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1511     */
1512    public CmsRemovedElementStatus getRemovedElementStatus(String id, CmsUUID contextId, CmsUUID containerpageId)
1513    throws CmsRpcException {
1514
1515        if ((id == null) || !id.matches(CmsUUID.UUID_REGEX + ".*$")) {
1516            return new CmsRemovedElementStatus(null, null, false, null);
1517        }
1518        try {
1519            CmsUUID structureId = convertToServerId(id);
1520            return internalGetRemovedElementStatus(structureId, contextId, containerpageId);
1521        } catch (CmsException e) {
1522            error(e);
1523            return null;
1524        }
1525    }
1526
1527    /**
1528     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#getReuseInfo(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
1529     */
1530    public CmsReuseInfo getReuseInfo(CmsUUID pageId, CmsUUID detailId, CmsUUID elementId) throws CmsRpcException {
1531
1532        try {
1533            CmsObject cms = getCmsObject();
1534            Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1535            CmsResource detailResource = null;
1536            CmsResource element = cms.readResource(elementId, CmsResourceFilter.IGNORE_EXPIRATION);
1537            if (detailId != null) {
1538                detailResource = cms.readResource(detailId, CmsResourceFilter.IGNORE_EXPIRATION);
1539            }
1540            Set<CmsUUID> idsForCurrentPage = CmsElementUtil.getPageAndDetailOnlyIds(
1541                getCmsObject(),
1542                pageId,
1543                detailResource);
1544            List<CmsResource> allUses = OpenCms.getADEManager().getOfflineElementUses(element).filter(
1545                res -> !idsForCurrentPage.contains(res.getStructureId())).collect(Collectors.toList());
1546            List<CmsResourceListInfo> infos = new ArrayList<>();
1547            int visibleCount = 0;
1548            for (CmsResource use : allUses) {
1549                try {
1550                    // make sure resource is visible to current user, otherwise continue with next resource
1551                    cms.readResource(use.getStructureId(), CmsResourceFilter.IGNORE_EXPIRATION.addRequireVisible());
1552                    visibleCount += 1;
1553                    CmsResourceListInfo info = new CmsResourceListInfo();
1554                    CmsVfsService.addPageInfo(cms, use, info);
1555                    info.setStructureId(use.getStructureId());
1556                    infos.add(info);
1557                    if (visibleCount >= MAX_VISIBLE_ELEMENT_USES) {
1558                        break;
1559                    }
1560                } catch (CmsVfsResourceNotFoundException | CmsPermissionViolationException e) {
1561                    // ignore
1562                } catch (Exception e) {
1563                    LOG.error(e.getLocalizedMessage(), e);
1564                }
1565            }
1566            CmsListInfoBean elementInfo = CmsVfsService.getPageInfo(cms, element);
1567            String message;
1568            CmsMessages messages = Messages.get().getBundle(locale);
1569            if (allUses.size() > 0) {
1570                message = messages.key(Messages.GUI_REUSE_CHECK_WARNING_TEXT_1, "" + allUses.size());
1571            } else {
1572                message = "";
1573            }
1574            String title = messages.key(Messages.GUI_REUSE_CHECK_TITLE_0);
1575            if (allUses.size() > infos.size()) {
1576                message = message + "\n" + messages.key(Messages.GUI_REUSE_CHECK_ONLY_SHOW_N_1, infos.size());
1577            }
1578            CmsReuseInfo result = new CmsReuseInfo(elementInfo, infos, message, title, allUses.size());
1579            return result;
1580        } catch (Exception e) {
1581            error(e);
1582            return null;
1583        }
1584    }
1585
1586    /**
1587     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#handleDelete(java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1588     */
1589    public void handleDelete(String clientId, String deleteOption, CmsUUID pageId, String requestParams)
1590    throws CmsRpcException {
1591
1592        try {
1593            CmsResource pageResource = getCmsObject().readResource(
1594                pageId,
1595                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1596            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1597            element.initResource(getCmsObject());
1598            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1599            if (type instanceof CmsResourceTypeXmlContent) {
1600                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1601                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1602                    CmsEncoder.decode(requestParams),
1603                    true,
1604                    CmsEncoder.ENCODING_UTF_8);
1605                handler.handleDelete(getCmsObject(), element, deleteOption, pageId, params);
1606            }
1607        } catch (CmsException e) {
1608            error(e);
1609        }
1610    }
1611
1612    /**
1613     * Internal helper method to get the status of a removed element.<p>
1614     *
1615     * @param structureId the structure id of the removed element
1616     * @param contextId the id of the resource used to look up the sitemap configuration
1617     * @param containerpageId the id of the page to exclude from the relation check, or null if no page should be excluded
1618     *
1619     * @return the status of the removed element
1620     *
1621     * @throws CmsException in case reading the resource fails
1622     */
1623    public CmsRemovedElementStatus internalGetRemovedElementStatus(
1624        CmsUUID structureId,
1625        CmsUUID contextId,
1626        CmsUUID containerpageId)
1627    throws CmsException {
1628
1629        CmsObject cms = getCmsObject();
1630        CmsResource elementResource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1631        boolean hasWritePermissions = cms.hasPermissions(
1632            elementResource,
1633            CmsPermissionSet.ACCESS_WRITE,
1634            false,
1635            CmsResourceFilter.ALL);
1636        boolean isSystemResource = elementResource.getRootPath().startsWith(CmsResource.VFS_FOLDER_SYSTEM + "/");
1637        CmsRelationFilter relationFilter = CmsRelationFilter.relationsToStructureId(structureId);
1638        List<CmsRelation> relationsToElement = cms.readRelations(relationFilter);
1639        Iterator<CmsRelation> iter = relationsToElement.iterator();
1640
1641        // ignore XML_STRONG (i.e. container element) relations from the container page, this must be checked on the client side.
1642        while (iter.hasNext()) {
1643            CmsRelation relation = iter.next();
1644            if ((containerpageId != null)
1645                && containerpageId.equals(relation.getSourceId())
1646                && relation.getType().equals(CmsRelationType.XML_STRONG)) {
1647                iter.remove();
1648            }
1649        }
1650        ElementDeleteMode elementDeleteMode = null;
1651        if (contextId != null) {
1652            CmsResource contextResource = cms.readResource(contextId, CmsResourceFilter.IGNORE_EXPIRATION);
1653            CmsADEConfigData adeConfig = OpenCms.getADEManager().lookupConfiguration(
1654                cms,
1655                contextResource.getRootPath());
1656            CmsResourceTypeConfig typeConfig = adeConfig.getResourceType(
1657                OpenCms.getResourceManager().getResourceType(elementResource).getTypeName());
1658
1659            if (typeConfig != null) {
1660                elementDeleteMode = typeConfig.getElementDeleteMode();
1661            }
1662        } else {
1663            elementDeleteMode = ElementDeleteMode.askKeep;
1664        }
1665        boolean hasNoRelations = relationsToElement.isEmpty();
1666        boolean deletionCandidate = hasNoRelations && hasWritePermissions && !isSystemResource;
1667        CmsListInfoBean elementInfo = CmsVfsService.getPageInfo(cms, elementResource);
1668        return new CmsRemovedElementStatus(structureId, elementInfo, deletionCandidate, elementDeleteMode);
1669    }
1670
1671    /**
1672     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#loadClipboardTab()
1673     */
1674    public int loadClipboardTab() {
1675
1676        Integer clipboardTab = (Integer)(getRequest().getSession().getAttribute(ATTR_CLIPBOARD_TAB));
1677        if (clipboardTab == null) {
1678            clipboardTab = Integer.valueOf(0);
1679        }
1680        return clipboardTab.intValue();
1681    }
1682
1683    /**
1684     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prefetch()
1685     */
1686    public CmsCntPageData prefetch() throws CmsRpcException {
1687
1688        CmsCntPageData data = null;
1689        CmsObject cms = getCmsObject();
1690        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1691        HttpServletRequest request = getRequest();
1692
1693        try {
1694            Map<String, String> sessionStorageData = new HashMap<>();
1695            CmsTemplateContextInfo info = OpenCms.getTemplateContextManager().getContextInfoBean(cms, request);
1696            CmsResource containerPage = getContainerpage(cms);
1697            Set<String> detailTypes = getDetailTypes(cms, containerPage);
1698            boolean isEditingModelGroup = isEditingModelGroups(cms, containerPage);
1699            boolean isModelPage = isModelPage(cms, containerPage);
1700            if (isModelPage) {
1701                // the model edit confirm dialog should only be shown once per session, disable it after first model editing
1702                getRequest().getSession().setAttribute(
1703                    CmsVfsSitemapService.ATTR_SHOW_MODEL_EDIT_CONFIRM,
1704                    Boolean.FALSE);
1705            }
1706
1707            TemplateBean templateBean = (TemplateBean)getRequest().getAttribute(
1708                CmsTemplateContextManager.ATTR_TEMPLATE_BEAN);
1709            CmsADESessionCache sessionCache = CmsADESessionCache.getCache(getRequest(), cms);
1710            sessionCache.setTemplateBean(containerPage.getRootPath(), templateBean);
1711            long lastModified = containerPage.getDateLastModified();
1712            String editorUri = OpenCms.getWorkplaceManager().getEditorHandler().getEditorUri(
1713                cms,
1714                CmsResourceTypeXmlContent.getStaticTypeName(),
1715                "User agent",
1716                false);
1717            boolean useClassicEditor = (editorUri == null) || !editorUri.contains("acacia");
1718            CmsResource detailResource = CmsDetailPageResourceHandler.getDetailResource(request);
1719            String noEditReason;
1720            String detailContainerPage = null;
1721            CmsQuickLaunchLocationCache locationCache = CmsQuickLaunchLocationCache.getLocationCache(
1722                request.getSession());
1723            CmsUUID detailContainerPageId = null;
1724            if (detailResource != null) {
1725                locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), detailResource);
1726                CmsObject rootCms = OpenCms.initCmsObject(cms);
1727                rootCms.getRequestContext().setSiteRoot("");
1728                String detailResourcePath = detailResource.getRootPath();
1729                String locale = cms.getRequestContext().getLocale().toString();
1730                detailContainerPage = CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
1731                    cms,
1732                    containerPage,
1733                    detailResourcePath,
1734                    locale);
1735
1736                if (rootCms.existsResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION)) {
1737                    detailContainerPageId = rootCms.readResource(
1738                        detailContainerPage,
1739                        CmsResourceFilter.IGNORE_EXPIRATION).getStructureId();
1740                    noEditReason = getNoEditReason(
1741                        rootCms,
1742                        rootCms.readResource(detailContainerPage, CmsResourceFilter.IGNORE_EXPIRATION));
1743                } else {
1744                    String permissionFolder = CmsResource.getFolderPath(detailContainerPage);
1745                    while (!rootCms.existsResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION)) {
1746                        permissionFolder = CmsResource.getParentFolder(permissionFolder);
1747                    }
1748                    noEditReason = getNoEditReason(
1749                        rootCms,
1750                        rootCms.readResource(permissionFolder, CmsResourceFilter.IGNORE_EXPIRATION));
1751                }
1752            } else {
1753                if (!isModelPage && !isEditingModelGroup) {
1754                    locationCache.setPageEditorResource(cms, cms.getRequestContext().getSiteRoot(), containerPage);
1755                    sessionStorageData.put(
1756                        CmsGwtConstants.LAST_CONTAINER_PAGE_ID,
1757                        containerPage.getStructureId().toString());
1758                }
1759                noEditReason = getNoEditReason(cms, containerPage);
1760            }
1761
1762            String sitemapPath = "";
1763            boolean sitemapManager = OpenCms.getRoleManager().hasRole(cms, CmsRole.EDITOR);
1764            if (sitemapManager) {
1765                sitemapPath = CmsADEManager.PATH_SITEMAP_EDITOR_JSP;
1766            }
1767            CmsCntPageData.ElementReuseMode reuseMode = ElementReuseMode.reuse;
1768            String reuseModeString = getWorkplaceSettings().getUserSettings().getAdditionalPreference(
1769                "elementReuseMode",
1770                true);
1771
1772            try {
1773                reuseMode = ElementReuseMode.valueOf(reuseModeString);
1774            } catch (Exception e) {
1775                LOG.info("Invalid reuse mode : " + reuseModeString, e);
1776            }
1777            InitialElementViewProvider viewHelper = new InitialElementViewProvider();
1778            viewHelper.init(getSessionCache().getElementView(), containerPage, info);
1779            CmsLocaleGroup group = cms.getLocaleGroupService().readLocaleGroup(containerPage);
1780            Locale mainLocale = null;
1781
1782            if (group.isRealGroup() && !cms.getRequestContext().getLocale().equals(group.getMainLocale())) {
1783                mainLocale = group.getMainLocale();
1784            }
1785            CmsSiteManagerImpl siteManager = OpenCms.getSiteManager();
1786            String ownRoot = siteManager.getSiteRoot(containerPage.getRootPath());
1787            Map<String, CmsLocaleLinkBean> localeLinkBeans = null;
1788            if (group.isRealGroup()) {
1789                localeLinkBeans = Maps.newHashMap();
1790                Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1791                for (Map.Entry<Locale, CmsResource> entry : group.getResourcesByLocale().entrySet()) {
1792                    String otherRoot = siteManager.getSiteRoot(entry.getValue().getRootPath());
1793                    if ((otherRoot != null) && otherRoot.equals(ownRoot)) {
1794                        String theLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1795                            cms,
1796                            cms.getRequestContext().removeSiteRoot(entry.getValue().getRootPath()));
1797                        localeLinkBeans.put(entry.getKey().getDisplayLanguage(locale), CmsLocaleLinkBean.link(theLink));
1798                    } else {
1799                        localeLinkBeans.put(
1800                            entry.getKey().getDisplayLanguage(locale),
1801                            CmsLocaleLinkBean.error(
1802                                Messages.get().getBundle(locale).key(Messages.GUI_SHOWLOCALE_WRONG_SITE_0)));
1803                    }
1804                }
1805            }
1806
1807            String onlineLink = null;
1808            CmsSite site = OpenCms.getSiteManager().getSiteForSiteRoot(cms.getRequestContext().getSiteRoot());
1809            if ((site != null) && !OpenCms.getSiteManager().getWorkplaceServer().equals(site.getUrl())) {
1810                if (detailResource != null) {
1811                    onlineLink = OpenCms.getLinkManager().getOnlineLink(
1812                        cms,
1813                        cms.getSitePath(detailResource),
1814                        cms.getSitePath(containerPage),
1815                        false);
1816                } else {
1817                    onlineLink = OpenCms.getLinkManager().getOnlineLink(cms, cms.getSitePath(containerPage));
1818                }
1819            }
1820
1821            String modelGroupElementId = null;
1822            if (isEditingModelGroup) {
1823                CmsProperty modelElementProp = cms.readPropertyObject(
1824                    containerPage,
1825                    CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
1826                    false);
1827                if (!modelElementProp.isNullProperty() && CmsUUID.isValidUUID(modelElementProp.getValue())) {
1828                    modelGroupElementId = modelElementProp.getValue();
1829                }
1830            }
1831            String title = null;
1832            if (isModelPage || isEditingModelGroup) {
1833                title = Messages.get().getBundle(wpLocale).key(Messages.GUI_TITLE_MODEL_0);
1834
1835            }
1836            ElementDeleteMode deleteMode = OpenCms.getWorkplaceManager().getElementDeleteMode();
1837            if (deleteMode == null) {
1838                deleteMode = ElementDeleteMode.askDelete;
1839            }
1840            CmsListInfoBean pageInfo = CmsVfsService.getPageInfo(cms, containerPage);
1841            data = new CmsCntPageData(
1842                onlineLink,
1843                noEditReason,
1844                CmsRequestUtil.encodeParams(request),
1845                sitemapPath,
1846                sitemapManager,
1847                detailResource != null ? detailResource.getStructureId() : null,
1848                detailContainerPage,
1849                detailContainerPageId,
1850                detailTypes,
1851                lastModified,
1852                getLockInfo(containerPage),
1853                pageInfo,
1854                cms.getRequestContext().getLocale().toString(),
1855                useClassicEditor,
1856                info,
1857                isEditSmallElements(request, cms),
1858                Lists.newArrayList(viewHelper.getViewMap().values()),
1859                viewHelper.getDefaultView(),
1860                reuseMode,
1861                deleteMode,
1862                isModelPage,
1863                isEditingModelGroup,
1864                modelGroupElementId,
1865                mainLocale != null ? mainLocale.toString() : null,
1866                localeLinkBeans,
1867                title,
1868                System.currentTimeMillis());
1869            boolean allowSettingsInEditor = true;
1870            CmsModule baseModule = OpenCms.getModuleManager().getModule("org.opencms.base");
1871            if (baseModule != null) {
1872                String param = baseModule.getParameter("allowSettingsInEditor");
1873                allowSettingsInEditor = CmsStringUtil.isEmptyOrWhitespaceOnly(param)
1874                    || Boolean.valueOf(param).booleanValue();
1875            }
1876            data.setAllowSettingsInEditor(allowSettingsInEditor);
1877            String placementModeEnabledStr = (String)OpenCms.getRuntimeProperty(
1878                PARAM_PAGE_EDITOR_PLACEMENT_MODE_ENABLED);
1879            boolean placementModeEnabled = (placementModeEnabledStr == null)
1880                || Boolean.parseBoolean(placementModeEnabledStr);
1881            data.setPlacementModeEnabled(placementModeEnabled);
1882            data.setSessionStorageData(sessionStorageData);
1883        } catch (Throwable e) {
1884            error(e);
1885        }
1886        return data;
1887    }
1888
1889    /**
1890     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#prepareForEdit(java.lang.String, java.lang.String, org.opencms.util.CmsUUID, java.lang.String)
1891     */
1892    public CmsUUID prepareForEdit(String clientId, String editOption, CmsUUID pageId, String requestParams)
1893    throws CmsRpcException {
1894
1895        try {
1896            CmsResource pageResource = getCmsObject().readResource(
1897                pageId,
1898                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1899            CmsContainerElementBean element = getCachedElement(clientId, pageResource.getRootPath());
1900            element.initResource(getCmsObject());
1901            I_CmsResourceType type = OpenCms.getResourceManager().getResourceType(element.getResource());
1902            if (type instanceof CmsResourceTypeXmlContent) {
1903                I_CmsEditHandler handler = ((CmsResourceTypeXmlContent)type).getEditHandler(getCmsObject());
1904                Map<String, String[]> params = CmsRequestUtil.createParameterMap(
1905                    CmsEncoder.decode(requestParams),
1906                    true,
1907                    CmsEncoder.ENCODING_UTF_8);
1908                return handler.prepareForEdit(getCmsObject(), element, editOption, pageId, params);
1909            }
1910        } catch (CmsException e) {
1911            error(e);
1912        }
1913        return null;
1914    }
1915
1916    /**
1917     * @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)
1918     */
1919    public CmsContainerElementData replaceElement(
1920        CmsContainerPageRpcContext context,
1921        CmsUUID detailContentId,
1922        String reqParams,
1923        String clientId,
1924        String replaceId,
1925        Collection<CmsContainer> containers,
1926        String locale)
1927    throws CmsRpcException {
1928
1929        CmsContainerElementData element = null;
1930        try {
1931            ensureSession();
1932            CmsObject cms = getCmsObject();
1933            CmsResource pageResource = cms.readResource(
1934                context.getPageStructureId(),
1935                CmsResourceFilter.ignoreExpirationOffline(cms));
1936            initRequestFromRpcContext(context);
1937            String containerpageUri = cms.getSitePath(pageResource);
1938            Locale contentLocale = CmsLocaleManager.getLocale(locale);
1939            CmsElementUtil elemUtil = new CmsElementUtil(
1940                cms,
1941                containerpageUri,
1942                generateContainerPageForContainers(containers, pageResource.getRootPath()),
1943                detailContentId,
1944                getRequest(),
1945                getResponse(),
1946                false,
1947                contentLocale);
1948
1949            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
1950            Map<String, String> settings = new HashMap<String, String>(elementBean.getIndividualSettings());
1951            settings.remove(CmsContainerElement.ELEMENT_INSTANCE_ID);
1952            CmsContainerElementBean replaceBean = new CmsContainerElementBean(
1953                new CmsUUID(replaceId),
1954                elementBean.getFormatterId(),
1955                settings,
1956                elementBean.isCreateNew());
1957            getSessionCache().setCacheContainerElement(replaceBean.editorHash(), replaceBean);
1958            element = elemUtil.getElementData(pageResource, replaceBean, containers);
1959        } catch (Throwable e) {
1960            error(e);
1961        }
1962        return element;
1963    }
1964
1965    /**
1966     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveClipboardTab(int)
1967     */
1968    public void saveClipboardTab(int tabIndex) {
1969
1970        getRequest().getSession().setAttribute(ATTR_CLIPBOARD_TAB, Integer.valueOf(tabIndex));
1971    }
1972
1973    /**
1974     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveContainerpage(org.opencms.util.CmsUUID, java.util.List)
1975     */
1976    public CmsPageSaveStatus saveContainerpage(CmsUUID pageStructureId, List<CmsContainer> containers)
1977    throws CmsRpcException {
1978
1979        CmsObject cms = getCmsObject();
1980        try {
1981            ensureSession();
1982            CmsResource containerpage = cms.readResource(
1983                pageStructureId,
1984                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
1985            ensureLock(containerpage);
1986            String containerpageUri = cms.getSitePath(containerpage);
1987            saveContainers(cms, containerpage, containerpageUri, containers);
1988        } catch (Throwable e) {
1989            error(e);
1990        }
1991        return new CmsPageSaveStatus(pageStructureId, System.currentTimeMillis());
1992    }
1993
1994    /**
1995     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveDetailContainers(org.opencms.util.CmsUUID, java.lang.String, java.util.List)
1996     */
1997    public CmsPageSaveStatus saveDetailContainers(
1998        CmsUUID detailId,
1999        String detailContainerResource,
2000        List<CmsContainer> containers)
2001    throws CmsRpcException {
2002
2003        CmsObject cms = getCmsObject();
2004        CmsUUID id = null;
2005        try {
2006            ensureSession();
2007            CmsObject rootCms = OpenCms.initCmsObject(cms);
2008            rootCms.getRequestContext().setSiteRoot("");
2009            CmsResource containerpage;
2010            containerpage = CmsDetailOnlyContainerUtil.readOrCreateDetailOnlyPage(
2011                rootCms,
2012                detailId,
2013                detailContainerResource);
2014            id = containerpage.getStructureId();
2015            saveContainers(rootCms, containerpage, detailContainerResource, containers);
2016        } catch (Throwable e) {
2017            error(e);
2018        }
2019        return new CmsPageSaveStatus(id, System.currentTimeMillis());
2020    }
2021
2022    /**
2023     * @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)
2024     */
2025    public CmsContainerElementData saveElementSettings(
2026        CmsContainerPageRpcContext context,
2027        CmsUUID detailContentId,
2028        String reqParams,
2029        String clientId,
2030        Map<String, String> settings,
2031        List<CmsContainer> containers,
2032        String locale)
2033    throws CmsRpcException {
2034
2035        CmsContainerElementData element = null;
2036        try {
2037            ensureSession();
2038            CmsObject cms = getCmsObject();
2039            CmsResource pageResource = cms.readResource(
2040                context.getPageStructureId(),
2041                CmsResourceFilter.ignoreExpirationOffline(cms));
2042            initRequestFromRpcContext(context);
2043            Locale contentLocale = CmsLocaleManager.getLocale(locale);
2044            CmsContainerElementBean elementBean = getCachedElement(clientId, pageResource.getRootPath());
2045            elementBean.initResource(cms);
2046            storeFormatterSelection(elementBean, settings);
2047            // make sure to keep the element instance id
2048            if (!settings.containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)
2049                && elementBean.getIndividualSettings().containsKey(CmsContainerElement.ELEMENT_INSTANCE_ID)) {
2050                settings.put(
2051                    CmsContainerElement.ELEMENT_INSTANCE_ID,
2052                    elementBean.getIndividualSettings().get(CmsContainerElement.ELEMENT_INSTANCE_ID));
2053            }
2054            if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.SETTING_PAGE_ID)) {
2055                settings.put(
2056                    CmsContainerElement.SETTING_PAGE_ID,
2057                    elementBean.getIndividualSettings().get(CmsContainerElement.SETTING_PAGE_ID));
2058            }
2059            if (!isEditingModelGroups(cms, pageResource)) {
2060                // in case of model group state set to 'noGroup', the group will be dissolved and former group id forgotten
2061                if (!(settings.containsKey(CmsContainerElement.MODEL_GROUP_STATE)
2062                    && (ModelGroupState.noGroup == ModelGroupState.evaluate(
2063                        settings.get(CmsContainerElement.MODEL_GROUP_STATE))))) {
2064                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_ID)) {
2065                        // make sure to keep the model group id
2066                        settings.put(
2067                            CmsContainerElement.MODEL_GROUP_ID,
2068                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_ID));
2069                    }
2070                    if (elementBean.getIndividualSettings().containsKey(CmsContainerElement.MODEL_GROUP_STATE)) {
2071                        settings.put(
2072                            CmsContainerElement.MODEL_GROUP_STATE,
2073                            elementBean.getIndividualSettings().get(CmsContainerElement.MODEL_GROUP_STATE));
2074                    }
2075                }
2076            }
2077            elementBean = CmsContainerElementBean.cloneWithSettings(
2078                elementBean,
2079                convertSettingValues(elementBean.getResource(), settings, contentLocale));
2080            getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
2081
2082            // update client id within container data
2083            for (CmsContainer container : containers) {
2084                for (CmsContainerElement child : container.getElements()) {
2085                    if (child.getClientId().equals(clientId)) {
2086                        child.setClientId(elementBean.editorHash());
2087                    }
2088                }
2089            }
2090            if (detailContentId == null) {
2091                saveContainers(cms, pageResource, cms.getSitePath(pageResource), containers);
2092            } else {
2093                List<CmsContainer> detailContainers = new ArrayList<CmsContainer>();
2094                for (CmsContainer container : containers) {
2095                    if (container.isDetailOnly()) {
2096                        detailContainers.add(container);
2097                    }
2098                }
2099                CmsObject rootCms = OpenCms.initCmsObject(cms);
2100                rootCms.getRequestContext().setSiteRoot("");
2101                CmsResource detailResource = rootCms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2102                String detailRootPath = detailResource.getRootPath();
2103                CmsResource detailContainerPage = rootCms.readResource(
2104                    CmsDetailOnlyContainerUtil.getDetailOnlyPageName(cms, pageResource, detailRootPath, locale));
2105
2106                ensureLock(detailContainerPage);
2107                saveContainers(rootCms, detailContainerPage, detailContainerPage.getRootPath(), detailContainers);
2108            }
2109            String containerpageUri = cms.getSitePath(pageResource);
2110            CmsElementUtil elemUtil = new CmsElementUtil(
2111                cms,
2112                containerpageUri,
2113                generateContainerPageForContainers(containers, pageResource.getRootPath()),
2114                detailContentId,
2115                getRequest(),
2116                getResponse(),
2117                false,
2118                contentLocale);
2119            element = elemUtil.getElementData(pageResource, elementBean, containers);
2120        } catch (Throwable e) {
2121            error(e);
2122        }
2123        return element;
2124    }
2125
2126    /**
2127     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveFavoriteList(java.util.List, java.lang.String)
2128     */
2129    public void saveFavoriteList(List<String> clientIds, String uri) throws CmsRpcException {
2130
2131        try {
2132            ensureSession();
2133            OpenCms.getADEManager().saveFavoriteList(
2134                getCmsObject(),
2135                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2136        } catch (Throwable e) {
2137            error(e);
2138        }
2139    }
2140
2141    /**
2142     * @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)
2143     */
2144    public CmsGroupContainerSaveResult saveGroupContainer(
2145        CmsContainerPageRpcContext context,
2146
2147        CmsUUID detailContentId,
2148        String reqParams,
2149        CmsGroupContainer groupContainer,
2150        Collection<CmsContainer> containers,
2151        String locale)
2152    throws CmsRpcException {
2153
2154        CmsObject cms = getCmsObject();
2155        List<CmsRemovedElementStatus> removedElements = null;
2156        try {
2157            CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> saveResult = internalSaveGroupContainer(
2158                cms,
2159                context.getPageStructureId(),
2160                groupContainer);
2161            removedElements = saveResult.getSecond();
2162        } catch (Throwable e) {
2163            error(e);
2164        }
2165        Collection<String> ids = new ArrayList<String>();
2166        ids.add(groupContainer.getClientId());
2167        // update offline indices
2168        OpenCms.getSearchManager().updateOfflineIndexes();
2169        return new CmsGroupContainerSaveResult(
2170            getElementsData(context, detailContentId, reqParams, ids, containers, false, null, locale),
2171            removedElements);
2172    }
2173
2174    /**
2175     * @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)
2176     */
2177    public Map<String, CmsContainerElementData> saveInheritanceContainer(
2178        CmsUUID pageStructureId,
2179        CmsUUID detailContentId,
2180        CmsInheritanceContainer inheritanceContainer,
2181        Collection<CmsContainer> containers,
2182        String locale)
2183    throws CmsRpcException {
2184
2185        try {
2186            CmsObject cms = getCmsObject();
2187            CmsADEConfigData rpcConfig = OpenCms.getADEManager().lookupConfiguration(
2188                cms,
2189                cms.getRequestContext().getRootUri());
2190            CmsResource containerPage = cms.readResource(
2191                pageStructureId,
2192                CmsResourceFilter.ignoreExpirationOffline(getCmsObject()));
2193            String sitePath = cms.getSitePath(containerPage);
2194            Locale requestedLocale = CmsLocaleManager.getLocale(locale);
2195            CmsResource referenceResource = null;
2196            if (inheritanceContainer.isNew()) {
2197                CmsADEConfigData config = getConfigData(containerPage.getRootPath());
2198                CmsResourceTypeConfig typeConfig = config.getResourceType(
2199                    CmsResourceTypeXmlContainerPage.INHERIT_CONTAINER_TYPE_NAME);
2200                referenceResource = typeConfig.createNewElement(cms, containerPage.getRootPath());
2201                inheritanceContainer.setClientId(referenceResource.getStructureId().toString());
2202            }
2203            if (referenceResource == null) {
2204                CmsUUID id = convertToServerId(inheritanceContainer.getClientId());
2205                referenceResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
2206            }
2207            ensureLock(referenceResource);
2208            saveInheritanceGroup(referenceResource, inheritanceContainer);
2209            tryUnlock(referenceResource);
2210            List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2211            for (CmsContainerElement clientElement : inheritanceContainer.getElements()) {
2212                CmsContainerElementBean elementBean = getCachedElement(
2213                    clientElement.getClientId(),
2214                    containerPage.getRootPath());
2215                elementBean = CmsContainerElementBean.cloneWithSettings(
2216                    elementBean,
2217                    elementBean.getIndividualSettings());
2218                CmsInheritanceInfo inheritanceInfo = clientElement.getInheritanceInfo();
2219                // if a local elements misses the key it was newly added
2220                if (inheritanceInfo.isNew() && CmsStringUtil.isEmptyOrWhitespaceOnly(inheritanceInfo.getKey())) {
2221                    // generating new key
2222                    inheritanceInfo.setKey(CmsResource.getFolderPath(sitePath) + new CmsUUID().toString());
2223                }
2224                elementBean.setInheritanceInfo(inheritanceInfo);
2225                elements.add(elementBean);
2226            }
2227            cms.getRequestContext().setLocale(requestedLocale);
2228            if (inheritanceContainer.getElementsChanged()) {
2229                OpenCms.getADEManager().saveInheritedContainer(
2230                    cms,
2231                    containerPage,
2232                    inheritanceContainer.getName(),
2233                    true,
2234                    elements);
2235            }
2236            return getElements(
2237                rpcConfig,
2238                containerPage,
2239                new ArrayList<String>(Collections.singletonList(inheritanceContainer.getClientId())),
2240                sitePath,
2241                detailContentId,
2242                containers,
2243                false,
2244                null,
2245                false,
2246                requestedLocale);
2247        } catch (Exception e) {
2248            error(e);
2249        }
2250        return null;
2251    }
2252
2253    /**
2254     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#saveRecentList(java.util.List, java.lang.String)
2255     */
2256    public void saveRecentList(List<String> clientIds, String uri) throws CmsRpcException {
2257
2258        try {
2259            ensureSession();
2260            OpenCms.getADEManager().saveRecentList(
2261                getCmsObject(),
2262                getCachedElements(clientIds, getCmsObject().getRequestContext().addSiteRoot(uri)));
2263        } catch (Throwable e) {
2264            error(e);
2265        }
2266    }
2267
2268    /**
2269     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setEditSmallElements(boolean)
2270     */
2271    public void setEditSmallElements(boolean editSmallElements) throws CmsRpcException {
2272
2273        try {
2274            CmsObject cms = getCmsObject();
2275            CmsUser user = cms.getRequestContext().getCurrentUser();
2276            user.getAdditionalInfo().put(ADDINFO_EDIT_SMALL_ELEMENTS, "" + editSmallElements);
2277            cms.writeUser(user);
2278        } catch (Throwable t) {
2279            error(t);
2280        }
2281    }
2282
2283    /**
2284     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setElementView(org.opencms.util.CmsUUID)
2285     */
2286    public void setElementView(CmsUUID elementView) {
2287
2288        getSessionCache().setElementView(elementView);
2289    }
2290
2291    /**
2292     * @see org.opencms.ade.containerpage.shared.rpc.I_CmsContainerpageService#setLastPage(org.opencms.util.CmsUUID, org.opencms.util.CmsUUID)
2293     */
2294    public void setLastPage(CmsUUID pageId, CmsUUID detailId) throws CmsRpcException {
2295
2296        try {
2297            HttpServletRequest req = getRequest();
2298            CmsObject cms = getCmsObject();
2299            CmsADESessionCache cache = CmsADESessionCache.getCache(req, cms);
2300            cache.setLastPage(cms, pageId, detailId);
2301        } catch (Exception e) {
2302            error(e);
2303        }
2304
2305    }
2306
2307    /**
2308     * Sets the session cache.<p>
2309     *
2310     * @param cache the session cache
2311     */
2312    public void setSessionCache(CmsADESessionCache cache) {
2313
2314        m_sessionCache = cache;
2315    }
2316
2317    /**
2318     * Helper method for collecting the type information for the galleries in the container page editor.
2319     *
2320     *
2321     * @param cms the CMS context
2322     * @param containers the page containers
2323     * @param elementView the element view
2324     * @param uri the page URI
2325     * @param detailContentId the detail content id
2326     * @param locale the content locale
2327     * @param contextInfo the template context information
2328     *
2329     * @return the type beans
2330     *
2331     * @throws CmsRpcException in case something goes wrong
2332     */
2333    protected List<CmsResourceTypeBean> getGalleryTypesForView(
2334        CmsObject cms,
2335        final List<CmsContainer> containers,
2336        CmsUUID elementView,
2337        String uri,
2338        CmsUUID detailContentId,
2339        String locale,
2340        CmsTemplateContextInfo templateContextInfo)
2341    throws CmsException {
2342
2343        String pageFolderRootPath = cms.getRequestContext().addSiteRoot(uri);
2344        CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(cms, pageFolderRootPath);
2345        Map<String, CmsResourceTypeConfig> typesByName = config.getTypesByName();
2346        final String templateContextStr = (templateContextInfo != null)
2347            && (templateContextInfo.getCurrentContext() != null) ? templateContextInfo.getCurrentContext() : null;
2348        CmsAddDialogTypeHelper typeHelper = new CmsAddDialogTypeHelper(CmsResourceTypeConfig.AddMenuType.ade) {
2349
2350            @Override
2351            protected boolean exclude(CmsResourceTypeBean type) {
2352
2353                CmsResourceTypeConfig typeConfig = typesByName.get(type.getType());
2354                if ((typeConfig != null)
2355                    && (templateContextStr != null)
2356                    && !typeConfig.isAvailableInTemplate(templateContextStr)) {
2357                    return true;
2358                }
2359                return false;
2360
2361            }
2362        };
2363        if (detailContentId != null) {
2364            try {
2365                CmsResource page = cms.readResource(uri, CmsResourceFilter.IGNORE_EXPIRATION);
2366                CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2367                pageFolderRootPath = CmsResource.getParentFolder(
2368                    CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
2369                        cms,
2370                        page,
2371                        detailContent.getRootPath(),
2372                        "" + locale));
2373            } catch (Exception e) {
2374                LOG.error(e.getLocalizedMessage(), e);
2375            }
2376        }
2377        List<CmsResourceTypeBean> resTypeBeans = typeHelper.getResourceTypes(
2378            cms,
2379            cms.getRequestContext().addSiteRoot(uri),
2380            pageFolderRootPath,
2381            uri,
2382            OpenCms.getADEManager().getElementViews(cms).get(elementView),
2383            new I_CmsResourceTypeEnabledCheck() {
2384
2385                public boolean checkEnabled(CmsObject paramCms, CmsADEConfigData config2, I_CmsResourceType resType) {
2386
2387                    boolean isModelGroup = CmsResourceTypeXmlContainerPage.MODEL_GROUP_TYPE_NAME.equals(
2388                        resType.getTypeName());
2389                    return isModelGroup || config2.hasFormatters(paramCms, resType, containers);
2390                }
2391            });
2392        return resTypeBeans;
2393    }
2394
2395    /**
2396     * Gets the settings which should be updated for an element in the DND case.<p>
2397     *
2398     * @param config the sitemap configuration
2399     * @param originalSettings the original settings
2400     * @param formatterConfig the formatter configuration for the element
2401     * @param containers the containers
2402     * @param dndContainer the id of the DND origin container
2403     *
2404     * @return the map of settings to update
2405     */
2406    Map<String, String> getSettingsToChangeForDnd(
2407        CmsADEConfigData config,
2408        Map<String, String> originalSettings,
2409        CmsFormatterConfiguration formatterConfig,
2410        Collection<CmsContainer> containers,
2411        String dndContainer) {
2412
2413        Map<String, String> result = Maps.newHashMap();
2414
2415        if (dndContainer == null) {
2416            return result;
2417        }
2418        String key = CmsFormatterConfig.getSettingsKeyForContainer(dndContainer);
2419        String formatterId = originalSettings.get(key);
2420        if (formatterId == null) {
2421            return result;
2422        }
2423        for (CmsContainer container : containers) {
2424            if (container.getName().equals(dndContainer)) {
2425                continue;
2426            }
2427
2428            Map<String, I_CmsFormatterBean> formatterSelection = formatterConfig.getFormatterSelection(
2429                container.getType(),
2430                container.getWidth());
2431            I_CmsFormatterBean currentBean = config.findFormatter(formatterId);
2432            if (currentBean != null) {
2433                if (CmsFormatterConfiguration.matchFormatter(currentBean, container.getType(), container.getWidth())) {
2434                    String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2435                    result.put(newKey, currentBean.getKeyOrId());
2436                }
2437            } else if (formatterSelection.containsKey(formatterId)) {
2438                // for backwards compatibility with schema-configured formatters
2439                String newKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2440                result.put(newKey, formatterId);
2441            }
2442        }
2443        return result;
2444    }
2445
2446    /**
2447     * Creates a new container element bean from an existing one, but changes some of the individual settings in the copy.<p>
2448     *
2449     * @param element the original container element
2450     * @param settingsToOverride the map of settings to change
2451     *
2452     * @return the new container element bean with the changed settings
2453     */
2454    CmsContainerElementBean overrideSettings(CmsContainerElementBean element, Map<String, String> settingsToOverride) {
2455
2456        Map<String, String> settings = Maps.newHashMap(element.getIndividualSettings());
2457        settings.putAll(settingsToOverride);
2458        CmsContainerElementBean result = new CmsContainerElementBean(
2459            element.getId(),
2460            element.getFormatterId(),
2461            settings,
2462            element.isCreateNew());
2463        return result;
2464    }
2465
2466    /**
2467     * Adds the formatter to the recently used formatter list.<p>
2468     *
2469     * @param elementBean the element bean
2470     * @param settings the changed settings
2471     */
2472    void storeFormatterSelection(CmsContainerElementBean elementBean, Map<String, String> settings) {
2473
2474        Entry<String, String> previousFormatterEntry = null;
2475        for (Entry<String, String> entry : elementBean.getIndividualSettings().entrySet()) {
2476            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2477                previousFormatterEntry = entry;
2478                break;
2479            }
2480        }
2481        Entry<String, String> formatterEntry = null;
2482        for (Entry<String, String> entry : settings.entrySet()) {
2483            if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
2484                formatterEntry = entry;
2485                break;
2486            }
2487        }
2488        if ((formatterEntry != null)
2489            && ((previousFormatterEntry == null)
2490                || !formatterEntry.getKey().equals(previousFormatterEntry.getKey())
2491                || !formatterEntry.getValue().equals(previousFormatterEntry.getValue()))) {
2492            String idString = formatterEntry.getValue();
2493            if (idString != null) {
2494                // the formatter setting has changed
2495                I_CmsResourceType resType = OpenCms.getResourceManager().getResourceType(elementBean.getResource());
2496                if (!(resType instanceof CmsResourceTypeFunctionConfig)) {
2497                    getSessionCache().addRecentFormatter(resType.getTypeName(), idString);
2498                }
2499            }
2500        }
2501    }
2502
2503    /**
2504     * Converts the given setting values according to the setting configuration of the given resource.<p>
2505     *
2506     * @param resource the resource
2507     * @param settings the settings to convert
2508     * @param locale the locale used for accessing the element settings
2509     *
2510     * @return the converted settings
2511     * @throws CmsException if something goes wrong
2512     */
2513    private Map<String, String> convertSettingValues(CmsResource resource, Map<String, String> settings, Locale locale)
2514    throws CmsException {
2515
2516        CmsObject cms = getCmsObject();
2517        Locale origLocale = cms.getRequestContext().getLocale();
2518        try {
2519            cms.getRequestContext().setLocale(locale);
2520            Map<String, CmsXmlContentProperty> settingsConf = OpenCms.getADEManager().getElementSettings(cms, resource);
2521            Map<String, String> changedSettings = new HashMap<String, String>();
2522            if (settings != null) {
2523                for (Map.Entry<String, String> entry : settings.entrySet()) {
2524                    String settingName = entry.getKey();
2525                    String settingType = "string";
2526                    if (settingsConf.get(settingName) != null) {
2527                        settingType = settingsConf.get(settingName).getType();
2528                    }
2529                    changedSettings.put(
2530                        settingName,
2531                        CmsXmlContentPropertyHelper.getPropValueIds(getCmsObject(), settingType, entry.getValue()));
2532                }
2533            }
2534            return changedSettings;
2535        } finally {
2536            cms.getRequestContext().setLocale(origLocale);
2537        }
2538    }
2539
2540    /**
2541     * Generates the XML container page bean for the given containers.<p>
2542     *
2543     * @param containers the containers
2544     * @param containerpageRootPath the container page root path
2545     *
2546     * @return the container page bean
2547     * @throws CmsException in case generating the page data fails
2548     */
2549    private CmsContainerPageBean generateContainerPageForContainers(
2550        Collection<CmsContainer> containers,
2551        String containerpageRootPath)
2552    throws CmsException {
2553
2554        List<CmsContainerBean> containerBeans = new ArrayList<CmsContainerBean>();
2555        for (CmsContainer container : containers) {
2556            CmsContainerBean containerBean = getContainerBeanToSave(container, containerpageRootPath);
2557            containerBeans.add(containerBean);
2558        }
2559        CmsContainerPageBean page = new CmsContainerPageBean(containerBeans);
2560        return page;
2561    }
2562
2563    /**
2564     * Returns a list of container elements from a list with client id's.<p>
2565     *
2566     * @param clientIds list of client id's
2567     * @param pageRootPath the container page root path
2568     *
2569     * @return a list of element beans
2570     * @throws CmsException in case reading the element resource fails
2571     */
2572    private List<CmsContainerElementBean> getCachedElements(List<String> clientIds, String pageRootPath)
2573    throws CmsException {
2574
2575        List<CmsContainerElementBean> result = new ArrayList<CmsContainerElementBean>();
2576        for (String id : clientIds) {
2577            try {
2578                result.add(getCachedElement(id, pageRootPath));
2579            } catch (CmsIllegalArgumentException e) {
2580                log(e.getLocalizedMessage(), e);
2581            }
2582        }
2583        return result;
2584    }
2585
2586    /**
2587     * Returns the configuration data of the current container page context.<p>
2588     *
2589     * @param pageRootPath the container page root path
2590     *
2591     * @return the configuration data of the current container page context
2592     */
2593    private CmsADEConfigData getConfigData(String pageRootPath) {
2594
2595        if (m_configData == null) {
2596            m_configData = OpenCms.getADEManager().lookupConfiguration(getCmsObject(), pageRootPath);
2597        }
2598        return m_configData;
2599    }
2600
2601    /**
2602     * Helper method for converting a CmsContainer to a CmsContainerBean when saving a container page.<p>
2603     *
2604     * @param container the container for which the CmsContainerBean should be created
2605     * @param containerpageRootPath the container page root path
2606     *
2607     * @return a container bean
2608     *
2609     * @throws CmsException in case generating the container data fails
2610     */
2611    private CmsContainerBean getContainerBeanToSave(CmsContainer container, String containerpageRootPath)
2612    throws CmsException {
2613
2614        CmsObject cms = getCmsObject();
2615        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2616        for (CmsContainerElement elementData : container.getElements()) {
2617            if (!elementData.isNew()) {
2618                CmsContainerElementBean newElementBean = getContainerElementBeanToSave(
2619                    cms,
2620                    containerpageRootPath,
2621                    container,
2622                    elementData);
2623                if (newElementBean != null) {
2624                    elements.add(newElementBean);
2625                }
2626            }
2627        }
2628        CmsContainerBean result = CmsElementUtil.clientToServerContainer(container, elements);
2629        return result;
2630    }
2631
2632    /**
2633     * Converts container page element data to a bean which can be saved in a container page.<p>
2634     *
2635     * @param cms the current CMS context
2636     * @param containerpageRootPath the container page root path
2637     * @param container the container containing the element
2638     * @param elementData the data for the single element
2639     *
2640     * @return the container element bean
2641     *
2642     * @throws CmsException if something goes wrong
2643     */
2644    private CmsContainerElementBean getContainerElementBeanToSave(
2645        CmsObject cms,
2646        String containerpageRootPath,
2647        CmsContainer container,
2648        CmsContainerElement elementData)
2649    throws CmsException {
2650
2651        String elementClientId = elementData.getClientId();
2652        boolean hasUuidPrefix = (elementClientId != null) && elementClientId.matches(CmsUUID.UUID_REGEX + ".*$");
2653        boolean isCreateNew = elementData.isCreateNew();
2654        if (elementData.isNew() && !hasUuidPrefix) {
2655
2656            // Due to the changed save system without the save button, we need to make sure that new elements
2657            // are only created once. This must happen when the user first edits a new element. But we still
2658            // want to save changes to non-new elements on the page, so we skip new elements while saving.
2659            return null;
2660        }
2661        CmsContainerElementBean element = getCachedElement(elementData.getClientId(), containerpageRootPath);
2662
2663        CmsResource resource;
2664        if (element.getResource() == null) {
2665            element.initResource(cms);
2666            resource = element.getResource();
2667        } else {
2668            // make sure resource is readable, this is necessary for new content elements
2669            if (element.getId().isNullUUID()) {
2670                // in memory only element, can not be read nor saved
2671                return null;
2672            }
2673            resource = cms.readResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION);
2674        }
2675
2676        // check if there is a valid formatter
2677        int containerWidth = container.getWidth();
2678        CmsADEConfigData config = getConfigData(containerpageRootPath);
2679        CmsFormatterConfiguration formatters = config.getFormatters(cms, resource);
2680        String containerType = null;
2681        containerType = container.getType();
2682        I_CmsFormatterBean formatter = null;
2683        String formatterConfigId = null;
2684        formatterConfigId = element.getFormatterKey(container.getName());
2685        if (formatterConfigId != null) {
2686            I_CmsFormatterBean dynamicFmt = config.findFormatter(formatterConfigId);
2687            if (dynamicFmt != null) {
2688                formatter = dynamicFmt;
2689            } else if (formatterConfigId.startsWith(CmsFormatterConfig.SCHEMA_FORMATTER_ID)
2690                && CmsUUID.isValidUUID(formatterConfigId.substring(CmsFormatterConfig.SCHEMA_FORMATTER_ID.length()))) {
2691                formatter = formatters.getFormatterSelection(containerType, containerWidth).get(formatterConfigId);
2692            }
2693        }
2694        if (formatter == null) {
2695            formatter = CmsElementUtil.getFormatterForContainer(cms, element, container, config, getSessionCache());
2696            if (formatter != null) {
2697                formatterConfigId = formatter.isFromFormatterConfigFile()
2698                ? formatter.getId()
2699                : CmsFormatterConfig.SCHEMA_FORMATTER_ID + formatter.getJspStructureId().toString();
2700            }
2701        }
2702        CmsContainerElementBean newElementBean = null;
2703        if (formatter != null) {
2704            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
2705            String formatterKey = CmsFormatterConfig.getSettingsKeyForContainer(container.getName());
2706            settings.put(formatterKey, formatterConfigId);
2707            // remove not used formatter settings
2708            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
2709            while (entries.hasNext()) {
2710                Entry<String, String> entry = entries.next();
2711                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)
2712                    && !entry.getKey().equals(formatterKey)) {
2713                    entries.remove();
2714                }
2715            }
2716
2717            newElementBean = new CmsContainerElementBean(
2718                element.getId(),
2719                formatter.getJspStructureId(),
2720                settings,
2721                isCreateNew);
2722        }
2723        return newElementBean;
2724    }
2725
2726    /**
2727     * Returns the requested container-page resource.<p>
2728     *
2729     * @param cms the current cms object
2730     *
2731     * @return the container-page resource
2732     *
2733     * @throws CmsException if the resource could not be read for any reason
2734     */
2735    private CmsResource getContainerpage(CmsObject cms) throws CmsException {
2736
2737        String currentUri = cms.getRequestContext().getUri();
2738        CmsResource containerPage = cms.readResource(currentUri, CmsResourceFilter.ignoreExpirationOffline(cms));
2739        if (!CmsResourceTypeXmlContainerPage.isContainerPage(containerPage)) {
2740            // container page is used as template
2741            String cntPagePath = cms.readPropertyObject(
2742                containerPage,
2743                CmsPropertyDefinition.PROPERTY_TEMPLATE_ELEMENTS,
2744                true).getValue("");
2745            try {
2746                containerPage = cms.readResource(cntPagePath, CmsResourceFilter.ignoreExpirationOffline(cms));
2747            } catch (CmsException e) {
2748                if (!LOG.isDebugEnabled()) {
2749                    LOG.warn(e.getLocalizedMessage());
2750                }
2751                LOG.debug(e.getLocalizedMessage(), e);
2752            }
2753        }
2754        return containerPage;
2755    }
2756
2757    /**
2758     * Gets the (potentially empty) set of types for which the container page is registered as a detail page.
2759     *
2760     * @param cms the CMS context
2761     * @param containerPage a container page resource
2762     *
2763     * @return the set of names of types for which the container page is a detail page
2764     */
2765    private Set<String> getDetailTypes(CmsObject cms, CmsResource containerPage) {
2766
2767        List<CmsDetailPageInfo> infos = OpenCms.getADEManager().getAllDetailPages(cms);
2768        Set<CmsUUID> ids = new HashSet<>();
2769        ids.add(containerPage.getStructureId());
2770        Set<String> result = new HashSet<>();
2771        if (containerPage.isFile()) {
2772            try {
2773                CmsResource folder = cms.readParentFolder(containerPage.getStructureId());
2774                if (folder != null) {
2775                    ids.add(folder.getStructureId());
2776                }
2777            } catch (CmsException e) {
2778                LOG.error(e.getLocalizedMessage(), e);
2779            }
2780        }
2781        for (CmsDetailPageInfo info : infos) {
2782            if (ids.contains(info.getId())) {
2783                result.add(info.getType());
2784            }
2785        }
2786
2787        return result;
2788
2789    }
2790
2791    /**
2792     * Returns the data of the given elements.<p>
2793     *
2794     * @param config the sitemap configuration
2795     * @param page the current container page
2796     * @param clientIds the list of IDs of the elements to retrieve the data for
2797     * @param uriParam the current URI
2798     * @param detailContentId the detail content structure id
2799     * @param containers the containers for which the element data should be fetched
2800     * @param allwaysCopy <code>true</code> in case reading data for a clipboard element used as a copy group
2801     * @param dndOriginContainer the container from which an element was dragged (null if this method is not called for DND)
2802     * @param isDragMode if the page is in drag mode
2803     * @param locale the locale to use
2804     *
2805     * @return the elements data
2806     *
2807     * @throws CmsException if something really bad happens
2808     */
2809    private Map<String, CmsContainerElementData> getElements(
2810        CmsADEConfigData config,
2811        CmsResource page,
2812        Collection<String> clientIds,
2813        String uriParam,
2814        CmsUUID detailContentId,
2815        Collection<CmsContainer> containers,
2816        boolean allwaysCopy,
2817        String dndOriginContainer,
2818        boolean isDragMode,
2819        Locale locale)
2820    throws CmsException {
2821
2822        CmsObject cms = getCmsObject();
2823        CmsContainerPageBean pageBean = generateContainerPageForContainers(
2824            containers,
2825            cms.getRequestContext().addSiteRoot(uriParam));
2826        Map<String, CmsContainerElementBean> idMapping = new HashMap<String, CmsContainerElementBean>();
2827        for (String elemId : clientIds) {
2828            if ((elemId == null)) {
2829                continue;
2830            }
2831            CmsContainerElementBean element = getCachedElement(elemId, cms.getRequestContext().addSiteRoot(uriParam));
2832            if (element.getInstanceId() == null) {
2833                element = element.clone();
2834                getSessionCache().setCacheContainerElement(element.editorHash(), element);
2835            }
2836            element.initResource(cms);
2837            idMapping.put(elemId, element);
2838        }
2839        List<String> foundGroups = new ArrayList<String>();
2840        if (CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2841            // this indicates the element is added to the page and not being repositioned, check for model group data
2842            CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
2843                cms,
2844                getConfigData(uriParam),
2845                getSessionCache(),
2846                isEditingModelGroups(cms, page));
2847            String createElementContext = CmsResource.getParentFolder(page.getRootPath());
2848            if (detailContentId != null) {
2849                try {
2850                    CmsResource detailContent = cms.readResource(detailContentId, CmsResourceFilter.IGNORE_EXPIRATION);
2851                    createElementContext = CmsResource.getParentFolder(
2852                        CmsDetailOnlyContainerUtil.getDetailOnlyPageName(
2853                            cms,
2854                            page,
2855                            detailContent.getRootPath(),
2856                            "" + locale));
2857                } catch (Exception e) {
2858                    LOG.error(e.getLocalizedMessage(), e);
2859                }
2860            }
2861            pageBean = modelHelper.prepareforModelGroupContent(
2862                idMapping,
2863                foundGroups,
2864                pageBean,
2865                allwaysCopy,
2866                locale,
2867                createElementContext);
2868        }
2869
2870        CmsElementUtil elemUtil = new CmsElementUtil(
2871            cms,
2872            uriParam,
2873            pageBean,
2874            detailContentId,
2875            getRequest(),
2876            getResponse(),
2877            isDragMode,
2878            locale);
2879        Map<String, CmsContainerElementData> result = new HashMap<String, CmsContainerElementData>();
2880        Set<String> ids = new HashSet<String>();
2881        for (Entry<String, CmsContainerElementBean> entry : idMapping.entrySet()) {
2882            CmsContainerElementBean element = entry.getValue();
2883            String dndId = null;
2884            if (ids.contains(element.editorHash())) {
2885                continue;
2886            }
2887            if ((dndOriginContainer != null) && !CmsContainerElement.MENU_CONTAINER_ID.equals(dndOriginContainer)) {
2888                CmsFormatterConfiguration formatterConfig = elemUtil.getFormatterConfiguration(element.getResource());
2889                Map<String, String> dndSettings = getSettingsToChangeForDnd(
2890                    config,
2891                    element.getIndividualSettings(),
2892                    formatterConfig,
2893                    containers,
2894                    dndOriginContainer);
2895                if (!dndSettings.isEmpty()) {
2896                    CmsContainerElementBean dndElementBean = overrideSettings(element, dndSettings);
2897                    getSessionCache().setCacheContainerElement(dndElementBean.editorHash(), dndElementBean);
2898                    element = dndElementBean;
2899                    dndId = dndElementBean.editorHash();
2900                    Map<String, CmsContainerElementData> dndResults = getElements(
2901                        config,
2902                        page,
2903                        Arrays.asList(dndId),
2904                        uriParam,
2905                        detailContentId,
2906                        containers,
2907                        false,
2908                        null,
2909                        isDragMode,
2910                        locale);
2911                    result.putAll(dndResults);
2912                }
2913            }
2914
2915            CmsContainerElementData elementData = elemUtil.getElementData(page, element, containers);
2916            if (elementData == null) {
2917                continue;
2918            }
2919            getSessionCache().setCacheContainerElement(element.editorHash(), element);
2920            elementData.setDndId(dndId);
2921            result.put(entry.getKey(), elementData);
2922            if (elementData.isGroupContainer() || elementData.isInheritContainer()) {
2923                // this is a group-container
2924                CmsResource elementRes = cms.readResource(element.getId());
2925                List<CmsContainerElementBean> subElements = elementData.isGroupContainer()
2926                ? getGroupContainerElements(elementRes)
2927                : getInheritedElements(elementRes, locale, uriParam);
2928                // adding all sub-items to the elements data
2929                for (CmsContainerElementBean subElement : subElements) {
2930                    getSessionCache().setCacheContainerElement(subElement.editorHash(), subElement);
2931                    if (!ids.contains(subElement.editorHash())) {
2932                        CmsContainerElementData subItemData = elemUtil.getElementData(page, subElement, containers);
2933                        ids.add(subElement.editorHash());
2934                        result.put(subElement.editorHash(), subItemData);
2935                    }
2936                }
2937            }
2938            ids.add(element.editorHash());
2939        }
2940        for (CmsContainerElementData elementData : result.values()) {
2941            elementData.setGroup(foundGroups.contains(elementData.getClientId()));
2942        }
2943        return result;
2944    }
2945
2946    /**
2947     * Helper method for converting a CmsGroupContainer to a CmsGroupContainerBean when saving a group container.<p>
2948     *
2949     * @param groupContainer the group-container data
2950     * @param containerPage the container page
2951     * @param locale the locale to use
2952     *
2953     * @return the group-container bean
2954     */
2955    private CmsGroupContainerBean getGroupContainerBean(
2956        CmsGroupContainer groupContainer,
2957        CmsResource containerPage,
2958        String locale) {
2959
2960        CmsObject cms = getCmsObject();
2961        List<CmsContainerElementBean> elements = new ArrayList<CmsContainerElementBean>();
2962        for (CmsContainerElement elementData : groupContainer.getElements()) {
2963            try {
2964                if (elementData.isNew()) {
2965                    elementData = createNewElement(
2966                        containerPage.getStructureId(),
2967                        null,
2968                        elementData.getClientId(),
2969                        elementData.getResourceType(),
2970                        null,
2971                        locale);
2972                }
2973                CmsContainerElementBean element = getCachedElement(
2974                    elementData.getClientId(),
2975                    containerPage.getRootPath());
2976
2977                // make sure resource is readable,
2978                if (cms.existsResource(element.getId(), CmsResourceFilter.IGNORE_EXPIRATION)) {
2979                    elements.add(element);
2980                }
2981
2982            } catch (Exception e) {
2983                log(e.getLocalizedMessage(), e);
2984            }
2985        }
2986        return new CmsGroupContainerBean(
2987            groupContainer.getTitle(),
2988            groupContainer.getDescription(),
2989            elements,
2990            groupContainer.getTypes());
2991    }
2992
2993    /**
2994     * Returns the sub-elements of this group container resource.<p>
2995     *
2996     * @param resource the group container resource
2997     *
2998     * @return the sub-elements
2999     *
3000     * @throws CmsException if something goes wrong reading the resource
3001     */
3002    private List<CmsContainerElementBean> getGroupContainerElements(CmsResource resource) throws CmsException {
3003
3004        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(
3005            getCmsObject(),
3006            resource,
3007            getRequest());
3008        CmsGroupContainerBean groupContainer = xmlGroupContainer.getGroupContainer(getCmsObject());
3009        return groupContainer.getElements();
3010    }
3011
3012    /**
3013     * Gets the structure ids of group container elements from an unmarshalled group container for a single locale.<p>
3014     *
3015     * @param groupContainer the group container
3016     * @param locale the locale for which we want the element ids
3017     *
3018     * @return the group container's element ids for the given locale
3019     */
3020    private Set<CmsUUID> getGroupElementIds(CmsXmlGroupContainer groupContainer, Locale locale) {
3021
3022        Set<CmsUUID> idSet = new HashSet<CmsUUID>();
3023        CmsGroupContainerBean groupContainerBean = groupContainer.getGroupContainer(getCmsObject());
3024        if (groupContainerBean != null) {
3025            for (CmsContainerElementBean element : groupContainerBean.getElements()) {
3026                idSet.add(element.getId());
3027            }
3028        }
3029        return idSet;
3030
3031    }
3032
3033    /**
3034     * Returns the sub-elements of this inherit container resource.<p>
3035     *
3036     * @param resource the inherit container resource
3037     * @param locale the requested locale
3038     * @param uriParam the current URI
3039     *
3040     * @return the sub-elements
3041     *
3042     * @throws CmsException if something goes wrong reading the resource
3043     */
3044    private List<CmsContainerElementBean> getInheritedElements(CmsResource resource, Locale locale, String uriParam)
3045    throws CmsException {
3046
3047        CmsObject cms = getCmsObject();
3048        cms.getRequestContext().setLocale(locale);
3049        CmsInheritanceReferenceParser parser = new CmsInheritanceReferenceParser(cms);
3050        parser.parse(resource);
3051        CmsInheritanceReference ref = parser.getReference(locale);
3052        if (ref == null) {
3053            // new inheritance reference, return an empty list
3054            return Collections.emptyList();
3055        }
3056        String name = ref.getName();
3057        CmsADEManager adeManager = OpenCms.getADEManager();
3058        CmsInheritedContainerState result = adeManager.getInheritedContainerState(cms, cms.addSiteRoot(uriParam), name);
3059        return result.getElements(true);
3060    }
3061
3062    /**
3063     * Returns the data of the given elements.<p>
3064     *
3065     * @param listElements the list of element beans to retrieve the data for
3066     * @param containerpageUri the current URI
3067     * @param detailContentId the detail content structure id
3068     * @param containers the containers which exist on the container page
3069     * @param locale the locale to use
3070     *
3071     * @return the elements data
3072     *
3073     * @throws CmsException if something really bad happens
3074     */
3075    private List<CmsContainerElementData> getListElementsData(
3076        List<CmsContainerElementBean> listElements,
3077        String containerpageUri,
3078        CmsUUID detailContentId,
3079        Collection<CmsContainer> containers,
3080        Locale locale)
3081    throws CmsException {
3082
3083        CmsObject cms = getCmsObject();
3084        CmsElementUtil elemUtil = new CmsElementUtil(
3085            cms,
3086            containerpageUri,
3087            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(containerpageUri)),
3088            detailContentId,
3089            getRequest(),
3090            getResponse(),
3091            true,
3092            locale);
3093        CmsADESessionCache cache = getSessionCache();
3094        List<CmsContainerElementData> result = new ArrayList<CmsContainerElementData>();
3095        for (CmsContainerElementBean element : listElements) {
3096            // checking if resource exists
3097            if (cms.existsResource(element.getId(), CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFile())) {
3098                try {
3099                    CmsContainerElementBean clone = element.clone();
3100                    // Because ensureNewInstanceId() just generates a new UUID,
3101                    // the key for the element cache will not collide with anything else, so
3102                    // we do not need to set the SYSTEM::pageId setting for disambiguation here.
3103                    clone.ensureNewInstanceId();
3104                    cache.setCacheContainerElement(clone.editorHash(), clone);
3105                    CmsContainerElementData elementData = elemUtil.getElementData(
3106                        elemUtil.getPage(),
3107                        clone,
3108                        containers);
3109                    result.add(elementData);
3110                } catch (CmsVfsResourceNotFoundException e) {
3111                    // model group id not found, or other resources
3112                    LOG.info(e.getLocalizedMessage(), e);
3113                }
3114            }
3115        }
3116        return result;
3117    }
3118
3119    /**
3120     * Returns the lock information to the given resource.<p>
3121     *
3122     * @param resource the resource
3123     *
3124     * @return lock information, if the page is locked by another user
3125     *
3126     * @throws CmsException if something goes wrong reading the lock owner user
3127     */
3128    private String getLockInfo(CmsResource resource) throws CmsException {
3129
3130        CmsObject cms = getCmsObject();
3131        CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource);
3132        CmsLock lock = resourceUtil.getLock();
3133        String lockInfo = null;
3134        if (!lock.isLockableBy(cms.getRequestContext().getCurrentUser())) {
3135            if (lock.getType() == CmsLockType.PUBLISH) {
3136                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3137                    Messages.GUI_LOCKED_FOR_PUBLISH_0);
3138            } else {
3139                CmsUser lockOwner = cms.readUser(lock.getUserId());
3140                lockInfo = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
3141                    Messages.GUI_LOCKED_BY_1,
3142                    lockOwner.getFullName());
3143            }
3144        }
3145        return lockInfo;
3146    }
3147
3148    /**
3149     * Returns the element data for a new element not existing in the VFS yet.<p>
3150     *
3151     * @param resourceTypeName the resource type name
3152     * @param uriParam the request parameters
3153     * @param detailContentId the detail content structure id
3154     * @param containers the containers of the template
3155     * @param locale the current locale
3156     *
3157     * @return the element data
3158     *
3159     * @throws CmsException if something goes wrong
3160     */
3161    private CmsContainerElementData getNewElement(
3162        String resourceTypeName,
3163        String uriParam,
3164        CmsUUID detailContentId,
3165        Collection<CmsContainer> containers,
3166        Locale locale)
3167    throws CmsException {
3168
3169        CmsObject cms = getCmsObject();
3170        CmsElementUtil elemUtil = new CmsElementUtil(
3171            cms,
3172            uriParam,
3173            generateContainerPageForContainers(containers, cms.getRequestContext().addSiteRoot(uriParam)),
3174            detailContentId,
3175            getRequest(),
3176            getResponse(),
3177            true,
3178            locale);
3179        CmsADEConfigData configData = getConfigData(cms.getRequestContext().addSiteRoot(uriParam));
3180        CmsResourceTypeConfig typeConfig = configData.getResourceType(resourceTypeName);
3181        CmsContainerElementBean elementBean = CmsContainerElementBean.createElementForResourceType(
3182            cms,
3183            OpenCms.getResourceManager().getResourceType(resourceTypeName),
3184            "/",
3185            Collections.<String, String> emptyMap(),
3186            typeConfig.isCopyInModels(),
3187            locale);
3188        CmsContainerElementData data = elemUtil.getElementData(elemUtil.getPage(), elementBean, containers);
3189        data.setClientId(elementBean.editorHash());
3190        getSessionCache().setCacheContainerElement(resourceTypeName, elementBean);
3191        getSessionCache().setCacheContainerElement(elementBean.editorHash(), elementBean);
3192        return data;
3193    }
3194
3195    /**
3196     * Returns the no-edit reason for the given resource.<p>
3197     *
3198     * @param cms the current cms object
3199     * @param containerPage the resource
3200     *
3201     * @return the no-edit reason, empty if editing is allowed
3202     *
3203     * @throws CmsException is something goes wrong
3204     */
3205    private String getNoEditReason(CmsObject cms, CmsResource containerPage) throws CmsException {
3206
3207        return new CmsResourceUtil(cms, containerPage).getNoEditReason(
3208            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms),
3209            !cms.getRequestContext().getCurrentProject().isOnlineProject());
3210    }
3211
3212    /**
3213     * Returns the session cache.<p>
3214     *
3215     * @return the session cache
3216     */
3217    private CmsADESessionCache getSessionCache() {
3218
3219        if (m_sessionCache == null) {
3220            m_sessionCache = CmsADESessionCache.getCache(getRequest(), getCmsObject());
3221        }
3222        return m_sessionCache;
3223    }
3224
3225    /**
3226     * Returns the workplace settings of the current user.<p>
3227     *
3228     * @return the workplace settings
3229     */
3230    private CmsWorkplaceSettings getWorkplaceSettings() {
3231
3232        if (m_workplaceSettings == null) {
3233            m_workplaceSettings = CmsWorkplace.getWorkplaceSettings(getCmsObject(), getRequest());
3234        }
3235        return m_workplaceSettings;
3236    }
3237
3238    /**
3239     * Checks if results for the stored gallery data can be restored for the new gallery data.<p>
3240     *
3241     * @param originalGalleryData the original gallery data
3242     * @param data the new gallery data
3243     * @param search the search bean
3244     *
3245     * @return true if the original and new gallery data are compatible, i.e. we can restore the search results
3246     */
3247    private boolean hasCompatibleSearchData(
3248        CmsGalleryDataBean originalGalleryData,
3249        CmsGalleryDataBean data,
3250        CmsGallerySearchBean search) {
3251
3252        Set<String> originalUsableTypes = Sets.newHashSet();
3253        Set<String> usableTypes = Sets.newHashSet();
3254        for (CmsResourceTypeBean type : originalGalleryData.getTypes()) {
3255            if (!type.isDeactivated()) {
3256                originalUsableTypes.add(type.getType());
3257            }
3258        }
3259        for (CmsResourceTypeBean type : data.getTypes()) {
3260            if (!type.isDeactivated()) {
3261                usableTypes.add(type.getType());
3262            }
3263        }
3264        if (!usableTypes.containsAll(originalUsableTypes)) {
3265            return false;
3266        }
3267        return true;
3268    }
3269
3270    /**
3271     * Initializes request attributes using data from the RPC context.<p>
3272     *
3273     * @param context the RPC context
3274     */
3275    private void initRequestFromRpcContext(CmsContainerPageRpcContext context) {
3276
3277        if (context.getTemplateContext() != null) {
3278            getRequest().setAttribute(
3279                CmsTemplateContextManager.ATTR_RPC_CONTEXT_OVERRIDE,
3280                context.getTemplateContext());
3281        }
3282    }
3283
3284    /**
3285     * Internal method for saving a group container.<p>
3286     *
3287     * @param cms the cms context
3288     * @param pageStructureId the container page structure id
3289     * @param groupContainer the group container to save
3290     *
3291     * @return the container element representing the group container
3292     *
3293     * @throws CmsException if something goes wrong
3294     * @throws CmsXmlException if the XML processing goes wrong
3295     */
3296    private CmsPair<CmsContainerElement, List<CmsRemovedElementStatus>> internalSaveGroupContainer(
3297        CmsObject cms,
3298        CmsUUID pageStructureId,
3299        CmsGroupContainer groupContainer)
3300    throws CmsException, CmsXmlException {
3301
3302        ensureSession();
3303        CmsResource pageResource = getCmsObject().readResource(pageStructureId, CmsResourceFilter.IGNORE_EXPIRATION);
3304        CmsResource groupContainerResource = null;
3305        if (groupContainer.isNew()) {
3306            CmsADEConfigData config = getConfigData(pageResource.getRootPath());
3307            CmsResourceTypeConfig typeConfig = config.getResourceType(
3308                CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3309            groupContainerResource = typeConfig.createNewElement(getCmsObject(), pageResource.getRootPath());
3310            String resourceName = cms.getSitePath(groupContainerResource);
3311            groupContainer.setSitePath(resourceName);
3312            groupContainer.setClientId(groupContainerResource.getStructureId().toString());
3313        }
3314        if (groupContainerResource == null) {
3315            CmsUUID id = convertToServerId(groupContainer.getClientId());
3316            groupContainerResource = cms.readResource(id, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
3317        }
3318        CmsGroupContainerBean groupContainerBean = getGroupContainerBean(
3319            groupContainer,
3320            pageResource,
3321            Locale.ENGLISH.toString());
3322
3323        cms.lockResourceTemporary(groupContainerResource);
3324        CmsFile groupContainerFile = cms.readFile(groupContainerResource);
3325        Locale locale = Locale.ENGLISH;
3326        CmsXmlGroupContainer xmlGroupContainer = CmsXmlGroupContainerFactory.unmarshal(cms, groupContainerFile);
3327        Set<CmsUUID> oldElementIds = getGroupElementIds(xmlGroupContainer, locale);
3328        xmlGroupContainer.clearLocales();
3329        xmlGroupContainer.save(cms, groupContainerBean, locale);
3330        cms.unlockResource(groupContainerResource);
3331        Set<CmsUUID> newElementIds = getGroupElementIds(xmlGroupContainer, locale);
3332        Set<CmsUUID> removedElementIds = Sets.difference(oldElementIds, newElementIds);
3333        List<CmsRemovedElementStatus> deletionCandidateStatuses = new ArrayList<CmsRemovedElementStatus>();
3334        for (CmsUUID removedId : removedElementIds) {
3335            CmsRemovedElementStatus status = internalGetRemovedElementStatus(removedId, null, null);
3336            if (status.isDeletionCandidate()) {
3337                deletionCandidateStatuses.add(status);
3338            }
3339        }
3340        CmsContainerElement element = new CmsContainerElement();
3341        element.setClientId(groupContainerFile.getStructureId().toString());
3342        element.setSitePath(cms.getSitePath(groupContainerFile));
3343        element.setResourceType(CmsResourceTypeXmlContainerPage.GROUP_CONTAINER_TYPE_NAME);
3344        return CmsPair.create(element, deletionCandidateStatuses);
3345    }
3346
3347    /**
3348     * Checks if small elements in a container page should be initially editable.<p>
3349     *
3350     * @param request the current request
3351     * @param cms the current CMS context
3352     * @return true if small elements should be initially editable
3353     */
3354    private boolean isEditSmallElements(HttpServletRequest request, CmsObject cms) {
3355
3356        CmsUser user = cms.getRequestContext().getCurrentUser();
3357        String editSmallElementsStr = (String)(user.getAdditionalInfo().get(ADDINFO_EDIT_SMALL_ELEMENTS));
3358        if (editSmallElementsStr == null) {
3359            return true;
3360        } else {
3361            return Boolean.valueOf(editSmallElementsStr).booleanValue();
3362        }
3363    }
3364
3365    /**
3366     * Checks if a page is a model page.<p>
3367     *
3368     * @param cms the CMS context to use
3369     * @param containerPage the page to check
3370     *
3371     * @return true if the resource is a model page
3372     */
3373    private boolean isModelPage(CmsObject cms, CmsResource containerPage) {
3374
3375        CmsADEConfigData config = getConfigData(containerPage.getRootPath());
3376        for (CmsModelPageConfig modelConfig : config.getModelPages()) {
3377            if (modelConfig.getResource().getStructureId().equals(containerPage.getStructureId())) {
3378                return true;
3379            }
3380        }
3381        return false;
3382    }
3383
3384    /**
3385     * Saves the given containers to the container page resource.<p>
3386     *
3387     * @param cms the cms context
3388     * @param containerpage the container page resource
3389     * @param containerpageUri the container page site path
3390     * @param containers the container to save
3391     *
3392     * @throws CmsException if something goes wrong writing the file
3393     */
3394    private void saveContainers(
3395        CmsObject cms,
3396        CmsResource containerpage,
3397        String containerpageUri,
3398        List<CmsContainer> containers)
3399    throws CmsException {
3400
3401        CmsContainerPageBean page = generateContainerPageForContainers(containers, containerpage.getRootPath());
3402
3403        CmsModelGroupHelper modelHelper = new CmsModelGroupHelper(
3404            getCmsObject(),
3405            getConfigData(containerpage.getRootPath()),
3406            getSessionCache(),
3407            isEditingModelGroups(cms, containerpage));
3408        if (isEditingModelGroups(cms, containerpage)) {
3409            page = modelHelper.saveModelGroups(page, containerpage);
3410        } else {
3411            page = modelHelper.removeModelGroupContainers(page);
3412        }
3413        CmsXmlContainerPage xmlCnt = CmsXmlContainerPageFactory.unmarshal(
3414            cms,
3415            cms.readFile(containerpageUri, CmsResourceFilter.ignoreExpirationOffline(cms)));
3416        xmlCnt.save(cms, page);
3417    }
3418
3419    /**
3420     * Saves the inheritance group.<p>
3421     *
3422     * @param resource the inheritance group resource
3423     * @param inheritanceContainer the inherited group container data
3424     *
3425     * @throws CmsException if something goes wrong
3426     */
3427    private void saveInheritanceGroup(CmsResource resource, CmsInheritanceContainer inheritanceContainer)
3428    throws CmsException {
3429
3430        CmsObject cms = getCmsObject();
3431        CmsFile file = cms.readFile(resource);
3432        CmsXmlContent document = CmsXmlContentFactory.unmarshal(cms, file);
3433
3434        for (Locale docLocale : document.getLocales()) {
3435            document.removeLocale(docLocale);
3436        }
3437        Locale locale = Locale.ENGLISH;
3438        document.addLocale(cms, locale);
3439        document.getValue("Title", locale).setStringValue(cms, inheritanceContainer.getTitle());
3440        document.getValue("Description", locale).setStringValue(cms, inheritanceContainer.getDescription());
3441        document.getValue("ConfigName", locale).setStringValue(cms, inheritanceContainer.getName());
3442        byte[] content = document.marshal();
3443        file.setContents(content);
3444        cms.writeFile(file);
3445    }
3446
3447    /**
3448     * Update favorite or recent list with the given element.<p>
3449     *
3450     * @param containerPage the edited container page
3451     * @param clientId the elements client id
3452     * @param list the list to update
3453     *
3454     * @return the updated list
3455     *
3456     * @throws CmsException in case reading the element resource fails
3457     */
3458    private List<CmsContainerElementBean> updateFavoriteRecentList(
3459        CmsResource containerPage,
3460        String clientId,
3461        List<CmsContainerElementBean> list)
3462    throws CmsException {
3463
3464        try {
3465            CmsContainerElementBean element = getCachedElement(clientId, containerPage.getRootPath());
3466            Map<String, String> settings = new HashMap<String, String>(element.getIndividualSettings());
3467            String formatterID = null;
3468            Iterator<Entry<String, String>> entries = settings.entrySet().iterator();
3469            while (entries.hasNext()) {
3470                Entry<String, String> entry = entries.next();
3471                if (entry.getKey().startsWith(CmsFormatterConfig.FORMATTER_SETTINGS_KEY)) {
3472                    formatterID = entry.getValue();
3473                    entries.remove();
3474                }
3475            }
3476            settings.put(CmsFormatterConfig.FORMATTER_SETTINGS_KEY, formatterID);
3477            settings.put(SOURCE_CONTAINERPAGE_ID_SETTING, containerPage.getStructureId().toString());
3478            settings.remove(CmsContainerElement.SETTING_PAGE_ID);
3479            element = CmsContainerElementBean.cloneWithSettings(element, settings);
3480            Iterator<CmsContainerElementBean> listIt = list.iterator();
3481            while (listIt.hasNext()) {
3482                CmsContainerElementBean listElem = listIt.next();
3483                if (element.getInstanceId().equals(listElem.getInstanceId())) {
3484                    listIt.remove();
3485                }
3486            }
3487            list.add(0, element);
3488            return list;
3489        } catch (CmsVfsResourceNotFoundException e) {
3490            LOG.warn(e.getLocalizedMessage(), e);
3491            return list;
3492        }
3493    }
3494
3495}