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