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.util;
029
030import org.opencms.ade.configuration.CmsADEConfigData;
031import org.opencms.file.CmsObject;
032import org.opencms.file.CmsProject;
033import org.opencms.file.CmsRequestContext;
034import org.opencms.file.CmsResource;
035import org.opencms.file.CmsResourceFilter;
036import org.opencms.file.CmsUser;
037import org.opencms.file.types.CmsResourceTypeXmlContent;
038import org.opencms.file.types.CmsResourceTypeXmlPage;
039import org.opencms.i18n.CmsLocaleGroup;
040import org.opencms.jsp.CmsJspResourceWrapper;
041import org.opencms.jsp.util.CmsJspValueTransformers.CmsLocalePropertyLoaderTransformer;
042import org.opencms.jsp.util.CmsJspValueTransformers.CmsPropertyLoaderTransformer;
043import org.opencms.main.CmsException;
044import org.opencms.main.CmsLog;
045import org.opencms.main.OpenCms;
046import org.opencms.security.CmsPermissionSet;
047import org.opencms.util.CmsCollectionsGenericWrapper;
048import org.opencms.util.CmsStringUtil;
049
050import java.util.Collections;
051import java.util.HashMap;
052import java.util.List;
053import java.util.Locale;
054import java.util.Map;
055
056import org.apache.commons.collections.Transformer;
057import org.apache.commons.logging.Log;
058
059/**
060 * Provides utility methods that allow convenient access to the OpenCms VFS,
061 * indented to be used from a JSP with the JSTL or EL.<p>
062 *
063 * @since 7.0.2
064 *
065 * @see CmsJspContentAccessBean
066 */
067public final class CmsJspVfsAccessBean {
068
069    /**
070     * Transformer that loads a resource from the OpenCms VFS,
071     * the input is used as String for the resource name to read.<p>
072     */
073    public class CmsAvailableLocaleLoaderTransformer implements Transformer {
074
075        /**
076         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
077         */
078        public Object transform(Object input) {
079
080            List<Locale> result;
081            // read the available locales
082            result = OpenCms.getLocaleManager().getAvailableLocales(getCmsObject(), String.valueOf(input));
083            return result;
084        }
085    }
086
087    /**
088     * Provides Booleans that indicate if a specified resource exists in the OpenCms VFS,
089     * the input is used as String for the resource name to read.<p>
090     */
091    public class CmsExistsResourceTransformer implements Transformer {
092
093        /**
094         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
095         */
096        public Object transform(Object input) {
097
098            return Boolean.valueOf(getReadResource().get(input) != null);
099        }
100    }
101
102    /**
103     * Provides Booleans that indicate if a specified resource exists in the OpenCms VFS
104     * and is of type XML content or XML page,
105     * the input is used as String for the resource name to read.<p>
106     */
107    public class CmsExistsXmlTransformer implements Transformer {
108
109        /**
110         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
111         */
112        public Object transform(Object input) {
113
114            // first read the resource using the lazy map
115            CmsJspResourceWrapper resource = getReadResource().get(input);
116            return Boolean.valueOf(
117                (resource != null)
118                    && (CmsResourceTypeXmlPage.isXmlPage(resource)
119                        || CmsResourceTypeXmlContent.isXmlContent(resource)));
120        }
121    }
122
123    /**
124     * Transformer that loads a resource permission from the OpenCms VFS,
125     * the input is used as String for the resource name to read the permissions for.<p>
126     */
127    public class CmsPermissionsLoaderTransformer implements Transformer {
128
129        /**
130         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
131         */
132        public Object transform(Object input) {
133
134            CmsPermissionSet result;
135            try {
136                // read the requested resource permissions
137                result = getCmsObject().getPermissions((String)input);
138            } catch (CmsException e) {
139                // unable to read resource, return null
140                result = null;
141            }
142            return result;
143        }
144    }
145
146    /**
147     * Transformer that a properties of a resource from the OpenCms VFS,
148     * the input is used as String for the property name to read.<p>
149     */
150    public class CmsPropertyLoaderSingleTransformer implements Transformer {
151
152        /** The resource where the properties are read from. */
153        private CmsResource m_resource;
154
155        /** Indicates if properties should be searched when loaded. */
156        private boolean m_search;
157
158        /**
159         * Creates a new property loading Transformer.<p>
160         *
161         * @param resource the resource where the properties are read from
162         * @param search indicates if properties should be searched when loaded
163         */
164        public CmsPropertyLoaderSingleTransformer(CmsResource resource, boolean search) {
165
166            m_resource = resource;
167            m_search = search;
168        }
169
170        /**
171         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
172         */
173        public Object transform(Object input) {
174
175            String result;
176            try {
177                // read the properties of the requested resource
178                result = getCmsObject().readPropertyObject(m_resource, String.valueOf(input), m_search).getValue();
179            } catch (CmsException e) {
180                // in case of any error we assume the property does not exist
181                result = null;
182            }
183            return result;
184        }
185    }
186
187    /**
188     * Transformer that loads a resource from the OpenCms VFS,
189     * the input is used as String for the resource name to read.<p>
190     */
191    public class CmsResourceLoaderTransformer implements Transformer {
192
193        /**
194         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
195         */
196        public Object transform(Object input) {
197
198            CmsJspResourceWrapper result;
199            try {
200                // read the requested resource
201                result = CmsJspElFunctions.convertResource(getCmsObject(), input);
202            } catch (CmsException e) {
203                // unable to read resource, return null
204                result = null;
205            }
206            return result;
207        }
208    }
209
210    /**
211     * Transformer that loads properties of a resource from the OpenCms VFS with another lazy map,
212     * the input is used as String for the resource name to read.<p>
213     */
214    public class CmsResourceLocalePropertyLoaderTransformer implements Transformer {
215
216        /** Indicates if properties should be searched when loaded. */
217        private boolean m_search;
218
219        /**
220         * Creates a new property loading Transformer.<p>
221         *
222         * @param search indicates if properties should be searched when loaded
223         */
224        public CmsResourceLocalePropertyLoaderTransformer(boolean search) {
225
226            m_search = search;
227        }
228
229        /**
230         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
231         */
232        public Object transform(Object input) {
233
234            Map<String, String> result = null;
235            // first read the resource using the lazy map
236            CmsJspResourceWrapper resource = getReadResource().get(input);
237            if (resource != null) {
238                result = CmsCollectionsGenericWrapper.createLazyMap(
239                    new CmsLocalePropertyLoaderTransformer(getCmsObject(), resource, m_search));
240            }
241            // result may still be null
242            return (result == null) ? Collections.EMPTY_MAP : result;
243        }
244    }
245
246    /**
247     * Transformer that loads properties of a resource from the OpenCms VFS with another lazy map,
248     * the input is used as String for the resource name to read.<p>
249     */
250    public class CmsResourcePropertyLoaderTransformer implements Transformer {
251
252        /** Indicates if properties should be searched when loaded. */
253        private boolean m_search;
254
255        /**
256         * Creates a new property loading Transformer.<p>
257         *
258         * @param search indicates if properties should be searched when loaded
259         */
260        public CmsResourcePropertyLoaderTransformer(boolean search) {
261
262            m_search = search;
263        }
264
265        /**
266         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
267         */
268        public Object transform(Object input) {
269
270            Map<String, String> result = null;
271            // first read the resource using the lazy map
272            CmsJspResourceWrapper resource = getReadResource().get(input);
273            if (resource != null) {
274                result = CmsCollectionsGenericWrapper.createLazyMap(
275                    new CmsPropertyLoaderTransformer(getCmsObject(), resource, m_search));
276            }
277            // result may still be null
278            return (result == null) ? Collections.EMPTY_MAP : result;
279        }
280    }
281
282    /**
283     * Transformer that calculates links to resources in the OpenCms VFS,
284     * the input is used as String for the resource name to use as link target.<p>
285     *
286     * This is using the same logic as
287     * {@link org.opencms.jsp.CmsJspTagLink#linkTagAction(String, javax.servlet.ServletRequest)}.<p>
288     */
289    public class CmsVfsLinkTransformer implements Transformer {
290
291        /**
292         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
293         */
294        public Object transform(Object input) {
295
296            return A_CmsJspValueWrapper.substituteLink(getCmsObject(), String.valueOf(input));
297        }
298    }
299
300    /**
301     * Provides XML content access beans for VFS resources.<p>
302     */
303    public class CmsXmlContentAccessTransformer implements Transformer {
304
305        /**
306         * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
307         */
308        public Object transform(Object input) {
309
310            CmsJspContentAccessBean result = null;
311            // first read the resource using the lazy map
312            CmsJspResourceWrapper resource = getReadResource().get(input);
313            if ((resource != null)
314                && (CmsResourceTypeXmlPage.isXmlPage(resource) || CmsResourceTypeXmlContent.isXmlContent(resource))) {
315                // make sure we have a resource that really is an XML content
316                result = new CmsJspContentAccessBean(getCmsObject(), resource);
317            }
318            return result;
319        }
320    }
321
322    /** Request context attribute for indicating the model file for a create resource operation. */
323    public static final String ATTRIBUTE_VFS_ACCESS_BEAN = CmsJspVfsAccessBean.class.getName() + ".VFS_ACCESS_BEAN";
324
325    /** Logger instance for this class. */
326    private static final Log LOG = CmsLog.getLog(CmsJspVfsAccessBean.class);
327
328    /** The OpenCms context of the current user. */
329    protected CmsObject m_cms;
330
331    /** Contains booleans that indicate if a resource exists in the VFS. */
332    private Map<String, Boolean> m_existsResource;
333
334    /** Contains booleans that indicate if a resource exists and is an XML content. */
335    private Map<String, Boolean> m_existsXml;
336
337    /** Links calculated for the OpenCms VFS. */
338    private Map<String, String> m_links;
339
340    /** Resource permissions loaded from the OpenCms VFS. */
341    private Map<String, CmsPermissionSet> m_permissions;
342
343    /** Properties loaded from the OpenCms VFS. */
344    private Map<String, Map<String, String>> m_properties;
345
346    /** Properties loaded locale specific from the OpenCms VFS. */
347    private Map<String, Map<String, Map<String, String>>> m_propertiesLocale;
348
349    /** Properties loaded from the OpenCms VFS with search. */
350    private Map<String, Map<String, String>> m_propertiesSearch;
351
352    /** Properties loaded locale specific from the OpenCms VFS with search. */
353    private Map<String, Map<String, Map<String, String>>> m_propertiesSearchLocale;
354
355    /** Available locales as determined by the {@link org.opencms.i18n.CmsLocaleManager}. */
356    private Map<String, List<Locale>> m_availableLocales;
357
358    /** Resources loaded from the OpenCms VFS. */
359    private Map<String, CmsJspResourceWrapper> m_resources;
360
361    /** XML contents read from the VFS. */
362    private Map<String, CmsJspContentAccessBean> m_xmlContent;
363
364    /**
365     * Creates a new context bean using the OpenCms context of the current user.<p>
366     *
367     * @param cms the OpenCms context of the current user
368     */
369    private CmsJspVfsAccessBean(CmsObject cms) {
370
371        m_cms = cms;
372    }
373
374    /**
375     * Creates a new instance of the JSP VFS access utility bean.<p>
376     *
377     * To prevent multiple creations of the bean during a request, the OpenCms request context
378     * attributes are used to cache the created VFS access utility bean.<p>
379     *
380     * @param cms the current OpenCms user context
381     *
382     * @return a new instance of the JSP VFS access utility bean
383     */
384    public static CmsJspVfsAccessBean create(CmsObject cms) {
385
386        CmsJspVfsAccessBean result;
387        Object attribute = cms.getRequestContext().getAttribute(ATTRIBUTE_VFS_ACCESS_BEAN);
388        if (attribute != null) {
389            result = (CmsJspVfsAccessBean)attribute;
390        } else {
391            result = new CmsJspVfsAccessBean(cms);
392            cms.getRequestContext().setAttribute(ATTRIBUTE_VFS_ACCESS_BEAN, result);
393        }
394        return result;
395    }
396
397    /**
398     * Returns a lazily generated map from site paths of resources to the available locales for the resource.
399     *
400     * @return a lazily generated map from site paths of resources to the available locales for the resource.
401     */
402    public Map<String, List<Locale>> getAvailableLocales() {
403
404        if (m_availableLocales == null) {
405            // create lazy map only on demand
406            m_availableLocales = CmsCollectionsGenericWrapper.createLazyMap(new CmsAvailableLocaleLoaderTransformer());
407        }
408        return m_availableLocales;
409    }
410
411    /**
412     * Returns the OpenCms user context this bean was initialized with.<p>
413     *
414     * @return the OpenCms user context this bean was initialized with
415     */
416    public CmsObject getCmsObject() {
417
418        return m_cms;
419    }
420
421    /**
422     * Short form for {@link #getRequestContext()}.<p>
423     *
424     * Usage example on a JSP with the EL:<pre>
425     * The current URI is: ${cms:vfs(pageContext).context.uri}
426     * </pre>
427     *
428     * @return the OpenCms request context of the current user this bean was initialized with
429     *
430     * @see #getRequestContext()
431     */
432    public CmsRequestContext getContext() {
433
434        return getRequestContext();
435    }
436
437    /**
438     * Returns the current project from the context.<p>
439     *
440     * Usage example on a JSP with the EL:<pre>
441     * The current project name is: ${cms:vfs(pageContext).currentProject.name}
442     * </pre>
443     *
444     * @return the current project
445     */
446    public CmsProject getCurrentProject() {
447
448        return m_cms.getRequestContext().getCurrentProject();
449    }
450
451    /**
452     * Returns the current user from the context.<p>
453     *
454     * Usage example on a JSP with the EL:<pre>
455     * The current user name is: ${cms:vfs(pageContext).currentUser.name}
456     * </pre>
457     *
458     * @return the current user
459     */
460    public CmsUser getCurrentUser() {
461
462        return m_cms.getRequestContext().getCurrentUser();
463    }
464
465    /**
466     * Short form for {@link #getExistsResource()}.<p>
467     *
468     * Usage example on a JSP with the EL / JSTL:<pre>
469     * &lt;c:if test="${cms:vfs(pageContext).exists['/checkme.html']}" &gt;
470     *     The resource "/checkme.html" exists.
471     * &lt;/c:if&gt;
472     * </pre>
473     *
474     * @return a map that lazily reads resources from the OpenCms VFS
475     *
476     * @see #getExistsResource()
477     */
478    public Map<String, Boolean> getExists() {
479
480        return getExistsResource();
481    }
482
483    /**
484     * Returns a map that lazily checks if a resources exists in the OpenCms VFS.<p>
485     *
486     * Usage example on a JSP with the EL / JSTL:<pre>
487     * &lt;c:if test="${cms:vfs(pageContext).existsResource['/checkme.html']}" &gt;
488     *     The resource "/checkme.html" exists.
489     * &lt;/c:if&gt;
490     * </pre>
491     *
492     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
493     * &lt;cms:contentload ... &gt;
494     *     &lt;cms:contentaccess var="content" /&gt;
495     *     &lt;c:if test="${content.vfs.existsResource['/checkme.html']}" &gt;
496     *         The resource "/checkme.html" exists.
497     *     &lt;/c:if&gt;
498     * &lt;/cms:contentload&gt;</pre>
499     *
500     * @return a map that lazily checks if a resources exists in the OpenCms VFS
501     *
502     * @see #getExists() for a short form of this method
503     */
504    public Map<String, Boolean> getExistsResource() {
505
506        if (m_existsResource == null) {
507            // create lazy map only on demand
508            m_existsResource = CmsCollectionsGenericWrapper.createLazyMap(new CmsExistsResourceTransformer());
509        }
510        return m_existsResource;
511    }
512
513    /**
514     * Returns a map that lazily checks if a resources exists in the VFS and is of type XML content or XML page.<p>
515     *
516     * Usage example on a JSP with the EL / JSTL:<pre>
517     * &lt;c:if test="${cms:vfs(pageContext).existsXml['/text.xml']}" &gt;
518     *     The resource "/text.xml" exists and is an XML document.
519     * &lt;/c:if&gt;
520     * </pre>
521     *
522     * @return a map that lazily checks if a resources exists in the VFS and is of type XML content or XML page
523     */
524    public Map<String, Boolean> getExistsXml() {
525
526        if (m_existsXml == null) {
527            // create lazy map only on demand
528            m_existsXml = CmsCollectionsGenericWrapper.createLazyMap(new CmsExistsXmlTransformer());
529        }
530        return m_existsXml;
531    }
532
533    /**
534     * Flushes the internal caches of this VFS access bean.<p>
535     *
536     * The VFS access bean uses lazy initialized Maps for all access, but once a value has been
537     * read it is cached in the Map and not read again from the VFS. This means the lazy Maps
538     * act as another layer of cache to the VFS.<p>
539     *
540     * The VFS access bean instance itself is cached in the OpenCms request context attributes of the {@link CmsObject},
541     * see {@link #create(CmsObject)}. Normally there is a new {@link CmsObject} created for
542     * all incoming requests, so the live-time of the VFS access bean is short.
543     * In that case the caching of the lazy Maps should improve performance and not be an issue.
544     * However, in rare cases an instance of a {@link CmsObject} may be kept for a long time in
545     * some custom code. In theses cases flushing the caches of the lazy Maps manually may be required, otherwise
546     * the Map caches may be out of sync with the VFS.
547     *
548     * @return always returns <code>true</code>
549     */
550    public boolean getFlushCaches() {
551
552        m_resources = null;
553        m_properties = null;
554        m_propertiesSearch = null;
555
556        return true;
557    }
558
559    /**
560     * Returns a map that lazily calculates links to files in the OpenCms VFS,
561     * which have been adjusted according to the web application path and the
562     * OpenCms static export rules.<p>
563     *
564     * Please note that the target is always assumed to be in the OpenCms VFS, so you can't use
565     * this method for links external to OpenCms.<p>
566     *
567     * Relative links are converted to absolute links, using the current element URI as base.<p>
568     *
569     * Relative links are converted to absolute links, using the current OpenCms request context URI as base.<p>
570     *
571     * Usage example on a JSP with the EL:<pre>
572     * Link to the "/index.html" file: ${cms:vfs(pageContext).link['/index.html']}
573     * </pre>
574     *
575     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
576     * &lt;cms:contentload ... &gt;
577     *     &lt;cms:contentaccess var="content" /&gt;
578     *     Link to the "/index.html" file: ${content.vfs.link['/index.html']}
579     * &lt;/cms:contentload&gt;</pre>
580     *
581     * @return a map that lazily calculates links to resources in the OpenCms VFS
582     *
583     * @see org.opencms.jsp.CmsJspActionElement#link(String)
584     * @see org.opencms.jsp.CmsJspTagLink#linkTagAction(String, javax.servlet.ServletRequest)
585     */
586    public Map<String, String> getLink() {
587
588        if (m_links == null) {
589            // create lazy map only on demand
590            m_links = CmsCollectionsGenericWrapper.createLazyMap(new CmsVfsLinkTransformer());
591        }
592        return m_links;
593    }
594
595    /**
596     * Gets a lazy loading map used to access locale variants of a resource with a given path.<p>
597     *
598     * Usage in JSP: ${myvfsaccessbeaninstance.localeResource['/foo/bar/index.html']['de']}
599     *
600     * @return the lazy loading map
601     */
602    public Map<String, Map<String, CmsJspResourceWrapper>> getLocaleResource() {
603
604        return CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
605
606            @SuppressWarnings("synthetic-access")
607            public Object transform(Object arg) {
608
609                if (!(arg instanceof String)) {
610                    return new HashMap<String, CmsJspResourceWrapper>();
611                }
612                String path = (String)arg;
613                try {
614                    CmsResource res = m_cms.readResource(path);
615                    CmsJspResourceWrapper wrapper = CmsJspResourceWrapper.wrap(m_cms, res);
616                    return wrapper.getLocaleResource();
617                } catch (Exception e) {
618                    LOG.warn(e.getLocalizedMessage(), e);
619                    return new HashMap<String, CmsJspResourceWrapper>();
620                }
621            }
622
623        });
624    }
625
626    /**
627     * Returns a lazy loading map used to detect the main locale of a resource which is part of a locale group.<p>
628     *
629     * Usage in JSPs: ${myvfsaccessbeaninstance.mainLocale['/foo/index.html']}
630     *
631     * @return the lazy loading map
632     */
633    public Map<String, Locale> getMainLocale() {
634
635        return CmsCollectionsGenericWrapper.createLazyMap(new Transformer() {
636
637            @SuppressWarnings("synthetic-access")
638            public Object transform(Object arg) {
639
640                if (!(arg instanceof String)) {
641                    return null;
642                }
643                String path = (String)arg;
644                try {
645                    CmsResource res = m_cms.readResource(path);
646                    CmsLocaleGroup localeGroup = m_cms.getLocaleGroupService().readLocaleGroup(res);
647                    return localeGroup.getMainLocale();
648                } catch (Exception e) {
649                    LOG.warn(e.getLocalizedMessage(), e);
650                    return null;
651                }
652            }
653        });
654    }
655
656    /**
657     * Returns the parent folder of a resource.<p>
658     *
659     * This assumes the parameter is either a CmsResource, or a String representing a file name.
660     * If the parameter is a CmsResource, the result will be relative to the current site.</p>
661     *
662     * @return the parent folder of a resource
663     *
664     * @param obj a CmsResource or a String representing a resource name
665     *
666     * @see CmsResource#getParentFolder(String)
667     * @see org.opencms.jsp.CmsJspResourceWrapper#getSitePathParentFolder()
668     */
669    public String getParentFolder(Object obj) {
670
671        String result;
672        if (obj instanceof CmsResource) {
673            result = CmsResource.getParentFolder(m_cms.getRequestContext().getSitePath((CmsResource)obj));
674        } else {
675            result = CmsResource.getParentFolder(String.valueOf(obj));
676        }
677        return result;
678    }
679
680    /**
681     * Returns the directory level of a resource.<p>
682     *
683     * This assumes the parameter is either a CmsResource, or a String representing a file name.
684     * If the parameter is a CmsResource, the result will be relative to the current site.</p>
685     *
686     * The root folder "/" has level 0,
687     * a folder "/foo/" would have level 1,
688     * a folder "/foo/bar/" level 2 etc.<p>
689     *
690     * @param obj a CmsResource or a String representing a resource name
691     *
692     * @return the directory level of a resource
693     *
694     * @see CmsResource#getPathLevel(String)
695     * @see org.opencms.jsp.CmsJspResourceWrapper#getSitePathLevel()
696     */
697    public int getPathLevel(Object obj) {
698
699        int result;
700        if (obj instanceof CmsResource) {
701            result = CmsResource.getPathLevel(m_cms.getRequestContext().getSitePath((CmsResource)obj));
702        } else {
703            result = CmsResource.getPathLevel(String.valueOf(obj));
704        }
705        return result;
706    }
707
708    /**
709     * Short form for {@link #getReadPermissions()}.<p>
710     *
711     * Usage example on a JSP with the EL:<pre>
712     * Permission string of the "/index.html" resource: ${cms:vfs(pageContext).readPermissions['/index.html'].permissionString}
713     * </pre>
714     *
715     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
716     * &lt;cms:contentload ... &gt;
717     *     &lt;cms:contentaccess var="content" /&gt;
718     *     Permission string of the "/index.html" resource: ${content.vfs.readPermissions['/index.html'].permissionString}
719     * &lt;/cms:contentload&gt;</pre>
720     *
721     * @return a map that lazily reads resource permissions from the OpenCms VFS
722     *
723     * @see #getReadPermissions()
724     */
725    public Map<String, CmsPermissionSet> getPermissions() {
726
727        return getReadPermissions();
728    }
729
730    /**
731     * Short form for {@link #getReadProperties()}.<p>
732     *
733     * Usage example on a JSP with the EL:<pre>
734     * Title property of the "/index.html" resource: ${cms:vfs(pageContext).property['/index.html']['Title']}
735     * </pre>
736     *
737     * @return a map that lazily reads all resource properties from the OpenCms VFS, without search
738     *
739     * @see #getReadProperties()
740     */
741    public Map<String, Map<String, String>> getProperty() {
742
743        return getReadProperties();
744    }
745
746    /**
747     * Short form for {@link #getReadPropertiesLocale()}.<p>
748     *
749     * Usage example on a JSP with the EL:<pre>
750     * Title property of the "/index.html" resource for locale "de": ${cms:vfs(pageContext).property['/index.html']['de']['Title']}
751     * </pre>
752     *
753     * @return a map that lazily reads all resource properties from the OpenCms VFS, without search
754     *
755     * @see #getReadPropertiesLocale()
756     */
757    public Map<String, Map<String, Map<String, String>>> getPropertyLocale() {
758
759        return getReadPropertiesLocale();
760    }
761
762    /**
763     * Short form for {@link #getReadPropertiesSearch()}.<p>
764     *
765     * Usage example on a JSP with the EL:<pre>
766     * Title property of the "/index.html" resource (searched): ${cms:vfs(pageContext).propertySearch['/index.html']['Title']}
767     * </pre>
768     *
769     * @return a map that lazily reads all resource properties from the OpenCms VFS, with search
770     *
771     * @see #getReadPropertiesSearch()
772     */
773    public Map<String, Map<String, String>> getPropertySearch() {
774
775        return getReadPropertiesSearch();
776    }
777
778    /**
779     * Short form for {@link #getReadPropertiesSearchLocale()}.<p>
780     *
781     * Usage example on a JSP with the EL:<pre>
782     * Title property of the "/index.html" resource (searched) for locale "de": ${cms:vfs(pageContext).propertySearch['/index.html']['de']['Title']}
783     * </pre>
784     *
785     * @return a map that lazily reads all resource properties from the OpenCms VFS, with search
786     *
787     * @see #getReadPropertiesSearchLocale()
788     */
789    public Map<String, Map<String, Map<String, String>>> getPropertySearchLocale() {
790
791        return getReadPropertiesSearchLocale();
792    }
793
794    /**
795     * Returns a map that lazily reads resource permissions from the OpenCms VFS.<p>
796     *
797     * Usage example on a JSP with the EL:<pre>
798     * Permission string of the "/index.html" resource: ${cms:vfs(pageContext).readPermissions['/index.html'].permissionString}
799     * </pre>
800     *
801     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
802     * &lt;cms:contentload ... &gt;
803     *     &lt;cms:contentaccess var="content" /&gt;
804     *     Permission string of the "/index.html" resource: ${content.vfs.readPermissions['/index.html'].permissionString}
805     * &lt;/cms:contentload&gt;</pre>
806     *
807     * @return a map that lazily reads resource permissions from the OpenCms VFS
808     *
809     * @see #getPermissions() for a short form of this method
810     */
811    public Map<String, CmsPermissionSet> getReadPermissions() {
812
813        if (m_permissions == null) {
814            // create lazy map only on demand
815            m_permissions = CmsCollectionsGenericWrapper.createLazyMap(new CmsPermissionsLoaderTransformer());
816        }
817        return m_permissions;
818    }
819
820    /**
821     * Returns a map that lazily reads all resource properties from the OpenCms VFS, without search.<p>
822     *
823     * Usage example on a JSP with the EL:<pre>
824     * Title property of the "/index.html" resource: ${cms:vfs(pageContext).readProperties['/index.html']['Title']}
825     * </pre>
826     *
827     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
828     * &lt;cms:contentload ... &gt;
829     *     &lt;cms:contentaccess var="content" /&gt;
830     *     Title property of the "/index.html" resource: ${content.vfs.readProperties['/index.html']['Title']}
831     * &lt;/cms:contentload&gt;</pre>
832     *
833     * @return a map that lazily reads all resource properties from the OpenCms VFS, without search
834     *
835     * @see #getProperty() for a short form of this method
836     */
837    public Map<String, Map<String, String>> getReadProperties() {
838
839        if (m_properties == null) {
840            // create lazy map only on demand
841            m_properties = CmsCollectionsGenericWrapper.createLazyMap(new CmsResourcePropertyLoaderTransformer(false));
842        }
843        return m_properties;
844    }
845
846    /**
847     * Returns a map that lazily reads all resource properties from the OpenCms VFS, without search.<p>
848     *
849     * Usage example on a JSP with the EL:<pre>
850     * Title property of the "/index.html" resource for locale "de": ${cms:vfs(pageContext).readProperties['/index.html']['de']['Title']}
851     * </pre>
852     *
853     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
854     * &lt;cms:contentload ... &gt;
855     *     &lt;cms:contentaccess var="content" /&gt;
856     *     Title property of the "/index.html" resource: ${content.vfs.readProperties['/index.html']['Title']}
857     * &lt;/cms:contentload&gt;</pre>
858     *
859     * @return a map that lazily reads all resource properties from the OpenCms VFS, without search
860     *
861     * @see #getProperty() for a short form of this method
862     */
863    public Map<String, Map<String, Map<String, String>>> getReadPropertiesLocale() {
864
865        if (m_propertiesLocale == null) {
866            // create lazy map only on demand
867            m_propertiesLocale = CmsCollectionsGenericWrapper.createLazyMap(
868                new CmsResourceLocalePropertyLoaderTransformer(false));
869        }
870        return m_propertiesLocale;
871    }
872
873    /**
874     * Returns a map that lazily reads all resource properties from the OpenCms VFS, with search.<p>
875     *
876     * Usage example on a JSP with the EL:<pre>
877     * Title property of the "/index.html" resource (searched): ${cms:vfs(pageContext).readPropertiesSearch['/index.html']['Title']}
878     * </pre>
879     *
880     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
881     * &lt;cms:contentload ... &gt;
882     *     &lt;cms:contentaccess var="content" /&gt;
883     *     Title property of the "/index.html" resource (searched): ${content.vfs.readPropertiesSearch['/index.html']['Title']}
884     * &lt;/cms:contentload&gt;</pre>
885     *
886     * @return a map that lazily reads all resource properties from the OpenCms VFS, with search
887     *
888     * @see #getPropertySearch() for a short form of this method
889     */
890    public Map<String, Map<String, String>> getReadPropertiesSearch() {
891
892        if (m_propertiesSearch == null) {
893            // create lazy map only on demand
894            m_propertiesSearch = CmsCollectionsGenericWrapper.createLazyMap(
895                new CmsResourcePropertyLoaderTransformer(true));
896        }
897        return m_propertiesSearch;
898    }
899
900    /**
901     * Returns a map that lazily reads all resource properties from the OpenCms VFS, with search and provides locale specific access to them.<p>
902     *
903     * Usage example on a JSP with the EL:<pre>
904     * Title property of the "/index.html" resource (searched): ${cms:vfs(pageContext).readPropertiesSearch['/index.html']['Title']}
905     * </pre>
906     *
907     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
908     * &lt;cms:contentload ... &gt;
909     *     &lt;cms:contentaccess var="content" /&gt;
910     *     Title property of the "/index.html" resource (searched) for locale "de": ${content.vfs.readPropertiesSearchLocale['/index.html']['de']['Title']}
911     * &lt;/cms:contentload&gt;</pre>
912     *
913     * @return a map that lazily reads all resource properties from the OpenCms VFS, with search
914     *
915     * @see #getPropertySearch() for a short form of this method
916     */
917    public Map<String, Map<String, Map<String, String>>> getReadPropertiesSearchLocale() {
918
919        if (m_propertiesSearchLocale == null) {
920            // create lazy map only on demand
921            m_propertiesSearchLocale = CmsCollectionsGenericWrapper.createLazyMap(
922                new CmsResourceLocalePropertyLoaderTransformer(true));
923        }
924        return m_propertiesSearchLocale;
925    }
926
927    /**
928     * Returns a map that lazily reads resources from the OpenCms VFS.<p>
929     *
930     * Usage example on a JSP with the EL:<pre>
931     * Root path of the "/index.html" resource: ${cms:vfs(pageContext).readResource['/index.html'].rootPath}
932     * </pre>
933     *
934     * Usage example on a JSP with the <code>&lt;cms:contentaccess&gt;</code> tag:<pre>
935     * &lt;cms:contentload ... &gt;
936     *     &lt;cms:contentaccess var="content" /&gt;
937     *     Root path of the "/index.html" resource: ${content.vfs.readResource['/index.html'].rootPath}
938     * &lt;/cms:contentload&gt;</pre>
939     *
940     * @return a map that lazily reads resources from the OpenCms VFS
941     *
942     * @see #getResource() for a short form of this method
943     */
944    public Map<String, CmsJspResourceWrapper> getReadResource() {
945
946        if (m_resources == null) {
947            // create lazy map only on demand
948            m_resources = CmsCollectionsGenericWrapper.createLazyMap(new CmsResourceLoaderTransformer());
949        }
950        return m_resources;
951    }
952
953    /**
954     * Returns a map that lazily reads XML documents from the OpenCms VFS that are wrapped using a
955     * {@link CmsJspContentAccessBean}.<p>
956     *
957     * Usage example on a JSP with the EL:<pre>
958     * Title of "/text.xml": ${cms:vfs(pageContext).readXml['/text.xml'].value['Title']}
959     * </pre>
960     *
961     * @return a map that lazily reads wrapped XML documents from the OpenCms VFS
962     *
963     * @see #getXml() for a short form of this method
964     */
965    public Map<String, CmsJspContentAccessBean> getReadXml() {
966
967        if (m_xmlContent == null) {
968            // create lazy map only on demand
969            m_xmlContent = CmsCollectionsGenericWrapper.createLazyMap(new CmsXmlContentAccessTransformer());
970        }
971        return m_xmlContent;
972    }
973
974    /**
975     * Returns the OpenCms request context the current user this bean was initialized with.<p>
976     *
977     * Usage example on a JSP with the EL:<pre>
978     * The current URI is: ${cms:vfs(pageContext).requestContext.uri}
979     * </pre>
980     *
981     * @return the OpenCms request context the current user this bean was initialized with
982     *
983     * @see #getContext() for a short form of this method
984     */
985    public CmsRequestContext getRequestContext() {
986
987        return m_cms.getRequestContext();
988    }
989
990    /**
991     * Short form for {@link #getReadResource()}.<p>
992     *
993     * Usage example on a JSP with the EL:<pre>
994     * Root path of the "/index.html" resource: ${cms:vfs(pageContext).resource['/index.html'].rootPath}
995     * </pre>
996     *
997     * @return a map that lazily reads resources from the OpenCms VFS
998     *
999     * @see #getReadResource()
1000     */
1001    public Map<String, CmsJspResourceWrapper> getResource() {
1002
1003        return getReadResource();
1004    }
1005
1006    /**
1007     * Returns the resource name extension if present.<p>
1008     *
1009     * This assumes the parameter is either a CmsResource, or a String representing a resource name.</p>
1010     *
1011     * The extension will always be lower case.<p>
1012     *
1013     * @param obj a CmsResource or a String representing a resource name
1014     *
1015     * @return the extension or <code>null</code> if not available
1016     *
1017     * @see CmsResource#getExtension(String)
1018     * @see org.opencms.jsp.CmsJspResourceWrapper#getResourceExtension()
1019     */
1020    public String getResourceExtension(Object obj) {
1021
1022        String result;
1023        if (obj instanceof CmsResource) {
1024            result = CmsResource.getExtension(((CmsResource)obj).getRootPath());
1025        } else {
1026            result = CmsResource.getExtension(String.valueOf(obj));
1027        }
1028        return result;
1029    }
1030
1031    /**
1032     * Returns the name of a resource without the path information.<p>
1033     *
1034     * This assumes the parameter is either a CmsResource, or a String representing a resource name.<p>
1035     *
1036     * The resource name of a file is the name of the file.
1037     * The resource name of a folder is the folder name with trailing "/".
1038     * The resource name of the root folder is <code>/</code>.<p>
1039     *
1040     * @param obj a CmsResource or a String representing a resource name
1041     *
1042     * @return the name of a resource without the path information
1043     *
1044     * @see CmsResource#getName()
1045     * @see org.opencms.jsp.CmsJspResourceWrapper#getResourceName()
1046     */
1047    public String getResourceName(Object obj) {
1048
1049        String result;
1050        if (obj instanceof CmsResource) {
1051            result = ((CmsResource)obj).getName();
1052        } else {
1053            result = CmsResource.getName(String.valueOf(obj));
1054        }
1055        return result;
1056    }
1057
1058    /**
1059     * Short form for {@link #getReadXml()}.<p>
1060     *
1061     * Usage example on a JSP with the EL:<pre>
1062     * Title of "/text.xml": ${cms:vfs(pageContext).xml['/text.xml'].value['Title']}
1063     * </pre>
1064     *
1065     * @return a map that lazily reads wrapped XML documents from the OpenCms VFS
1066     *
1067     * @see #getReadXml()
1068     */
1069    public Map<String, CmsJspContentAccessBean> getXml() {
1070
1071        return getReadXml();
1072    }
1073
1074    /**
1075     * Reads the resources in the given folder.<p>
1076     *
1077     * @param resourcePath the site path to the folder
1078     *
1079     * @return the resources
1080     *
1081     * @throws CmsException in case reading the resources fails
1082     */
1083    public List<CmsJspResourceWrapper> readFilesInFolder(String resourcePath) throws CmsException {
1084
1085        return CmsJspElFunctions.convertResourceList(m_cms, m_cms.getFilesInFolder(resourcePath));
1086    }
1087
1088    /**
1089     * Reads the resources in the given folder using the provided filter.<p>
1090     *
1091     * @param resourcePath the site path to the folder
1092     * @param filterString a comma separated list of resource type names
1093     *
1094     * @return the resources
1095     *
1096     * @throws CmsException in case reading the resources fails
1097     */
1098    public List<CmsJspResourceWrapper> readFilesInFolder(String resourcePath, String filterString) throws CmsException {
1099
1100        CmsResourceFilter filter = CmsResourceFilter.DEFAULT;
1101        if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(filterString)) {
1102            String[] types = filterString.split(",");
1103            for (String type : types) {
1104                if (OpenCms.getResourceManager().hasResourceType(type)) {
1105                    filter.addRequireType(OpenCms.getResourceManager().getResourceType(type));
1106                }
1107            }
1108        }
1109        return CmsJspElFunctions.convertResourceList(m_cms, m_cms.getFilesInFolder(resourcePath, filter));
1110    }
1111
1112    /**
1113     * Reads the sub site folder resource.<p>
1114     *
1115     * @param path the current site path
1116     *
1117     * @return the folder resource
1118     *
1119     * @throws CmsException in case reading the resource fails
1120     */
1121    public CmsJspResourceWrapper readSubsiteFor(String path) throws CmsException {
1122
1123        CmsADEConfigData config = OpenCms.getADEManager().lookupConfiguration(
1124            m_cms,
1125            m_cms.getRequestContext().addSiteRoot(path));
1126        return CmsJspResourceWrapper.wrap(
1127            m_cms,
1128            m_cms.readResource(m_cms.getRequestContext().removeSiteRoot(config.getBasePath())));
1129    }
1130}