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