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#getDetailName(org.opencms.util.CmsUUID, java.lang.String)
578     */
579    public String getDetailName(CmsUUID id, String localeStr) throws CmsRpcException {
580
581        CmsObject cms = getCmsObject();
582        try {
583            OpenCms.getLocaleManager();
584            Locale locale = CmsLocaleManager.getLocale(localeStr);
585            return cms.readBestUrlName(id, locale, OpenCms.getLocaleManager().getDefaultLocales());
586        } catch (Exception e) {
587            error(e);
588            return null;
589        }
590    }
591
592    /**
593     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getFileReplaceInfo(org.opencms.util.CmsUUID)
594     */
595    public CmsReplaceInfo getFileReplaceInfo(CmsUUID structureId) throws CmsRpcException {
596
597        CmsReplaceInfo result = null;
598        try {
599            CmsObject cms = getCmsObject();
600            CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
601            CmsListInfoBean fileInfo = getPageInfo(res);
602            boolean isLockable = cms.getLock(res).isLockableBy(cms.getRequestContext().getCurrentUser());
603            long maxFileSize = OpenCms.getWorkplaceManager().getFileBytesMaxUploadSize(cms);
604            result = new CmsReplaceInfo(fileInfo, cms.getSitePath(res), isLockable, maxFileSize);
605        } catch (Throwable e) {
606            error(e);
607        }
608        return result;
609    }
610
611    /**
612     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getHistoryPreviewInfo(org.opencms.util.CmsUUID, java.lang.String, org.opencms.gwt.shared.CmsHistoryVersion)
613     */
614    public CmsPreviewInfo getHistoryPreviewInfo(CmsUUID structureId, String locale, CmsHistoryVersion versionBean)
615    throws CmsRpcException {
616
617        try {
618            CmsObject cms = getCmsObject();
619            CmsResource previewResource = null;
620            if (versionBean.getVersionNumber() != null) {
621                previewResource = (CmsResource)(cms.readResource(
622                    structureId,
623                    versionBean.getVersionNumber().intValue()));
624            } else if (versionBean.isOffline()) {
625                previewResource = cms.readResource(structureId, CmsResourceFilter.ALL);
626            } else if (versionBean.isOnline()) {
627                CmsProject online = cms.readProject(CmsProject.ONLINE_PROJECT_ID);
628                cms = OpenCms.initCmsObject(cms);
629                cms.getRequestContext().setCurrentProject(online);
630                previewResource = cms.readResource(structureId, CmsResourceFilter.ALL);
631            }
632            CmsFile previewFile = cms.readFile(previewResource);
633            return getPreviewInfo(cms, previewFile, CmsLocaleManager.getLocale(locale));
634        } catch (Exception e) {
635            error(e);
636            return null; // return statement will never be reached
637        }
638    }
639
640    /**
641     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getLockReportInfo(org.opencms.util.CmsUUID)
642     */
643    public CmsLockReportInfo getLockReportInfo(CmsUUID structureId) throws CmsRpcException {
644
645        CmsLockReportInfo result = null;
646        CmsObject cms = getCmsObject();
647        try {
648            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
649            List<CmsListInfoBean> lockedInfos = new ArrayList<CmsListInfoBean>();
650            List<CmsResource> lockedResources = cms.getBlockingLockedResources(resource);
651            if (lockedResources != null) {
652                for (CmsResource lockedResource : lockedResources) {
653                    lockedInfos.add(getPageInfoWithLock(cms, lockedResource));
654                }
655            }
656            result = new CmsLockReportInfo(getPageInfoWithLock(cms, resource), lockedInfos);
657        } catch (Throwable e) {
658            error(e);
659        }
660        return result;
661    }
662
663    /**
664     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPageInfo(org.opencms.util.CmsUUID)
665     */
666    public CmsListInfoBean getPageInfo(CmsUUID structureId) throws CmsRpcException {
667
668        try {
669            CmsResource res = getCmsObject().readResource(structureId, CmsResourceFilter.ALL);
670            return getPageInfo(res);
671        } catch (Throwable e) {
672            error(e);
673            return null; // will never be reached
674        }
675    }
676
677    /**
678     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPageInfo(java.lang.String)
679     */
680    public CmsListInfoBean getPageInfo(String vfsPath) throws CmsRpcException {
681
682        try {
683            CmsResource res = getCmsObject().readResource(vfsPath, CmsResourceFilter.IGNORE_EXPIRATION);
684            return getPageInfo(res);
685        } catch (Throwable e) {
686            error(e);
687            return null; // will never be reached
688        }
689    }
690
691    /**
692     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPreviewInfo(org.opencms.util.CmsUUID, java.lang.String)
693     */
694    public CmsPreviewInfo getPreviewInfo(CmsUUID structureId, String locale) throws CmsRpcException {
695
696        CmsPreviewInfo result = null;
697        try {
698            result = getPreviewInfo(
699                getCmsObject(),
700                getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION),
701                CmsLocaleManager.getLocale(locale));
702        } catch (Exception e) {
703            error(e);
704        }
705        return result;
706
707    }
708
709    /**
710     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getPreviewInfo(java.lang.String, java.lang.String)
711     */
712    public CmsPreviewInfo getPreviewInfo(String sitePath, String locale) throws CmsRpcException {
713
714        CmsPreviewInfo result = null;
715        try {
716            result = getPreviewInfo(
717                getCmsObject(),
718                getCmsObject().readResource(sitePath, CmsResourceFilter.IGNORE_EXPIRATION),
719                CmsLocaleManager.getLocale(locale));
720        } catch (Exception e) {
721            error(e);
722        }
723        return result;
724    }
725
726    /**
727     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRenameInfo(org.opencms.util.CmsUUID)
728     */
729    public CmsRenameInfoBean getRenameInfo(CmsUUID structureId) throws CmsRpcException {
730
731        try {
732            CmsObject cms = getCmsObject();
733            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
734            CmsListInfoBean listInfo = getPageInfo(resource);
735            String sitePath = cms.getSitePath(resource);
736            return new CmsRenameInfoBean(sitePath, structureId, listInfo);
737        } catch (Throwable e) {
738            error(e);
739            return null;
740        }
741    }
742
743    /**
744     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getResourceHistory(org.opencms.util.CmsUUID)
745     */
746    public CmsHistoryResourceCollection getResourceHistory(CmsUUID structureId) throws CmsRpcException {
747
748        try {
749            CmsHistoryResourceCollection result = getResourceHistoryInternal(structureId);
750            CmsListInfoBean info = getPageInfo(structureId);
751            result.setContentInfo(info);
752            return result;
753
754        } catch (Exception e) {
755            error(e);
756            return null; // return statement will  never be reached
757        }
758    }
759
760    /**
761     * Internal version of getResourceHistory.<p>
762     *
763     * @param structureId the structure id of the resource
764     *
765     * @return the resource history
766     *
767     * @throws CmsException if something goes wrong
768     */
769    public CmsHistoryResourceCollection getResourceHistoryInternal(CmsUUID structureId) throws CmsException {
770
771        CmsHistoryResourceCollection result = new CmsHistoryResourceCollection();
772        CmsObject cms = getCmsObject();
773        CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
774        List<I_CmsHistoryResource> versions = cms.readAllAvailableVersions(resource);
775        if (!resource.getState().isUnchanged()) {
776            result.add(createHistoryResourceBean(cms, resource, true, -1));
777        }
778        int maxVersion = 0;
779
780        if (versions.isEmpty()) {
781            try {
782                CmsProject online = cms.readProject(CmsProject.ONLINE_PROJECT_ID);
783                CmsObject onlineCms = OpenCms.initCmsObject(cms);
784                onlineCms.getRequestContext().setCurrentProject(online);
785                CmsResource onlineResource = onlineCms.readResource(structureId, CmsResourceFilter.ALL);
786                CmsHistoryResourceBean onlineResBean = createHistoryResourceBean(onlineCms, onlineResource, false, 0);
787                result.add(onlineResBean);
788            } catch (CmsVfsResourceNotFoundException e) {
789                LOG.info(e.getLocalizedMessage(), e);
790            } catch (Exception e) {
791                LOG.error(e.getLocalizedMessage(), e);
792            }
793        } else {
794            for (I_CmsHistoryResource historyRes : versions) {
795                maxVersion = Math.max(maxVersion, historyRes.getVersion());
796            }
797            for (I_CmsHistoryResource historyRes : versions) {
798                CmsHistoryResourceBean historyBean = createHistoryResourceBean(
799                    cms,
800                    (CmsResource)historyRes,
801                    false,
802                    maxVersion);
803                result.add(historyBean);
804            }
805        }
806        return result;
807    }
808
809    /**
810     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getResourceStatus(org.opencms.util.CmsUUID, java.lang.String, boolean, org.opencms.util.CmsUUID, java.util.Map)
811     */
812    public CmsResourceStatusBean getResourceStatus(
813        CmsUUID structureId,
814        String contentLocale,
815        boolean includeTargets,
816        CmsUUID detailContentId,
817        Map<String, String> context)
818    throws CmsRpcException {
819
820        if (context == null) {
821            context = new HashMap<>();
822        }
823        try {
824            CmsObject cms = getCmsObject();
825            CmsDefaultResourceStatusProvider provider = new CmsDefaultResourceStatusProvider();
826            return provider.getResourceStatus(
827                getRequest(),
828                cms,
829                structureId,
830                contentLocale,
831                includeTargets,
832                detailContentId,
833                detailContentId != null ? Collections.singletonList(detailContentId) : null,
834                context);
835        } catch (Throwable e) {
836            error(e);
837            return null;
838        }
839    }
840
841    /**
842     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRestoreInfo(org.opencms.util.CmsUUID)
843     */
844    public CmsRestoreInfoBean getRestoreInfo(CmsUUID structureId) throws CmsRpcException {
845
846        try {
847            CmsObject cms = getCmsObject();
848            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
849            CmsListInfoBean listInfo = getPageInfo(resource);
850            CmsRestoreInfoBean result = new CmsRestoreInfoBean();
851            result.setListInfoBean(listInfo);
852
853            CmsObject onlineCms = OpenCms.initCmsObject(cms);
854            CmsProject onlineProject = cms.readProject(CmsProject.ONLINE_PROJECT_NAME);
855            onlineCms.getRequestContext().setCurrentProject(onlineProject);
856            CmsResource onlineResource = onlineCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
857            result.setOnlinePath(onlineResource.getRootPath());
858            result.setOfflinePath(resource.getRootPath());
859
860            String offlineDate = formatDateTime(resource.getDateLastModified());
861            String onlineDate = formatDateTime(onlineResource.getDateLastModified());
862            result.setOfflineDate(offlineDate);
863            result.setOnlineDate(onlineDate);
864            result.setStructureId(structureId);
865
866            CmsObject offlineRootCms = OpenCms.initCmsObject(cms);
867            offlineRootCms.getRequestContext().setSiteRoot("");
868            CmsObject onlineRootCms = OpenCms.initCmsObject(onlineCms);
869            onlineRootCms.getRequestContext().setSiteRoot("");
870            String parent = CmsResource.getParentFolder(onlineResource.getRootPath());
871            boolean canUndoMove = offlineRootCms.existsResource(parent, CmsResourceFilter.IGNORE_EXPIRATION);
872
873            result.setCanUndoMove(canUndoMove);
874
875            return result;
876        } catch (Throwable e) {
877            error(e);
878            return null;
879        }
880    }
881
882    /**
883     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getRootEntries()
884     */
885    public List<CmsVfsEntryBean> getRootEntries() throws CmsRpcException {
886
887        try {
888            CmsObject cms = getCmsObject();
889            List<CmsResource> roots = new ArrayList<CmsResource>();
890            roots.add(cms.readResource("/", CmsResourceFilter.IGNORE_EXPIRATION));
891            return makeEntryBeans(roots, true);
892        } catch (CmsException e) {
893            error(e);
894        }
895        return null;
896    }
897
898    /**
899     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#getSitePath(org.opencms.util.CmsUUID)
900     */
901    public String getSitePath(CmsUUID structureId) {
902
903        try {
904            CmsResource resource = getCmsObject().readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
905            return getCmsObject().getSitePath(resource);
906        } catch (CmsException e) {
907            if (LOG.isWarnEnabled()) {
908                LOG.warn(e.getMessageContainer(), e);
909            }
910        }
911        return null;
912    }
913
914    /**
915     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadLinkInfo(org.opencms.util.CmsUUID)
916     */
917    public CmsExternalLinkInfoBean loadLinkInfo(CmsUUID structureId) throws CmsRpcException {
918
919        CmsExternalLinkInfoBean info = new CmsExternalLinkInfoBean();
920        CmsObject cms = getCmsObject();
921        try {
922            CmsResource linkResource = cms.readResource(structureId, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
923            addPageInfo(cms, linkResource, info);
924            CmsFile linkFile = cms.readFile(linkResource);
925            OpenCms.getLocaleManager();
926            String link = new String(linkFile.getContents(), CmsLocaleManager.getResourceEncoding(cms, linkResource));
927            info.setLink(link);
928            info.setSitePath(cms.getSitePath(linkResource));
929        } catch (Exception e) {
930            error(e);
931        }
932        return info;
933    }
934
935    /**
936     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadPropertyData(org.opencms.util.CmsUUID)
937     */
938    public CmsPropertiesBean loadPropertyData(CmsUUID id) throws CmsRpcException {
939
940        CmsObject cms = getCmsObject();
941        try {
942            CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(cms);
943            return helper.loadPropertyData(id);
944        } catch (Throwable e) {
945            error(e);
946        }
947        return null;
948    }
949
950    /**
951     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#loadQuickLaunchItems(org.opencms.gwt.shared.CmsQuickLaunchParams)
952     */
953    public List<CmsQuickLaunchData> loadQuickLaunchItems(CmsQuickLaunchParams params) throws CmsRpcException {
954
955        try {
956            return CmsQuickLaunchProvider.getQuickLaunchData(getCmsObject(), getRequest().getSession(), params);
957        } catch (Exception e) {
958            error(e);
959            return null;
960        }
961    }
962
963    /**
964     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#prepareEdit(org.opencms.util.CmsUUID, java.lang.String)
965     */
966    public CmsPrepareEditResponse prepareEdit(CmsUUID currentPageId, String pathWithMacros) throws CmsRpcException {
967
968        try {
969            CmsObject cms = getCmsObject();
970            CmsResource resource = null;
971            if (cms.existsResource(pathWithMacros, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
972                resource = cms.readResource(pathWithMacros, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
973            } else {
974                CmsResource currentPage = cms.readResource(currentPageId, CmsResourceFilter.IGNORE_EXPIRATION);
975                String path = prepareFileNameForEditor(cms, currentPage, pathWithMacros);
976                resource = cms.readResource(path, CmsResourceFilter.IGNORE_EXPIRATION);
977            }
978            ensureLock(resource);
979            CmsPrepareEditResponse result = new CmsPrepareEditResponse();
980            result.setRootPath(resource.getRootPath());
981            result.setSitePath(cms.getSitePath(resource));
982            result.setStructureId(resource.getStructureId());
983            return result;
984        } catch (Throwable e) {
985            error(e);
986        }
987        return null;
988    }
989
990    /**
991     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#renameResource(org.opencms.util.CmsUUID, java.lang.String)
992     */
993    public String renameResource(CmsUUID structureId, String newName) throws CmsRpcException {
994
995        try {
996            return renameResourceInternal(structureId, newName);
997        } catch (Throwable e) {
998            error(e);
999            return null;
1000        }
1001    }
1002
1003    /**
1004     * Internal implementation for renaming a resource.<p>
1005     *
1006     * @param structureId the structure id of the resource to rename
1007     * @param newName the new resource name
1008     * @return either null if the rename was successful, or an error message
1009     *
1010     * @throws CmsException if something goes wrong
1011     */
1012    public String renameResourceInternal(CmsUUID structureId, String newName) throws CmsException {
1013
1014        newName = newName.trim();
1015        CmsObject rootCms = OpenCms.initCmsObject(getCmsObject());
1016        rootCms.getRequestContext().setSiteRoot("");
1017        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(rootCms);
1018        try {
1019            CmsResource.checkResourceName(newName);
1020        } catch (CmsIllegalArgumentException e) {
1021            return e.getLocalizedMessage(locale);
1022        }
1023        CmsResource resource = rootCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1024        String oldPath = resource.getRootPath();
1025        String parentPath = CmsResource.getParentFolder(oldPath);
1026        String newPath = CmsStringUtil.joinPaths(parentPath, newName);
1027        try {
1028            ensureLock(resource);
1029            rootCms.moveResource(oldPath, newPath);
1030            resource = rootCms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1031        } catch (CmsException e) {
1032            return e.getLocalizedMessage(OpenCms.getWorkplaceManager().getWorkplaceLocale(rootCms));
1033        }
1034        tryUnlock(resource);
1035        return null;
1036    }
1037
1038    /**
1039     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#restoreResource(org.opencms.util.CmsUUID, int)
1040     */
1041    public void restoreResource(CmsUUID structureId, int version) throws CmsRpcException {
1042
1043        CmsObject cms = getCmsObject();
1044        try {
1045            ensureLock(structureId);
1046            cms.restoreResourceVersion(structureId, version);
1047            try {
1048                CmsResource res = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1049                cms.unlockResource(res);
1050            } catch (Exception e) {
1051                LOG.error(e.getLocalizedMessage(), e);
1052            }
1053
1054        } catch (Exception e) {
1055            error(e);
1056            return; // return stmt  will never be reached
1057        }
1058
1059    }
1060
1061    /**
1062     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveAliases(org.opencms.util.CmsUUID, java.util.List)
1063     */
1064    public void saveAliases(CmsUUID structureId, List<CmsAliasBean> aliasBeans) throws CmsRpcException {
1065
1066        try {
1067            m_aliasHelper.saveAliases(structureId, aliasBeans);
1068        } catch (Throwable e) {
1069            error(e);
1070        }
1071    }
1072
1073    /**
1074     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveExternalLink(org.opencms.util.CmsUUID, java.lang.String, java.lang.String, java.lang.String)
1075     */
1076    public void saveExternalLink(CmsUUID structureId, String title, String link, String fileName)
1077    throws CmsRpcException {
1078
1079        try {
1080            CmsObject cms = getCmsObject();
1081            CmsResource res = cms.readResource(structureId);
1082            ensureLock(res);
1083            CmsFile file = cms.readFile(res);
1084            String oldLink = new String(file.getContents(), CmsLocaleManager.getResourceEncoding(cms, res));
1085            if (!oldLink.equals(link)) {
1086                file.setContents(link.getBytes(CmsLocaleManager.getResourceEncoding(cms, res)));
1087                cms.writeFile(file);
1088            }
1089            CmsProperty titleProp = cms.readPropertyObject(res, CmsPropertyDefinition.PROPERTY_TITLE, false);
1090            if (titleProp.isNullProperty()) {
1091                titleProp = new CmsProperty(CmsPropertyDefinition.PROPERTY_TITLE, title, null);
1092                cms.writePropertyObject(cms.getSitePath(res), titleProp);
1093            } else if (!titleProp.getValue().equals(title)) {
1094                titleProp.setStructureValue(title);
1095                cms.writePropertyObject(cms.getSitePath(res), titleProp);
1096            }
1097            if (!res.getName().equals(fileName)) {
1098                String oldSitePath = cms.getSitePath(res);
1099                String newSitePath = CmsStringUtil.joinPaths(CmsResource.getParentFolder(oldSitePath), fileName);
1100                getCmsObject().renameResource(oldSitePath, newSitePath);
1101            }
1102            tryUnlock(res);
1103            // update the offline search indices
1104            OpenCms.getSearchManager().updateOfflineIndexes();
1105        } catch (Exception e) {
1106            error(e);
1107        }
1108    }
1109
1110    /**
1111     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#saveProperties(org.opencms.gwt.shared.property.CmsPropertyChangeSet)
1112     */
1113    public void saveProperties(CmsPropertyChangeSet changes) throws CmsRpcException {
1114
1115        String origSiteRoot = getCmsObject().getRequestContext().getSiteRoot();
1116        try {
1117            getCmsObject().getRequestContext().setSiteRoot("");
1118            CmsPropertyEditorHelper helper = new CmsPropertyEditorHelper(getCmsObject());
1119            helper.saveProperties(changes);
1120        } catch (Throwable t) {
1121            error(t);
1122        } finally {
1123            getCmsObject().getRequestContext().setSiteRoot(origSiteRoot);
1124        }
1125    }
1126
1127    /**
1128     * Sets the current cms context.<p>
1129     *
1130     * @param cms the current cms context to set
1131     */
1132    @Override
1133    public synchronized void setCms(CmsObject cms) {
1134
1135        super.setCms(cms);
1136        m_aliasHelper.setCms(cms);
1137    }
1138
1139    /**
1140     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#substituteLinkForRootPath(java.lang.String, java.lang.String)
1141     */
1142    public String substituteLinkForRootPath(String currentSiteRoot, String rootPath) throws CmsRpcException {
1143
1144        String result = null;
1145        try {
1146            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1147            cms.getRequestContext().setSiteRoot(currentSiteRoot);
1148            result = OpenCms.getLinkManager().substituteLinkForRootPath(cms, rootPath);
1149        } catch (CmsException e) {
1150            error(e);
1151        }
1152        return result;
1153    }
1154
1155    /**
1156     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#syncDeleteResource(org.opencms.util.CmsUUID)
1157     */
1158    public void syncDeleteResource(CmsUUID structureId) throws CmsRpcException {
1159
1160        deleteResource(structureId);
1161    }
1162
1163    /**
1164     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#undelete(org.opencms.util.CmsUUID)
1165     */
1166    public void undelete(CmsUUID structureId) throws CmsRpcException {
1167
1168        try {
1169            CmsObject cms = OpenCms.initCmsObject(getCmsObject());
1170            cms.getRequestContext().setSiteRoot("");
1171            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.ALL);
1172            ensureLock(resource);
1173            cms.undeleteResource(resource.getRootPath(), true);
1174        } catch (Exception e) {
1175            error(e);
1176        }
1177    }
1178
1179    /**
1180     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#undoChanges(org.opencms.util.CmsUUID, boolean)
1181     */
1182    public void undoChanges(CmsUUID structureId, boolean undoMove) throws CmsRpcException {
1183
1184        try {
1185            CmsObject cms = getCmsObject();
1186            CmsResource resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1187            ensureLock(resource);
1188            CmsResourceUndoMode mode = undoMove ? CmsResource.UNDO_MOVE_CONTENT : CmsResource.UNDO_CONTENT;
1189            String path = cms.getSitePath(resource);
1190            cms.undoChanges(path, mode);
1191            try {
1192                resource = cms.readResource(structureId, CmsResourceFilter.IGNORE_EXPIRATION);
1193                path = cms.getSitePath(resource);
1194                cms.unlockResource(path);
1195            } catch (CmsException e) {
1196                LOG.info("Could not unlock resource after undoing changes: " + e.getLocalizedMessage(), e);
1197            }
1198        } catch (Throwable e) {
1199            error(e);
1200        }
1201    }
1202
1203    /**
1204     * @see org.opencms.gwt.shared.rpc.I_CmsVfsService#validateAliases(org.opencms.util.CmsUUID, java.util.Map)
1205     */
1206    public Map<String, String> validateAliases(CmsUUID uuid, Map<String, String> aliasPaths) throws CmsRpcException {
1207
1208        try {
1209            return m_aliasHelper.validateAliases(uuid, aliasPaths);
1210        } catch (Throwable e) {
1211            error(e);
1212        }
1213        return null;
1214
1215    }
1216
1217    /**
1218     * Creates a "broken link" bean based on a resource.<p>
1219     *
1220     * @param resource the resource
1221     *
1222     * @return the "broken link" bean with the data from the resource
1223     *
1224     * @throws CmsException if something goes wrong
1225     */
1226    protected CmsBrokenLinkBean createSitemapBrokenLinkBean(CmsResource resource) throws CmsException {
1227
1228        CmsObject cms = getCmsObject();
1229        CmsProperty titleProp = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, true);
1230        String typeName = OpenCms.getResourceManager().getResourceType(resource).getTypeName();
1231        String defaultTitle = "";
1232        String title = titleProp.getValue(defaultTitle);
1233        String path = cms.getSitePath(resource);
1234        String subtitle = path;
1235
1236        CmsBrokenLinkBean result = new CmsBrokenLinkBean(resource.getStructureId(), title, subtitle, typeName);
1237
1238        return result;
1239    }
1240
1241    /**
1242     * Helper method for creating a VFS entry bean from a resource.<p>
1243     *
1244     * @param resource the resource whose data should be stored in the bean
1245     * @param root true if the resource is a root resource
1246     *
1247     * @return the data bean representing the resource
1248     *
1249     * @throws CmsException if something goes wrong
1250     */
1251    protected CmsVfsEntryBean makeEntryBean(CmsResource resource, boolean root) throws CmsException {
1252
1253        CmsObject cms = getCmsObject();
1254        boolean isFolder = resource.isFolder();
1255        String name = root ? "/" : resource.getName();
1256        String path = cms.getSitePath(resource);
1257        boolean hasChildren = false;
1258        if (isFolder) {
1259            List<CmsResource> children = cms.getResourcesInFolder(
1260                cms.getRequestContext().getSitePath(resource),
1261                CmsResourceFilter.DEFAULT);
1262            if (!children.isEmpty()) {
1263                hasChildren = true;
1264            }
1265        }
1266        String resourceType = OpenCms.getResourceManager().getResourceType(resource.getTypeId()).getTypeName();
1267
1268        return new CmsVfsEntryBean(path, name, resourceType, isFolder, hasChildren);
1269    }
1270
1271    /**
1272     * Helper method for creating a list of VFS entry beans from a list of the corresponding resources.<p>
1273     *
1274     * @param resources the list of resources which should be converted to entry beans
1275     * @param root true if the resources in the list are root resources
1276     *
1277     * @return the list of VFS entry beans for the resources
1278     *
1279     * @throws CmsException if something goes wrong
1280     */
1281    protected List<CmsVfsEntryBean> makeEntryBeans(List<CmsResource> resources, boolean root) throws CmsException {
1282
1283        List<CmsVfsEntryBean> result = new ArrayList<CmsVfsEntryBean>();
1284        for (CmsResource res : resources) {
1285            result.add(makeEntryBean(res, root));
1286        }
1287        return result;
1288    }
1289
1290    /**
1291     * Adds additional info items for broken links.<p>
1292     *
1293     * @param cms the CMS context to use
1294     * @param resource the resource from which the additional infos should be read
1295     * @param result the result in which to store the additional info
1296     */
1297    private void addBrokenLinkAdditionalInfo(CmsObject cms, CmsResource resource, CmsBrokenLinkBean result) {
1298
1299        String dateLastModifiedLabel = org.opencms.workplace.commons.Messages.get().getBundle(
1300            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1301                org.opencms.workplace.commons.Messages.GUI_LABEL_DATE_LAST_MODIFIED_0);
1302        String dateLastModified = CmsVfsService.formatDateTime(cms, resource.getDateLastModified());
1303
1304        String userLastModifiedLabel = org.opencms.workplace.commons.Messages.get().getBundle(
1305            OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1306                org.opencms.workplace.commons.Messages.GUI_LABEL_USER_LAST_MODIFIED_0);
1307        String userLastModified = "" + resource.getUserLastModified();
1308        try {
1309            userLastModified = cms.readUser(resource.getUserLastModified()).getName();
1310        } catch (CmsException e) {
1311            LOG.error(e.getLocalizedMessage(), e);
1312        }
1313
1314        result.addInfo(dateLastModifiedLabel, dateLastModified);
1315        result.addInfo(userLastModifiedLabel, userLastModified);
1316    }
1317
1318    /**
1319     * Creates a bean representing a historical resource version.<p>
1320     *
1321     * @param cms the current CMS context
1322     * @param historyRes the historical resource
1323     * @param offline true if this resource was read from the offline project
1324     * @param maxVersion the largest version number found
1325     *
1326     * @return the bean representing the historical resource
1327     * @throws CmsException if something goes wrong
1328     */
1329    private CmsHistoryResourceBean createHistoryResourceBean(
1330        CmsObject cms,
1331        CmsResource historyRes,
1332        boolean offline,
1333        int maxVersion)
1334    throws CmsException {
1335
1336        CmsHistoryResourceBean result = new CmsHistoryResourceBean();
1337
1338        Locale locale = OpenCms.getWorkplaceManager().getWorkplaceLocale(cms);
1339        result.setStructureId(historyRes.getStructureId());
1340        result.setRootPath(historyRes.getRootPath());
1341        result.setDateLastModified(formatDate(historyRes.getDateLastModified(), locale));
1342        CmsUUID userId = historyRes.getUserLastModified();
1343        String userName = userId.toString();
1344        try {
1345            CmsUser user = cms.readUser(userId);
1346            userName = user.getName();
1347        } catch (CmsException e) {
1348            LOG.warn(e.getLocalizedMessage(), e);
1349        }
1350        result.setUserLastModified(userName);
1351        result.setSize(historyRes.getLength());
1352        if (historyRes instanceof I_CmsHistoryResource) {
1353            int publishTag = ((I_CmsHistoryResource)historyRes).getPublishTag();
1354            CmsHistoryProject project = cms.readHistoryProject(publishTag);
1355            long publishDate = project.getPublishingDate();
1356            result.setDatePublished(formatDate(publishDate, locale));
1357            int version = ((I_CmsHistoryResource)historyRes).getVersion();
1358            result.setVersion(
1359                new CmsHistoryVersion(
1360                    Integer.valueOf(historyRes.getVersion()),
1361                    maxVersion == version ? OfflineOnline.online : null));
1362
1363            List<CmsProperty> historyProperties = cms.readHistoryPropertyObjects((I_CmsHistoryResource)historyRes);
1364            Map<String, CmsProperty> historyPropertyMap = CmsProperty.toObjectMap(historyProperties);
1365            CmsProperty titleProp = CmsProperty.wrapIfNull(
1366                historyPropertyMap.get(CmsPropertyDefinition.PROPERTY_TITLE));
1367            CmsProperty descProp = CmsProperty.wrapIfNull(
1368                historyPropertyMap.get(CmsPropertyDefinition.PROPERTY_DESCRIPTION));
1369            result.setTitle(titleProp.getValue());
1370            result.setDescription(descProp.getValue());
1371        } else {
1372            if (offline) {
1373                result.setVersion(new CmsHistoryVersion(null, OfflineOnline.offline));
1374            } else {
1375                result.setVersion(new CmsHistoryVersion(null, OfflineOnline.online));
1376            }
1377        }
1378        return result;
1379    }
1380
1381    /**
1382     * Internal method to delete the given resource.<p>
1383     *
1384     * @param resource the resource to delete
1385     *
1386     * @throws CmsException if something goes wrong
1387     */
1388    private void deleteResource(CmsResource resource) throws CmsException {
1389
1390        String path = null;
1391        CmsObject cms = getCmsObject();
1392        try {
1393            path = cms.getSitePath(resource);
1394            cms.lockResource(path);
1395            cms.deleteResource(path, CmsResource.DELETE_PRESERVE_SIBLINGS);
1396            // check if any detail container page resources exist to this resource
1397            List<CmsResource> detailContainers = CmsDetailOnlyContainerUtil.getDetailOnlyResources(cms, resource);
1398            for (CmsResource detailContainer : detailContainers) {
1399                deleteResource(detailContainer);
1400            }
1401        } finally {
1402            try {
1403                if (path != null) {
1404                    getCmsObject().unlockResource(path);
1405                }
1406            } catch (Exception e) {
1407                // should really never happen
1408                LOG.debug(e.getLocalizedMessage(), e);
1409            }
1410        }
1411    }
1412
1413    /**
1414     * Converts a date to a date bean.<p>
1415     *
1416     * @param date the date to convert
1417     * @param locale the locale to use for the conversion
1418     *
1419     * @return the date bean
1420     */
1421    private CmsClientDateBean formatDate(long date, Locale locale) {
1422
1423        return new CmsClientDateBean(date, formatDateTime(date));
1424    }
1425
1426    /**
1427     * Formats the date for the current user's locale.<p>
1428     *
1429     * @param date the date to format
1430     *
1431     * @return the formatted date for the current user's locale
1432     */
1433    private String formatDateTime(long date) {
1434
1435        CmsObject cms = getCmsObject();
1436        return formatDateTime(cms, date);
1437    }
1438
1439    /**
1440     * Returns the available locales mapped to there display name for the given resource
1441     * or <code>null</code> in case of non xml-content/xml-page resources.<p>
1442     *
1443     * @param resource the resource
1444     *
1445     * @return the available locales
1446     */
1447    private LinkedHashMap<String, String> getAvailableLocales(CmsResource resource) {
1448
1449        LinkedHashMap<String, String> result = null;
1450        List<Locale> locales = null;
1451        try {
1452            if (CmsResourceTypeXmlPage.isXmlPage(resource)) {
1453                locales = CmsXmlPageFactory.unmarshal(getCmsObject(), resource, getRequest()).getLocales();
1454            } else if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
1455                locales = CmsXmlContentFactory.unmarshal(getCmsObject(), resource, getRequest()).getLocales();
1456            } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)) {
1457                locales = CmsXmlContainerPageFactory.unmarshal(getCmsObject(), resource).getLocales();
1458            }
1459        } catch (CmsException e) {
1460            LOG.warn(e.getLocalizedMessage(), e);
1461        }
1462        if (locales != null) {
1463            Locale wpLocale = OpenCms.getWorkplaceManager().getWorkplaceLocale(getCmsObject());
1464            result = new LinkedHashMap<String, String>();
1465            for (Locale locale : locales) {
1466                result.put(locale.toString(), locale.getDisplayName(wpLocale));
1467            }
1468        }
1469        return result;
1470    }
1471
1472    /**
1473     * Helper method for converting a map which maps resources to resources to a list of "broken link" beans,
1474     * which have beans representing the source of the corresponding link as children.<p>
1475     *
1476     * @param linkMap a multimap from resource to resources
1477     *
1478     * @return a list of beans representing links which will be broken
1479     *
1480     * @throws CmsException if something goes wrong
1481     */
1482    private List<CmsBrokenLinkBean> getBrokenLinkBeans(Multimap<CmsResource, CmsResource> linkMap) throws CmsException {
1483
1484        CmsBrokenLinkRenderer brokenLinkRenderer = new CmsBrokenLinkRenderer(getCmsObject());
1485
1486        Multimap<CmsBrokenLinkBean, CmsBrokenLinkBean> resultMap = HashMultimap.create();
1487
1488        for (CmsResource source : linkMap.keySet()) {
1489
1490            for (CmsResource target : linkMap.get(source)) {
1491                CmsBrokenLinkBean targetBean = createSitemapBrokenLinkBean(target);
1492                addBrokenLinkAdditionalInfo(getCmsObject(), target, targetBean);
1493                List<CmsBrokenLinkBean> brokenLinkBeans = brokenLinkRenderer.renderBrokenLink(target, source);
1494                for (CmsBrokenLinkBean childBean : brokenLinkBeans) {
1495                    addBrokenLinkAdditionalInfo(getCmsObject(), source, childBean);
1496                    resultMap.put(childBean, targetBean);
1497                }
1498            }
1499        }
1500
1501        // now convert multimap representation to parent/child representation
1502        for (CmsBrokenLinkBean parent : resultMap.keySet()) {
1503            for (CmsBrokenLinkBean child : resultMap.get(parent)) {
1504                parent.addChild(child);
1505            }
1506        }
1507        return Lists.newArrayList(resultMap.keySet());
1508    }
1509
1510    /**
1511     * Internal method to get the broken links information for the given resource.<p>
1512     *
1513     * @param entryResource the resource
1514     *
1515     * @return the broken links information
1516     *
1517     * @throws CmsException if something goes wrong
1518     */
1519    private CmsDeleteResourceBean getBrokenLinks(CmsResource entryResource) throws CmsException {
1520
1521        CmsDeleteResourceBean result = null;
1522
1523        CmsListInfoBean info = null;
1524        List<CmsBrokenLinkBean> brokenLinks = null;
1525
1526        CmsObject cms = getCmsObject();
1527        String resourceSitePath = cms.getSitePath(entryResource);
1528
1529        ensureSession();
1530
1531        List<CmsResource> descendants = new ArrayList<CmsResource>();
1532        HashSet<CmsUUID> deleteIds = new HashSet<CmsUUID>();
1533
1534        descendants.add(entryResource);
1535        if (entryResource.isFolder()) {
1536            descendants.addAll(cms.readResources(resourceSitePath, CmsResourceFilter.IGNORE_EXPIRATION));
1537        }
1538
1539        for (CmsResource deleteRes : descendants) {
1540            deleteIds.add(deleteRes.getStructureId());
1541        }
1542        Multimap<CmsResource, CmsResource> linkMap = HashMultimap.create();
1543        for (CmsResource resource : descendants) {
1544            List<CmsRelation> relations = cms.getRelationsForResource(resource, CmsRelationFilter.SOURCES);
1545            List<CmsResource> result1 = new ArrayList<CmsResource>();
1546            for (CmsRelation relation : relations) {
1547                // only add related resources that are not going to be deleted
1548                if (!deleteIds.contains(relation.getSourceId())) {
1549                    CmsResource source1 = relation.getSource(cms, CmsResourceFilter.ALL);
1550                    if (!source1.getState().isDeleted()) {
1551                        result1.add(source1);
1552                    }
1553                }
1554            }
1555            List<CmsResource> linkSources = result1;
1556            for (CmsResource source : linkSources) {
1557                linkMap.put(source, resource);
1558            }
1559        }
1560
1561        brokenLinks = getBrokenLinkBeans(linkMap);
1562        info = getPageInfo(entryResource);
1563
1564        result = new CmsDeleteResourceBean(resourceSitePath, info, brokenLinks);
1565
1566        return result;
1567    }
1568
1569    /**
1570     * Gets the resources which link to a given structure id.<p>
1571     *
1572     * @param cms the current CMS context
1573     * @param resource the relation target resource
1574     * @param deleteIds set of resources to delete
1575     *
1576     * @return the list of resources which link to the given id
1577     *
1578     * @throws CmsException if something goes wrong
1579     */
1580    @SuppressWarnings("unused")
1581    private List<CmsResource> getLinkSources(CmsObject cms, CmsResource resource, HashSet<CmsUUID> deleteIds)
1582    throws CmsException {
1583
1584        List<CmsRelation> relations = cms.getRelationsForResource(resource, CmsRelationFilter.SOURCES);
1585        List<CmsResource> result = new ArrayList<CmsResource>();
1586        for (CmsRelation relation : relations) {
1587            // only add related resources that are not going to be deleted
1588            if (!deleteIds.contains(relation.getSourceId())) {
1589                CmsResource source = relation.getSource(cms, CmsResourceFilter.ALL);
1590                if (!source.getState().isDeleted()) {
1591                    result.add(source);
1592                }
1593            }
1594        }
1595        return result;
1596    }
1597
1598    /**
1599     * Returns a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget}.<p>
1600     *
1601     * @param res the resource to get the page info for
1602     *
1603     * @return a bean to display the {@link org.opencms.gwt.client.ui.CmsListItemWidget}.<p>
1604     *
1605     * @throws CmsLoaderException if the resource type could not be found
1606     * @throws CmsException if something else goes wrong
1607     */
1608    private CmsListInfoBean getPageInfo(CmsResource res) throws CmsException, CmsLoaderException {
1609
1610        CmsObject cms = getCmsObject();
1611        return getPageInfo(cms, res);
1612    }
1613
1614    /**
1615     * Returns the preview info for the given resource.<p>
1616     *
1617     *@param cms the CMS context
1618     * @param resource the resource
1619     * @param locale the requested locale
1620     *
1621     * @return the preview info
1622     */
1623    private CmsPreviewInfo getPreviewInfo(CmsObject cms, CmsResource resource, Locale locale) {
1624
1625        String title = "";
1626        try {
1627            CmsProperty titleProperty = cms.readPropertyObject(resource, CmsPropertyDefinition.PROPERTY_TITLE, false);
1628            title = titleProperty.getValue("");
1629        } catch (CmsException e) {
1630            LOG.warn(e.getLocalizedMessage(), e);
1631        }
1632        String noPreviewReason = getNoPreviewReason(cms, resource);
1633        String previewContent = null;
1634        int height = 0;
1635        int width = 0;
1636        LinkedHashMap<String, String> locales = getAvailableLocales(resource);
1637        if (noPreviewReason != null) {
1638            previewContent = "<div>" + noPreviewReason + "</div>";
1639            return new CmsPreviewInfo(
1640                "<div>" + noPreviewReason + "</div>",
1641                null,
1642                false,
1643                title,
1644                cms.getSitePath(resource),
1645                locale.toString());
1646        } else if (OpenCms.getResourceManager().matchResourceType(
1647            CmsResourceTypeImage.getStaticTypeName(),
1648            resource.getTypeId())) {
1649                CmsImageScaler scaler = new CmsImageScaler(cms, resource);
1650                String imageLink = null;
1651                if (resource instanceof I_CmsHistoryResource) {
1652                    int version = ((I_CmsHistoryResource)resource).getVersion();
1653                    imageLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1654                        cms,
1655                        CmsHistoryListUtil.getHistoryLink(cms, resource.getStructureId(), "" + version));
1656                } else {
1657                    imageLink = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath());
1658                }
1659                imageLink = CmsRequestUtil.appendParameter(imageLink, "random", "" + Math.random());
1660                previewContent = "<img src=\"" + imageLink + "\" title=\"" + title + "\" style=\"display:block\" />";
1661                height = scaler.getHeight();
1662                width = scaler.getWidth();
1663            } else if (CmsResourceTypeXmlContainerPage.isContainerPage(resource)
1664                || CmsResourceTypeXmlPage.isXmlPage(resource)) {
1665                    String link = "";
1666                    if (resource instanceof I_CmsHistoryResource) {
1667                        int version = ((I_CmsHistoryResource)resource).getVersion();
1668                        link = OpenCms.getLinkManager().substituteLinkForUnknownTarget(
1669                            cms,
1670                            CmsHistoryListUtil.getHistoryLink(cms, resource.getStructureId(), "" + version));
1671                    } else {
1672                        link = OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath());
1673                    }
1674                    return new CmsPreviewInfo(null, link, true, null, cms.getSitePath(resource), locale.toString());
1675                } else if (CmsResourceTypeXmlContent.isXmlContent(resource)) {
1676                    if (!locales.containsKey(locale.toString())) {
1677                        locale = CmsLocaleManager.getMainLocale(cms, resource);
1678                    }
1679                    previewContent = CmsPreviewService.getPreviewContent(
1680                        getRequest(),
1681                        getResponse(),
1682                        cms,
1683                        resource,
1684                        locale);
1685
1686                } else if (CmsResourceTypePlain.getStaticTypeId() == resource.getTypeId()) {
1687                    try {
1688                        previewContent = "<pre><code>"
1689                            + new String(cms.readFile(resource).getContents())
1690                            + "</code></pre>";
1691                    } catch (CmsException e) {
1692                        LOG.warn(e.getLocalizedMessage(), e);
1693                        previewContent = "<div>"
1694                            + Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(cms)).key(
1695                                Messages.GUI_NO_PREVIEW_CAN_T_READ_CONTENT_0)
1696                            + "</div>";
1697                    }
1698                }
1699        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(previewContent)) {
1700            CmsPreviewInfo result = new CmsPreviewInfo(
1701                previewContent,
1702                null,
1703                false,
1704                title,
1705                cms.getSitePath(resource),
1706                locale.toString());
1707            result.setHeight(height);
1708            result.setWidth(width);
1709            result.setLocales(locales);
1710            return result;
1711        }
1712        if (CmsResourceTypeXmlContainerPage.isContainerPage(resource) || CmsResourceTypeXmlPage.isXmlPage(resource)) {
1713            CmsPreviewInfo result = new CmsPreviewInfo(
1714                null,
1715                OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath())
1716                    + "?"
1717                    + CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT
1718                    + "=true"
1719                    + "&__locale="
1720                    + locale.toString(),
1721                false,
1722                title,
1723                cms.getSitePath(resource),
1724                locale.toString());
1725            result.setLocales(locales);
1726            return result;
1727        }
1728        return new CmsPreviewInfo(
1729            null,
1730            OpenCms.getLinkManager().substituteLinkForUnknownTarget(cms, resource.getRootPath())
1731                + "?"
1732                + CmsGwtConstants.PARAM_DISABLE_DIRECT_EDIT
1733                + "=true",
1734            true,
1735            title,
1736            cms.getSitePath(resource),
1737            locale.toString());
1738    }
1739
1740}