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