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.gwt;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.ade.configuration.CmsGalleryDisabledTypesMode;
032import org.opencms.db.CmsResourceState;
033import org.opencms.file.CmsObject;
034import org.opencms.file.CmsProject;
035import org.opencms.file.CmsPropertyDefinition;
036import org.opencms.file.CmsResource;
037import org.opencms.file.CmsResourceFilter;
038import org.opencms.file.CmsUser;
039import org.opencms.file.CmsVfsResourceNotFoundException;
040import org.opencms.flex.CmsFlexController;
041import org.opencms.gwt.shared.CmsBroadcastMessage;
042import org.opencms.gwt.shared.CmsCategoryTreeEntry;
043import org.opencms.gwt.shared.CmsContextMenuEntryBean;
044import org.opencms.gwt.shared.CmsCoreData;
045import org.opencms.gwt.shared.CmsCoreData.AdeContext;
046import org.opencms.gwt.shared.CmsCoreData.UserInfo;
047import org.opencms.gwt.shared.CmsLockInfo;
048import org.opencms.gwt.shared.CmsResourceCategoryInfo;
049import org.opencms.gwt.shared.CmsReturnLinkInfo;
050import org.opencms.gwt.shared.CmsTinyMCEData;
051import org.opencms.gwt.shared.CmsUploadRestrictionInfo;
052import org.opencms.gwt.shared.CmsUserSettingsBean;
053import org.opencms.gwt.shared.CmsValidationQuery;
054import org.opencms.gwt.shared.CmsValidationResult;
055import org.opencms.gwt.shared.rpc.I_CmsCoreService;
056import org.opencms.i18n.CmsMessages;
057import org.opencms.lock.CmsLock;
058import org.opencms.main.CmsBroadcast;
059import org.opencms.main.CmsException;
060import org.opencms.main.CmsIllegalArgumentException;
061import org.opencms.main.CmsLog;
062import org.opencms.main.CmsSessionInfo;
063import org.opencms.main.OpenCms;
064import org.opencms.module.CmsModule;
065import org.opencms.relations.CmsCategory;
066import org.opencms.relations.CmsCategoryService;
067import org.opencms.security.CmsPasswordInfo;
068import org.opencms.security.CmsRole;
069import org.opencms.security.CmsRoleManager;
070import org.opencms.security.CmsSecurityException;
071import org.opencms.site.CmsSite;
072import org.opencms.ui.CmsUserIconHelper;
073import org.opencms.ui.CmsVaadinUtils;
074import org.opencms.ui.I_CmsDialogContext;
075import org.opencms.ui.I_CmsDialogContextWithAdeContext;
076import org.opencms.ui.actions.I_CmsADEAction;
077import org.opencms.ui.apps.A_CmsWorkplaceApp;
078import org.opencms.ui.apps.CmsFileExplorerConfiguration;
079import org.opencms.ui.components.CmsBasicDialog.DialogWidth;
080import org.opencms.ui.contextmenu.CmsContextMenuTreeBuilder;
081import org.opencms.ui.contextmenu.CmsMenuItemVisibilityMode;
082import org.opencms.ui.contextmenu.I_CmsContextMenuItem;
083import org.opencms.ui.dialogs.CmsEmbeddedDialogsUI;
084import org.opencms.util.CmsFileUtil;
085import org.opencms.util.CmsStringUtil;
086import org.opencms.util.CmsTreeNode;
087import org.opencms.util.CmsUUID;
088import org.opencms.workplace.CmsWorkplace;
089import org.opencms.workplace.CmsWorkplaceLoginHandler;
090import org.opencms.xml.containerpage.CmsADESessionCache;
091
092import java.util.ArrayList;
093import java.util.Collection;
094import java.util.Collections;
095import java.util.HashMap;
096import java.util.HashSet;
097import java.util.LinkedHashMap;
098import java.util.List;
099import java.util.Locale;
100import java.util.Map;
101import java.util.Map.Entry;
102import java.util.Set;
103
104import javax.servlet.http.HttpServletRequest;
105
106import org.apache.commons.collections.Buffer;
107import org.apache.commons.logging.Log;
108
109import com.vaadin.ui.Component;
110import com.vaadin.ui.Window;
111
112/**
113 * Provides general core services.<p>
114 *
115 * @since 8.0.0
116 *
117 * @see org.opencms.gwt.CmsCoreService
118 * @see org.opencms.gwt.shared.rpc.I_CmsCoreService
119 * @see org.opencms.gwt.shared.rpc.I_CmsCoreServiceAsync
120 */
121public class CmsCoreService extends CmsGwtService implements I_CmsCoreService {
122
123    /** The editor back-link URI. */
124    private static final String EDITOR_BACKLINK_URI = "/system/workplace/commons/editor-backlink.html";
125
126    /** The xml-content editor URI. */
127    private static final String EDITOR_URI = "/system/workplace/editors/editor.jsp";
128
129    /** The log instance for this class. */
130    private static final Log LOG = CmsLog.getLog(CmsCoreService.class);
131
132    /** Serialization uid. */
133    private static final long serialVersionUID = 5915848952948986278L;
134
135    /**
136     * Builds the tree structure for the given categories.<p>
137     *
138     * @param cms the current cms context
139     * @param categories the categories
140     *
141     * @return the tree root element
142     */
143    public static List<CmsCategoryTreeEntry> buildCategoryTree(CmsObject cms, List<CmsCategory> categories) {
144
145        List<CmsCategoryTreeEntry> result = new ArrayList<CmsCategoryTreeEntry>();
146        for (CmsCategory category : categories) {
147            CmsCategoryTreeEntry current = new CmsCategoryTreeEntry(category);
148            current.setSitePath(cms.getRequestContext().removeSiteRoot(category.getRootPath()));
149            String parentPath = CmsResource.getParentFolder(current.getPath());
150            CmsCategoryTreeEntry parent = null;
151            parent = findCategory(result, parentPath);
152            if (parent != null) {
153                parent.addChild(current);
154            } else {
155                result.add(current);
156            }
157        }
158        return result;
159    }
160
161    /**
162     * Helper method for getting the category beans for the given site path.<p>
163     *
164     * @param cms the CMS context to use
165     * @param sitePath the site path
166     * @return the list of category beans
167     *
168     * @throws CmsException if something goes wrong
169     */
170    public static List<CmsCategoryTreeEntry> getCategoriesForSitePathStatic(CmsObject cms, String sitePath)
171    throws CmsException {
172
173        return getCategoriesForSitePathStatic(cms, sitePath, null);
174    }
175
176    /**
177     * Helper method for getting the category beans for the given site path.<p>
178     *
179     * @param cms the CMS context to use
180     * @param sitePath the site path
181     * @param localCategoryRepositoryPath the categories for this repository are added separately
182     * @return the list of category beans
183     *
184     * @throws CmsException if something goes wrong
185     */
186    public static List<CmsCategoryTreeEntry> getCategoriesForSitePathStatic(
187        CmsObject cms,
188        String sitePath,
189        String localCategoryRepositoryPath)
190    throws CmsException {
191
192        List<CmsCategoryTreeEntry> result;
193        CmsCategoryService catService = CmsCategoryService.getInstance();
194        List<CmsCategory> categories;
195        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
196        // get the categories
197        if (null == localCategoryRepositoryPath) {
198            categories = catService.readCategories(cms, "", true, sitePath);
199            categories = catService.localizeCategories(cms, categories, wpLocale);
200            result = buildCategoryTree(cms, categories);
201        } else {
202            List<String> repositories = catService.getCategoryRepositories(cms, sitePath);
203            repositories.remove(localCategoryRepositoryPath);
204            categories = catService.readCategoriesForRepositories(cms, "", true, repositories);
205            categories = catService.localizeCategories(cms, categories, wpLocale);
206            result = buildCategoryTree(cms, categories);
207            categories = catService.readCategoriesForRepositories(
208                cms,
209                "",
210                true,
211                Collections.singletonList(localCategoryRepositoryPath));
212            categories = catService.localizeCategories(cms, categories, wpLocale);
213            List<CmsCategoryTreeEntry> localCategories = buildCategoryTree(cms, categories);
214            result.addAll(localCategories);
215        }
216
217        return result;
218    }
219
220    /**
221     * Returns the context menu entries for the given URI.<p>
222     *
223     * @param cms the cms context
224     * @param structureId the currently requested structure id
225     * @param context the ade context (sitemap or containerpage)
226     * @param params the additional parameters
227     *
228     * @return the context menu entries
229     */
230    public static List<CmsContextMenuEntryBean> getContextMenuEntries(
231        final CmsObject cms,
232        CmsUUID structureId,
233        final AdeContext context,
234        Map<String, String> params) {
235
236        Map<String, CmsContextMenuEntryBean> entries = new LinkedHashMap<String, CmsContextMenuEntryBean>();
237        try {
238            final List<CmsResource> resources;
239            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL.addRequireVisible());
240            // in case of sitemap editor check visibility with empty list
241            if (context.equals(AdeContext.sitemapeditor)) {
242                resources = Collections.emptyList();
243                cms.getRequestContext().setAttribute(I_CmsDialogContext.ATTR_SITEMAP_CONFIG_RESOURCE, resource);
244            } else {
245                resources = Collections.singletonList(resource);
246            }
247            Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
248            final Map<String, String> paramsFinal = params != null ? params : new HashMap<>();
249            // context to check item visibility
250            I_CmsDialogContext dcontext = new I_CmsDialogContextWithAdeContext() {
251
252                public void error(Throwable error) {
253
254                    // not supported
255                }
256
257                public void finish(CmsProject project, String siteRoot) {
258
259                    // not supported
260                }
261
262                public void finish(Collection<CmsUUID> result) {
263
264                    // not supported
265                }
266
267                public void focus(CmsUUID id) {
268
269                    // not supported
270                }
271
272                public AdeContext getAdeContext() {
273
274                    return context;
275                }
276
277                public List<CmsUUID> getAllStructureIdsInView() {
278
279                    return null;
280                }
281
282                public String getAppId() {
283
284                    return context.name();
285                }
286
287                public CmsObject getCms() {
288
289                    return cms;
290                }
291
292                public ContextType getContextType() {
293
294                    ContextType type;
295                    switch (context) {
296                        case pageeditor:
297                        case editprovider:
298                            type = ContextType.containerpageToolbar;
299                            break;
300                        case sitemapeditor:
301                            type = ContextType.sitemapToolbar;
302                            break;
303                        default:
304                            type = ContextType.fileTable;
305                    }
306                    return type;
307                }
308
309                public Map<String, String> getParameters() {
310
311                    return paramsFinal;
312                }
313
314                public List<CmsResource> getResources() {
315
316                    return resources;
317                }
318
319                public void navigateTo(String appId) {
320
321                    // not supported
322                }
323
324                public void onViewChange() {
325
326                    // not supported
327                }
328
329                public void reload() {
330
331                    // not supported
332                }
333
334                public void setWindow(Window window) {
335
336                    // not supported
337                }
338
339                public void start(String title, Component dialog) {
340
341                    // not supported
342                }
343
344                public void start(String title, Component dialog, DialogWidth width) {
345
346                    // not supported
347                }
348
349                public void updateUserInfo() {
350
351                    // not supported
352                }
353            };
354            CmsContextMenuTreeBuilder builder = new CmsContextMenuTreeBuilder(dcontext);
355            List<I_CmsContextMenuItem> items = new ArrayList<I_CmsContextMenuItem>();
356            CmsTreeNode<I_CmsContextMenuItem> root = builder.buildAll(
357                OpenCms.getWorkplaceAppManager().getMenuItemProvider().getMenuItems());
358            for (CmsTreeNode<I_CmsContextMenuItem> child : root.getChildren()) {
359                child.addDataInPreOrder(items);
360            }
361            Map<String, List<CmsContextMenuEntryBean>> submenus = new HashMap<String, List<CmsContextMenuEntryBean>>();
362            for (I_CmsContextMenuItem item : items) {
363                if (!item.isLeafItem()) {
364                    CmsMenuItemVisibilityMode visibility = item.getVisibility(dcontext);
365                    entries.put(
366                        item.getId(),
367                        new CmsContextMenuEntryBean(
368                            visibility.isActive(),
369                            true,
370                            null,
371                            item.getTitle(locale),
372                            null,
373                            CmsStringUtil.isEmptyOrWhitespaceOnly(visibility.getMessageKey())
374                            ? null
375                            : OpenCms.getWorkplaceManager().getMessages(locale).getString(visibility.getMessageKey()),
376                            false,
377                            new ArrayList<CmsContextMenuEntryBean>()));
378
379                } else if ((item instanceof I_CmsADEAction) && ((I_CmsADEAction)item).isAdeSupported()) {
380                    CmsMenuItemVisibilityMode visibility = item.getVisibility(dcontext);
381
382                    String jspPath = ((I_CmsADEAction)item).getJspPath();
383                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(jspPath)) {
384                        jspPath = OpenCms.getLinkManager().substituteLink(cms, jspPath);
385                    }
386                    CmsContextMenuEntryBean itemBean = new CmsContextMenuEntryBean(
387                        visibility.isActive(),
388                        true,
389                        jspPath,
390                        item.getTitle(locale),
391                        ((I_CmsADEAction)item).getCommandClassName(),
392                        CmsStringUtil.isEmptyOrWhitespaceOnly(visibility.getMessageKey())
393                        ? null
394                        : OpenCms.getWorkplaceManager().getMessages(locale).getString(visibility.getMessageKey()),
395                        false,
396                        null);
397                    Map<String, String> clientParams = ((I_CmsADEAction)item).getParams();
398                    if (clientParams != null) {
399                        clientParams = new HashMap<String, String>(clientParams);
400                        for (Entry<String, String> param : clientParams.entrySet()) {
401                            String value = CmsVfsService.prepareFileNameForEditor(cms, resource, param.getValue());
402                            param.setValue(value);
403                        }
404                        itemBean.setParams(clientParams);
405                    }
406                    entries.put(item.getId(), itemBean);
407                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(item.getParentId())) {
408                        List<CmsContextMenuEntryBean> submenu;
409                        if (submenus.containsKey(item.getParentId())) {
410                            submenu = submenus.get(item.getParentId());
411                        } else {
412                            submenu = new ArrayList<CmsContextMenuEntryBean>();
413                            submenus.put(item.getParentId(), submenu);
414                        }
415                        submenu.add(itemBean);
416                    }
417                }
418            }
419            List<CmsContextMenuEntryBean> result = new ArrayList<CmsContextMenuEntryBean>();
420            for (I_CmsContextMenuItem item : items) {
421                if (entries.containsKey(item.getId())) {
422                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(item.getParentId())) {
423                        if (entries.containsKey(item.getParentId())) {
424                            CmsContextMenuEntryBean parent = entries.get(item.getParentId());
425                            if (parent.getSubMenu() != null) {
426                                parent.getSubMenu().add(entries.get(item.getId()));
427                            }
428                        }
429                    } else {
430                        result.add(entries.get(item.getId()));
431                    }
432                }
433            }
434            return result;
435        } catch (CmsException e) {
436            // ignore, the user probably has not enough permissions to read the resource
437            LOG.debug(e.getLocalizedMessage(), e);
438        }
439        return Collections.emptyList();
440    }
441
442    /**
443     * Returns the file explorer link prefix. Append resource site path for complete link.<p>
444     *
445     * @param cms the cms context
446     * @param siteRoot the site root
447     *
448     * @return the file explorer link prefix
449     */
450    public static String getFileExplorerLink(CmsObject cms, String siteRoot) {
451
452        return CmsVaadinUtils.getWorkplaceLink(
453            CmsFileExplorerConfiguration.APP_ID,
454            cms.getRequestContext().getCurrentProject().getUuid()
455                + A_CmsWorkplaceApp.PARAM_SEPARATOR
456                + siteRoot
457                + A_CmsWorkplaceApp.PARAM_SEPARATOR);
458    }
459
460    /**
461     * Returns the workplace link.<p>
462     *
463     * @param cms the cms context
464     * @param structureId the structure id of the current resource
465     *
466     * @return the workplace link
467     */
468    public static String getVaadinWorkplaceLink(CmsObject cms, CmsUUID structureId) {
469
470        String resourceRootFolder = null;
471
472        if (structureId != null) {
473            try {
474                resourceRootFolder = CmsResource.getFolderPath(
475                    cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED).getRootPath());
476            } catch (CmsException e) {
477                LOG.debug("Error reading resource for workplace link.", e);
478            }
479        }
480        if (resourceRootFolder == null) {
481            resourceRootFolder = cms.getRequestContext().getSiteRoot();
482        }
483        return getVaadinWorkplaceLink(cms, resourceRootFolder);
484
485    }
486
487    /**
488     * Returns the workplace link.<p>
489     *
490     * @param cms the cms context
491     * @param resourceRootFolder the resource folder root path
492     *
493     * @return the workplace link
494     */
495    public static String getVaadinWorkplaceLink(CmsObject cms, String resourceRootFolder) {
496
497        CmsSite site = OpenCms.getSiteManager().getSiteForRootPath(resourceRootFolder);
498        String siteRoot = site != null
499        ? site.getSiteRoot()
500        : OpenCms.getSiteManager().startsWithShared(resourceRootFolder)
501        ? OpenCms.getSiteManager().getSharedFolder()
502        : "";
503        String sitePath = resourceRootFolder.substring(siteRoot.length());
504        String link = getFileExplorerLink(cms, siteRoot) + sitePath;
505        return link;
506    }
507
508    /**
509     * Internal helper method for getting a validation service.<p>
510     *
511     * @param name the class name of the validation service
512     *
513     * @return the validation service
514     *
515     * @throws CmsException if something goes wrong
516     */
517    public static I_CmsValidationService getValidationService(String name) throws CmsException {
518
519        try {
520            Class<?> cls = Class.forName(name, false, I_CmsValidationService.class.getClassLoader());
521            if (!I_CmsValidationService.class.isAssignableFrom(cls)) {
522                throw new CmsIllegalArgumentException(
523                    Messages.get().container(Messages.ERR_VALIDATOR_INCORRECT_TYPE_1, name));
524            }
525            return (I_CmsValidationService)cls.newInstance();
526        } catch (ClassNotFoundException e) {
527            throw new CmsException(Messages.get().container(Messages.ERR_VALIDATOR_INSTANTIATION_FAILED_1, name), e);
528        } catch (InstantiationException e) {
529            throw new CmsException(Messages.get().container(Messages.ERR_VALIDATOR_INSTANTIATION_FAILED_1, name), e);
530        } catch (IllegalAccessException e) {
531            throw new CmsException(Messages.get().container(Messages.ERR_VALIDATOR_INSTANTIATION_FAILED_1, name), e);
532        }
533    }
534
535    /**
536     * Instantiates a class given its name using its default constructor.<p>
537     *
538     * Also checks whether the class with the given name is the subclass of another class/interface.<p>
539     *
540     *
541     * @param <T> the type of the interface/class passed as a parameter
542     *
543     * @param anInterface the interface or class against which the class should be checked
544     * @param className the name of the class
545     * @return a new instance of the class
546     *
547     * @throws CmsException if the instantiation fails
548     */
549    public static <T> T instantiate(Class<T> anInterface, String className) throws CmsException {
550
551        try {
552            Class<?> cls = Class.forName(className, false, anInterface.getClassLoader());
553            if (!anInterface.isAssignableFrom(cls)) {
554                // class was found, but does not implement the interface
555                throw new CmsIllegalArgumentException(
556                    Messages.get().container(
557                        Messages.ERR_INSTANTIATION_INCORRECT_TYPE_2,
558                        className,
559                        anInterface.getName()));
560            }
561
562            // we use another variable so we don't have to put the @SuppressWarnings on the method itself
563            @SuppressWarnings("unchecked")
564            Class<T> typedClass = (Class<T>)cls;
565            return typedClass.newInstance();
566        } catch (ClassNotFoundException e) {
567            throw new CmsException(Messages.get().container(Messages.ERR_INSTANTIATION_FAILED_1, className), e);
568        } catch (InstantiationException e) {
569            throw new CmsException(Messages.get().container(Messages.ERR_INSTANTIATION_FAILED_1, className), e);
570        } catch (IllegalAccessException e) {
571            throw new CmsException(Messages.get().container(Messages.ERR_INSTANTIATION_FAILED_1, className), e);
572        }
573    }
574
575    /**
576     * Implementation method for getting the link for a given return code.<p>
577     *
578     * @param cms the CMS context
579     * @param returnCode the return code
580     * @return the link for the return code
581     *
582     * @throws CmsException if something goes wrong
583     */
584    public static CmsReturnLinkInfo internalGetLinkForReturnCode(CmsObject cms, String returnCode) throws CmsException {
585
586        if (CmsUUID.isValidUUID(returnCode)) {
587            try {
588                CmsResource pageRes = cms.readResource(new CmsUUID(returnCode), CmsResourceFilter.IGNORE_EXPIRATION);
589                return new CmsReturnLinkInfo(
590                    OpenCms.getLinkManager().substituteLink(cms, pageRes),
591                    CmsReturnLinkInfo.Status.ok);
592            } catch (CmsVfsResourceNotFoundException e) {
593                LOG.debug(e.getLocalizedMessage(), e);
594                return new CmsReturnLinkInfo(null, CmsReturnLinkInfo.Status.notfound);
595            }
596        } else {
597            int colonIndex = returnCode.indexOf(':');
598            if (colonIndex >= 0) {
599                String before = returnCode.substring(0, colonIndex);
600                String after = returnCode.substring(colonIndex + 1);
601
602                if (CmsUUID.isValidUUID(before) && CmsUUID.isValidUUID(after)) {
603                    try {
604                        CmsUUID pageId = new CmsUUID(before);
605                        CmsUUID detailId = new CmsUUID(after);
606                        CmsResource pageRes = cms.readResource(pageId);
607                        CmsResource folder = pageRes.isFolder()
608                        ? pageRes
609                        : cms.readParentFolder(pageRes.getStructureId());
610                        String pageLink = OpenCms.getLinkManager().substituteLink(cms, folder);
611                        CmsResource detailRes = cms.readResource(detailId);
612                        String detailName = cms.getDetailName(
613                            detailRes,
614                            cms.getRequestContext().getLocale(),
615                            OpenCms.getLocaleManager().getDefaultLocales());
616                        String link = CmsFileUtil.removeTrailingSeparator(pageLink) + "/" + detailName;
617                        return new CmsReturnLinkInfo(link, CmsReturnLinkInfo.Status.ok);
618                    } catch (CmsVfsResourceNotFoundException e) {
619                        LOG.debug(e.getLocalizedMessage(), e);
620                        return new CmsReturnLinkInfo(null, CmsReturnLinkInfo.Status.notfound);
621
622                    }
623                }
624            }
625            throw new IllegalArgumentException("return code has wrong format");
626        }
627    }
628
629    /**
630     * Fetches the core data.<p>
631     *
632     * @param request the current request
633     *
634     * @return the core data
635     */
636    public static CmsCoreData prefetch(HttpServletRequest request) {
637
638        CmsCoreService srv = new CmsCoreService();
639        srv.setCms(CmsFlexController.getCmsObject(request));
640        srv.setRequest(request);
641        CmsCoreData result = null;
642        try {
643            result = srv.prefetch();
644        } finally {
645            srv.clearThreadStorage();
646        }
647        return result;
648    }
649
650    /**
651     * FInds a category in the given tree.<p>
652     *
653     * @param tree the the tree to search in
654     * @param path the path to search for
655     *
656     * @return the category with the given path or <code>null</code> if not found
657     */
658    private static CmsCategoryTreeEntry findCategory(List<CmsCategoryTreeEntry> tree, String path) {
659
660        if (path == null) {
661            return null;
662        }
663        // we assume that the category to find is descendant of tree
664        List<CmsCategoryTreeEntry> children = tree;
665        boolean found = true;
666        while (found) {
667            if (children == null) {
668                return null;
669            }
670            // since the categories are sorted it is faster to go backwards
671            found = false;
672            for (int i = children.size() - 1; i >= 0; i--) {
673                CmsCategoryTreeEntry child = children.get(i);
674                if (path.equals(child.getPath())) {
675                    return child;
676                }
677                if (path.startsWith(child.getPath())) {
678                    children = child.getChildren();
679                    found = true;
680                    break;
681                }
682            }
683        }
684        return null;
685    }
686
687    /**
688     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#changePassword(java.lang.String, java.lang.String, java.lang.String)
689     */
690    public String changePassword(String oldPassword, String newPassword, String newPasswordConfirm)
691    throws CmsRpcException {
692
693        CmsObject cms = getCmsObject();
694        CmsPasswordInfo passwordBean = new CmsPasswordInfo(cms);
695        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
696        try {
697            passwordBean.setCurrentPwd(oldPassword);
698            passwordBean.setNewPwd(newPassword);
699            passwordBean.setConfirmation(newPasswordConfirm);
700            passwordBean.applyChanges();
701            return null;
702        } catch (CmsSecurityException e) {
703            LOG.error(e.getLocalizedMessage(), e);
704            return e.getMessageContainer().key(wpLocale);
705        } catch (CmsIllegalArgumentException e) {
706            LOG.warn(e.getLocalizedMessage(), e);
707            return e.getMessageContainer().key(wpLocale);
708        } catch (Exception e) {
709            error(e);
710            return null; // will never be executed
711        }
712    }
713
714    /**
715     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#createUUID()
716     */
717    public CmsUUID createUUID() {
718
719        return new CmsUUID();
720    }
721
722    /**
723     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getBroadcast()
724     */
725    @SuppressWarnings("unchecked")
726    public List<CmsBroadcastMessage> getBroadcast() {
727
728        setBroadcastPoll();
729        Set<CmsBroadcast> repeatedBroadcasts = new HashSet<CmsBroadcast>();
730        OpenCms.getWorkplaceManager().checkWorkplaceRequest(getRequest(), getCmsObject());
731        CmsSessionInfo sessionInfo = OpenCms.getSessionManager().getSessionInfo(getRequest().getSession());
732        if (sessionInfo == null) {
733            return null;
734        }
735        String sessionId = sessionInfo.getSessionId().toString();
736        Buffer messageQueue = OpenCms.getSessionManager().getBroadcastQueue(sessionId);
737        if (!messageQueue.isEmpty()) {
738            CmsMessages messages = org.opencms.workplace.Messages.get().getBundle(
739                OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()));
740            List<CmsBroadcastMessage> result = new ArrayList<CmsBroadcastMessage>();
741            // the user has pending messages, display them all
742            while (!messageQueue.isEmpty()) {
743
744                CmsBroadcast broadcastMessage = (CmsBroadcast)messageQueue.remove();
745                if ((broadcastMessage.getLastDisplay()
746                    + CmsBroadcast.DISPLAY_AGAIN_TIME) < System.currentTimeMillis()) {
747                    CmsUserIconHelper helper = OpenCms.getWorkplaceAppManager().getUserIconHelper();
748                    String picPath = "";
749                    if (broadcastMessage.getUser() != null) {
750                        picPath = helper.getSmallIconPath(getCmsObject(), broadcastMessage.getUser());
751                    }
752                    CmsBroadcastMessage message = new CmsBroadcastMessage(
753                        broadcastMessage.getUser() != null
754                        ? broadcastMessage.getUser().getName()
755                        : messages.key(org.opencms.workplace.Messages.GUI_LABEL_BROADCAST_FROM_SYSTEM_0),
756                        picPath,
757                        messages.getDateTime(broadcastMessage.getSendTime()),
758                        broadcastMessage.getMessage());
759                    result.add(message);
760                    if (broadcastMessage.isRepeat()) {
761                        repeatedBroadcasts.add(broadcastMessage.withLastDisplay(System.currentTimeMillis()));
762                    }
763                } else {
764                    repeatedBroadcasts.add(broadcastMessage);
765                }
766            }
767            if (!repeatedBroadcasts.isEmpty()) {
768                for (CmsBroadcast broadcast : repeatedBroadcasts) {
769                    messageQueue.add(broadcast);
770                }
771            }
772            return result;
773        }
774        // no message pending, return null
775        return null;
776    }
777
778    /**
779     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getCategories(java.lang.String, boolean, java.lang.String)
780     */
781    public List<CmsCategoryTreeEntry> getCategories(String fromPath, boolean includeSubCats, String refPath)
782    throws CmsRpcException {
783
784        return getCategories(fromPath, includeSubCats, refPath, false);
785    }
786
787    /**
788     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getCategories(java.lang.String, boolean, java.lang.String, boolean)
789     */
790    public List<CmsCategoryTreeEntry> getCategories(
791        String fromPath,
792        boolean includeSubCats,
793        String refPath,
794        boolean showWithRepositories)
795    throws CmsRpcException {
796
797        CmsObject cms = getCmsObject();
798        CmsCategoryService catService = CmsCategoryService.getInstance();
799
800        List<String> repositories = new ArrayList<String>();
801        repositories.addAll(catService.getCategoryRepositories(getCmsObject(), refPath));
802
803        List<CmsCategoryTreeEntry> result = null;
804        try {
805            // get the categories
806            List<CmsCategory> categories = catService.readCategoriesForRepositories(
807                cms,
808                fromPath,
809                includeSubCats,
810                repositories,
811                showWithRepositories);
812            categories = catService.localizeCategories(
813                cms,
814                categories,
815                OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
816            result = buildCategoryTree(cms, categories);
817        } catch (Throwable e) {
818            error(e);
819        }
820        return result;
821    }
822
823    /**
824     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getCategoriesForSitePath(java.lang.String)
825     */
826    public List<CmsCategoryTreeEntry> getCategoriesForSitePath(String sitePath) throws CmsRpcException {
827
828        List<CmsCategoryTreeEntry> result = null;
829        CmsObject cms = getCmsObject();
830        try {
831            result = getCategoriesForSitePathStatic(cms, sitePath);
832        } catch (Throwable e) {
833            error(e);
834        }
835        return result;
836    }
837
838    /**
839     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getCategoryInfo(org.opencms.util.CmsUUID)
840     */
841    public CmsResourceCategoryInfo getCategoryInfo(CmsUUID structureId) throws CmsRpcException {
842
843        CmsObject cms = getCmsObject();
844        CmsCategoryService catService = CmsCategoryService.getInstance();
845        try {
846            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ignoreExpirationOffline(cms));
847            List<CmsCategory> categories = catService.readResourceCategories(cms, resource);
848            List<String> currentCategories = new ArrayList<String>();
849            for (CmsCategory category : categories) {
850                currentCategories.add(category.getPath());
851            }
852            return new CmsResourceCategoryInfo(
853                structureId,
854                CmsVfsService.getPageInfoWithLock(cms, resource),
855                currentCategories,
856                getCategories(
857                    null,
858                    true,
859                    cms.getSitePath(resource),
860                    OpenCms.getWorkplaceManager().isDisplayCategoriesByRepository()));
861        } catch (CmsException e) {
862            error(e);
863        }
864        return null;
865    }
866
867    /**
868     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getContextMenuEntries(org.opencms.util.CmsUUID, org.opencms.gwt.shared.CmsCoreData.AdeContext)
869     */
870    public List<CmsContextMenuEntryBean> getContextMenuEntries(CmsUUID structureId, AdeContext context)
871    throws CmsRpcException {
872
873        List<CmsContextMenuEntryBean> result = null;
874        try {
875            result = getContextMenuEntries(getCmsObject(), structureId, context, new HashMap<>());
876        } catch (Throwable e) {
877            error(e);
878        }
879        return result;
880    }
881
882    /**
883     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getContextMenuEntries(org.opencms.util.CmsUUID, org.opencms.gwt.shared.CmsCoreData.AdeContext)
884     */
885    public List<CmsContextMenuEntryBean> getContextMenuEntries(
886        CmsUUID structureId,
887        AdeContext context,
888        Map<String, String> params)
889    throws CmsRpcException {
890
891        List<CmsContextMenuEntryBean> result = null;
892        try {
893            result = getContextMenuEntries(getCmsObject(), structureId, context, params);
894        } catch (Throwable e) {
895            error(e);
896        }
897        return result;
898    }
899
900    /**
901     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getLinkForReturnCode(java.lang.String)
902     */
903    public CmsReturnLinkInfo getLinkForReturnCode(String returnCode) throws CmsRpcException {
904
905        try {
906            return internalGetLinkForReturnCode(getCmsObject(), returnCode);
907        } catch (Throwable e) {
908            error(e);
909            return null;
910
911        }
912    }
913
914    /**
915     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getResourceState(org.opencms.util.CmsUUID)
916     */
917    public CmsResourceState getResourceState(CmsUUID structureId) throws CmsRpcException {
918
919        CmsObject cms = getCmsObject();
920        CmsResourceState result = null;
921        try {
922            try {
923                CmsResource res = cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
924                result = res.getState();
925            } catch (CmsVfsResourceNotFoundException e) {
926                LOG.debug(e.getLocalizedMessage(), e);
927                result = CmsResourceState.STATE_DELETED;
928            }
929        } catch (CmsException e) {
930            error(e);
931        }
932        return result;
933    }
934
935    /**
936     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getUniqueFileName(java.lang.String, java.lang.String)
937     */
938    public String getUniqueFileName(String parentFolder, String baseName) {
939
940        return OpenCms.getResourceManager().getNameGenerator().getUniqueFileName(
941            getCmsObject(),
942            parentFolder,
943            baseName);
944    }
945
946    /**
947     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getUserInfo()
948     */
949    public UserInfo getUserInfo() {
950
951        CmsObject cms = getCmsObject();
952        CmsRoleManager roleManager = OpenCms.getRoleManager();
953        boolean isAdmin = roleManager.hasRole(cms, CmsRole.ADMINISTRATOR);
954        boolean isDeveloper = roleManager.hasRole(cms, CmsRole.DEVELOPER);
955        boolean isCategoryManager = roleManager.hasRole(cms, CmsRole.CATEGORY_EDITOR);
956        boolean isWorkplaceUser = roleManager.hasRole(cms, CmsRole.WORKPLACE_USER);
957        UserInfo userInfo = new UserInfo(
958            cms.getRequestContext().getCurrentUser().getName(),
959            OpenCms.getWorkplaceAppManager().getUserIconHelper().getSmallIconPath(
960                cms,
961                cms.getRequestContext().getCurrentUser()),
962            isAdmin,
963            isDeveloper,
964            isCategoryManager,
965            isWorkplaceUser,
966            cms.getRequestContext().getCurrentUser().isManaged());
967        return userInfo;
968    }
969
970    /**
971     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getWorkplaceLink(org.opencms.util.CmsUUID)
972     */
973    public String getWorkplaceLink(CmsUUID structureId) throws CmsRpcException {
974
975        String result = null;
976        CmsObject cms = getCmsObject();
977        try {
978            String resourceRootFolder = structureId != null
979            ? CmsResource.getFolderPath(
980                cms.readResource(structureId, CmsResourceFilter.ALL.addRequireVisible()).getRootPath())
981            : cms.getRequestContext().getSiteRoot();
982            result = getVaadinWorkplaceLink(cms, resourceRootFolder);
983        } catch (Exception e) {
984            error(e);
985        }
986        return result;
987    }
988
989    /**
990     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#getWorkplaceLinkForPath(java.lang.String)
991     */
992    public String getWorkplaceLinkForPath(String path) throws CmsRpcException {
993
994        CmsObject cms = getCmsObject();
995        try {
996            CmsObject workCms = cms;
997            if (path.startsWith("/sites/")) {
998                workCms = OpenCms.initCmsObject(cms);
999                workCms.getRequestContext().setSiteRoot("");
1000            }
1001            String currentPath = CmsResource.getParentFolder(path);
1002            CmsResource folder = null;
1003            try {
1004                folder = workCms.readResource(currentPath, CmsResourceFilter.IGNORE_EXPIRATION.addRequireVisible());
1005            } catch (CmsVfsResourceNotFoundException | CmsSecurityException e) {
1006                throw new CmsException(Messages.get().container(Messages.ERR_COULD_NOT_FIND_PARENT_FOLDER_1, path), e);
1007            }
1008            return getVaadinWorkplaceLink(cms, folder.getRootPath());
1009        } catch (Exception e) {
1010            error(e);
1011            return null;
1012        }
1013    }
1014
1015    /**
1016     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#loadUserSettings()
1017     */
1018    public CmsUserSettingsBean loadUserSettings() throws CmsRpcException {
1019
1020        CmsObject cms = getCmsObject();
1021        CmsClientUserSettingConverter converter = new CmsClientUserSettingConverter(cms, getRequest(), getResponse());
1022        try {
1023            return converter.loadSettings();
1024        } catch (Exception e) {
1025            error(e);
1026            return null;
1027        }
1028    }
1029
1030    /**
1031     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#lockIfExists(java.lang.String)
1032     */
1033    public String lockIfExists(String sitePath) throws CmsRpcException {
1034
1035        CmsObject cms = getCmsObject();
1036        String errorMessage = null;
1037        try {
1038            if (cms.existsResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION)) {
1039
1040                try {
1041                    ensureLock(cms.readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION));
1042                } catch (CmsException e) {
1043                    errorMessage = e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1044                }
1045
1046            } else {
1047                // check if parent folder may be locked by the current user
1048                String parentFolder = CmsResource.getParentFolder(sitePath);
1049                while ((parentFolder != null)
1050                    && !cms.existsResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION)) {
1051                    parentFolder = CmsResource.getParentFolder(parentFolder);
1052                }
1053                if (parentFolder != null) {
1054                    CmsResource ancestorFolder = cms.readResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION);
1055                    CmsUser user = cms.getRequestContext().getCurrentUser();
1056                    CmsLock lock = cms.getLock(ancestorFolder);
1057                    if (!lock.isLockableBy(user)) {
1058                        errorMessage = "Can not lock parent folder '" + parentFolder + "'.";
1059                    }
1060                } else {
1061                    errorMessage = "Can not access any parent folder.";
1062                }
1063            }
1064        } catch (Throwable e) {
1065            error(e);
1066        }
1067
1068        return errorMessage;
1069    }
1070
1071    /**
1072     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#lockIfExists(java.lang.String, long)
1073     */
1074    public String lockIfExists(String sitePath, long loadTime) throws CmsRpcException {
1075
1076        CmsObject cms = getCmsObject();
1077        String errorMessage = null;
1078        try {
1079            if (cms.existsResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION)) {
1080
1081                try {
1082                    CmsResource resource = cms.readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
1083                    if (resource.getDateLastModified() > loadTime) {
1084                        // the resource has been changed since it was loaded
1085                        CmsUser user = null;
1086                        try {
1087                            user = cms.readUser(resource.getUserLastModified());
1088                        } catch (CmsException e) {
1089                            // ignore
1090                        }
1091                        CmsMessages messages = Messages.get().getBundle(
1092                            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1093                        return user != null
1094                        ? messages.key(
1095                            Messages.ERR_LOCKING_MODIFIED_RESOURCE_2,
1096                            resource.getRootPath(),
1097                            user.getFullName())
1098                        : messages.key(Messages.ERR_LOCKING_MODIFIED_RESOURCE_1, resource.getRootPath());
1099                    }
1100                    ensureLock(resource);
1101                } catch (CmsException e) {
1102                    errorMessage = e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1103                }
1104
1105            } else {
1106                // check if parent folder may be locked by the current user
1107                String parentFolder = CmsResource.getParentFolder(sitePath);
1108                while ((parentFolder != null)
1109                    && !cms.existsResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION)) {
1110                    parentFolder = CmsResource.getParentFolder(parentFolder);
1111                }
1112                if (parentFolder != null) {
1113                    CmsResource ancestorFolder = cms.readResource(parentFolder, CmsResourceFilter.IGNORE_EXPIRATION);
1114                    CmsUser user = cms.getRequestContext().getCurrentUser();
1115                    CmsLock lock = cms.getLock(ancestorFolder);
1116                    if (!lock.isLockableBy(user)) {
1117                        errorMessage = "Can not lock parent folder '" + parentFolder + "'.";
1118                    }
1119                } else {
1120                    errorMessage = "Can not access any parent folder.";
1121                }
1122            }
1123        } catch (Throwable e) {
1124            error(e);
1125        }
1126
1127        return errorMessage;
1128    }
1129
1130    /**
1131     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#lockTemp(org.opencms.util.CmsUUID)
1132     */
1133    public String lockTemp(CmsUUID structureId) throws CmsRpcException {
1134
1135        CmsObject cms = getCmsObject();
1136        try {
1137            try {
1138                ensureLock(structureId);
1139            } catch (CmsException e) {
1140                return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1141            }
1142        } catch (Throwable e) {
1143            error(e);
1144        }
1145        return null;
1146    }
1147
1148    /**
1149     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#lockTemp(org.opencms.util.CmsUUID, long)
1150     */
1151    public String lockTemp(CmsUUID structureId, long loadTime) throws CmsRpcException {
1152
1153        CmsObject cms = getCmsObject();
1154        try {
1155            try {
1156                CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1157                if (resource.getDateLastModified() > loadTime) {
1158                    // the resource has been changed since it was loaded
1159                    CmsUser user = null;
1160                    try {
1161                        user = cms.readUser(resource.getUserLastModified());
1162                    } catch (CmsException e) {
1163                        // ignore
1164                    }
1165                    CmsMessages messages = Messages.get().getBundle(
1166                        OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1167                    return user != null
1168                    ? messages.key(Messages.ERR_LOCKING_MODIFIED_RESOURCE_2, resource.getRootPath(), user.getFullName())
1169                    : messages.key(Messages.ERR_LOCKING_MODIFIED_RESOURCE_1, resource.getRootPath());
1170                }
1171                ensureLock(resource);
1172            } catch (CmsException e) {
1173                return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1174            }
1175        } catch (Throwable e) {
1176            error(e);
1177        }
1178        return null;
1179    }
1180
1181    /**
1182     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#prefetch()
1183     */
1184    public CmsCoreData prefetch() {
1185
1186        CmsObject cms = getCmsObject();
1187        String navigationUri = cms.getRequestContext().getUri();
1188        CmsADEConfigData sitemapConfig = OpenCms.getADEManager().lookupConfigurationWithCache(
1189            cms,
1190            cms.getRequestContext().getRootUri());
1191        boolean toolbarVisible = CmsADESessionCache.getCache(getRequest(), getCmsObject()).isToolbarVisible();
1192        boolean isShowHelp = OpenCms.getADEManager().isShowEditorHelp(cms);
1193
1194        CmsUUID structureId = null;
1195
1196        try {
1197            CmsResource requestedResource = cms.readResource(
1198                cms.getRequestContext().getUri(),
1199                CmsResourceFilter.ignoreExpirationOffline(cms));
1200            structureId = requestedResource.getStructureId();
1201        } catch (CmsException e) {
1202            // may happen in case of VAADIN UI
1203            LOG.debug("Could not read resource for URI.", e);
1204            structureId = CmsUUID.getNullUUID();
1205        }
1206        String loginUrl = CmsWorkplaceLoginHandler.LOGIN_FORM;
1207        try {
1208            loginUrl = cms.readPropertyObject(
1209                cms.getRequestContext().getUri(),
1210                CmsPropertyDefinition.PROPERTY_LOGIN_FORM,
1211                true).getValue(loginUrl);
1212        } catch (CmsException e) {
1213            log(e.getLocalizedMessage(), e);
1214        }
1215        String defaultWorkplaceLink = OpenCms.getSystemInfo().getWorkplaceContext();
1216        Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1217        UserInfo userInfo = getUserInfo();
1218        String aboutLink = OpenCms.getLinkManager().substituteLink(
1219            getCmsObject(),
1220            "/system/workplace/commons/about.jsp");
1221        String tinyMCE = CmsWorkplace.getStaticResourceUri("/editors/tinymce/jscripts/tinymce/tinymce.min.js");
1222        boolean uploadDisabled = OpenCms.getWorkplaceManager().isAdeGalleryUploadDisabled(cms);
1223        CmsUploadRestrictionInfo uploadRestrictionInfo = OpenCms.getWorkplaceManager().getUploadRestriction().getUploadRestrictionInfo(
1224            cms);
1225        String categoryBaseFolder = CmsCategoryService.getInstance().getRepositoryBaseFolderName(cms);
1226        CmsGalleryDisabledTypesMode disabledTypesMode = sitemapConfig.getDisabledTypeMode(
1227            CmsGalleryDisabledTypesMode.mark);
1228        boolean hideDisabledTypes = disabledTypesMode == CmsGalleryDisabledTypesMode.hide;
1229
1230        CmsCoreData data = new CmsCoreData(
1231            EDITOR_URI,
1232            EDITOR_BACKLINK_URI,
1233            loginUrl,
1234            OpenCms.getStaticExportManager().getVfsPrefix(),
1235            getFileExplorerLink(cms, cms.getRequestContext().getSiteRoot()),
1236            OpenCms.getSystemInfo().getStaticResourceContext(),
1237            CmsEmbeddedDialogsUI.getEmbeddedDialogsContextPath(),
1238            cms.getRequestContext().getSiteRoot(),
1239            OpenCms.getSiteManager().getSharedFolder(),
1240            cms.getRequestContext().getCurrentProject().getId(),
1241            cms.getRequestContext().getLocale().toString(),
1242            wpLocale.toString(),
1243            cms.getRequestContext().getUri(),
1244            navigationUri,
1245            structureId,
1246            new HashMap<String, String>(OpenCms.getResourceManager().getExtensionMapping()),
1247            CmsIconUtil.getExtensionIconMapping(),
1248            System.currentTimeMillis(),
1249            isShowHelp,
1250            toolbarVisible,
1251            defaultWorkplaceLink,
1252            aboutLink,
1253            userInfo,
1254            OpenCms.getWorkplaceManager().getFileBytesMaxUploadSize(getCmsObject()),
1255            OpenCms.getWorkplaceManager().isKeepAlive(),
1256            uploadDisabled,
1257            OpenCms.getADEManager().getParameters(getCmsObject()),
1258            uploadRestrictionInfo,
1259            categoryBaseFolder,
1260            hideDisabledTypes);
1261        CmsTinyMCEData tinyMCEData = new CmsTinyMCEData();
1262        tinyMCEData.setLink(tinyMCE);
1263        data.setTinymce(tinyMCEData);
1264        return data;
1265    }
1266
1267    /**
1268     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#saveUserSettings(java.util.Map, java.util.Set)
1269     */
1270    public void saveUserSettings(Map<String, String> userSettings, Set<String> edited) throws CmsRpcException {
1271
1272        try {
1273            CmsObject cms = getCmsObject();
1274            CmsClientUserSettingConverter converter = new CmsClientUserSettingConverter(
1275                cms,
1276                getRequest(),
1277                getResponse());
1278            userSettings.keySet().retainAll(edited);
1279            converter.saveSettings(userSettings);
1280        } catch (Exception e) {
1281            error(e);
1282        }
1283    }
1284
1285    /**
1286     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#setResourceCategories(org.opencms.util.CmsUUID, java.util.List)
1287     */
1288    public void setResourceCategories(CmsUUID structureId, List<String> categories) throws CmsRpcException {
1289
1290        CmsObject cms = getCmsObject();
1291        CmsCategoryService catService = CmsCategoryService.getInstance();
1292        try {
1293            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1294            ensureLock(resource);
1295            String sitePath = cms.getSitePath(resource);
1296            List<CmsCategory> previousCategories = catService.readResourceCategories(cms, resource);
1297            for (CmsCategory category : previousCategories) {
1298                if (categories.contains(category.getPath())) {
1299                    categories.remove(category.getPath());
1300                } else {
1301                    catService.removeResourceFromCategory(cms, sitePath, category);
1302                }
1303            }
1304            for (String path : categories) {
1305                if (!path.isEmpty()) { // Prevent adding category repositories itself.
1306                    catService.addResourceToCategory(cms, sitePath, path);
1307                }
1308            }
1309            tryUnlock(resource);
1310        } catch (Throwable t) {
1311            error(t);
1312        }
1313    }
1314
1315    /**
1316     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#setShowEditorHelp(boolean)
1317     */
1318    public void setShowEditorHelp(boolean visible) throws CmsRpcException {
1319
1320        try {
1321            OpenCms.getADEManager().setShowEditorHelp(getCmsObject(), visible);
1322        } catch (Throwable e) {
1323            error(e);
1324        }
1325    }
1326
1327    /**
1328     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#setToolbarVisible(boolean)
1329     */
1330    public void setToolbarVisible(boolean visible) throws CmsRpcException {
1331
1332        try {
1333            ensureSession();
1334            CmsADESessionCache.getCache(getRequest(), getCmsObject()).setToolbarVisible(visible);
1335        } catch (Throwable e) {
1336            error(e);
1337        }
1338    }
1339
1340    /**
1341     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#unlock(org.opencms.util.CmsUUID)
1342     */
1343    public String unlock(CmsUUID structureId) throws CmsRpcException {
1344
1345        CmsObject cms = getCmsObject();
1346        try {
1347            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1348            tryUnlock(resource);
1349        } catch (CmsException e) {
1350            return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
1351        } catch (Throwable e) {
1352            error(e);
1353        }
1354        return null;
1355    }
1356
1357    /**
1358     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#unlock(java.lang.String)
1359     */
1360    public String unlock(String sitePath) throws CmsRpcException {
1361
1362        try {
1363            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1364            cms.getRequestContext().setSiteRoot("");
1365            if (cms.existsResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION)) {
1366                CmsResource resource = cms.readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
1367                tryUnlock(resource);
1368            }
1369        } catch (CmsException e) {
1370            return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()));
1371        } catch (Throwable e) {
1372            error(e);
1373        }
1374        return null;
1375    }
1376
1377    /**
1378     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#validate(java.util.Map)
1379     */
1380    public Map<String, CmsValidationResult> validate(Map<String, CmsValidationQuery> validationQueries)
1381    throws CmsRpcException {
1382
1383        try {
1384            Map<String, CmsValidationResult> result = new HashMap<String, CmsValidationResult>();
1385            for (Map.Entry<String, CmsValidationQuery> queryEntry : validationQueries.entrySet()) {
1386                String fieldName = queryEntry.getKey();
1387                CmsValidationQuery query = queryEntry.getValue();
1388                result.put(fieldName, validate(query.getValidatorId(), query.getValue(), query.getConfig()));
1389            }
1390            return result;
1391        } catch (Throwable e) {
1392            error(e);
1393        }
1394        return null;
1395    }
1396
1397    /**
1398     * @see org.opencms.gwt.shared.rpc.I_CmsCoreService#validate(java.lang.String, java.util.Map, java.util.Map, java.lang.String)
1399     */
1400    public Map<String, CmsValidationResult> validate(
1401        String formValidatorClass,
1402        Map<String, CmsValidationQuery> validationQueries,
1403        Map<String, String> values,
1404        String config)
1405    throws CmsRpcException {
1406
1407        try {
1408            I_CmsFormValidator formValidator = instantiate(I_CmsFormValidator.class, formValidatorClass);
1409            return formValidator.validate(getCmsObject(), validationQueries, values, config);
1410        } catch (Throwable e) {
1411            error(e);
1412        }
1413        return null;
1414    }
1415
1416    /**
1417     * Collect GWT build ids from the different ADE modules.<p>
1418     *
1419     * @return the map of GWT build ids
1420     */
1421    protected Map<String, String> getBuildIds() {
1422
1423        List<CmsModule> modules = OpenCms.getModuleManager().getAllInstalledModules();
1424        Map<String, String> result = new HashMap<String, String>();
1425        for (CmsModule module : modules) {
1426            String buildid = module.getParameter(CmsCoreData.KEY_GWT_BUILDID);
1427            if (buildid != null) {
1428                result.put(module.getName(), buildid);
1429            }
1430        }
1431        return result;
1432    }
1433
1434    /**
1435     * Helper method for locking a resource which returns some information on whether the locking
1436     * failed, and why.<p>
1437     *
1438     * @param structureId the structure id of the resource
1439     * @return the locking information
1440     *
1441     * @throws CmsException if something went wrong
1442     */
1443    protected CmsLockInfo getLock(CmsUUID structureId) throws CmsException {
1444
1445        CmsResource res = getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1446        return getLock(getCmsObject().getSitePath(res));
1447    }
1448
1449    /**
1450     * Helper method for locking a resource which returns some information on whether the locking
1451     * failed, and why.<p>
1452     *
1453     * @param sitepath the site path of the resource to lock
1454     * @return the locking information
1455     *
1456     * @throws CmsException if something went wrong
1457     */
1458    protected CmsLockInfo getLock(String sitepath) throws CmsException {
1459
1460        CmsObject cms = getCmsObject();
1461        CmsUser user = cms.getRequestContext().getCurrentUser();
1462        CmsLock lock = cms.getLock(sitepath);
1463        if (lock.isOwnedBy(user)) {
1464            return CmsLockInfo.forSuccess();
1465        }
1466        if (lock.getUserId().isNullUUID()) {
1467            cms.lockResourceTemporary(sitepath);
1468            return CmsLockInfo.forSuccess();
1469        }
1470        CmsUser owner = cms.readUser(lock.getUserId());
1471        return CmsLockInfo.forLockedResource(owner.getName());
1472    }
1473
1474    /**
1475     * Internal helper method for validating a single value.<p>
1476     *
1477     * @param validator the class name of the validation service
1478     * @param value the value to validate
1479     * @param config the configuration for the validation service
1480     *
1481     * @return the result of the validation
1482     *
1483     * @throws Exception if something goes wrong
1484     */
1485    private CmsValidationResult validate(String validator, String value, String config) throws Exception {
1486
1487        I_CmsValidationService validationService = getValidationService(validator);
1488        return validationService.validate(getCmsObject(), value, config);
1489    }
1490}