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.jsp;
029
030import org.opencms.file.CmsFile;
031import org.opencms.file.CmsFolder;
032import org.opencms.file.CmsObject;
033import org.opencms.file.CmsProperty;
034import org.opencms.file.CmsPropertyDefinition;
035import org.opencms.file.CmsRequestContext;
036import org.opencms.file.CmsResource;
037import org.opencms.file.CmsResourceFilter;
038import org.opencms.file.types.CmsResourceTypeXmlContent;
039import org.opencms.file.types.CmsResourceTypeXmlPage;
040import org.opencms.i18n.CmsLocaleGroup;
041import org.opencms.jsp.util.CmsJspContentAccessBean;
042import org.opencms.jsp.util.CmsJspImageBean;
043import org.opencms.jsp.util.CmsJspValueTransformers.CmsLocalePropertyLoaderTransformer;
044import org.opencms.main.CmsException;
045import org.opencms.main.CmsLog;
046import org.opencms.main.OpenCms;
047import org.opencms.security.CmsSecurityException;
048import org.opencms.util.CmsCollectionsGenericWrapper;
049import org.opencms.util.CmsUUID;
050
051import java.util.ArrayList;
052import java.util.Collections;
053import java.util.HashMap;
054import java.util.List;
055import java.util.Locale;
056import java.util.Map;
057
058import org.apache.commons.logging.Log;
059
060import com.google.common.collect.Maps;
061
062/**
063 * Wrapper subclass of CmsResource with some convenience methods.<p>
064 */
065public class CmsJspResourceWrapper extends CmsResource {
066
067    /** Serial version id. */
068    private static final long serialVersionUID = 1L;
069
070    /** Logger instance for this class. */
071    @SuppressWarnings("unused")
072    private static final Log LOG = CmsLog.getLog(CmsJspResourceWrapper.class);
073
074    /** The CMS context. */
075    private CmsObject m_cms;
076
077    /** The set of locale variants. */
078    private Map<String, CmsJspResourceWrapper> m_localeResources;
079
080    /** The main locale. */
081    private Locale m_mainLocale;
082
083    /** The file object for this resource. */
084    private CmsFile m_file;
085
086    /** The resource / file content as a String. */
087    private String m_content;
088
089    /** The calculated site path of the resource. */
090    private String m_sitePath;
091
092    /** Properties of this resource. */
093    private Map<String, String> m_properties;
094
095    /** Properties of this resource with search. */
096    private Map<String, String> m_propertiesSearch;
097
098    /** Locale properties of this resource. */
099    private Map<String, Map<String, String>> m_propertiesLocale;
100
101    /** Locale properties of this resource with search. */
102    private Map<String, Map<String, String>> m_propertiesLocaleSearch;
103
104    /** The XML content access bean. */
105    private CmsJspContentAccessBean m_xml;
106
107    /** Stores if this resource is an XML content or not. */
108    private Boolean m_isXml;
109
110    /** All parent folder of this resource in the current site as a list. */
111    public List<CmsJspResourceWrapper> m_parentFolders;
112
113    /** The parent folder of this resource in the current site. */
114    private CmsJspResourceWrapper m_parentFolder;
115
116    /** The default file of this resource, assumed that this resource is a folder. */
117    CmsJspResourceWrapper m_navigationDefaultFile;
118
119    /** The navigation builder for this resource. */
120    CmsJspNavBuilder m_navBuilder;
121
122    /** The navigation info elements in this resource, assuming that this resource is a folder. */
123    private List<CmsJspNavElement> m_navigationForFolder;
124
125    /** The navigation info element for this resource. */
126    private CmsJspNavElement m_navigation;
127
128    /** Image bean instance created from this resource. */
129    private CmsJspImageBean m_imageBean;
130
131    /**
132     * Creates a new instance.<p>
133     *
134     * @param cms the current CMS context
135     * @param res the resource to wrap
136     */
137    private CmsJspResourceWrapper(CmsObject cms, CmsResource res) {
138
139        super(
140            res.getStructureId(),
141            res.getResourceId(),
142            res.getRootPath(),
143            res.getTypeId(),
144            res.isFolder(),
145            res.getFlags(),
146            res.getProjectLastModified(),
147            res.getState(),
148            res.getDateCreated(),
149            res.getUserCreated(),
150            res.getDateLastModified(),
151            res.getUserLastModified(),
152            res.getDateReleased(),
153            res.getDateExpired(),
154            res.getSiblingCount(),
155            res.getLength(),
156            res.getDateContent(),
157            res.getVersion());
158        m_cms = cms;
159        m_file = null;
160        m_content = "";
161    }
162
163    /**
164     * Factory method to create a new {@link CmsJspResourceWrapper} instance from a {@link CmsResource}.<p>
165     *
166     * In case the parameter resource already is a wrapped resource AND the OpenCms request context is
167     * the same as the provided context, the parameter object is returned.<p>
168     *
169     * @param cms the current CMS context
170     * @param res the resource to wrap
171     *
172     * @return a new instance of a {@link CmsJspResourceWrapper}
173     */
174    public static CmsJspResourceWrapper wrap(CmsObject cms, CmsResource res) {
175
176        CmsJspResourceWrapper result = null;
177        if ((cms != null) && (res != null)) {
178            if (res instanceof CmsJspResourceWrapper) {
179                CmsJspResourceWrapper wrapper = (CmsJspResourceWrapper)res;
180                if (cms.getRequestContext().getSiteRoot().equals(wrapper.getRequestContext().getSiteRoot())) {
181                    result = wrapper;
182                } else {
183                    result = new CmsJspResourceWrapper(cms, res);
184                }
185            } else {
186                result = new CmsJspResourceWrapper(cms, res);
187            }
188        }
189        return result;
190    }
191
192    /**
193     * Two resources are considered equal in case their structure id is equal.<p>
194     *
195     * @see CmsResource#equals(java.lang.Object)
196     */
197    @Override
198    public boolean equals(Object obj) {
199
200        if (obj == null) {
201            return false;
202        }
203
204        if (obj == this) {
205            return true;
206        }
207        if (obj instanceof CmsResource) {
208            return ((CmsResource)obj).getStructureId().equals(getStructureId());
209        }
210        return false;
211    }
212
213    /**
214     * Returns the OpenCms user context this resource was initialized with.<p>
215     *
216     * @return the OpenCms user context this resource was initialized with
217     */
218    public CmsObject getCmsObject() {
219
220        return m_cms;
221    }
222
223    /**
224     * Returns the content of the file as a String.<p>
225     *
226     * @return the content of the file as a String
227     */
228    public String getContent() {
229
230        if ((m_content.length() == 0) && (getFile() != null)) {
231            m_content = new String(getFile().getContents());
232        }
233        return m_content;
234    }
235
236    /**
237     * Returns this resources name extension (if present).<p>
238     *
239     * The extension will always be lower case.<p>
240     *
241     * @return the extension or <code>null</code> if not available
242     *
243     * @see CmsResource#getExtension(String)
244     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getResourceExtension(Object)
245     */
246    public String getExtension() {
247
248        return getExtension(getRootPath());
249    }
250
251    /**
252     * Returns the full file object for this resource.<p>
253     *
254     * @return the full file object for this resource
255     */
256    public CmsFile getFile() {
257
258        if ((m_file == null) && !isFolder()) {
259            try {
260                m_file = m_cms.readFile(this);
261            } catch (CmsException e) {
262                // this should not happen since we are updating from a resource object
263            }
264        }
265        return m_file;
266    }
267
268    /**
269     * Returns the folder of this resource.<p>
270     *
271     * In case this resource already is a {@link CmsFolder}, it is returned without modification.
272     * In case it is a {@link CmsFile}, the parent folder of the file is returned.<p>
273     *
274     * @return the folder of this resource
275     *
276     * @see #getSitePathFolder()
277     */
278    public CmsJspResourceWrapper getFolder() {
279
280        CmsJspResourceWrapper result;
281        if (isFolder()) {
282            result = this;
283        } else {
284            result = readResource(getSitePathFolder());
285        }
286        return result;
287    }
288
289    /**
290     * Returns <code>true</code> in case this resource is an image in the VFS.<p>
291     *
292     * @return <code>true</code> in case this resource is an image in the VFS
293     */
294    public boolean getIsImage() {
295
296        return getToImage().isImage();
297    }
298
299    /**
300     * Returns <code>true</code> in case this resource is an XML content.<p>
301     *
302     * @return <code>true</code> in case this resource is an XML content
303     */
304    public boolean getIsXml() {
305
306        if (m_isXml == null) {
307            m_isXml = Boolean.valueOf(
308                CmsResourceTypeXmlPage.isXmlPage(this) || CmsResourceTypeXmlContent.isXmlContent(this));
309        }
310        return m_isXml.booleanValue();
311    }
312
313    /**
314     * Returns a substituted link to this resource.<p>
315     *
316     * @return the link
317     */
318    public String getLink() {
319
320        return OpenCms.getLinkManager().substituteLinkForUnknownTarget(
321            m_cms,
322            m_cms.getRequestContext().getSitePath(this));
323    }
324
325    /**
326     * Returns a map of the locale group for the current resource, with locale strings as keys.<p>
327     *
328     * @return a map with locale strings as keys and resource wrappers for the corresponding locale variants
329     */
330    public Map<String, CmsJspResourceWrapper> getLocaleResource() {
331
332        if (m_localeResources != null) {
333            return m_localeResources;
334        }
335        try {
336            CmsLocaleGroup localeGroup = m_cms.getLocaleGroupService().readLocaleGroup(this);
337            Map<Locale, CmsResource> resourcesByLocale = localeGroup.getResourcesByLocale();
338            Map<String, CmsJspResourceWrapper> result = Maps.newHashMap();
339            for (Map.Entry<Locale, CmsResource> entry : resourcesByLocale.entrySet()) {
340                result.put(entry.getKey().toString(), CmsJspResourceWrapper.wrap(m_cms, entry.getValue()));
341            }
342            m_localeResources = result;
343            return result;
344        } catch (CmsException e) {
345            return new HashMap<String, CmsJspResourceWrapper>();
346        }
347    }
348
349    /**
350     * Returns the main locale for this resource.<p>
351     *
352     * @return the main locale for this resource
353     */
354    public Locale getMainLocale() {
355
356        if (m_mainLocale != null) {
357            return m_mainLocale;
358        }
359        try {
360            CmsLocaleGroup localeGroup = m_cms.getLocaleGroupService().readLocaleGroup(this);
361            m_mainLocale = localeGroup.getMainLocale();
362            return m_mainLocale;
363        } catch (CmsException e) {
364            return null;
365        }
366    }
367
368    /**
369     * Returns the mime type for this resource.<p>
370     *
371     * In case no valid mime type can be determined from the file extension, <code>text/plain</code> is returned.<p>
372     *
373     * @return the mime type for this resource
374     */
375    public String getMimeType() {
376
377        return OpenCms.getResourceManager().getMimeType(getRootPath(), null, "text/plain");
378    }
379
380    /**
381     * Returns the navigation builder for this resource.<p>
382     *
383     * This will be initialized with this resource as default URI.<p>
384     *
385     * @return the navigation builder for this resource
386     */
387    public CmsJspNavBuilder getNavBuilder() {
388
389        if (m_navBuilder == null) {
390            m_navBuilder = new CmsJspNavBuilder();
391            m_navBuilder.init(m_cms, null, getSitePath());
392        }
393        return m_navBuilder;
394    }
395
396    /**
397     * Returns the navigation info element for this resource.<p>
398     *
399     * @return the navigation info element for this resource
400     */
401    public CmsJspNavElement getNavigation() {
402
403        if (m_navigation == null) {
404            m_navigation = getNavBuilder().getNavigationForResource();
405        }
406        return m_navigation;
407    }
408
409    /**
410     * Returns the default resource for this resource.<p>
411     *
412     * If this resource is a file, then this file is returned.<p>
413     *
414     * Otherwise, in case this resource is a folder:<br>
415     * <ol>
416     *   <li>the {@link CmsPropertyDefinition#PROPERTY_DEFAULT_FILE} is checked, and
417     *   <li>if still no file could be found, the configured default files in the
418     *       <code>opencms-vfs.xml</code> configuration are iterated until a match is
419     *       found, and
420     *   <li>if still no file could be found, <code>null</code> is returned
421     * </ol>
422     *
423     * @return the default file for the given folder
424     *
425     * @see CmsObject#readDefaultFile(CmsResource, CmsResourceFilter)
426     */
427    public CmsJspResourceWrapper getNavigationDefaultFile() {
428
429        if (m_navigationDefaultFile == null) {
430            if (isFolder()) {
431                try {
432                    m_navigationDefaultFile = wrap(m_cms, m_cms.readDefaultFile(this, CmsResourceFilter.DEFAULT));
433                } catch (CmsSecurityException e) {
434                    if (LOG.isDebugEnabled()) {
435                        LOG.debug(e.getMessage(), e);
436                    }
437                }
438            }
439        } else {
440            m_navigationDefaultFile = this;
441        }
442        return m_navigationDefaultFile;
443    }
444
445    /**
446     * Returns the navigation info elements in this resource, assuming that this resource is a folder.<p>
447     *
448     * @return the navigation info elements in this resource, assuming that this resource is a folder
449     */
450    public List<CmsJspNavElement> getNavigationForFolder() {
451
452        if (m_navigationForFolder == null) {
453            m_navigationForFolder = getNavBuilder().getNavigationForFolder();
454        }
455        return m_navigationForFolder;
456    }
457
458    /**
459     * Returns the parent folder of this resource in the current site.<p>
460     *
461     * In case this resource represents the site root folder, <code>null</code> is returned.<p>
462     *
463     * @return the parent folder of this resource in the current site
464     *
465     * @see #getSitePathParentFolder()
466     * @see CmsResource#getParentFolder(String)
467     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getParentFolder(Object)
468     */
469    public CmsJspResourceWrapper getParentFolder() {
470
471        if (m_parentFolder == null) {
472            String parentFolder = getSitePathParentFolder();
473            if (parentFolder != null) {
474                m_parentFolder = readResource(getSitePathParentFolder());
475            }
476        }
477        return m_parentFolder;
478    }
479
480    /**
481     * Returns all parent folder of this resource in the current site as a list.<p>
482     *
483     * First resource in the list will be the direct parent folder of this resource,
484     * the last element will be the site root folder.<p>
485     *
486     * @return all parent folder of this resource in the current site as a list
487     */
488    public List<CmsJspResourceWrapper> getParentFolders() {
489
490        if (m_parentFolders == null) {
491            m_parentFolders = new ArrayList<CmsJspResourceWrapper>();
492            CmsJspResourceWrapper parentFolder = getParentFolder();
493            while (parentFolder != null) {
494                m_parentFolders.add(parentFolder);
495                parentFolder = parentFolder.getParentFolder();
496            }
497        }
498        return m_parentFolders;
499    }
500
501    /**
502     * Returns the direct properties of this resource in a map.<p>
503     *
504     * This is without "search", so it will not include inherited properties from the parent folders.<p>
505     *
506     * @return the direct properties of this resource in a map
507     */
508    public Map<String, String> getProperty() {
509
510        if (m_properties == null) {
511            try {
512                List<CmsProperty> properties = m_cms.readPropertyObjects(this, false);
513                m_properties = CmsProperty.toMap(properties);
514            } catch (CmsException e) {
515                if (LOG.isDebugEnabled()) {
516                    LOG.debug(e.getMessage(), e);
517                }
518            }
519        }
520        return m_properties;
521    }
522
523    /**
524     * Returns the direct properties of this resource in a map for a given locale.<p>
525     *
526     * This is without "search", so it will not include inherited properties from the parent folders.<p>
527     *
528     * @return the direct properties of this resource in a map for  a given locale
529     */
530    public Map<String, Map<String, String>> getPropertyLocale() {
531
532        if (m_propertiesLocale == null) {
533            m_propertiesLocale = CmsCollectionsGenericWrapper.createLazyMap(
534                new CmsLocalePropertyLoaderTransformer(getCmsObject(), this, false));
535            // result may still be null
536            return (m_propertiesLocale == null) ? Collections.EMPTY_MAP : m_propertiesLocale;
537        }
538        return m_propertiesLocale;
539    }
540
541    /**
542     * Returns the searched properties of this resource in a map for a given locale.<p>
543     *
544     * This is with "search", so it will include inherited properties from the parent folders.<p>
545     *
546     * @return the direct properties of this resource in a map for a given locale
547     */
548    public Map<String, Map<String, String>> getPropertyLocaleSearch() {
549
550        if (m_propertiesLocaleSearch == null) {
551            m_propertiesLocaleSearch = CmsCollectionsGenericWrapper.createLazyMap(
552                new CmsLocalePropertyLoaderTransformer(getCmsObject(), this, true));
553            // result may still be null
554            return (m_propertiesLocaleSearch == null) ? Collections.EMPTY_MAP : m_propertiesLocaleSearch;
555        }
556        return m_propertiesLocaleSearch;
557    }
558
559    /**
560     * Returns the searched properties of this resource in a map.<p>
561     *
562     * This is with "search", so it will include inherited properties from the parent folders.<p>
563     *
564     * @return the direct properties of this resource in a map
565     */
566    public Map<String, String> getPropertySearch() {
567
568        if (m_propertiesSearch == null) {
569            try {
570                List<CmsProperty> properties = m_cms.readPropertyObjects(this, true);
571                m_propertiesSearch = CmsProperty.toMap(properties);
572            } catch (CmsException e) {
573                if (LOG.isDebugEnabled()) {
574                    LOG.debug(e.getMessage(), e);
575                }
576            }
577        }
578        return m_propertiesSearch;
579    }
580
581    /**
582     * Returns the OpenCms user request context this resource was initialized with.<p>
583     *
584     * @return the OpenCms user request context this resource was initialized with
585     */
586    public CmsRequestContext getRequestContext() {
587
588        return m_cms.getRequestContext();
589    }
590
591    /**
592     * Returns this resources name extension (if present).<p>
593     *
594     * The extension will always be lower case.<p>
595     *
596     * @return the extension or <code>null</code> if not available
597     *
598     * @see CmsResource#getExtension(String)
599     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getResourceExtension(Object)
600     */
601    public String getResourceExtension() {
602
603        return getExtension();
604    }
605
606    /**
607     * Returns the name of this resource without the path information.<p>
608     *
609     * The resource name of a file is the name of the file.
610     * The resource name of a folder is the folder name with trailing "/".
611     * The resource name of the root folder is <code>/</code>.<p>
612     *
613     * @return the name of this resource without the path information
614     *
615     * @see CmsResource#getName()
616     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getResourceName(Object)
617     */
618    public String getResourceName() {
619
620        return getName();
621    }
622
623    /**
624     * Returns the folder name of this resource from the root site.<p>
625     *
626     * In case this resource already is a {@link CmsFolder}, the folder path is returned without modification.
627     * In case it is a {@link CmsFile}, the parent folder name of the file is returned.<p>
628     *
629     * @return  the folder name of this resource from the root site
630     */
631    public String getRootPathFolder() {
632
633        String result;
634        if (isFile()) {
635            result = getRootPathParentFolder();
636        } else {
637            result = getRootPath();
638        }
639        return result;
640    }
641
642    /**
643     * Returns the directory level of a resource from the root site.<p>
644     *
645     * The root folder "/" has level 0,
646     * a folder "/foo/" would have level 1,
647     * a folder "/foo/bar/" level 2 etc.<p>
648     *
649     * @return the directory level of a resource from the root site
650     *
651     * @see CmsResource#getPathLevel(String)
652     */
653    public int getRootPathLevel() {
654
655        return getPathLevel(getRootPath());
656    }
657
658    /**
659     * Returns the parent folder of this resource from the root site.<p>
660     *
661     * @return the parent folder of this resource from the root site
662     *
663     * @see CmsResource#getParentFolder(String)
664     */
665    public String getRootPathParentFolder() {
666
667        return getParentFolder(getRootPath());
668    }
669
670    /**
671     * Returns the current site path to this resource.<p>
672     *
673     * @return the current site path to this resource
674     *
675     * @see org.opencms.file.CmsRequestContext#getSitePath(CmsResource)
676     */
677    public String getSitePath() {
678
679        if (m_sitePath == null) {
680            m_sitePath = m_cms.getRequestContext().getSitePath(this);
681        }
682
683        return m_sitePath;
684    }
685
686    /**
687     * Returns the folder name of this resource in the current site.<p>
688     *
689     * In case this resource already is a {@link CmsFolder}, the folder path is returned without modification.
690     * In case it is a {@link CmsFile}, the parent folder name of the file is returned.<p>
691     *
692     * @return  the folder name of this resource in the current site
693     */
694    public String getSitePathFolder() {
695
696        String result;
697        if (isFile()) {
698            result = getSitePathParentFolder();
699        } else {
700            result = getSitePath();
701        }
702        return result;
703    }
704
705    /**
706     * Returns the directory level of a resource in the current site.<p>
707     *
708     * The root folder "/" has level 0,
709     * a folder "/foo/" would have level 1,
710     * a folder "/foo/bar/" level 2 etc.<p>
711     *
712     * @return the directory level of a resource in the current site
713     *
714     * @see CmsResource#getPathLevel(String)
715     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getPathLevel(Object)
716     */
717    public int getSitePathLevel() {
718
719        return getPathLevel(getSitePath());
720    }
721
722    /**
723     * Returns the parent folder of this resource in the current site.<p>
724     *
725     * @return the parent folder of this resource in the current site
726     *
727     * @see CmsResource#getParentFolder(String)
728     * @see org.opencms.jsp.util.CmsJspVfsAccessBean#getParentFolder(Object)
729     */
730    public String getSitePathParentFolder() {
731
732        return getParentFolder(getSitePath());
733    }
734
735    /**
736     * Returns a scaled image bean from the wrapped value.<p>
737     *
738     * In case the value does not point to an image resource, <code>null</code> is returned.
739     *
740     * @return the scaled image bean
741     */
742    public CmsJspImageBean getToImage() {
743
744        if (m_imageBean == null) {
745            m_imageBean = new CmsJspImageBean(getCmsObject(), this, null);
746        }
747        return m_imageBean;
748    }
749
750    /**
751     * Returns an XML content access bean created for this resource.<p>
752     *
753     * In case this resource is not an XML content, <code>null</code> is returned.<p>
754     *
755     * @return an XML content access bean created for this resource
756     *
757     * @see #getIsXml()
758     */
759    public CmsJspContentAccessBean getToXml() {
760
761        if ((m_xml == null) && getIsXml()) {
762            m_xml = new CmsJspContentAccessBean(m_cms, this);
763        }
764        return m_xml;
765    }
766
767    /**
768     * Returns an XML content access bean created for this resource.<p>
769     *
770     * In case this resource is not an XML content, <code>null</code> is returned.<p>
771     *
772     * @return an XML content access bean created for this resource
773     *
774     * @see #getToXml()
775     * @see #getIsXml()
776     */
777    public CmsJspContentAccessBean getXml() {
778
779        return getToXml();
780    }
781
782    /**
783     * @see CmsResource#hashCode()
784     * @see java.lang.Object#hashCode()
785     */
786    @Override
787    public int hashCode() {
788
789        if (getStructureId() != null) {
790            return getStructureId().hashCode();
791        }
792
793        return CmsUUID.getNullUUID().hashCode();
794    }
795
796    /**
797     * Returns <code>true</code> in case this resource is child resource of the provided resource which is assumed to be a folder.<p>
798     *
799     * @param resource the resource to check
800     *
801     * @return <code>true</code> in case this resource is child resource of the provided resource which is assumed to be a folder
802     */
803    public boolean isChildResourceOf(CmsResource resource) {
804
805        return (resource != null)
806            && resource.isFolder()
807            && !(getStructureId().equals(resource.getStructureId()))
808            && ((getRootPath().indexOf(resource.getRootPath()) == 0));
809    }
810
811    /**
812     * Returns <code>true</code> in case this resource is child resource of the provided resource path which is assumed to be a folder in the current site.<p>
813     *
814     * No check is performed to see if the provided site path resource actually exists.<p>
815     *
816     * @param sitePath the resource to check
817     *
818     * @return <code>true</code> in case this resource is child resource of the provided resource path which is assumed to be a folder in the current site
819     */
820    public boolean isChildResourceOf(String sitePath) {
821
822        return (sitePath != null)
823            && ((getSitePath().indexOf(sitePath) == 0))
824            && (sitePath.length() < getSitePath().length());
825    }
826
827    /**
828     * Returns <code>true</code> in case this resource is a parent folder of the provided resource.<p>
829     *
830     * @param resource the resource to check
831     *
832     * @return <code>true</code> in case this resource is a parent folder of the provided resource
833     */
834    public boolean isParentFolderOf(CmsResource resource) {
835
836        return (resource != null)
837            && isFolder()
838            && !(getStructureId().equals(resource.getStructureId()))
839            && ((resource.getRootPath().indexOf(getRootPath()) == 0));
840    }
841
842    /**
843     * Returns <code>true</code> in case this resource is a parent folder of the provided resource path in the current site.<p>
844     *
845     * No check is performed to see if the provided site path resource actually exists.<p>
846     *
847     * @param sitePath the path to check
848     *
849     * @return <code>true</code> in case this resource is a parent folder of the provided resource path in the current site
850     */
851    public boolean isParentFolderOf(String sitePath) {
852
853        return (sitePath != null)
854            && isFolder()
855            && ((sitePath.indexOf(getSitePath()) == 0))
856            && (sitePath.length() > getSitePath().length());
857    }
858
859    /**
860     * Reads a resource, suppressing possible exceptions.<p>
861     *
862     * @param sitePath the site path of the resource to read.
863     *
864     * @return the resource of <code>null</code> on case an exception occurred while reading
865     */
866    private CmsJspResourceWrapper readResource(String sitePath) {
867
868        CmsJspResourceWrapper result = null;
869        try {
870            result = new CmsJspResourceWrapper(m_cms, m_cms.readResource(sitePath));
871        } catch (CmsException e) {
872            if (LOG.isDebugEnabled()) {
873                LOG.debug(e.getMessage(), e);
874            }
875        }
876        return result;
877    }
878}