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