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 GmbH & Co. KG, 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.workplace.explorer;
029
030import org.opencms.db.CmsDbEntryNotFoundException;
031import org.opencms.db.CmsResourceState;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsProject;
034import org.opencms.file.CmsPropertyDefinition;
035import org.opencms.file.CmsRequestContext;
036import org.opencms.file.CmsResource;
037import org.opencms.file.CmsResourceFilter;
038import org.opencms.file.history.I_CmsHistoryResource;
039import org.opencms.file.types.CmsResourceTypePlain;
040import org.opencms.file.types.CmsResourceTypeUnknownFile;
041import org.opencms.file.types.CmsResourceTypeUnknownFolder;
042import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
043import org.opencms.file.types.I_CmsResourceType;
044import org.opencms.i18n.CmsMessages;
045import org.opencms.jsp.CmsJspNavBuilder;
046import org.opencms.lock.CmsLock;
047import org.opencms.main.CmsException;
048import org.opencms.main.CmsLog;
049import org.opencms.main.OpenCms;
050import org.opencms.search.galleries.CmsGallerySearch;
051import org.opencms.search.galleries.CmsGallerySearchResult;
052import org.opencms.security.CmsOrganizationalUnit;
053import org.opencms.security.CmsPermissionSet;
054import org.opencms.security.CmsPermissionSetCustom;
055import org.opencms.security.CmsPrincipal;
056import org.opencms.ui.CmsCssIcon;
057import org.opencms.util.A_CmsModeIntEnumeration;
058import org.opencms.util.CmsStringUtil;
059import org.opencms.util.CmsUUID;
060import org.opencms.workplace.CmsWorkplace;
061
062import java.util.ArrayList;
063import java.util.List;
064import java.util.Locale;
065import java.util.Map;
066
067import org.apache.commons.logging.Log;
068
069import com.google.common.collect.Maps;
070import com.vaadin.server.ExternalResource;
071import com.vaadin.server.Resource;
072
073/**
074 * Provides {@link CmsResource} utility functions.<p>
075 *
076 * This class provides in java all resource information used by the explorer view,
077 * mostly generated in javascript (see explorer.js)<p>
078 *
079 * @since 6.0.0
080 */
081public final class CmsResourceUtil {
082
083    /**
084     * Enumeration class for defining the resource project state.<p>
085     */
086    public static class CmsResourceProjectState extends A_CmsModeIntEnumeration {
087
088        /** Constant for the project state unlocked. */
089        protected static final CmsResourceProjectState CLEAN = new CmsResourceProjectState(0);
090
091        /** Constant for the project state locked for publishing. */
092        protected static final CmsResourceProjectState LOCKED_FOR_PUBLISHING = new CmsResourceProjectState(5);
093
094        /** Constant for the project state locked in current project. */
095        protected static final CmsResourceProjectState MODIFIED_IN_CURRENT_PROJECT = new CmsResourceProjectState(1);
096
097        /** Constant for the project state locked in other project. */
098        protected static final CmsResourceProjectState MODIFIED_IN_OTHER_PROJECT = new CmsResourceProjectState(2);
099
100        /** serial version UID. */
101        private static final long serialVersionUID = 4580450220255428716L;
102
103        /**
104         * Default constructor.<p>
105         *
106         * @param mode the mode descriptor
107         */
108        protected CmsResourceProjectState(int mode) {
109
110            super(mode);
111        }
112
113        /**
114         * Checks if this is a {@link #LOCKED_FOR_PUBLISHING} state.<p>
115         *
116         * @return <code>true</code> if this is a {@link #LOCKED_FOR_PUBLISHING} state
117         */
118        public boolean isLockedForPublishing() {
119
120            return (this == LOCKED_FOR_PUBLISHING);
121        }
122
123        /**
124         * Checks if this is a {@link #MODIFIED_IN_CURRENT_PROJECT} state.<p>
125         *
126         * @return <code>true</code> if this is a {@link #MODIFIED_IN_CURRENT_PROJECT} state
127         */
128        public boolean isModifiedInCurrentProject() {
129
130            return (this == MODIFIED_IN_CURRENT_PROJECT);
131        }
132
133        /**
134         * Checks if this is a {@link #MODIFIED_IN_OTHER_PROJECT} state.<p>
135         *
136         * @return <code>true</code> if this is a {@link #MODIFIED_IN_OTHER_PROJECT} state
137         */
138        public boolean isModifiedInOtherProject() {
139
140            return (this == MODIFIED_IN_OTHER_PROJECT);
141        }
142
143        /**
144         * Checks if this is a {@link #CLEAN} state.<p>
145         *
146         * @return <code>true</code> if this is a {@link #CLEAN} state
147         */
148        public boolean isUnlocked() {
149
150            return (this == CLEAN);
151        }
152    }
153
154    /**
155     * Enumeration class for defining the site modes.<p>
156     */
157    private static class CmsResourceUtilSiteMode {
158
159        /**
160         * Default constructor.<p>
161         */
162        protected CmsResourceUtilSiteMode() {
163
164            // noop
165        }
166    }
167
168    /** Layout style for resources after expire date. */
169    public static final int LAYOUTSTYLE_AFTEREXPIRE = 2;
170
171    /** Layout style for resources before release date. */
172    public static final int LAYOUTSTYLE_BEFORERELEASE = 1;
173
174    /** Layout style for resources after release date and before expire date. */
175    public static final int LAYOUTSTYLE_INRANGE = 0;
176
177    /** Constant that signalizes that all path operations will be based on the current site. */
178    public static final CmsResourceUtilSiteMode SITE_MODE_CURRENT = new CmsResourceUtilSiteMode();
179
180    /** Constant that signalizes that all path operations will be based on the best matching site. */
181    public static final CmsResourceUtilSiteMode SITE_MODE_MATCHING = new CmsResourceUtilSiteMode();
182
183    /** Constant that signalizes that all path operations will be based on the root path. */
184    public static final CmsResourceUtilSiteMode SITE_MODE_ROOT = new CmsResourceUtilSiteMode();
185
186    /** Constant for the project state locked for publishing. */
187    public static final CmsResourceProjectState STATE_LOCKED_FOR_PUBLISHING = CmsResourceProjectState.LOCKED_FOR_PUBLISHING;
188
189    /** Constant for the project state locked in current project. */
190    public static final CmsResourceProjectState STATE_MODIFIED_IN_CURRENT_PROJECT = CmsResourceProjectState.MODIFIED_IN_CURRENT_PROJECT;
191
192    /** Constant for the project state locked in other project. */
193    public static final CmsResourceProjectState STATE_MODIFIED_IN_OTHER_PROJECT = CmsResourceProjectState.MODIFIED_IN_OTHER_PROJECT;
194
195    /** The log object for this class. */
196    private static final Log LOG = CmsLog.getLog(CmsResourceUtil.class);
197
198    /** The folder size display string constant. */
199    private static final String SIZE_DIR = "-";
200
201    /** Constant for the project state unlocked. */
202    private static final CmsResourceProjectState STATE_CLEAN = CmsResourceProjectState.CLEAN;
203
204    /** If greater than zero, the path will be formatted to this number of chars. */
205    private int m_abbrevLength;
206
207    /** The current cms context. */
208    private CmsObject m_cms;
209
210    /** The current resource lock. */
211    private CmsLock m_lock;
212
213    /** The message bundle for formatting dates, depends on the request locale. */
214    private CmsMessages m_messages;
215
216    /** Reference project resources cache. */
217    private List<String> m_projectResources;
218
219    /** The project to use to check project state, if <code>null</code> the current project will be used. */
220    private CmsProject m_referenceProject;
221
222    /** The 'relative to' path. */
223    private String m_relativeTo;
224
225    /** The current request context. */
226    private CmsRequestContext m_request;
227
228    /** The current resource. */
229    private CmsResource m_resource;
230
231    /** The current resource type. */
232    private I_CmsResourceType m_resourceType;
233
234    /** The search result map. */
235    private Map<Locale, CmsGallerySearchResult> m_searchResultMap = Maps.newHashMap();
236
237    /** The current site mode. */
238    private CmsResourceUtilSiteMode m_siteMode = SITE_MODE_CURRENT;
239
240    /**
241     * Creates a new {@link CmsResourceUtil} object.<p>
242     *
243     * @param cms the cms context
244     */
245    public CmsResourceUtil(CmsObject cms) {
246
247        setCms(cms);
248    }
249
250    /**
251     * Creates a new {@link CmsResourceUtil} object.<p>
252     *
253     * @param cms the cms context
254     * @param resource the resource
255     */
256    public CmsResourceUtil(CmsObject cms, CmsResource resource) {
257
258        setCms(cms);
259        setResource(resource);
260    }
261
262    /**
263     * Creates a new {@link CmsResourceUtil} object.<p>
264     *
265     * @param resource the resource
266     */
267    public CmsResourceUtil(CmsResource resource) {
268
269        setResource(resource);
270    }
271
272    /**
273     * Returns the big icon resource for the given resource.<p>
274     *
275     * @param explorerType the resource explorer type settings
276     * @param resourceName the resource name
277     *
278     * @return the icon resource
279     */
280    public static Resource getBigIconResource(CmsExplorerTypeSettings explorerType, String resourceName) {
281
282        if (explorerType == null) {
283            explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
284                (resourceName == null) && !CmsResource.isFolder(resourceName)
285                ? CmsResourceTypeUnknownFile.RESOURCE_TYPE_NAME
286                : CmsResourceTypeUnknownFolder.RESOURCE_TYPE_NAME);
287        }
288        if (!explorerType.getIconRules().isEmpty() && (resourceName != null)) {
289            String extension = CmsResource.getExtension(resourceName);
290            if (extension != null) {
291                CmsIconRule rule = explorerType.getIconRules().get(extension);
292                if ((rule != null) && (rule.getBigIconStyle() != null)) {
293                    return new CmsCssIcon(rule.getBigIconStyle());
294                }
295            }
296        }
297        if (explorerType.getBigIconStyle() != null) {
298            return new CmsCssIcon(explorerType.getBigIconStyle());
299        } else if (explorerType.getBigIcon() != null) {
300            return new ExternalResource(
301                CmsWorkplace.getResourceUri(CmsWorkplace.RES_PATH_FILETYPES + explorerType.getBigIcon()));
302        } else {
303            return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_DEFAULT_BIG);
304        }
305    }
306
307    /**
308     * Returns the small icon resource for the given resource.<p>
309     *
310     * @param explorerType the resource explorer type settings
311     * @param resourceName the resource name
312     *
313     * @return the icon resource
314     */
315    public static Resource getSmallIconResource(CmsExplorerTypeSettings explorerType, String resourceName) {
316
317        if (explorerType == null) {
318            explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(
319                (resourceName == null) && !CmsResource.isFolder(resourceName)
320                ? CmsResourceTypeUnknownFile.RESOURCE_TYPE_NAME
321                : "unknown_folder");
322        }
323
324        if (!explorerType.getIconRules().isEmpty() && (resourceName != null)) {
325            String extension = CmsResource.getExtension(resourceName);
326            if (extension != null) {
327                CmsIconRule rule = explorerType.getIconRules().get(extension);
328                if ((rule != null) && (rule.getSmallIconStyle() != null)) {
329                    return new CmsCssIcon(rule.getSmallIconStyle());
330                }
331            }
332        }
333        if (explorerType.getSmallIconStyle() != null) {
334            return new CmsCssIcon(explorerType.getSmallIconStyle());
335        } else {
336            return new ExternalResource(
337                CmsWorkplace.getResourceUri(CmsWorkplace.RES_PATH_FILETYPES + explorerType.getOriginalIcon()));
338        }
339    }
340
341    /**
342     * Returns the path abbreviation length.<p>
343     *
344     * If greater than zero, the path will be formatted to this number of chars.<p>
345     *
346     * This only affects the generation of the path for the current resource.<p>
347     *
348     * @return the path abbreviation Length
349     */
350    public int getAbbrevLength() {
351
352        return m_abbrevLength;
353    }
354
355    /**
356     * Returns the big icon resource of the current resource.<p>
357     *
358     * @return the icon resource
359     */
360    public Resource getBigIconResource() {
361
362        if ((m_cms != null) && CmsJspNavBuilder.isNavLevelFolder(m_cms, m_resource)) {
363            return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_NAV_LEVEL_BIG);
364        }
365        if ((m_cms != null) && CmsResourceTypeXmlContainerPage.isModelCopyGroup(m_cms, m_resource)) {
366            return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_MODEL_GROUP_COPY_BIG);
367        }
368        I_CmsResourceType type = getResourceType();
369        CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(type.getTypeName());
370        return getBigIconResource(explorerType, m_resource != null ? m_resource.getName() : null);
371    }
372
373    /**
374     * Returns the cms context.<p>
375     *
376     * @return the cms context
377     */
378    public CmsObject getCms() {
379
380        return m_cms;
381    }
382
383    /**
384     * Returns the formatted date of expiration.<p>
385     *
386     * @return the formatted date of expiration
387     */
388    public String getDateExpired() {
389
390        long release = m_resource.getDateExpired();
391        if (release != CmsResource.DATE_EXPIRED_DEFAULT) {
392            return getMessages().getDateTime(release);
393        } else {
394            return CmsWorkplace.DEFAULT_DATE_STRING;
395        }
396    }
397
398    /**
399     * Returns the formatted date of release.<p>
400     *
401     * @return the formatted date of release
402     */
403    public String getDateReleased() {
404
405        long release = m_resource.getDateReleased();
406        if (release != CmsResource.DATE_RELEASED_DEFAULT) {
407            return getMessages().getDateTime(release);
408        } else {
409            return CmsWorkplace.DEFAULT_DATE_STRING;
410        }
411    }
412
413    /**
414     * Returns the path of the current resource, taking into account just the site mode.<p>
415     *
416     * @return the full path
417     */
418    public String getFullPath() {
419
420        String path = m_resource.getRootPath();
421        if ((m_siteMode != SITE_MODE_ROOT) && (m_cms != null)) {
422            String site = getSite();
423            if (path.startsWith(site)) {
424                path = path.substring(site.length());
425            }
426        }
427        return path;
428    }
429
430    /**
431     * Returns the gallery description of the current resource.<p>
432     *
433     * @param locale the content locale
434     *
435     * @return the gallery description
436     */
437    public String getGalleryDescription(Locale locale) {
438
439        return getSearchResult(locale).getDescription();
440    }
441
442    /**
443     * Returns the gallery title of the current resource.<p>
444     *
445     * @param locale the content locale
446     *
447     * @return the gallery title
448     */
449    public String getGalleryTitle(Locale locale) {
450
451        return getSearchResult(locale).getTitle();
452    }
453
454    /**
455     * Returns the resource icon path displayed in the explorer view for the given resource.<p>
456     *
457     * Relative to <code>/system/workplace/resources/</code>.<p>
458     *
459     * If the resource has no sibling it is the same as {@link #getIconPathResourceType()}.<p>
460     *
461     * @return the resource icon path displayed in the explorer view for the given resource
462     *
463     * @see #getStyleSiblings()
464     */
465    public String getIconPathExplorer() {
466
467        if (m_resource.getSiblingCount() > 1) {
468            // links are present
469            if (m_resource.isLabeled()) {
470                // there is at least one link in a marked site
471                return "explorer/link_labeled.gif";
472            } else {
473                // common links are present
474                return "explorer/link.gif";
475            }
476        } else {
477            return getIconPathResourceType();
478        }
479    }
480
481    /**
482     * Returns the lock icon path for the given resource.<p>
483     *
484     * Relative to <code>/system/workplace/resources/</code>.<p>
485     *
486     * Returns <code>explorer/project_none.gif</code> if request context is <code>null</code>.<p>
487     *
488     * @return the lock icon path for the given resource
489     */
490    public String getIconPathLock() {
491
492        CmsLock lock = getLock();
493        String iconPath = null;
494        if (!lock.isUnlocked() && (m_request != null) && isInsideProject()) {
495            if (getLock().isOwnedBy(m_request.getCurrentUser())
496                && (getLockedInProjectId().equals(getReferenceProject().getUuid()))) {
497                if (lock.isShared()) {
498                    iconPath = "shared";
499                } else {
500                    iconPath = "user";
501                }
502            } else {
503                iconPath = "other";
504            }
505        }
506        if (iconPath == null) {
507            iconPath = "project_none";
508        } else {
509            iconPath = "lock_" + iconPath;
510        }
511        return "explorer/" + iconPath + ".gif";
512    }
513
514    /**
515     * Returns the project state icon path for the given resource.<p>
516     *
517     * Relative to <code>/system/workplace/resources/</code>.<p>
518     *
519     * @return the project state icon path for the given resource
520     */
521    public String getIconPathProjectState() {
522
523        String iconPath;
524        if (getProjectState() == STATE_MODIFIED_IN_CURRENT_PROJECT) {
525            iconPath = "this.png";
526        } else if (getProjectState() == STATE_MODIFIED_IN_OTHER_PROJECT) {
527            iconPath = "other.png";
528        } else if (getProjectState() == STATE_LOCKED_FOR_PUBLISHING) {
529            iconPath = "publish.png";
530        } else {
531            // STATE_UNLOCKED
532            iconPath = "none.gif";
533        }
534        return "explorer/project_" + iconPath;
535    }
536
537    /**
538     * Returns the resource type icon path for the given resource.<p>
539     *
540     * Relative to <code>/system/workplace/resources/</code>.<p>
541     *
542     * @return the resource type icon path for the given resource
543     */
544    public String getIconPathResourceType() {
545
546        if (!isEditable()) {
547            return CmsWorkplace.RES_PATH_FILETYPES
548                + OpenCms.getWorkplaceManager().getExplorerTypeSetting(
549                    CmsResourceTypePlain.getStaticTypeName()).getIcon();
550        }
551        return CmsWorkplace.RES_PATH_FILETYPES
552            + OpenCms.getWorkplaceManager().getExplorerTypeSetting(getResourceTypeName()).getIcon();
553    }
554
555    /**
556     * Returns an integer representation for the link type.<p>
557     *
558     * <ul>
559     *   <li><code>0</code>: No sibling
560     *   <li><code>1</code>: Sibling
561     *   <li><code>2</code>: Labeled sibling
562     * </ul>
563     *
564     * @return an integer representation for the link type
565     */
566    public int getLinkType() {
567
568        if (m_resource.getSiblingCount() > 1) {
569            // links are present
570            if (m_resource.isLabeled()) {
571                // there is at least one link in a marked site
572                return 2;
573            } else {
574                // common links are present
575                return 1;
576            }
577        } else {
578            // no links to the resource are in the VFS
579            return 0;
580        }
581    }
582
583    /**
584     * Returns the the lock for the given resource.<p>
585     *
586     * @return the lock the given resource
587     */
588    public CmsLock getLock() {
589
590        if (m_lock == null) {
591            try {
592                m_lock = getCms().getLock(m_resource);
593            } catch (Throwable e) {
594                m_lock = CmsLock.getNullLock();
595                LOG.error(e.getLocalizedMessage(), e);
596            }
597        }
598        return m_lock;
599    }
600
601    /**
602     * Returns the user name who owns the lock for the given resource.<p>
603     *
604     * @return the user name who owns the lock for the given resource
605     */
606    public String getLockedByName() {
607
608        String lockedBy = "";
609        if (!getLock().isNullLock()) {
610            // user
611            lockedBy = getLock().getUserId().toString();
612            try {
613                lockedBy = getCurrentOuRelativeName(
614                    CmsPrincipal.readPrincipalIncludingHistory(getCms(), getLock().getUserId()).getName());
615            } catch (Throwable e) {
616                lockedBy = e.getMessage();
617            }
618        }
619        return lockedBy;
620    }
621
622    /**
623     * Returns the id of the project in which the given resource is locked.<p>
624     *
625     * @return the id of the project in which the given resource is locked
626     */
627    public CmsUUID getLockedInProjectId() {
628
629        CmsUUID lockedInProject = null;
630        if (getLock().isNullLock() && !getResource().getState().isUnchanged()) {
631            // resource is unlocked and modified
632            lockedInProject = getResource().getProjectLastModified();
633        } else if (!getResource().getState().isUnchanged()) {
634            // resource is locked and modified
635            lockedInProject = getProjectId();
636        } else if (!getLock().isNullLock()) {
637            // resource is locked and unchanged
638            lockedInProject = getLock().getProjectId();
639        }
640        return lockedInProject;
641    }
642
643    /**
644     * Returns the project name that locked the current resource's.<p>
645     *
646     * @return the the project name that locked the current resource's
647     */
648    public String getLockedInProjectName() {
649
650        try {
651            CmsUUID pId = getLockedInProjectId();
652            if ((pId == null) || pId.isNullUUID()) {
653                // the resource is unlocked and unchanged
654                return "";
655            }
656            try {
657                return getCurrentOuRelativeName(getCms().readProject(pId).getName());
658            } catch (CmsDbEntryNotFoundException e) {
659                return getCurrentOuRelativeName(getCms().readHistoryProject(pId).getName());
660            }
661        } catch (Throwable e) {
662            LOG.error(e.getLocalizedMessage(), e);
663            return "";
664        }
665    }
666
667    /**
668     * Returns the lock state of the current resource.<p>
669     *
670     * @return the lock state of the current resource
671     */
672    public int getLockState() {
673
674        if (CmsStringUtil.isEmptyOrWhitespaceOnly(getLockedByName())) {
675            // unlocked
676            return 0;
677        }
678        if (!getLockedByName().equals(getCurrentOuRelativeName(m_request.getCurrentUser().getName()))
679            || !getLockedInProjectId().equals(m_request.getCurrentProject().getUuid())) {
680            // locked by other user and/or project
681            return 1;
682        }
683        if (getLock().getType().isShared()) {
684            // shared lock
685            return 2;
686        }
687        // exclusive lock
688        return 3;
689    }
690
691    /**
692     * Returns the navtext of a resource.<p>
693     *
694     * @return the navtext for that resource
695     */
696    public String getNavText() {
697
698        String navText = "";
699        try {
700            navText = getCms().readPropertyObject(
701                getCms().getSitePath(m_resource),
702                CmsPropertyDefinition.PROPERTY_NAVTEXT,
703                false).getValue();
704        } catch (Throwable e) {
705            String storedSiteRoot = getCms().getRequestContext().getSiteRoot();
706            try {
707                getCms().getRequestContext().setSiteRoot("");
708                navText = getCms().readPropertyObject(
709                    m_resource.getRootPath(),
710                    CmsPropertyDefinition.PROPERTY_NAVTEXT,
711                    false).getValue();
712            } catch (Exception e1) {
713                // should usually never happen
714                if (LOG.isInfoEnabled()) {
715                    LOG.info(e.getLocalizedMessage(), e);
716                }
717            } finally {
718                getCms().getRequestContext().setSiteRoot(storedSiteRoot);
719            }
720        }
721        if (navText == null) {
722            navText = "";
723        }
724        return navText;
725    }
726
727    /**
728     * Checks is the current resource can be edited by the current user.<p>
729     *
730     * @param locale the locale to use for the messages
731     *
732     * @return an empty string if editable, or a localized string with the reason
733     *
734     * @throws CmsException if something goes wrong
735     */
736    public String getNoEditReason(Locale locale) throws CmsException {
737
738        return getNoEditReason(locale, false);
739    }
740
741    /**
742     * Checks is the current resource can be edited by the current user.<p>
743     *
744     * @param locale the locale to use for the messages
745     * @param ignoreExpiration <code>true</code> to ignore resource release and expiration date
746     *
747     * @return an empty string if editable, or a localized string with the reason
748     *
749     * @throws CmsException if something goes wrong
750     */
751    public String getNoEditReason(Locale locale, boolean ignoreExpiration) throws CmsException {
752
753        String reason = "";
754        if (m_resource instanceof I_CmsHistoryResource) {
755            reason = Messages.get().getBundle(locale).key(Messages.GUI_NO_EDIT_REASON_HISTORY_0);
756        } else if (!m_cms.hasPermissions(
757            m_resource,
758            CmsPermissionSet.ACCESS_WRITE,
759            false,
760            ignoreExpiration ? CmsResourceFilter.IGNORE_EXPIRATION : CmsResourceFilter.DEFAULT) || !isEditable()) {
761                reason = Messages.get().getBundle(locale).key(Messages.GUI_NO_EDIT_REASON_PERMISSION_0);
762            } else if (!getLock().isLockableBy(m_cms.getRequestContext().getCurrentUser())) {
763                if (getLock().getSystemLock().isPublish()) {
764                    reason = Messages.get().getBundle(locale).key(Messages.GUI_PUBLISH_TOOLTIP_0);
765                } else {
766                    reason = Messages.get().getBundle(locale).key(
767                        Messages.GUI_NO_EDIT_REASON_LOCK_1,
768                        getLockedByName());
769                }
770            }
771        return reason;
772    }
773
774    /**
775     * Returns the path of the current resource.<p>
776     *
777     * Taking into account following settings:<br>
778     * <ul>
779     *    <li>site mode
780     *    <li>abbreviation length
781     *    <li>relative to
782     * </ul>
783     *
784     * @return the path
785     */
786    public String getPath() {
787
788        String path = getFullPath();
789        if (m_relativeTo != null) {
790            path = getResource().getRootPath();
791            if (path.startsWith(m_relativeTo)) {
792                path = path.substring(m_relativeTo.length());
793                if (path.length() == 0) {
794                    path = ".";
795                }
796            } else {
797                String site = getSite();
798                if (path.startsWith(site + "/") || path.equals(site)) {
799                    path = path.substring(site.length());
800                }
801            }
802        }
803        if (m_abbrevLength > 0) {
804            boolean absolute = path.startsWith("/");
805            path = CmsStringUtil.formatResourceName(path, m_abbrevLength);
806            if (!absolute && path.startsWith("/")) {
807                // remove leading '/'
808                path = path.substring(1);
809            }
810        }
811        return path;
812    }
813
814    /**
815     * Returns the permission set for the given resource.<p>
816     *
817     * @return the permission set for the given resource
818     */
819    public CmsPermissionSet getPermissionSet() {
820
821        CmsPermissionSetCustom pset = new CmsPermissionSetCustom();
822        CmsResource resource = getResource();
823        try {
824            if (getCms().hasPermissions(resource, CmsPermissionSet.ACCESS_CONTROL, false, CmsResourceFilter.ALL)) {
825                pset.grantPermissions(CmsPermissionSet.PERMISSION_CONTROL);
826            } else {
827                pset.denyPermissions(CmsPermissionSet.PERMISSION_CONTROL);
828            }
829        } catch (CmsException e) {
830            LOG.error(e.getLocalizedMessage());
831        }
832        try {
833            if (getCms().hasPermissions(
834                resource,
835                CmsPermissionSet.ACCESS_DIRECT_PUBLISH,
836                false,
837                CmsResourceFilter.ALL)) {
838                pset.grantPermissions(CmsPermissionSet.PERMISSION_DIRECT_PUBLISH);
839            } else {
840                pset.denyPermissions(CmsPermissionSet.PERMISSION_DIRECT_PUBLISH);
841            }
842        } catch (CmsException e) {
843            LOG.error(e.getLocalizedMessage());
844        }
845        try {
846            if (getCms().hasPermissions(resource, CmsPermissionSet.ACCESS_READ, false, CmsResourceFilter.ALL)) {
847                pset.grantPermissions(CmsPermissionSet.PERMISSION_READ);
848            } else {
849                pset.denyPermissions(CmsPermissionSet.PERMISSION_READ);
850            }
851        } catch (CmsException e) {
852            LOG.error(e.getLocalizedMessage());
853        }
854        try {
855            if (getCms().hasPermissions(resource, CmsPermissionSet.ACCESS_VIEW, false, CmsResourceFilter.ALL)) {
856                pset.grantPermissions(CmsPermissionSet.PERMISSION_VIEW);
857            } else {
858                pset.denyPermissions(CmsPermissionSet.PERMISSION_VIEW);
859            }
860        } catch (CmsException e) {
861            LOG.error(e.getLocalizedMessage());
862        }
863        try {
864            if (getCms().hasPermissions(resource, CmsPermissionSet.ACCESS_WRITE, false, CmsResourceFilter.ALL)) {
865                pset.grantPermissions(CmsPermissionSet.PERMISSION_WRITE);
866            } else {
867                pset.denyPermissions(CmsPermissionSet.PERMISSION_WRITE);
868            }
869        } catch (CmsException e) {
870            LOG.error(e.getLocalizedMessage());
871        }
872
873        return pset;
874    }
875
876    /**
877     * Returns the permissions string for the given resource.<p>
878     *
879     * @return the permissions string for the given resource
880     */
881    public String getPermissionString() {
882
883        return getPermissionSet().getPermissionString();
884    }
885
886    /**
887     * Returns the id of the project which the resource belongs to.<p>
888     *
889     * @return the id of the project which the resource belongs to
890     */
891    public CmsUUID getProjectId() {
892
893        CmsUUID projectId = m_resource.getProjectLastModified();
894        if (!getLock().isUnlocked() && !getLock().isInherited()) {
895            // use lock project ID only if lock is not inherited
896            projectId = getLock().getProjectId();
897        }
898        return projectId;
899    }
900
901    /**
902     * Returns the project state of the given resource.<p>
903     *
904     * <ul>
905     *   <li>null: unchanged.</li>
906     *   <li>true: locked in current project.</li>
907     *   <li>false: not locked in current project.</li>
908     * </ul>
909     *
910     * @return the project state of the given resource
911     */
912    public CmsResourceProjectState getProjectState() {
913
914        if (getResource().getState().isUnchanged()) {
915            return STATE_CLEAN; // STATE_CLEAN
916        } else if (getLock().getSystemLock().isPublish()) {
917            return STATE_LOCKED_FOR_PUBLISHING;
918        } else if (getResource().getProjectLastModified().equals(getReferenceProject().getUuid())) {
919            return STATE_MODIFIED_IN_CURRENT_PROJECT; // STATE_MODIFIED_CURRENT_PROJECT
920        } else {
921            return STATE_MODIFIED_IN_OTHER_PROJECT; // STATE_MODIFIED_OTHER_PROJECT
922        }
923    }
924
925    /**
926     * Returns the project to use to check project state.<p>
927     *
928     * @return the project to use to check project state
929     */
930    public CmsProject getReferenceProject() {
931
932        if (m_referenceProject == null) {
933            if (m_request != null) {
934                m_referenceProject = m_request.getCurrentProject();
935            }
936        }
937        return m_referenceProject;
938    }
939
940    /**
941     * Returns the 'relative to' path.<p>
942     *
943     * This only affects the generation of the path for the current resource.<p>
944     *
945     * @return the 'relative to' path
946     */
947    public String getRelativeTo() {
948
949        return m_relativeTo;
950    }
951
952    /**
953     * Returns the resource.<p>
954     *
955     * @return the resource
956     */
957    public CmsResource getResource() {
958
959        return m_resource;
960    }
961
962    /**
963     * Returns the resource type for the given resource.<p>
964     *
965     * @return the resource type for the given resource
966     */
967    public I_CmsResourceType getResourceType() {
968
969        if (m_resourceType == null) {
970            m_resourceType = OpenCms.getResourceManager().getResourceType(m_resource);
971        }
972        return m_resourceType;
973    }
974
975    /**
976     * Returns the resource type id for the given resource.<p>
977     *
978     * @return the resource type id for the given resource
979     */
980    @SuppressWarnings("deprecation")
981    public int getResourceTypeId() {
982
983        return getResourceType().getTypeId();
984    }
985
986    /**
987     * Returns the resource type name for the given resource.<p>
988     *
989     * @return the resource type name for the given resource
990     */
991    public String getResourceTypeName() {
992
993        return getResourceType().getTypeName();
994    }
995
996    /**
997     * Returns the SOLR search result for the current resource.<p>
998     *
999     * @param locale the content locale
1000     *
1001     * @return the search result
1002     */
1003    public CmsGallerySearchResult getSearchResult(Locale locale) {
1004
1005        if (!m_searchResultMap.containsKey(locale)) {
1006            CmsGallerySearchResult sResult;
1007            try {
1008                sResult = CmsGallerySearch.searchById(m_cms, m_resource.getStructureId(), locale);
1009                m_searchResultMap.put(locale, sResult);
1010            } catch (CmsException e) {
1011                LOG.error(e.getLocalizedMessage(), e);
1012            }
1013        }
1014        return m_searchResultMap.get(locale);
1015    }
1016
1017    /**
1018     * Returns the site of the current resources,
1019     * taking into account the set site mode.<p>
1020     *
1021     * @return the site path
1022     */
1023    public String getSite() {
1024
1025        String site = null;
1026        if ((m_siteMode == SITE_MODE_MATCHING) || (m_cms == null)) {
1027            site = OpenCms.getSiteManager().getSiteRoot(m_resource.getRootPath());
1028        } else if (m_siteMode == SITE_MODE_CURRENT) {
1029            site = m_cms.getRequestContext().getSiteRoot();
1030        } else if (m_siteMode == SITE_MODE_ROOT) {
1031            site = "";
1032        }
1033        return (site == null ? "" : site);
1034    }
1035
1036    /**
1037     * Returns the site mode.<p>
1038     *
1039     * This only affects the generation of the path for the current resource.<p>
1040     *
1041     * @return the site mode
1042     */
1043    public CmsResourceUtilSiteMode getSiteMode() {
1044
1045        return m_siteMode;
1046    }
1047
1048    /**
1049     * Returns the title of the site.<p>
1050     *
1051     * @return the title of the site
1052     */
1053    public String getSiteTitle() {
1054
1055        String title = getSite();
1056        String rootSite = getCms().getRequestContext().getSiteRoot();
1057        try {
1058            getCms().getRequestContext().setSiteRoot("");
1059            title = getCms().readPropertyObject(title, CmsPropertyDefinition.PROPERTY_TITLE, false).getValue(title);
1060        } catch (CmsException e) {
1061            // ignore
1062        } finally {
1063            getCms().getRequestContext().setSiteRoot(rootSite);
1064        }
1065        return title;
1066    }
1067
1068    /**
1069     * Returns the size of the given resource as a String.<p>
1070     *
1071     * For directories it returns <code>SIZE_DIR</code>.<p>
1072     *
1073     * @return the size of the given resource as a String
1074     */
1075    public String getSizeString() {
1076
1077        return m_resource.getLength() == -1 ? SIZE_DIR : "" + m_resource.getLength();
1078    }
1079
1080    /**
1081     * Returns the small icon resource of the current resource.<p>
1082     *
1083     * @return the icon resource
1084     */
1085    public Resource getSmallIconResource() {
1086
1087        if ((m_cms != null) && CmsJspNavBuilder.isNavLevelFolder(m_cms, m_resource)) {
1088            return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_NAV_LEVEL_BIG);
1089        }
1090        if ((m_cms != null) && CmsResourceTypeXmlContainerPage.isModelCopyGroup(m_cms, m_resource)) {
1091            return new CmsCssIcon(CmsExplorerTypeSettings.ICON_STYLE_MODEL_GROUP_COPY_BIG);
1092        }
1093        I_CmsResourceType type = getResourceType();
1094        CmsExplorerTypeSettings explorerType = OpenCms.getWorkplaceManager().getExplorerTypeSetting(type.getTypeName());
1095        return getSmallIconResource(explorerType, m_resource != null ? m_resource.getName() : null);
1096    }
1097
1098    /**
1099     * Returns resource state abbreviation.<p>
1100     *
1101     * @return resource state abbreviation
1102     */
1103    public char getStateAbbreviation() {
1104
1105        return getResource().getState().getAbbreviation();
1106    }
1107
1108    /**
1109     * Returns the state name for a resource.<p>
1110     *
1111     * Uses default locale if request context is <code>null</code>.<p>
1112     *
1113     * @return the state name for that resource
1114     */
1115    public String getStateName() {
1116
1117        CmsResourceState state = m_resource.getState();
1118        String name;
1119        if (m_request == null) {
1120            name = org.opencms.workplace.explorer.Messages.get().getBundle().key(
1121                org.opencms.workplace.explorer.Messages.getStateKey(state));
1122        } else {
1123            name = org.opencms.workplace.explorer.Messages.get().getBundle(m_request.getLocale()).key(
1124                org.opencms.workplace.explorer.Messages.getStateKey(state));
1125        }
1126        return name;
1127    }
1128
1129    /**
1130     * Returns the style class to use for the given resource.<p>
1131     *
1132     * @return style class name
1133     *
1134     * @see org.opencms.workplace.list.CmsListExplorerColumn#getExplorerStyleDef()
1135     */
1136    public String getStyleClassName() {
1137
1138        if (isInsideProject() && isEditable()) {
1139            if (m_resource.getState().isChanged()) {
1140                return "fc";
1141            } else if (m_resource.getState().isNew()) {
1142                return "fn";
1143            } else if (m_resource.getState().isDeleted()) {
1144                return "fd";
1145            } else {
1146                return "nf";
1147            }
1148        }
1149        return "fp";
1150    }
1151
1152    /**
1153     * Returns additional style sheets for the resource type icon depending on siblings.<p>
1154     *
1155     * That is, depending on {@link CmsResource#getSiblingCount()}
1156     *
1157     * Use it with the {@link #getIconPathExplorer} method.<p>
1158     *
1159     * @return additional style sheets depending on siblings
1160     */
1161    public String getStyleSiblings() {
1162
1163        StringBuffer style = new StringBuffer(128);
1164        if (m_resource.getSiblingCount() > 1) {
1165            style.append("background-image:url(");
1166            style.append(CmsWorkplace.getSkinUri());
1167            style.append(getIconPathResourceType());
1168            style.append("); background-position: 0px 0px; background-repeat: no-repeat; ");
1169        }
1170        return style.toString();
1171    }
1172
1173    /**
1174     * Returns the system lock information tooltip for the explorer view.<p>
1175     *
1176     * @param forExplorer if the tool tip should be generated for the explorer view
1177     *
1178     * @return the system lock information tooltip
1179     */
1180    public String getSystemLockInfo(boolean forExplorer) {
1181
1182        if (getLock().getSystemLock().isPublish()) {
1183            if (!forExplorer) {
1184                return getMessages().key(Messages.GUI_PUBLISH_TOOLTIP_0);
1185            } else {
1186                // see explorer.js(sysLockInfo) and top_js.jsp(publishlock)
1187                return "p"; // should have length == 1
1188            }
1189        }
1190        return "";
1191    }
1192
1193    /**
1194     * Returns additional style sheets depending on publication constraints.<p>
1195     *
1196     * That is, depending on {@link CmsResource#getDateReleased()} and
1197     * {@link CmsResource#getDateExpired()}.<p>
1198     *
1199     * @return additional style sheets depending on publication constraints
1200     *
1201     * @see #getTimeWindowLayoutType()
1202     */
1203    public String getTimeWindowLayoutStyle() {
1204
1205        return getTimeWindowLayoutType() == CmsResourceUtil.LAYOUTSTYLE_INRANGE ? "" : "font-style:italic;";
1206    }
1207
1208    /**
1209     * Returns the layout style for the current time window state.<p>
1210     *
1211     * <ul>
1212     *   <li><code>{@link CmsResourceUtil#LAYOUTSTYLE_INRANGE}</code>: The time window is in range
1213     *   <li><code>{@link CmsResourceUtil#LAYOUTSTYLE_BEFORERELEASE}</code>: The resource is not yet released
1214     *   <li><code>{@link CmsResourceUtil#LAYOUTSTYLE_AFTEREXPIRE}</code>: The resource has already expired
1215     * </ul>
1216     *
1217     * @return the layout style for the current time window state
1218     *
1219     * @see #getTimeWindowLayoutStyle()
1220     */
1221    public int getTimeWindowLayoutType() {
1222
1223        int layoutstyle = CmsResourceUtil.LAYOUTSTYLE_INRANGE;
1224        if (!m_resource.isReleased(getCms().getRequestContext().getRequestTime())) {
1225            layoutstyle = CmsResourceUtil.LAYOUTSTYLE_BEFORERELEASE;
1226        } else if (m_resource.isExpired(getCms().getRequestContext().getRequestTime())) {
1227            layoutstyle = CmsResourceUtil.LAYOUTSTYLE_AFTEREXPIRE;
1228        }
1229        return layoutstyle;
1230    }
1231
1232    /**
1233     * Returns the title of a resource.<p>
1234     *
1235     * @return the title for that resource
1236     */
1237    public String getTitle() {
1238
1239        String title = "";
1240        try {
1241            title = getCms().readPropertyObject(
1242                getCms().getSitePath(m_resource),
1243                CmsPropertyDefinition.PROPERTY_TITLE,
1244                false).getValue();
1245        } catch (Throwable e) {
1246            String storedSiteRoot = getCms().getRequestContext().getSiteRoot();
1247            try {
1248                getCms().getRequestContext().setSiteRoot("");
1249                title = getCms().readPropertyObject(
1250                    m_resource.getRootPath(),
1251                    CmsPropertyDefinition.PROPERTY_TITLE,
1252                    false).getValue();
1253            } catch (Exception e1) {
1254                // should usually never happen
1255                if (LOG.isInfoEnabled()) {
1256                    LOG.info(e.getLocalizedMessage(), e);
1257                }
1258            } finally {
1259                getCms().getRequestContext().setSiteRoot(storedSiteRoot);
1260            }
1261        }
1262        if (title == null) {
1263            title = "";
1264        }
1265        return title;
1266    }
1267
1268    /**
1269     * Returns the name of the user who created the given resource.<p>
1270     *
1271     * @return the name of the user who created the given resource
1272     */
1273    public String getUserCreated() {
1274
1275        String user = m_resource.getUserCreated().toString();
1276        try {
1277            user = getCurrentOuRelativeName(
1278                CmsPrincipal.readPrincipalIncludingHistory(getCms(), m_resource.getUserCreated()).getName());
1279        } catch (Throwable e) {
1280            LOG.info(e.getLocalizedMessage());
1281        }
1282        return user;
1283    }
1284
1285    /**
1286     * Returns the name of the user who last modified the given resource.<p>
1287     *
1288     * @return the name of the user who last modified the given resource
1289     */
1290    public String getUserLastModified() {
1291
1292        String user = m_resource.getUserLastModified().toString();
1293        try {
1294            user = getCurrentOuRelativeName(
1295                CmsPrincipal.readPrincipalIncludingHistory(getCms(), m_resource.getUserLastModified()).getName());
1296        } catch (Throwable e) {
1297            LOG.info(e.getLocalizedMessage());
1298        }
1299        return user;
1300    }
1301
1302    /**
1303     * Returns <code>true</code> if the given resource is editable by the current user.<p>
1304     *
1305     * Returns <code>false</code> if no request context is set.<p>
1306     *
1307     * @return <code>true</code> if the given resource is editable by the current user
1308     */
1309    public boolean isEditable() {
1310
1311        if (m_request == null) {
1312            return false;
1313        }
1314        CmsExplorerTypeSettings settings = OpenCms.getWorkplaceManager().getExplorerTypeSetting(getResourceTypeName());
1315        if (settings != null) {
1316            String rightSite = OpenCms.getSiteManager().getSiteRoot(getResource().getRootPath());
1317            if (rightSite == null) {
1318                rightSite = "";
1319            }
1320            String currentSite = getCms().getRequestContext().getSiteRoot();
1321            try {
1322                getCms().getRequestContext().setSiteRoot(rightSite);
1323                return settings.isEditable(getCms(), getResource());
1324            } finally {
1325                getCms().getRequestContext().setSiteRoot(currentSite);
1326            }
1327        }
1328        return false;
1329    }
1330
1331    /**
1332     * Returns <code>true</code> if the given resource is in the reference project.<p>
1333     *
1334     * Returns <code>false</code> if the request context is <code>null</code>.<p>
1335     *
1336     * @return <code>true</code> if the given resource is in the reference project
1337     *
1338     * @see #getReferenceProject()
1339     */
1340    public boolean isInsideProject() {
1341
1342        return CmsProject.isInsideProject(getProjectResources(), getResource());
1343    }
1344
1345    /**
1346     * Returns <code>true</code> if the stored resource has been released and has not expired.<p>
1347     *
1348     * If no request context is available, the current time is used for the validation check.<p>
1349     *
1350     * @return <code>true</code> if the stored resource has been released and has not expired
1351     *
1352     * @see CmsResource#isReleasedAndNotExpired(long)
1353     */
1354    public boolean isReleasedAndNotExpired() {
1355
1356        long requestTime;
1357        if (m_request == null) {
1358            requestTime = System.currentTimeMillis();
1359        } else {
1360            requestTime = m_request.getRequestTime();
1361        }
1362        return m_resource.isReleasedAndNotExpired(requestTime);
1363    }
1364
1365    /**
1366     * Sets the path abbreviation length.<p>
1367     *
1368     * If greater than zero, the path will be formatted to this number of chars.<p>
1369     *
1370     * This only affects the generation of the path for the current resource.<p>
1371     *
1372     * @param abbrevLength the path abbreviation length to set
1373     */
1374    public void setAbbrevLength(int abbrevLength) {
1375
1376        m_abbrevLength = abbrevLength;
1377    }
1378
1379    /**
1380     * Sets the cms context.<p>
1381     *
1382     * @param cms the cms context to set
1383     */
1384    public void setCms(CmsObject cms) {
1385
1386        m_cms = cms;
1387        m_request = cms.getRequestContext();
1388        m_referenceProject = null;
1389        m_projectResources = null;
1390        m_messages = null;
1391    }
1392
1393    /**
1394     * Sets the project to use to check project state.<p>
1395     *
1396     * @param project the project to set
1397     */
1398    public void setReferenceProject(CmsProject project) {
1399
1400        m_referenceProject = project;
1401        m_projectResources = null;
1402    }
1403
1404    /**
1405     * Sets the 'relative to' path.<p>
1406     *
1407     * This only affects the generation of the path for the current resource.<p>
1408     *
1409     * @param relativeTo the 'relative to' path to set
1410     */
1411    public void setRelativeTo(String relativeTo) {
1412
1413        m_relativeTo = relativeTo;
1414        if (CmsStringUtil.isEmptyOrWhitespaceOnly(m_relativeTo)) {
1415            m_relativeTo = null;
1416        } else {
1417            if (!m_relativeTo.startsWith("/")) {
1418                m_relativeTo = "/" + m_relativeTo;
1419            }
1420            if (!m_relativeTo.endsWith("/")) {
1421                m_relativeTo += "/";
1422            }
1423        }
1424    }
1425
1426    /**
1427     * Sets the resource.<p>
1428     *
1429     * @param resource the resource to set
1430     */
1431    public void setResource(CmsResource resource) {
1432
1433        m_resource = resource;
1434        m_lock = null;
1435        m_resourceType = null;
1436    }
1437
1438    /**
1439     * Sets the site mode.<p>
1440     *
1441     * This only affects the generation of the path for the current resource.<p>
1442     *
1443     * @param siteMode the site mode to set
1444     */
1445    public void setSiteMode(CmsResourceUtilSiteMode siteMode) {
1446
1447        m_siteMode = siteMode;
1448    }
1449
1450    /**
1451     * Returns the simple name if the ou is the same as the current user's ou.<p>
1452     *
1453     * @param name the fully qualified name to check
1454     *
1455     * @return the simple name if the ou is the same as the current user's ou
1456     */
1457    private String getCurrentOuRelativeName(String name) {
1458
1459        if (m_request == null) {
1460            return CmsOrganizationalUnit.SEPARATOR + name;
1461        }
1462        String ou = CmsOrganizationalUnit.getParentFqn(name);
1463        if (ou.equals(m_request.getCurrentUser().getOuFqn())) {
1464            return CmsOrganizationalUnit.getSimpleName(name);
1465        }
1466        return CmsOrganizationalUnit.SEPARATOR + name;
1467    }
1468
1469    /**
1470     * Returns the message bundle for formatting dates, depends on the request locale.<p>
1471     *
1472     * @return the message bundle for formatting dates
1473     */
1474    private CmsMessages getMessages() {
1475
1476        if (m_messages == null) {
1477            if (m_cms != null) {
1478                m_messages = Messages.get().getBundle(OpenCms.getWorkplaceManager().getWorkplaceLocale(m_cms));
1479            } else {
1480                m_messages = Messages.get().getBundle();
1481            }
1482        }
1483        return m_messages;
1484    }
1485
1486    /**
1487     * Returns the reference project resources.<p>
1488     *
1489     * @return the reference project resources
1490     */
1491    private List<String> getProjectResources() {
1492
1493        if (m_projectResources == null) {
1494            try {
1495                m_projectResources = getCms().readProjectResources(getReferenceProject());
1496            } catch (Throwable e) {
1497                LOG.error(e.getLocalizedMessage(), e);
1498                // use an empty list (all resources are "outside")
1499                m_projectResources = new ArrayList<String>();
1500            }
1501        }
1502        return m_projectResources;
1503    }
1504}