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.containerpage.CmsDetailOnlyContainerUtil;
031import org.opencms.ade.galleries.CmsPreviewService;
032import org.opencms.configuration.CmsConfigurationException;
033import org.opencms.file.CmsFile;
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.CmsResource.CmsResourceUndoMode;
040import org.opencms.file.CmsResourceFilter;
041import org.opencms.file.CmsUser;
042import org.opencms.file.CmsVfsResourceNotFoundException;
043import org.opencms.file.history.CmsHistoryProject;
044import org.opencms.file.history.I_CmsHistoryResource;
045import org.opencms.file.types.CmsResourceTypeBinary;
046import org.opencms.file.types.CmsResourceTypeImage;
047import org.opencms.file.types.CmsResourceTypePlain;
048import org.opencms.file.types.CmsResourceTypePointer;
049import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
050import org.opencms.file.types.CmsResourceTypeXmlContent;
051import org.opencms.file.types.CmsResourceTypeXmlPage;
052import org.opencms.gwt.shared.CmsBrokenLinkBean;
053import org.opencms.gwt.shared.CmsClientDateBean;
054import org.opencms.gwt.shared.CmsDataViewConstants;
055import org.opencms.gwt.shared.CmsDeleteResourceBean;
056import org.opencms.gwt.shared.CmsExternalLinkInfoBean;
057import org.opencms.gwt.shared.CmsGwtConstants;
058import org.opencms.gwt.shared.CmsHistoryResourceBean;
059import org.opencms.gwt.shared.CmsHistoryResourceCollection;
060import org.opencms.gwt.shared.CmsHistoryVersion;
061import org.opencms.gwt.shared.CmsHistoryVersion.OfflineOnline;
062import org.opencms.gwt.shared.CmsListInfoBean;
063import org.opencms.gwt.shared.CmsListInfoBean.LockIcon;
064import org.opencms.gwt.shared.CmsLockReportInfo;
065import org.opencms.gwt.shared.CmsPrepareEditResponse;
066import org.opencms.gwt.shared.CmsPreviewInfo;
067import org.opencms.gwt.shared.CmsQuickLaunchData;
068import org.opencms.gwt.shared.CmsQuickLaunchParams;
069import org.opencms.gwt.shared.CmsRenameInfoBean;
070import org.opencms.gwt.shared.CmsReplaceInfo;
071import org.opencms.gwt.shared.CmsResourceStatusBean;
072import org.opencms.gwt.shared.CmsRestoreInfoBean;
073import org.opencms.gwt.shared.CmsVfsEntryBean;
074import org.opencms.gwt.shared.alias.CmsAliasBean;
075import org.opencms.gwt.shared.property.CmsPropertiesBean;
076import org.opencms.gwt.shared.property.CmsPropertyChangeSet;
077import org.opencms.gwt.shared.rpc.I_CmsVfsService;
078import org.opencms.i18n.CmsLocaleManager;
079import org.opencms.i18n.CmsMessageContainer;
080import org.opencms.i18n.CmsMessages;
081import org.opencms.json.JSONObject;
082import org.opencms.loader.CmsImageScaler;
083import org.opencms.loader.CmsLoaderException;
084import org.opencms.lock.CmsLock;
085import org.opencms.lock.CmsLockType;
086import org.opencms.main.CmsException;
087import org.opencms.main.CmsIllegalArgumentException;
088import org.opencms.main.CmsLog;
089import org.opencms.main.OpenCms;
090import org.opencms.relations.CmsRelation;
091import org.opencms.relations.CmsRelationFilter;
092import org.opencms.ui.components.CmsResourceIcon;
093import org.opencms.util.CmsDateUtil;
094import org.opencms.util.CmsMacroResolver;
095import org.opencms.util.CmsRequestUtil;
096import org.opencms.util.CmsStringUtil;
097import org.opencms.util.CmsUUID;
098import org.opencms.widgets.dataview.I_CmsDataView;
099import org.opencms.widgets.dataview.I_CmsDataViewItem;
100import org.opencms.workplace.comparison.CmsHistoryListUtil;
101import org.opencms.workplace.explorer.CmsExplorerTypeSettings;
102import org.opencms.workplace.explorer.CmsResourceUtil;
103import org.opencms.xml.containerpage.CmsXmlContainerPageFactory;
104import org.opencms.xml.content.CmsXmlContentFactory;
105import org.opencms.xml.content.CmsXmlContentProperty;
106import org.opencms.xml.page.CmsXmlPageFactory;
107
108import java.text.DateFormat;
109import java.util.ArrayList;
110import java.util.Collections;
111import java.util.Date;
112import java.util.HashMap;
113import java.util.HashSet;
114import java.util.LinkedHashMap;
115import java.util.List;
116import java.util.Locale;
117import java.util.Map;
118import java.util.Set;
119
120import org.apache.commons.collections.CollectionUtils;
121import org.apache.commons.logging.Log;
122
123import com.google.common.collect.HashMultimap;
124import com.google.common.collect.Lists;
125import com.google.common.collect.Multimap;
126
127/**
128 * A service class for reading the VFS tree.<p>
129 *
130 * @since 8.0.0
131 */
132public class CmsVfsService extends CmsGwtService implements I_CmsVfsService {
133
134    /** The static log object for this class. */
135    private static final Log LOG = CmsLog.getLog(CmsVfsService.class);
136
137    /** The allowed preview mime types. Checked for binary content only. */
138    private static Set<String> m_previewMimeTypes = new HashSet<String>();
139
140    /** Serialization id. */
141    private static final long serialVersionUID = -383483666952834348L;
142
143    /** A helper object containing the implementations of the alias-related service methods. */
144    private CmsAliasHelper m_aliasHelper = new CmsAliasHelper();
145
146    /** Initialize the preview mime types. */
147    static {
148        CollectionUtils.addAll(
149            m_previewMimeTypes,
150            (new String[] {
151                "application/msword",
152                "application/pdf",
153                "application/excel",
154                "application/mspowerpoint",
155                "application/zip"}));
156    }
157
158    /**
159     * Adds the lock state information to the resource info bean.<p>
160     *
161     * @param cms the CMS context
162     * @param resource the resource to get the page info for
163     * @param resourceInfo the resource info to add the lock state to
164     *
165     * @return the resource info bean
166     *
167     * @throws CmsException if something else goes wrong
168     */
169    public static CmsListInfoBean addLockInfo(CmsObject cms, CmsResource resource, CmsListInfoBean resourceInfo)
170    throws CmsException {
171
172        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
173        CmsResourceUtil resourceUtil = new CmsResourceUtil(cms, resource);
174        CmsLock lock = resourceUtil.getLock();
175        LockIcon icon = LockIcon.NONE;
176        String iconTitle = null;
177        CmsLockType lockType = lock.getType();
178        if (!lock.isOwnedBy(cms.getRequestContext().getCurrentUser())) {
179            if ((lockType == CmsLockType.EXCLUSIVE)
180                || (lockType == CmsLockType.INHERITED)
181                || (lockType == CmsLockType.TEMPORARY)) {
182                icon = LockIcon.CLOSED;
183            } else if ((lockType == CmsLockType.SHARED_EXCLUSIVE) || (lockType == CmsLockType.SHARED_INHERITED)) {
184                icon = LockIcon.SHARED_CLOSED;
185            }
186        } else {
187            if ((lockType == CmsLockType.EXCLUSIVE)
188                || (lockType == CmsLockType.INHERITED)
189                || (lockType == CmsLockType.TEMPORARY)) {
190                icon = LockIcon.OPEN;
191            } else if ((lockType == CmsLockType.SHARED_EXCLUSIVE) || (lockType == CmsLockType.SHARED_INHERITED)) {
192                icon = LockIcon.SHARED_OPEN;
193            }
194        }
195        if ((lock.getUserId() != null) && !lock.getUserId().isNullUUID()) {
196            CmsUser lockOwner = cms.readUser(lock.getUserId());
197            iconTitle = Messages.get().getBundle(locale).key(Messages.GUI_LOCKED_BY_1, lockOwner.getFullName());
198            resourceInfo.addAdditionalInfo(
199                Messages.get().getBundle(locale).key(Messages.GUI_LOCKED_OWNER_0),
200                lockOwner.getFullName());
201        }
202        resourceInfo.setLockIcon(icon);
203        resourceInfo.setLockIconTitle(iconTitle);
204        if (icon != LockIcon.NONE) {
205            resourceInfo.setTitle(resourceInfo.getTitle() + " (" + iconTitle + ")");
206        }
207        return resourceInfo;
208    }
209
210    /**
211     * Formats a date given the current user's workplace locale.<p>
212     *
213     * @param cms the current CMS context
214     * @param date the date to format
215     *
216     * @return the formatted date
217     */
218    public static String formatDateTime(CmsObject cms, long date) {
219
220        return CmsDateUtil.getDateTime(
221            new Date(date),
222            DateFormat.MEDIUM,
223            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms));
224    }
225
226    /**
227     * Returns the no preview reason if there is any.<p>
228     *
229     * @param cms the current cms context
230     * @param resource the resource to check
231     *
232     * @return the no preview reason if there is any
233     */
234    public static String getNoPreviewReason(CmsObject cms, CmsResource resource) {
235
236        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
237        String noPreviewReason = null;
238        if (resource.getState().isDeleted() && !(resource instanceof I_CmsHistoryResource)) {
239            noPreviewReason = Messages.get().getBundle(locale).key(Messages.GUI_NO_PREVIEW_DELETED_0);
240        } else if (resource.isFolder()) {
241            noPreviewReason = Messages.get().getBundle(locale).key(Messages.GUI_NO_PREVIEW_FOLDER_0);
242        } else {
243            String siteRoot = OpenCms.getSiteManager().getSiteRoot(resource.getRootPath());
244            // previewing only resources that are in the same site or don't have a site root at all
245            if ((siteRoot != null) && !siteRoot.equals(cms.getRequestContext().getSiteRoot())) {
246                noPreviewReason = Messages.get().getBundle(locale).key(Messages.GUI_NO_PREVIEW_OTHER_SITE_0);
247            } else if (resource.getTypeId() == CmsResourceTypeBinary.getStaticTypeId()) {
248                String mimeType = OpenCms.getResourceManager().getMimeType(resource.getName(), null, "empty");
249                if (!m_previewMimeTypes.contains(mimeType)) {
250                    noPreviewReason = Messages.get().getBundle(locale).key(Messages.GUI_NO_PREVIEW_WRONG_MIME_TYPE_0);
251                }
252            }
253        }
254        return noPreviewReason;
255    }
256
257    /**
258     * Gets page information of a resource.<p>
259     *
260     * @param cms the CMS context
261     * @param res the resource
262     *
263     * @return gets the page information for the given resource
264     *
265     * @throws CmsException if the resource info can not be read
266     */
267    public static CmsListInfoBean getPageInfo(CmsObject cms, CmsResource res) throws CmsException {
268
269        CmsListInfoBean result = new CmsListInfoBean();
270        addPageInfo(cms, res, result);
271        return result;
272    }
273
274    /**
275     * Returns a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget} including the lock state.<p>
276     *
277     * @param cms the CMS context
278     * @param resource the resource to get the page info for
279     *
280     * @return a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget}.<p>
281     *
282     * @throws CmsLoaderException if the resource type could not be found
283     * @throws CmsException if something else goes wrong
284     */
285    public static CmsListInfoBean getPageInfoWithLock(CmsObject cms, CmsResource resource)
286    throws CmsLoaderException, CmsException {
287
288        CmsListInfoBean result = getPageInfo(cms, resource);
289        addLockInfo(cms, resource, result);
290        return result;
291    }
292
293    /**
294     * Processes a file path, which may have macros in it, so it can be opened by the XML content editor.<p>
295     *
296     * @param cms the current CMS context
297     * @param res the resource for which the context menu option has been selected
298     * @param pathWithMacros the file path which may contain macros
299     *
300     * @return the processed file path
301     */
302    public static String prepareFileNameForEditor(CmsObject cms, CmsResource res, String pathWithMacros) {
303
304        String subsite = OpenCms.getADEManager().getSubSiteRoot(cms, res.getRootPath());
305        CmsMacroResolver resolver = new CmsMacroResolver();
306        if (subsite != null) {
307            resolver.addMacro("subsite", cms.getRequestContext().removeSiteRoot(subsite));
308        }
309        resolver.addMacro("file", cms.getSitePath(res));
310        String path = resolver.resolveMacros(pathWithMacros).replaceAll("/+", "/");
311        return path;
312    }
313
314    /**
315     * Gets page information of a resource and adds it to the given list info bean.<p>
316     *
317     * @param cms the CMS context
318     * @param resource the resource
319     * @param listInfo the list info bean to add the information to
320     *
321     * @return the list info bean
322     *
323     * @throws CmsException if the resource info can not be read
324     */
325    protected static CmsListInfoBean addPageInfo(CmsObject cms, CmsResource resource, CmsListInfoBean listInfo)
326    throws CmsException {
327
328        listInfo.setResourceState(resource.getState());
329
330        String title = cms.readPropertyObject(
331            resource,
332            CmsPropertyDefinition.PROPERTY_TITLE,
333            false,
334            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).getValue();
335        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(title)) {
336            listInfo.setTitle(title);
337        } else {
338            listInfo.setTitle(resource.getName());
339        }
340        listInfo.setSubTitle(cms.getSitePath(resource));
341        listInfo.setIsFolder(Boolean.valueOf(resource.isFolder()));
342        String resTypeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
343        CmsExplorerTypeSettings cmsExplorerTypeSettings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
344            resTypeName);
345        if (null == cmsExplorerTypeSettings) {
346            CmsMessageContainer errMsg = Messages.get().container(
347                Messages.ERR_EXPLORER_TYPE_SETTINGS_FOR_RESOURCE_TYPE_NOT_FOUND_3,
348                resource.getRootPath(),
349                resTypeName,
350                Integer.valueOf(resource.getTypeId()));
351            throw new CmsConfigurationException(errMsg);
352        }
353        String key = cmsExplorerTypeSettings.getKey();
354        Locale currentLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
355        CmsMessages messages = OpenCms.getWorkplaceManager().getMessages(currentLocale);
356        String resTypeNiceName = messages.key(key);
357        listInfo.addAdditionalInfo(
358            messages.key(org.opencms.workplace.commons.Messages.GUI_LABEL_TYPE_0),
359            resTypeNiceName);
360        listInfo.setResourceType(resTypeName);
361        listInfo.setBigIconClasses(
362            CmsIconUtil.getIconClasses(CmsIconUtil.getDisplayType(cms, resource), resource.getName(), false));
363        // set the default file and detail type info
364        String detailType = CmsResourceIcon.getDefaultFileOrDetailType(cms, resource);
365        if (detailType != null) {
366            listInfo.setSmallIconClasses(CmsIconUtil.getIconClasses(detailType, null, true));
367        }
368        return listInfo;
369    }
370
371    /**
372     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#createNewExternalLink(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
373     */
374    public void createNewExternalLink(String title, String link, String resourceName, String parentFolderPath)
375    throws CmsRpcException {
376
377        CmsObject cms = getCmsObject();
378        try {
379            CmsProperty titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, null);
380            @SuppressWarnings("deprecation")
381            CmsResource resource = cms.createResource(
382                CmsStringUtil.joinPaths(parentFolderPath, resourceName),
383                CmsResourceTypePointer.getStaticTypeId(),
384                new byte[0],
385                Collections.singletonList(titleProp));
386            CmsFile file = cms.readFile(resource);
387            file.setContents(link.getBytes(CmsLocaleManager.getResourceEncoding(cms, resource)));
388            cms.writeFile(file);
389            tryUnlock(resource);
390            // update the offline search indices
391            OpenCms.getSearchManager().updateOfflineIndexes();
392        } catch (Exception e) {
393            error(e);
394        }
395    }
396
397    /**
398     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#createPropertyDefinition(java.lang.String)
399     */
400    public void createPropertyDefinition(String name) throws CmsRpcException {
401
402        CmsObject cms = getCmsObject();
403        try {
404            cms.createPropertyDefinition(name.trim());
405        } catch (Exception e) {
406            error(e);
407        }
408
409    }
410
411    /**
412     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#deleteResource(org.opencms.util.CmsUUID)
413     */
414    public void deleteResource(CmsUUID structureId) throws CmsRpcException {
415
416        try {
417            CmsObject cms = getCmsObject();
418            CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
419            deleteResource(res);
420        } catch (Throwable e) {
421            error(e);
422        }
423    }
424
425    /**
426     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#deleteResource(java.lang.String)
427     */
428    public void deleteResource(String sitePath) throws CmsRpcException {
429
430        try {
431            CmsResource res = getCmsObject().readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
432            deleteResource(res);
433        } catch (Throwable e) {
434            error(e);
435        }
436    }
437
438    /**
439     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#forceUnlock(org.opencms.util.CmsUUID)
440     */
441    public void forceUnlock(CmsUUID structureId) throws CmsRpcException {
442
443        try {
444            CmsResource resource = getCmsObject().readResource(structureId, CmsResourceFilter.ALL);
445            // get the current lock
446            CmsLock currentLock = getCmsObject().getLock(resource);
447            // check if the resource is locked at all
448            if (currentLock.getEditionLock().isUnlocked() && currentLock.getSystemLock().isUnlocked()) {
449                getCmsObject().lockResourceTemporary(resource);
450            } else {
451                getCmsObject().changeLock(resource);
452            }
453            getCmsObject().unlockResource(resource);
454        } catch (Throwable e) {
455            error(e);
456        }
457    }
458
459    /**
460     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getAliasesForPage(org.opencms.util.CmsUUID)
461     */
462    public List<CmsAliasBean> getAliasesForPage(CmsUUID uuid) throws CmsRpcException {
463
464        try {
465            return m_aliasHelper.getAliasesForPage(uuid);
466        } catch (Throwable e) {
467            error(e);
468            return null;
469        }
470    }
471
472    /**
473     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getBrokenLinks(org.opencms.util.CmsUUID)
474     */
475    public CmsDeleteResourceBean getBrokenLinks(CmsUUID structureId) throws CmsRpcException {
476
477        try {
478            CmsResource entryResource = getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
479
480            return getBrokenLinks(entryResource);
481        } catch (Throwable e) {
482            error(e);
483            return null; // will never be reached
484        }
485    }
486
487    /**
488     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getBrokenLinks(java.lang.String)
489     */
490    public CmsDeleteResourceBean getBrokenLinks(String sitePath) throws CmsRpcException {
491
492        try {
493            CmsResource entryResource = getCmsObject().readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION);
494
495            return getBrokenLinks(entryResource);
496        } catch (Throwable e) {
497            error(e);
498            return null; // will never be reached
499        }
500    }
501
502    /**
503     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getChildren(java.lang.String)
504     */
505    public List<CmsVfsEntryBean> getChildren(String path) throws CmsRpcException {
506
507        try {
508            CmsObject cms = getCmsObject();
509            List<CmsResource> resources = new ArrayList<CmsResource>();
510            resources.addAll(cms.getResourcesInFolder(path, CmsResourceFilter.DEFAULT));
511            List<CmsVfsEntryBean> result = makeEntryBeans(resources, false);
512            return result;
513        } catch (Throwable e) {
514            error(e);
515        }
516        return null;
517    }
518
519    /**
520     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getDataViewThumbnail(java.lang.String, java.lang.String)
521     */
522    public String getDataViewThumbnail(String config, String id) throws CmsRpcException {
523
524        try {
525            JSONObject obj = new JSONObject(config);
526            String className = obj.optString(CmsDataViewConstants.CONFIG_VIEW_CLASS);
527            String classArg = obj.optString(CmsDataViewConstants.CONFIG_VIEW_ARG);
528            I_CmsDataView data = (I_CmsDataView)(Class.forName(className).newInstance());
529            data.initialize(getCmsObject(), classArg, OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject()));
530            I_CmsDataViewItem item = data.getItemById(id);
531            if (item == null) {
532                LOG.warn("no dataview item found for id: " + id + " (config=" + config + ")");
533                return null;
534            }
535            return item.getImage();
536        } catch (Exception e) {
537            error(e);
538            return null;
539        }
540    }
541
542    /**
543     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getDefaultProperties(java.util.List)
544     */
545    public Map<CmsUUID, Map<String, CmsXmlContentProperty>> getDefaultProperties(List<CmsUUID> structureIds)
546    throws CmsRpcException {
547
548        try {
549            CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(getCmsObject());
550            return helper.getDefaultProperties(structureIds);
551        } catch (Throwable e) {
552            error(e);
553            return null;
554        }
555    }
556
557    /**
558     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getDefinedProperties()
559     */
560    public ArrayList<String> getDefinedProperties() throws CmsRpcException {
561
562        CmsObject cms = getCmsObject();
563        try {
564            List<CmsPropertyDefinition> definitions = cms.readAllPropertyDefinitions();
565            ArrayList<String> result = new ArrayList<String>();
566            for (CmsPropertyDefinition def : definitions) {
567                result.add(def.getName());
568            }
569            return result;
570        } catch (Exception e) {
571            error(e);
572            return null;
573        }
574    }
575
576    /**
577     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getFileReplaceInfo(org.opencms.util.CmsUUID)
578     */
579    public CmsReplaceInfo getFileReplaceInfo(CmsUUID structureId) throws CmsRpcException {
580
581        CmsReplaceInfo result = null;
582        try {
583            CmsObject cms = getCmsObject();
584            CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
585            CmsListInfoBean fileInfo = getPageInfo(res);
586            boolean isLockable = cms.getLock(res).isLockableBy(cms.getRequestContext().getCurrentUser());
587            long maxFileSize = OpenCms.getWorkplaceManager().getFileBytesMaxUploadSize(cms);
588            result = new CmsReplaceInfo(fileInfo, cms.getSitePath(res), isLockable, maxFileSize);
589        } catch (Throwable e) {
590            error(e);
591        }
592        return result;
593    }
594
595    /**
596     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getHistoryPreviewInfo(org.opencms.util.CmsUUID, java.lang.String, org.opencms.gwt.shared.CmsHistoryVersion)
597     */
598    public CmsPreviewInfo getHistoryPreviewInfo(CmsUUID structureId, String locale, CmsHistoryVersion versionBean)
599    throws CmsRpcException {
600
601        try {
602            CmsObject cms = getCmsObject();
603            CmsResource previewResource = null;
604            if (versionBean.getVersionNumber() != null) {
605                previewResource = (CmsResource)(cms.readResource(
606                    structureId,
607                    versionBean.getVersionNumber().intValue()));
608            } else if (versionBean.isOffline()) {
609                previewResource = cms.readResource(structureId, CmsResourceFilter.ALL);
610            } else if (versionBean.isOnline()) {
611                CmsProject online = cms.readProject(CmsProject.ONLINE_PROJECT_ID);
612                cms = OpenCms.initCmsObject(cms);
613                cms.getRequestContext().setCurrentProject(online);
614                previewResource = cms.readResource(structureId, CmsResourceFilter.ALL);
615            }
616            CmsFile previewFile = cms.readFile(previewResource);
617            return getPreviewInfo(cms, previewFile, CmsLocaleManager.getLocale(locale));
618        } catch (Exception e) {
619            error(e);
620            return null; // return statement will never be reached
621        }
622    }
623
624    /**
625     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getLockReportInfo(org.opencms.util.CmsUUID)
626     */
627    public CmsLockReportInfo getLockReportInfo(CmsUUID structureId) throws CmsRpcException {
628
629        CmsLockReportInfo result = null;
630        CmsObject cms = getCmsObject();
631        try {
632            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
633            List<CmsListInfoBean> lockedInfos = new ArrayList<CmsListInfoBean>();
634            List<CmsResource> lockedResources = cms.getBlockingLockedResources(resource);
635            if (lockedResources != null) {
636                for (CmsResource lockedResource : lockedResources) {
637                    lockedInfos.add(getPageInfoWithLock(cms, lockedResource));
638                }
639            }
640            result = new CmsLockReportInfo(getPageInfoWithLock(cms, resource), lockedInfos);
641        } catch (Throwable e) {
642            error(e);
643        }
644        return result;
645    }
646
647    /**
648     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPageInfo(org.opencms.util.CmsUUID)
649     */
650    public CmsListInfoBean getPageInfo(CmsUUID structureId) throws CmsRpcException {
651
652        try {
653            CmsResource res = getCmsObject().readResource(structureId, CmsResourceFilter.ALL);
654            return getPageInfo(res);
655        } catch (Throwable e) {
656            error(e);
657            return null; // will never be reached
658        }
659    }
660
661    /**
662     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPageInfo(java.lang.String)
663     */
664    public CmsListInfoBean getPageInfo(String vfsPath) throws CmsRpcException {
665
666        try {
667            CmsResource res = getCmsObject().readResource(vfsPath, CmsResourceFilter.IGNORE_EXPIRATION);
668            return getPageInfo(res);
669        } catch (Throwable e) {
670            error(e);
671            return null; // will never be reached
672        }
673    }
674
675    /**
676     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPreviewInfo(org.opencms.util.CmsUUID, java.lang.String)
677     */
678    public CmsPreviewInfo getPreviewInfo(CmsUUID structureId, String locale) throws CmsRpcException {
679
680        CmsPreviewInfo result = null;
681        try {
682            result = getPreviewInfo(
683                getCmsObject(),
684                getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION),
685                CmsLocaleManager.getLocale(locale));
686        } catch (Exception e) {
687            error(e);
688        }
689        return result;
690
691    }
692
693    /**
694     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPreviewInfo(java.lang.String, java.lang.String)
695     */
696    public CmsPreviewInfo getPreviewInfo(String sitePath, String locale) throws CmsRpcException {
697
698        CmsPreviewInfo result = null;
699        try {
700            result = getPreviewInfo(
701                getCmsObject(),
702                getCmsObject().readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION),
703                CmsLocaleManager.getLocale(locale));
704        } catch (Exception e) {
705            error(e);
706        }
707        return result;
708    }
709
710    /**
711     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRenameInfo(org.opencms.util.CmsUUID)
712     */
713    public CmsRenameInfoBean getRenameInfo(CmsUUID structureId) throws CmsRpcException {
714
715        try {
716            CmsObject cms = getCmsObject();
717            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
718            CmsListInfoBean listInfo = getPageInfo(resource);
719            String sitePath = cms.getSitePath(resource);
720            return new CmsRenameInfoBean(sitePath, structureId, listInfo);
721        } catch (Throwable e) {
722            error(e);
723            return null;
724        }
725    }
726
727    /**
728     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getResourceHistory(org.opencms.util.CmsUUID)
729     */
730    public CmsHistoryResourceCollection getResourceHistory(CmsUUID structureId) throws CmsRpcException {
731
732        try {
733            CmsHistoryResourceCollection result = getResourceHistoryInternal(structureId);
734            CmsListInfoBean info = getPageInfo(structureId);
735            result.setContentInfo(info);
736            return result;
737
738        } catch (Exception e) {
739            error(e);
740            return null; // return statement will  never be reached
741        }
742    }
743
744    /**
745     * Internal version of getResourceHistory.<p>
746     *
747     * @param structureId the structure id of the resource
748     *
749     * @return the resource history
750     *
751     * @throws CmsException if something goes wrong
752     */
753    public CmsHistoryResourceCollection getResourceHistoryInternal(CmsUUID structureId) throws CmsException {
754
755        CmsHistoryResourceCollection result = new CmsHistoryResourceCollection();
756        CmsObject cms = getCmsObject();
757        CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
758        List<I_CmsHistoryResource> versions = cms.readAllAvailableVersions(resource);
759        if (!resource.getState().isUnchanged()) {
760            result.add(createHistoryResourceBean(cms, resource, true, -1));
761        }
762        int maxVersion = 0;
763
764        if (versions.isEmpty()) {
765            try {
766                CmsProject online = cms.readProject(CmsProject.ONLINE_PROJECT_ID);
767                CmsObject onlineCms = OpenCms.initCmsObject(cms);
768                onlineCms.getRequestContext().setCurrentProject(online);
769                CmsResource onlineResource = onlineCms.readResource(structureId, CmsResourceFilter.ALL);
770                CmsHistoryResourceBean onlineResBean = createHistoryResourceBean(onlineCms, onlineResource, false, 0);
771                result.add(onlineResBean);
772            } catch (CmsVfsResourceNotFoundException e) {
773                LOG.info(e.getLocalizedMessage(), e);
774            } catch (Exception e) {
775                LOG.error(e.getLocalizedMessage(), e);
776            }
777        } else {
778            for (I_CmsHistoryResource historyRes : versions) {
779                maxVersion = Math.max(maxVersion, historyRes.getVersion());
780            }
781            for (I_CmsHistoryResource historyRes : versions) {
782                CmsHistoryResourceBean historyBean = createHistoryResourceBean(
783                    cms,
784                    (CmsResource)historyRes,
785                    false,
786                    maxVersion);
787                result.add(historyBean);
788            }
789        }
790        return result;
791    }
792
793    /**
794     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getResourceStatus(org.opencms.util.CmsUUID, java.lang.String, boolean, org.opencms.util.CmsUUID, java.util.Map)
795     */
796    public CmsResourceStatusBean getResourceStatus(
797        CmsUUID structureId,
798        String contentLocale,
799        boolean includeTargets,
800        CmsUUID detailContentId,
801        Map<String, String> context)
802    throws CmsRpcException {
803
804        if (context == null) {
805            context = new HashMap<>();
806        }
807        try {
808            CmsObject cms = getCmsObject();
809            CmsDefaultResourceStatusProvider provider = new CmsDefaultResourceStatusProvider();
810            return provider.getResourceStatus(
811                getRequest(),
812                cms,
813                structureId,
814                contentLocale,
815                includeTargets,
816                detailContentId,
817                detailContentId != null ? Collections.singletonList(detailContentId) : null,
818                context);
819        } catch (Throwable e) {
820            error(e);
821            return null;
822        }
823    }
824
825    /**
826     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRestoreInfo(org.opencms.util.CmsUUID)
827     */
828    public CmsRestoreInfoBean getRestoreInfo(CmsUUID structureId) throws CmsRpcException {
829
830        try {
831            CmsObject cms = getCmsObject();
832            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
833            CmsListInfoBean listInfo = getPageInfo(resource);
834            CmsRestoreInfoBean result = new CmsRestoreInfoBean();
835            result.setListInfoBean(listInfo);
836
837            CmsObject onlineCms = OpenCms.initCmsObject(cms);
838            CmsProject onlineProject = cms.readProject(CmsProject.ONLINE_PROJECT_NAME);
839            onlineCms.getRequestContext().setCurrentProject(onlineProject);
840            CmsResource onlineResource = onlineCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
841            result.setOnlinePath(onlineResource.getRootPath());
842            result.setOfflinePath(resource.getRootPath());
843
844            String offlineDate = formatDateTime(resource.getDateLastModified());
845            String onlineDate = formatDateTime(onlineResource.getDateLastModified());
846            result.setOfflineDate(offlineDate);
847            result.setOnlineDate(onlineDate);
848            result.setStructureId(structureId);
849
850            CmsObject offlineRootCms = OpenCms.initCmsObject(cms);
851            offlineRootCms.getRequestContext().setSiteRoot("");
852            CmsObject onlineRootCms = OpenCms.initCmsObject(onlineCms);
853            onlineRootCms.getRequestContext().setSiteRoot("");
854            String parent = CmsResource.getParentFolder(onlineResource.getRootPath());
855            boolean canUndoMove = offlineRootCms.existsResource(parent, CmsResourceFilter.IGNORE_EXPIRATION);
856
857            result.setCanUndoMove(canUndoMove);
858
859            return result;
860        } catch (Throwable e) {
861            error(e);
862            return null;
863        }
864    }
865
866    /**
867     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRootEntries()
868     */
869    public List<CmsVfsEntryBean> getRootEntries() throws CmsRpcException {
870
871        try {
872            CmsObject cms = getCmsObject();
873            List<CmsResource> roots = new ArrayList<CmsResource>();
874            roots.add(cms.readResource("/", CmsResourceFilter.IGNORE_EXPIRATION));
875            return makeEntryBeans(roots, true);
876        } catch (CmsException e) {
877            error(e);
878        }
879        return null;
880    }
881
882    /**
883     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getSitePath(org.opencms.util.CmsUUID)
884     */
885    public String getSitePath(CmsUUID structureId) {
886
887        try {
888            CmsResource resource = getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
889            return getCmsObject().getSitePath(resource);
890        } catch (CmsException e) {
891            if (LOG.isWarnEnabled()) {
892                LOG.warn(e.getMessageContainer(), e);
893            }
894        }
895        return null;
896    }
897
898    /**
899     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadLinkInfo(org.opencms.util.CmsUUID)
900     */
901    public CmsExternalLinkInfoBean loadLinkInfo(CmsUUID structureId) throws CmsRpcException {
902
903        CmsExternalLinkInfoBean info = new CmsExternalLinkInfoBean();
904        CmsObject cms = getCmsObject();
905        try {
906            CmsResource linkResource = cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
907            addPageInfo(cms, linkResource, info);
908            CmsFile linkFile = cms.readFile(linkResource);
909            OpenCms.getLocaleManager();
910            String link = new String(linkFile.getContents(), CmsLocaleManager.getResourceEncoding(cms, linkResource));
911            info.setLink(link);
912            info.setSitePath(cms.getSitePath(linkResource));
913        } catch (Exception e) {
914            error(e);
915        }
916        return info;
917    }
918
919    /**
920     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadPropertyData(org.opencms.util.CmsUUID)
921     */
922    public CmsPropertiesBean loadPropertyData(CmsUUID id) throws CmsRpcException {
923
924        CmsObject cms = getCmsObject();
925        try {
926            CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(cms);
927            return helper.loadPropertyData(id);
928        } catch (Throwable e) {
929            error(e);
930        }
931        return null;
932    }
933
934    /**
935     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadQuickLaunchItems(org.opencms.gwt.shared.CmsQuickLaunchParams)
936     */
937    public List<CmsQuickLaunchData> loadQuickLaunchItems(CmsQuickLaunchParams params) throws CmsRpcException {
938
939        try {
940            return CmsQuickLaunchProvider.getQuickLaunchData(getCmsObject(), getRequest().getSession(), params);
941        } catch (Exception e) {
942            error(e);
943            return null;
944        }
945    }
946
947    /**
948     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#prepareEdit(org.opencms.util.CmsUUID, java.lang.String)
949     */
950    public CmsPrepareEditResponse prepareEdit(CmsUUID currentPageId, String pathWithMacros) throws CmsRpcException {
951
952        try {
953            CmsObject cms = getCmsObject();
954            CmsResource resource = null;
955            if (cms.existsResource(pathWithMacros, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
956                resource = cms.readResource(pathWithMacros, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
957            } else {
958                CmsResource currentPage = cms.readResource(currentPageId, CmsResourceFilter.IGNORE_EXPIRATION);
959                String path = prepareFileNameForEditor(cms, currentPage, pathWithMacros);
960                resource = cms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
961            }
962            ensureLock(resource);
963            CmsPrepareEditResponse result = new CmsPrepareEditResponse();
964            result.setRootPath(resource.getRootPath());
965            result.setSitePath(cms.getSitePath(resource));
966            result.setStructureId(resource.getStructureId());
967            return result;
968        } catch (Throwable e) {
969            error(e);
970        }
971        return null;
972    }
973
974    /**
975     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#renameResource(org.opencms.util.CmsUUID, java.lang.String)
976     */
977    public String renameResource(CmsUUID structureId, String newName) throws CmsRpcException {
978
979        try {
980            return renameResourceInternal(structureId, newName);
981        } catch (Throwable e) {
982            error(e);
983            return null;
984        }
985    }
986
987    /**
988     * Internal implementation for renaming a resource.<p>
989     *
990     * @param structureId the structure id of the resource to rename
991     * @param newName the new resource name
992     * @return either null if the rename was successful, or an error message
993     *
994     * @throws CmsException if something goes wrong
995     */
996    public String renameResourceInternal(CmsUUID structureId, String newName) throws CmsException {
997
998        newName = newName.trim();
999        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1000        rootCms.getRequestContext().setSiteRoot("");
1001        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(rootCms);
1002        try {
1003            CmsResource.checkResourceName(newName);
1004        } catch (CmsIllegalArgumentException e) {
1005            return e.getLocalizedMessage(locale);
1006        }
1007        CmsResource resource = rootCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1008        String oldPath = resource.getRootPath();
1009        String parentPath = CmsResource.getParentFolder(oldPath);
1010        String newPath = CmsStringUtil.joinPaths(parentPath, newName);
1011        try {
1012            ensureLock(resource);
1013            rootCms.moveResource(oldPath, newPath);
1014            resource = rootCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1015        } catch (CmsException e) {
1016            return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(rootCms));
1017        }
1018        tryUnlock(resource);
1019        return null;
1020    }
1021
1022    /**
1023     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#restoreResource(org.opencms.util.CmsUUID, int)
1024     */
1025    public void restoreResource(CmsUUID structureId, int version) throws CmsRpcException {
1026
1027        CmsObject cms = getCmsObject();
1028        try {
1029            ensureLock(structureId);
1030            cms.restoreResourceVersion(structureId, version);
1031            try {
1032                CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1033                cms.unlockResource(res);
1034            } catch (Exception e) {
1035                LOG.error(e.getLocalizedMessage(), e);
1036            }
1037
1038        } catch (Exception e) {
1039            error(e);
1040            return; // return stmt  will never be reached
1041        }
1042
1043    }
1044
1045    /**
1046     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveAliases(org.opencms.util.CmsUUID, java.util.List)
1047     */
1048    public void saveAliases(CmsUUID structureId, List<CmsAliasBean> aliasBeans) throws CmsRpcException {
1049
1050        try {
1051            m_aliasHelper.saveAliases(structureId, aliasBeans);
1052        } catch (Throwable e) {
1053            error(e);
1054        }
1055    }
1056
1057    /**
1058     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveExternalLink(org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.lang.String)
1059     */
1060    public void saveExternalLink(CmsUUID structureId, String title, String link, String fileName)
1061    throws CmsRpcException {
1062
1063        try {
1064            CmsObject cms = getCmsObject();
1065            CmsResource res = cms.readResource(structureId);
1066            ensureLock(res);
1067            CmsFile file = cms.readFile(res);
1068            String oldLink = new String(file.getContents(), CmsLocaleManager.getResourceEncoding(cms, res));
1069            if (!oldLink.equals(link)) {
1070                file.setContents(link.getBytes(CmsLocaleManager.getResourceEncoding(cms, res)));
1071                cms.writeFile(file);
1072            }
1073            CmsProperty titleProp = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false);
1074            if (titleProp.isNullProperty()) {
1075                titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, null);
1076                cms.writePropertyObject(cms.getSitePath(res), titleProp);
1077            } else if (!titleProp.getValue().equals(title)) {
1078                titleProp.setStructureValue(title);
1079                cms.writePropertyObject(cms.getSitePath(res), titleProp);
1080            }
1081            if (!res.getName().equals(fileName)) {
1082                String oldSitePath = cms.getSitePath(res);
1083                String newSitePath = CmsStringUtil.joinPaths(CmsResource.getParentFolder(oldSitePath), fileName);
1084                getCmsObject().renameResource(oldSitePath, newSitePath);
1085            }
1086            tryUnlock(res);
1087            // update the offline search indices
1088            OpenCms.getSearchManager().updateOfflineIndexes();
1089        } catch (Exception e) {
1090            error(e);
1091        }
1092    }
1093
1094    /**
1095     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveProperties(org.opencms.gwt.shared.property.CmsPropertyChangeSet)
1096     */
1097    public void saveProperties(CmsPropertyChangeSet changes) throws CmsRpcException {
1098
1099        String origSiteRoot = getCmsObject().getRequestContext().getSiteRoot();
1100        try {
1101            getCmsObject().getRequestContext().setSiteRoot("");
1102            CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(getCmsObject());
1103            helper.saveProperties(changes);
1104        } catch (Throwable t) {
1105            error(t);
1106        } finally {
1107            getCmsObject().getRequestContext().setSiteRoot(origSiteRoot);
1108        }
1109    }
1110
1111    /**
1112     * Sets the current cms context.<p>
1113     *
1114     * @param cms the current cms context to set
1115     */
1116    @Override
1117    public synchronized void setCms(CmsObject cms) {
1118
1119        super.setCms(cms);
1120        m_aliasHelper.setCms(cms);
1121    }
1122
1123    /**
1124     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#substituteLinkForRootPath(java.lang.String, java.lang.String)
1125     */
1126    public String substituteLinkForRootPath(String currentSiteRoot, String rootPath) throws CmsRpcException {
1127
1128        String result = null;
1129        try {
1130            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1131            cms.getRequestContext().setSiteRoot(currentSiteRoot);
1132            result = OpenCms.getLinkManager().substituteLinkForRootPath(cms, rootPath);
1133        } catch (CmsException e) {
1134            error(e);
1135        }
1136        return result;
1137    }
1138
1139    /**
1140     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#syncDeleteResource(org.opencms.util.CmsUUID)
1141     */
1142    public void syncDeleteResource(CmsUUID structureId) throws CmsRpcException {
1143
1144        deleteResource(structureId);
1145    }
1146
1147    /**
1148     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#undelete(org.opencms.util.CmsUUID)
1149     */
1150    public void undelete(CmsUUID structureId) throws CmsRpcException {
1151
1152        try {
1153            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1154            cms.getRequestContext().setSiteRoot("");
1155            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
1156            ensureLock(resource);
1157            cms.undeleteResource(resource.getRootPath(), true);
1158        } catch (Exception e) {
1159            error(e);
1160        }
1161    }
1162
1163    /**
1164     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#undoChanges(org.opencms.util.CmsUUID, boolean)
1165     */
1166    public void undoChanges(CmsUUID structureId, boolean undoMove) throws CmsRpcException {
1167
1168        try {
1169            CmsObject cms = getCmsObject();
1170            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1171            ensureLock(resource);
1172            CmsResourceUndoMode mode = undoMove ? CmsResource.UNDO_MOVE_CONTENT : CmsResource.UNDO_CONTENT;
1173            String path = cms.getSitePath(resource);
1174            cms.undoChanges(path, mode);
1175            try {
1176                resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1177                path = cms.getSitePath(resource);
1178                cms.unlockResource(path);
1179            } catch (CmsException e) {
1180                LOG.info("Could not unlock resource after undoing changes: " + e.getLocalizedMessage(), e);
1181            }
1182        } catch (Throwable e) {
1183            error(e);
1184        }
1185    }
1186
1187    /**
1188     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#validateAliases(org.opencms.util.CmsUUID, java.util.Map)
1189     */
1190    public Map<String, String> validateAliases(CmsUUID uuid, Map<String, String> aliasPaths) throws CmsRpcException {
1191
1192        try {
1193            return m_aliasHelper.validateAliases(uuid, aliasPaths);
1194        } catch (Throwable e) {
1195            error(e);
1196        }
1197        return null;
1198
1199    }
1200
1201    /**
1202     * Creates a "broken link" bean based on a resource.<p>
1203     *
1204     * @param resource the resource
1205     *
1206     * @return the "broken link" bean with the data from the resource
1207     *
1208     * @throws CmsException if something goes wrong
1209     */
1210    protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException {
1211
1212        CmsObject cms = getCmsObject();
1213        CmsProperty titleProp = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true);
1214        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
1215        String defaultTitle = "";
1216        String title = titleProp.getValue(defaultTitle);
1217        String path = cms.getSitePath(resource);
1218        String subtitle = path;
1219
1220        CmsBrokenLinkBean result = new CmsBrokenLinkBean(resource.getStructureId(), title, subtitle, typeName);
1221
1222        return result;
1223    }
1224
1225    /**
1226     * Helper method for creating a VFS entry bean from a resource.<p>
1227     *
1228     * @param resource the resource whose data should be stored in the bean
1229     * @param root true if the resource is a root resource
1230     *
1231     * @return the data bean representing the resource
1232     *
1233     * @throws CmsException if something goes wrong
1234     */
1235    protected CmsVfsEntryBean makeEntryBean(CmsResource resource, boolean root) throws CmsException {
1236
1237        CmsObject cms = getCmsObject();
1238        boolean isFolder = resource.isFolder();
1239        String name = root ? "/" : resource.getName();
1240        String path = cms.getSitePath(resource);
1241        boolean hasChildren = false;
1242        if (isFolder) {
1243            List<CmsResource> children = cms.getResourcesInFolder(
1244                cms.getRequestContext().getSitePath(resource),
1245                CmsResourceFilter.DEFAULT);
1246            if (!children.isEmpty()) {
1247                hasChildren = true;
1248            }
1249        }
1250        String resourceType = OpenCms.getResourceManager().getResourceType(resource.getTypeId()).getTypeName();
1251
1252        return new CmsVfsEntryBean(path, name, resourceType, isFolder, hasChildren);
1253    }
1254
1255    /**
1256     * Helper method for creating a list of VFS entry beans from a list of the corresponding resources.<p>
1257     *
1258     * @param resources the list of resources which should be converted to entry beans
1259     * @param root true if the resources in the list are root resources
1260     *
1261     * @return the list of VFS entry beans for the resources
1262     *
1263     * @throws CmsException if something goes wrong
1264     */
1265    protected List<CmsVfsEntryBean> makeEntryBeans(List<CmsResource> resources, boolean root) throws CmsException {
1266
1267        List<CmsVfsEntryBean> result = new ArrayList<CmsVfsEntryBean>();
1268        for (CmsResource res : resources) {
1269            result.add(makeEntryBean(res, root));
1270        }
1271        return result;
1272    }
1273
1274    /**
1275     * Adds additional info items for broken links.<p>
1276     *
1277     * @param cms the CMS context to use
1278     * @param resource the resource from which the additional infos should be read
1279     * @param result the result in which to store the additional info
1280     */
1281    private void addBrokenLinkAdditionalInfo(CmsObject cms, CmsResource resource, CmsBrokenLinkBean result) {
1282
1283        String dateLastModifiedLabel = org.opencms.workplace.commons.Messages.get().getBundle(
1284            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1285                org.opencms.workplace.commons.Messages.GUI_LABEL_DATE_LAST_MODIFIED_0);
1286        String dateLastModified = CmsVfsService.formatDateTime(cms, resource.getDateLastModified());
1287
1288        String userLastModifiedLabel = org.opencms.workplace.commons.Messages.get().getBundle(
1289            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1290                org.opencms.workplace.commons.Messages.GUI_LABEL_USER_LAST_MODIFIED_0);
1291        String userLastModified = "" + resource.getUserLastModified();
1292        try {
1293            userLastModified = cms.readUser(resource.getUserLastModified()).getName();
1294        } catch (CmsException e) {
1295            LOG.error(e.getLocalizedMessage(), e);
1296        }
1297
1298        result.addInfo(dateLastModifiedLabel, dateLastModified);
1299        result.addInfo(userLastModifiedLabel, userLastModified);
1300    }
1301
1302    /**
1303     * Creates a bean representing a historical resource version.<p>
1304     *
1305     * @param cms the current CMS context
1306     * @param historyRes the historical resource
1307     * @param offline true if this resource was read from the offline project
1308     * @param maxVersion the largest version number found
1309     *
1310     * @return the bean representing the historical resource
1311     * @throws CmsException if something goes wrong
1312     */
1313    private CmsHistoryResourceBean createHistoryResourceBean(
1314        CmsObject cms,
1315        CmsResource historyRes,
1316        boolean offline,
1317        int maxVersion)
1318    throws CmsException {
1319
1320        CmsHistoryResourceBean result = new CmsHistoryResourceBean();
1321
1322        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1323        result.setStructureId(historyRes.getStructureId());
1324        result.setRootPath(historyRes.getRootPath());
1325        result.setDateLastModified(formatDate(historyRes.getDateLastModified(), locale));
1326        CmsUUID userId = historyRes.getUserLastModified();
1327        String userName = userId.toString();
1328        try {
1329            CmsUser user = cms.readUser(userId);
1330            userName = user.getName();
1331        } catch (CmsException e) {
1332            LOG.warn(e.getLocalizedMessage(), e);
1333        }
1334        result.setUserLastModified(userName);
1335        result.setSize(historyRes.getLength());
1336        if (historyRes instanceof I_CmsHistoryResource) {
1337            int publishTag = ((I_CmsHistoryResource)historyRes).getPublishTag();
1338            CmsHistoryProject project = cms.readHistoryProject(publishTag);
1339            long publishDate = project.getPublishingDate();
1340            result.setDatePublished(formatDate(publishDate, locale));
1341            int version = ((I_CmsHistoryResource)historyRes).getVersion();
1342            result.setVersion(
1343                new CmsHistoryVersion(
1344                    Integer.valueOf(historyRes.getVersion()),
1345                    maxVersion == version ? OfflineOnline.online : null));
1346
1347            List<CmsProperty> historyProperties = cms.readHistoryPropertyObjects((I_CmsHistoryResource)historyRes);
1348            Map<String, CmsProperty> historyPropertyMap = CmsProperty.toObjectMap(historyProperties);
1349            CmsProperty titleProp = CmsProperty.wrapIfNull(
1350                historyPropertyMap.get(CmsPropertyDefinition.PROPERTY_TITLE));
1351            CmsProperty descProp = CmsProperty.wrapIfNull(
1352                historyPropertyMap.get(CmsPropertyDefinition.PROPERTY_DESCRIPTION));
1353            result.setTitle(titleProp.getValue());
1354            result.setDescription(descProp.getValue());
1355        } else {
1356            if (offline) {
1357                result.setVersion(new CmsHistoryVersion(null, OfflineOnline.offline));
1358            } else {
1359                result.setVersion(new CmsHistoryVersion(null, OfflineOnline.online));
1360            }
1361        }
1362        return result;
1363    }
1364
1365    /**
1366     * Internal method to delete the given resource.<p>
1367     *
1368     * @param resource the resource to delete
1369     *
1370     * @throws CmsException if something goes wrong
1371     */
1372    private void deleteResource(CmsResource resource) throws CmsException {
1373
1374        String path = null;
1375        CmsObject cms = getCmsObject();
1376        try {
1377            path = cms.getSitePath(resource);
1378            cms.lockResource(path);
1379            cms.deleteResource(path, CmsResource.DELETE_PRESERVE_SIBLINGS);
1380            // check if any detail container page resources exist to this resource
1381            List<CmsResource> detailContainers = CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, resource);
1382            for (CmsResource detailContainer : detailContainers) {
1383                deleteResource(detailContainer);
1384            }
1385        } finally {
1386            try {
1387                if (path != null) {
1388                    getCmsObject().unlockResource(path);
1389                }
1390            } catch (Exception e) {
1391                // should really never happen
1392                LOG.debug(e.getLocalizedMessage(), e);
1393            }
1394        }
1395    }
1396
1397    /**
1398     * Converts a date to a date bean.<p>
1399     *
1400     * @param date the date to convert
1401     * @param locale the locale to use for the conversion
1402     *
1403     * @return the date bean
1404     */
1405    private CmsClientDateBean formatDate(long date, Locale locale) {
1406
1407        return new CmsClientDateBean(date, formatDateTime(date));
1408    }
1409
1410    /**
1411     * Formats the date for the current user's locale.<p>
1412     *
1413     * @param date the date to format
1414     *
1415     * @return the formatted date for the current user's locale
1416     */
1417    private String formatDateTime(long date) {
1418
1419        CmsObject cms = getCmsObject();
1420        return formatDateTime(cms, date);
1421    }
1422
1423    /**
1424     * Returns the available locales mapped to there display name for the given resource
1425     * or <code>null</code> in case of non xml-content/xml-page resources.<p>
1426     *
1427     * @param resource the resource
1428     *
1429     * @return the available locales
1430     */
1431    private LinkedHashMap<String, String> getAvailableLocales(CmsResource resource) {
1432
1433        LinkedHashMap<String, String> result = null;
1434        List<Locale> locales = null;
1435        try {
1436            if (CmsResourceTypeXmlPage.isXmlPage(resource)) {
1437                locales = CmsXmlPageFactory.unmarshal(getCmsObject(), resource, getRequest()).getLocales();
1438            } else if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
1439                locales = CmsXmlContentFactory.unmarshal(getCmsObject(), resource, getRequest()).getLocales();
1440            } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) {
1441                locales = CmsXmlContainerPageFactory.unmarshal(getCmsObject(), resource).getLocales();
1442            }
1443        } catch (CmsException e) {
1444            LOG.warn(e.getLocalizedMessage(), e);
1445        }
1446        if (locales != null) {
1447            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1448            result = new LinkedHashMap<String, String>();
1449            for (Locale locale : locales) {
1450                result.put(locale.toString(), locale.getDisplayName(wpLocale));
1451            }
1452        }
1453        return result;
1454    }
1455
1456    /**
1457     * Helper method for converting a map which maps resources to resources to a list of "broken link" beans,
1458     * which have beans representing the source of the corresponding link as children.<p>
1459     *
1460     * @param linkMap a multimap from resource to resources
1461     *
1462     * @return a list of beans representing links which will be broken
1463     *
1464     * @throws CmsException if something goes wrong
1465     */
1466    private List<CmsBrokenLinkBean> getBrokenLinkBeans(Multimap<CmsResource, CmsResource> linkMap) throws CmsException {
1467
1468        CmsBrokenLinkRenderer brokenLinkRenderer = new CmsBrokenLinkRenderer(getCmsObject());
1469
1470        Multimap<CmsBrokenLinkBean, CmsBrokenLinkBean> resultMap = HashMultimap.create();
1471
1472        for (CmsResource source : linkMap.keySet()) {
1473
1474            for (CmsResource target : linkMap.get(source)) {
1475                CmsBrokenLinkBean targetBean = createSitemapBrokenLinkBean(target);
1476                addBrokenLinkAdditionalInfo(getCmsObject(), target, targetBean);
1477                List<CmsBrokenLinkBean> brokenLinkBeans = brokenLinkRenderer.renderBrokenLink(target, source);
1478                for (CmsBrokenLinkBean childBean : brokenLinkBeans) {
1479                    addBrokenLinkAdditionalInfo(getCmsObject(), source, childBean);
1480                    resultMap.put(childBean, targetBean);
1481                }
1482            }
1483        }
1484
1485        // now convert multimap representation to parent/child representation
1486        for (CmsBrokenLinkBean parent : resultMap.keySet()) {
1487            for (CmsBrokenLinkBean child : resultMap.get(parent)) {
1488                parent.addChild(child);
1489            }
1490        }
1491        return Lists.newArrayList(resultMap.keySet());
1492    }
1493
1494    /**
1495     * Internal method to get the broken links information for the given resource.<p>
1496     *
1497     * @param entryResource the resource
1498     *
1499     * @return the broken links information
1500     *
1501     * @throws CmsException if something goes wrong
1502     */
1503    private CmsDeleteResourceBean getBrokenLinks(CmsResource entryResource) throws CmsException {
1504
1505        CmsDeleteResourceBean result = null;
1506
1507        CmsListInfoBean info = null;
1508        List<CmsBrokenLinkBean> brokenLinks = null;
1509
1510        CmsObject cms = getCmsObject();
1511        String resourceSitePath = cms.getSitePath(entryResource);
1512
1513        ensureSession();
1514
1515        List<CmsResource> descendants = new ArrayList<CmsResource>();
1516        HashSet<CmsUUID> deleteIds = new HashSet<CmsUUID>();
1517
1518        descendants.add(entryResource);
1519        if (entryResource.isFolder()) {
1520            descendants.addAll(cms.readResources(resourceSitePath, CmsResourceFilter.IGNORE_EXPIRATION));
1521        }
1522
1523        for (CmsResource deleteRes : descendants) {
1524            deleteIds.add(deleteRes.getStructureId());
1525        }
1526        Multimap<CmsResource, CmsResource> linkMap = HashMultimap.create();
1527        for (CmsResource resource : descendants) {
1528            List<CmsRelation> relations = cms.getRelationsForResource(resource, CmsRelationFilter.SOURCES);
1529            List<CmsResource> result1 = new ArrayList<CmsResource>();
1530            for (CmsRelation relation : relations) {
1531                // only add related resources that are not going to be deleted
1532                if (!deleteIds.contains(relation.getSourceId())) {
1533                    CmsResource source1 = relation.getSource(cms, CmsResourceFilter.ALL);
1534                    if (!source1.getState().isDeleted()) {
1535                        result1.add(source1);
1536                    }
1537                }
1538            }
1539            List<CmsResource> linkSources = result1;
1540            for (CmsResource source : linkSources) {
1541                linkMap.put(source, resource);
1542            }
1543        }
1544
1545        brokenLinks = getBrokenLinkBeans(linkMap);
1546        info = getPageInfo(entryResource);
1547
1548        result = new CmsDeleteResourceBean(resourceSitePath, info, brokenLinks);
1549
1550        return result;
1551    }
1552
1553    /**
1554     * Gets the resources which link to a given structure id.<p>
1555     *
1556     * @param cms the current CMS context
1557     * @param resource the relation target resource
1558     * @param deleteIds set of resources to delete
1559     *
1560     * @return the list of resources which link to the given id
1561     *
1562     * @throws CmsException if something goes wrong
1563     */
1564    @SuppressWarnings("unused")
1565    private List<CmsResource> getLinkSources(CmsObject cms, CmsResource resource, HashSet<CmsUUID> deleteIds)
1566    throws CmsException {
1567
1568        List<CmsRelation> relations = cms.getRelationsForResource(resource, CmsRelationFilter.SOURCES);
1569        List<CmsResource> result = new ArrayList<CmsResource>();
1570        for (CmsRelation relation : relations) {
1571            // only add related resources that are not going to be deleted
1572            if (!deleteIds.contains(relation.getSourceId())) {
1573                CmsResource source = relation.getSource(cms, CmsResourceFilter.ALL);
1574                if (!source.getState().isDeleted()) {
1575                    result.add(source);
1576                }
1577            }
1578        }
1579        return result;
1580    }
1581
1582    /**
1583     * Returns a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget}.<p>
1584     *
1585     * @param res the resource to get the page info for
1586     *
1587     * @return a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget}.<p>
1588     *
1589     * @throws CmsLoaderException if the resource type could not be found
1590     * @throws CmsException if something else goes wrong
1591     */
1592    private CmsListInfoBean getPageInfo(CmsResource res) throws CmsException, CmsLoaderException {
1593
1594        CmsObject cms = getCmsObject();
1595        return getPageInfo(cms, res);
1596    }
1597
1598    /**
1599     * Returns the preview info for the given resource.<p>
1600     *
1601     *@param cms the CMS context
1602     * @param resource the resource
1603     * @param locale the requested locale
1604     *
1605     * @return the preview info
1606     */
1607    private CmsPreviewInfo getPreviewInfo(CmsObject cms, CmsResource resource, Locale locale) {
1608
1609        String title = "";
1610        try {
1611            CmsProperty titleProperty = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, false);
1612            title = titleProperty.getValue("");
1613        } catch (CmsException e) {
1614            LOG.warn(e.getLocalizedMessage(), e);
1615        }
1616        String noPreviewReason = getNoPreviewReason(cms, resource);
1617        String previewContent = null;
1618        int height = 0;
1619        int width = 0;
1620        LinkedHashMap<String, String> locales = getAvailableLocales(resource);
1621        if (noPreviewReason != null) {
1622            previewContent = "<div>" + noPreviewReason + "</div>";
1623            return new CmsPreviewInfo(
1624                "<div>" + noPreviewReason + "</div>",
1625                null,
1626                false,
1627                title,
1628                cms.getSitePath(resource),
1629                locale.toString());
1630        } else if (OpenCms.getResourceManager().matchResourceType(
1631            CmsResourceTypeImage.getStaticTypeName(),
1632            resource.getTypeId())) {
1633            CmsImageScaler scaler = new CmsImageScaler(cms, resource);
1634            String imageLink = null;
1635            if (resource instanceof I_CmsHistoryResource) {
1636                int version = ((I_CmsHistoryResource)resource).getVersion();
1637                imageLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1638                    cms,
1639                    CmsHistoryListUtil.getHistoryLink(cms, resource.getStructureId(), "" + version));
1640            } else {
1641                imageLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath());
1642            }
1643            imageLink = CmsRequestUtil.appendParameter(imageLink, "random", "" + Math.random());
1644            previewContent = "<img src=\"" + imageLink + "\" title=\"" + title + "\" style=\"display:block\" />";
1645            height = scaler.getHeight();
1646            width = scaler.getWidth();
1647        } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)
1648            || CmsResourceTypeXmlPage.isXmlPage(resource)) {
1649            String link = "";
1650            if (resource instanceof I_CmsHistoryResource) {
1651                int version = ((I_CmsHistoryResource)resource).getVersion();
1652                link = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1653                    cms,
1654                    CmsHistoryListUtil.getHistoryLink(cms, resource.getStructureId(), "" + version));
1655            } else {
1656                link = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath());
1657            }
1658            return new CmsPreviewInfo(null, link, true, null, cms.getSitePath(resource), locale.toString());
1659        } else if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
1660            if (!locales.containsKey(locale.toString())) {
1661                locale = CmsLocaleManager.getMainLocale(cms, resource);
1662            }
1663            previewContent = CmsPreviewService.getPreviewContent(getRequest(), getResponse(), cms, resource, locale);
1664
1665        } else if (CmsResourceTypePlain.getStaticTypeId() == resource.getTypeId()) {
1666            try {
1667                previewContent = "<pre><code>" + new String(cms.readFile(resource).getContents()) + "</code></pre>";
1668            } catch (CmsException e) {
1669                LOG.warn(e.getLocalizedMessage(), e);
1670                previewContent = "<div>"
1671                    + Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1672                        Messages.GUI_NO_PREVIEW_CAN_T_READ_CONTENT_0)
1673                    + "</div>";
1674            }
1675        }
1676        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(previewContent)) {
1677            CmsPreviewInfo result = new CmsPreviewInfo(
1678                previewContent,
1679                null,
1680                false,
1681                title,
1682                cms.getSitePath(resource),
1683                locale.toString());
1684            result.setHeight(height);
1685            result.setWidth(width);
1686            result.setLocales(locales);
1687            return result;
1688        }
1689        if (CmsResourceTypeXmlContainerPage.isContainerPage(resource) || CmsResourceTypeXmlPage.isXmlPage(resource)) {
1690            CmsPreviewInfo result = new CmsPreviewInfo(
1691                null,
1692                OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath())
1693                    + "?"
1694                    + CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT
1695                    + "=true"
1696                    + "&__locale="
1697                    + locale.toString(),
1698                false,
1699                title,
1700                cms.getSitePath(resource),
1701                locale.toString());
1702            result.setLocales(locales);
1703            return result;
1704        }
1705        return new CmsPreviewInfo(
1706            null,
1707            OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath())
1708                + "?"
1709                + CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT
1710                + "=true",
1711            true,
1712            title,
1713            cms.getSitePath(resource),
1714            locale.toString());
1715    }
1716
1717}