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