001: /*
002: * File : $Source: /usr/local/cvs/opencms/src/org/opencms/jsp/util/CmsJspContentAccessBean.java,v $
003: * Date : $Date: 2008-02-27 12:05:49 $
004: * Version: $Revision: 1.8 $
005: *
006: * This library is part of OpenCms -
007: * the Open Source Content Management System
008: *
009: * Copyright (c) 2002 - 2008 Alkacon Software GmbH (http://www.alkacon.com)
010: *
011: * This library is free software; you can redistribute it and/or
012: * modify it under the terms of the GNU Lesser General Public
013: * License as published by the Free Software Foundation; either
014: * version 2.1 of the License, or (at your option) any later version.
015: *
016: * This library is distributed in the hope that it will be useful,
017: * but WITHOUT ANY WARRANTY; without even the implied warranty of
018: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: * Lesser General Public License for more details.
020: *
021: * For further information about Alkacon Software, please see the
022: * company website: http://www.alkacon.com
023: *
024: * For further information about OpenCms, please see the
025: * project website: http://www.opencms.org
026: *
027: * You should have received a copy of the GNU Lesser General Public
028: * License along with this library; if not, write to the Free Software
029: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
030: */
031:
032: package org.opencms.jsp.util;
033:
034: import org.opencms.file.CmsFile;
035: import org.opencms.file.CmsObject;
036: import org.opencms.file.CmsResource;
037: import org.opencms.file.types.CmsResourceTypeXmlPage;
038: import org.opencms.i18n.CmsLocaleManager;
039: import org.opencms.main.CmsException;
040: import org.opencms.main.CmsRuntimeException;
041: import org.opencms.util.CmsConstantMap;
042: import org.opencms.xml.I_CmsXmlDocument;
043: import org.opencms.xml.content.CmsXmlContentFactory;
044: import org.opencms.xml.page.CmsXmlPageFactory;
045: import org.opencms.xml.types.I_CmsXmlContentValue;
046:
047: import java.util.ArrayList;
048: import java.util.HashMap;
049: import java.util.Iterator;
050: import java.util.List;
051: import java.util.Locale;
052: import java.util.Map;
053:
054: import org.apache.commons.collections.Transformer;
055: import org.apache.commons.collections.map.LazyMap;
056:
057: /**
058: * Allows access to the individual elements of an XML content, usually used inside a loop of a
059: * <code><cms:contentload></code> tag.<p>
060: *
061: * The implementation is optimized for performance and uses lazy initializing of the
062: * requested values as much as possible.<p>
063: *
064: * @author Alexander Kandzior
065: *
066: * @version $Revision: 1.8 $
067: *
068: * @since 7.0.2
069: *
070: * @see org.opencms.jsp.CmsJspTagContentAccess
071: */
072: public class CmsJspContentAccessBean {
073:
074: /**
075: * Provides Booleans that indicate if a specified locale is available in the XML content,
076: * the input is assumed to be a String that represents a Locale.<p>
077: */
078: public class CmsHasLocaleTransformer implements Transformer {
079:
080: /**
081: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
082: */
083: public Object transform(Object input) {
084:
085: return Boolean.valueOf(getRawContent().hasLocale(
086: CmsJspElFunctions.convertLocale(input)));
087: }
088: }
089:
090: /**
091: * Provides Booleans that indicate if a specified path exists in the XML content,
092: * the input is assumed to be a String that represents an xpath in the XML content.<p>
093: */
094: public class CmsHasLocaleValueTransformer implements Transformer {
095:
096: /**
097: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
098: */
099: public Object transform(Object input) {
100:
101: Locale locale = CmsJspElFunctions.convertLocale(input);
102: Map result;
103: if (getRawContent().hasLocale(locale)) {
104: result = LazyMap.decorate(new HashMap(),
105: new CmsHasValueTransformer(locale));
106: } else {
107: result = CmsConstantMap.CONSTANT_BOOLEAN_FALSE_MAP;
108: }
109: return result;
110: }
111: }
112:
113: /**
114: * Provides a Map with Booleans that indicate if a specified path exists in the XML content in the selected Locale,
115: * the input is assumed to be a String that represents an xpath in the XML content.<p>
116: */
117: public class CmsHasValueTransformer implements Transformer {
118:
119: /** The selected locale. */
120: private Locale m_selectedLocale;
121:
122: /**
123: * Constructor with a locale.<p>
124: *
125: * @param locale the locale to use
126: */
127: public CmsHasValueTransformer(Locale locale) {
128:
129: m_selectedLocale = locale;
130: }
131:
132: /**
133: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
134: */
135: public Object transform(Object input) {
136:
137: return Boolean.valueOf(getRawContent().hasValue(
138: String.valueOf(input), m_selectedLocale));
139: }
140: }
141:
142: /**
143: * Provides a Map which lets the user access the list of element names from the selected locale in an XML content,
144: * the input is assumed to be a String that represents a Locale.<p>
145: */
146: public class CmsLocaleNamesTransformer implements Transformer {
147:
148: /**
149: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
150: */
151: public Object transform(Object input) {
152:
153: Locale locale = CmsLocaleManager.getLocale(String
154: .valueOf(input));
155:
156: return getRawContent().getNames(locale);
157: }
158: }
159:
160: /**
161: * Provides a Map which lets the user access value Lists from the selected locale in an XML content,
162: * the input is assumed to be a String that represents a Locale.<p>
163: */
164: public class CmsLocaleValueListTransformer implements Transformer {
165:
166: /**
167: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
168: */
169: public Object transform(Object input) {
170:
171: Locale locale = CmsJspElFunctions.convertLocale(input);
172: Map result;
173: if (getRawContent().hasLocale(locale)) {
174: result = LazyMap.decorate(new HashMap(),
175: new CmsValueListTransformer(locale));
176: } else {
177: result = CmsConstantMap.CONSTANT_EMPTY_LIST_MAP;
178: }
179: return result;
180: }
181: }
182:
183: /**
184: * Provides a Map which lets the user access a value from the selected locale in an XML content,
185: * the input is assumed to be a String that represents a Locale.<p>
186: */
187: public class CmsLocaleValueTransformer implements Transformer {
188:
189: /**
190: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
191: */
192: public Object transform(Object input) {
193:
194: Locale locale = CmsLocaleManager.getLocale(String
195: .valueOf(input));
196: Map result;
197: if (getRawContent().hasLocale(locale)) {
198: result = LazyMap.decorate(new HashMap(),
199: new CmsValueTransformer(locale));
200: } else {
201: result = CONSTANT_NULL_VALUE_WRAPPER_MAP;
202: }
203: return result;
204: }
205: }
206:
207: /**
208: * Provides a Map which lets the user access value Lists in an XML content,
209: * the input is assumed to be a String that represents an xpath in the XML content.<p>
210: */
211: public class CmsValueListTransformer implements Transformer {
212:
213: /** The selected locale. */
214: private Locale m_selectedLocale;
215:
216: /**
217: * Constructor with a locale.<p>
218: *
219: * @param locale the locale to use
220: */
221: public CmsValueListTransformer(Locale locale) {
222:
223: m_selectedLocale = locale;
224: }
225:
226: /**
227: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
228: */
229: public Object transform(Object input) {
230:
231: List values = getRawContent().getValues(
232: String.valueOf(input), m_selectedLocale);
233: List result = new ArrayList();
234: Iterator i = values.iterator();
235: while (i.hasNext()) {
236: // XML content API offers List of values only as Objects, must iterate them and create Strings
237: I_CmsXmlContentValue value = (I_CmsXmlContentValue) i
238: .next();
239: result.add(CmsJspContentAccessValueWrapper
240: .createWrapper(getCmsObject(), value));
241: }
242: return result;
243: }
244: }
245:
246: /**
247: * Provides a Map which lets the user access a value in an XML content,
248: * the input is assumed to be a String that represents an xpath in the XML content.<p>
249: */
250: public class CmsValueTransformer implements Transformer {
251:
252: /** The selected locale. */
253: private Locale m_selectedLocale;
254:
255: /**
256: * Constructor with a locale.<p>
257: *
258: * @param locale the locale to use
259: */
260: public CmsValueTransformer(Locale locale) {
261:
262: m_selectedLocale = locale;
263: }
264:
265: /**
266: * @see org.apache.commons.collections.Transformer#transform(java.lang.Object)
267: */
268: public Object transform(Object input) {
269:
270: I_CmsXmlContentValue value = getRawContent().getValue(
271: String.valueOf(input), m_selectedLocale);
272: return CmsJspContentAccessValueWrapper.createWrapper(
273: getCmsObject(), value);
274: }
275: }
276:
277: /** Constant Map that always returns the {@link CmsJspContentAccessValueWrapper#NULL_VALUE_WRAPPER}.*/
278: protected static final Map CONSTANT_NULL_VALUE_WRAPPER_MAP = new CmsConstantMap(
279: CmsJspContentAccessValueWrapper.NULL_VALUE_WRAPPER);
280:
281: /** The OpenCms context of the current user. */
282: private CmsObject m_cms;
283:
284: /** The XMl content to access. */
285: private I_CmsXmlDocument m_content;
286:
287: /** The lazy initialized map for the "has locale" check. */
288: private Map m_hasLocale;
289:
290: /** The lazy initialized map for the "has locale value" check. */
291: private Map m_hasLocaleValue;
292:
293: /** The selected locale for accessing entries from the XML content. */
294: private Locale m_locale;
295:
296: /** The lazy initialized with the locale names. */
297: private Map m_localeNames;
298:
299: /** The lazy initialized with the locale value. */
300: private Map m_localeValue;
301:
302: /** The lazy initialized with the locale value lists. */
303: private Map m_localeValueList;
304:
305: /** Resource the XML content is created from. */
306: private CmsResource m_resource;
307:
308: /**
309: * No argument constructor, required for a JavaBean.<p>
310: *
311: * You must call {@link #init(CmsObject, Locale, I_CmsXmlDocument, CmsResource)} and provide the
312: * required values when you use this constructor.<p>
313: *
314: * @see #init(CmsObject, Locale, I_CmsXmlDocument, CmsResource)
315: */
316: public CmsJspContentAccessBean() {
317:
318: // must call init() manually later
319: }
320:
321: /**
322: * Creates a content access bean based on a Resource, using the current request context locale.<p>
323: *
324: * @param cms the OpenCms context of the current user
325: * @param resource the resource to create the content from
326: */
327: public CmsJspContentAccessBean(CmsObject cms, CmsResource resource) {
328:
329: this (cms, cms.getRequestContext().getLocale(), resource);
330: }
331:
332: /**
333: * Creates a content access bean based on a Resource.<p>
334: *
335: * @param cms the OpenCms context of the current user
336: * @param locale the Locale to use when accessing the content
337: * @param resource the resource to create the content from
338: */
339: public CmsJspContentAccessBean(CmsObject cms, Locale locale,
340: CmsResource resource) {
341:
342: init(cms, locale, null, resource);
343: }
344:
345: /**
346: * Creates a content access bean based on an XML content object.<p>
347: *
348: * @param cms the OpenCms context of the current user
349: * @param locale the Locale to use when accessing the content
350: * @param content the content to access
351: */
352: public CmsJspContentAccessBean(CmsObject cms, Locale locale,
353: I_CmsXmlDocument content) {
354:
355: init(cms, locale, content, content.getFile());
356: }
357:
358: /**
359: * Returns the OpenCms user context this bean was initialized with.<p>
360: *
361: * @return the OpenCms user context this bean was initialized with
362: */
363: public CmsObject getCmsObject() {
364:
365: return m_cms;
366: }
367:
368: /**
369: * Returns the raw VFS file object the content accessed by this bean was created from.<p>
370: *
371: * This can be used to access information from the raw file on a JSP.<p>
372: *
373: * Usage example on a JSP with the JSTL:<pre>
374: * <cms:contentload ... >
375: * <cms:contentaccess var="content" />
376: * Root path of the resource: ${content.file.rootPath}
377: * </cms:contentload></pre>
378: *
379: * @return the raw VFS file object the content accessed by this bean was created from
380: */
381: public CmsFile getFile() {
382:
383: return getRawContent().getFile();
384: }
385:
386: /**
387: * Returns the site path of the current resource, that is the result of
388: * {@link CmsObject#getSitePath(CmsResource)} with the resource
389: * obtained by {@link #getFile()}.<p>
390: *
391: * Usage example on a JSP with the JSTL:<pre>
392: * <cms:contentload ... >
393: * <cms:contentaccess var="content" />
394: * Site path of the resource: "${content.filename}";
395: * </cms:contentload></pre>
396: *
397: * @return the site path of the current resource
398: *
399: * @see CmsObject#getSitePath(CmsResource)
400: */
401: public String getFilename() {
402:
403: return m_cms.getSitePath(getRawContent().getFile());
404: }
405:
406: /**
407: * Returns a lazy initialized Map that provides Booleans that indicate if a specified Locale is available
408: * in the XML content.<p>
409: *
410: * The provided Map key is assumed to be a String that represents a Locale.<p>
411: *
412: * Usage example on a JSP with the JSTL:<pre>
413: * <cms:contentload ... >
414: * <cms:contentaccess var="content" />
415: * <c:if test="${content.hasLocale['de']}" >
416: * The content has a "de" Locale!
417: * </c:if>
418: * </cms:contentload></pre>
419: *
420: * @return a lazy initialized Map that provides Booleans that indicate if a specified Locale is available
421: * in the XML content
422: */
423: public Map getHasLocale() {
424:
425: if (m_hasLocale == null) {
426: m_hasLocale = LazyMap.decorate(new HashMap(),
427: new CmsHasLocaleTransformer());
428: }
429: return m_hasLocale;
430: }
431:
432: /**
433: * Returns a lazy initialized Map that provides a Map that provides Booleans that
434: * indicate if a value (xpath) is available in the XML content in the selected locale.<p>
435: *
436: * The first provided Map key is assumed to be a String that represents the Locale,
437: * the second provided Map key is assumed to be a String that represents the xpath to the value.<p>
438: *
439: * Usage example on a JSP with the JSTL:<pre>
440: * <cms:contentload ... >
441: * <cms:contentaccess var="content" />
442: * <c:if test="${content.hasLocaleValue['de']['Title']}" >
443: * The content has a "Title" value in the "de" Locale!
444: * </c:if>
445: * </cms:contentload></pre>
446: *
447: * Please note that you can also test if a locale value exists like this:<pre>
448: * <c:if test="${content.value['de']['Title'].exists}" > ... </c:if></pre>
449: *
450: * @return a lazy initialized Map that provides a Map that provides Booleans that
451: * indicate if a value (xpath) is available in the XML content in the selected locale
452: *
453: * @see #getHasValue()
454: */
455: public Map getHasLocaleValue() {
456:
457: if (m_hasLocaleValue == null) {
458: m_hasLocaleValue = LazyMap.decorate(new HashMap(),
459: new CmsHasLocaleValueTransformer());
460: }
461: return m_hasLocaleValue;
462: }
463:
464: /**
465: * Returns a lazy initialized Map that provides Booleans that
466: * indicate if a value (xpath) is available in the XML content in the current locale.<p>
467: *
468: * The provided Map key is assumed to be a String that represents the xpath to the value.<p>
469: *
470: * Usage example on a JSP with the JSTL:<pre>
471: * <cms:contentload ... >
472: * <cms:contentaccess var="content" />
473: * <c:if test="${content.hasValue['Title']}" >
474: * The content has a "Title" value in the current locale!
475: * </c:if>
476: * </cms:contentload></pre>
477: *
478: * Please note that you can also test if a value exists like this:<pre>
479: * <c:if test="${content.value['Title'].exists}" > ... </c:if></pre>
480: *
481: * @return a lazy initialized Map that provides Booleans that
482: * indicate if a value (xpath) is available in the XML content in the current locale
483: *
484: * @see #getHasLocaleValue()
485: */
486: public Map getHasValue() {
487:
488: return (Map) getHasLocaleValue().get(m_locale);
489: }
490:
491: /**
492: * Returns the Locale this bean was initialized with.<p>
493: *
494: * @return the locale this bean was initialized with
495: */
496: public Locale getLocale() {
497:
498: return m_locale;
499: }
500:
501: /**
502: * Returns a lazy initialized Map that provides a List with all available elements paths (Strings)
503: * used in this document in the selected locale.<p>
504: *
505: * The provided Map key is assumed to be a String that represents the Locale.<p>
506: *
507: * Usage example on a JSP with the JSTL:<pre>
508: * <cms:contentload ... >
509: * <cms:contentaccess var="content" />
510: * <c:forEach items="${content.localeNames['de']}" var="elem">
511: * <c:out value="${elem}" />
512: * </c:forEach>
513: * </cms:contentload></pre>
514: *
515: * @return a lazy initialized Map that provides a Map that provides
516: * values from the XML content in the selected locale
517: *
518: * @see #getNames()
519: */
520: public Map getLocaleNames() {
521:
522: if (m_localeNames == null) {
523: m_localeNames = LazyMap.decorate(new HashMap(),
524: new CmsLocaleNamesTransformer());
525: }
526: return m_localeNames;
527: }
528:
529: /**
530: * Returns a lazy initialized Map that provides a Map that provides
531: * values from the XML content in the selected locale.<p>
532: *
533: * The first provided Map key is assumed to be a String that represents the Locale,
534: * the second provided Map key is assumed to be a String that represents the xpath to the value.<p>
535: *
536: * Usage example on a JSP with the JSTL:<pre>
537: * <cms:contentload ... >
538: * <cms:contentaccess var="content" />
539: * The Title in Locale "de": ${content.localeValue['de']['Title']}
540: * </cms:contentload></pre>
541: *
542: * @return a lazy initialized Map that provides a Map that provides
543: * values from the XML content in the selected locale
544: *
545: * @see #getValue()
546: */
547: public Map getLocaleValue() {
548:
549: if (m_localeValue == null) {
550: m_localeValue = LazyMap.decorate(new HashMap(),
551: new CmsLocaleValueTransformer());
552: }
553: return m_localeValue;
554: }
555:
556: /**
557: * Returns a lazy initialized Map that provides a Map that provides Lists of values
558: * from the XML content in the selected locale.<p>
559: *
560: * The first provided Map key is assumed to be a String that represents the Locale,
561: * the second provided Map key is assumed to be a String that represents the xpath to the value.<p>
562: *
563: * Usage example on a JSP with the JSTL:<pre>
564: * <cms:contentload ... >
565: * <cms:contentaccess var="content" />
566: * <c:forEach var="teaser" items="${content.localeValueList['de']['Teaser']}">
567: * ${teaser}
568: * </c:forEach>
569: * </cms:contentload></pre>
570: *
571: * @return a lazy initialized Map that provides a Map that provides Lists of values
572: * from the XML content in the selected locale
573: *
574: * @see #getLocaleValue()
575: */
576: public Map getLocaleValueList() {
577:
578: if (m_localeValueList == null) {
579: m_localeValueList = LazyMap.decorate(new HashMap(),
580: new CmsLocaleValueListTransformer());
581: }
582: return m_localeValueList;
583: }
584:
585: /**
586: * Returns a list with all available elements paths (Strings) used in this document
587: * in the current locale.<p>
588: *
589: * Usage example on a JSP with the JSTL:<pre>
590: * <cms:contentload ... >
591: * <cms:contentaccess var="content" />
592: * <c:forEach items="${content.names}" var="elem">
593: * <c:out value="${elem}" />
594: * </c:forEach>
595: * </cms:contentload></pre>
596: *
597: * @return a list with all available elements paths (Strings) used in this document in the current locale
598: *
599: * @see #getLocaleNames()
600: */
601: public List getNames() {
602:
603: return (List) getLocaleNames().get(m_locale);
604: }
605:
606: /**
607: * Returns the raw XML content object that is accessed by this bean.<p>
608: *
609: * @return the raw XML content object that is accessed by this bean
610: */
611: public I_CmsXmlDocument getRawContent() {
612:
613: if (m_content == null) {
614: // content has not been provided, must unmarshal XML first
615: CmsFile file;
616: try {
617: file = m_cms.readFile(m_resource);
618: if (CmsResourceTypeXmlPage.isXmlPage(file)) {
619: // this is an XML page
620: m_content = CmsXmlPageFactory
621: .unmarshal(m_cms, file);
622: } else {
623: // this is an XML content
624: m_content = CmsXmlContentFactory.unmarshal(m_cms,
625: file);
626: }
627: } catch (CmsException e) {
628: // this usually should not happen, as the resource already has been read by the current user
629: // and we just upgrade it to a File
630: throw new CmsRuntimeException(Messages.get().container(
631: Messages.ERR_XML_CONTENT_UNMARSHAL_1,
632: m_resource.getRootPath()), e);
633: }
634: }
635: return m_content;
636: }
637:
638: /**
639: * Returns a lazy initialized Map that provides values from the XML content in the current locale.<p>
640: *
641: * The provided Map key is assumed to be a String that represents the xpath to the value.<p>
642: *
643: * Usage example on a JSP with the JSTL:<pre>
644: * <cms:contentload ... >
645: * <cms:contentaccess var="content" />
646: * The Title: ${content.value['Title']}
647: * </cms:contentload></pre>
648: *
649: * @return a lazy initialized Map that provides values from the XML content in the current locale
650: *
651: * @see #getLocaleValue()
652: */
653: public Map getValue() {
654:
655: return (Map) getLocaleValue().get(m_locale);
656: }
657:
658: /**
659: * Returns a lazy initialized Map that provides Lists of values from the XML content in the current locale.<p>
660: *
661: * The provided Map key is assumed to be a String that represents the xpath to the value.
662: * Use this method in case you want to iterate over a List of values form the XML content.<p>
663: *
664: * Usage example on a JSP with the JSTL:<pre>
665: * <cms:contentload ... >
666: * <cms:contentaccess var="content" />
667: * <c:forEach var="teaser" items="${content.valueList['Teaser']}">
668: * ${teaser}
669: * </c:forEach>
670: * </cms:contentload></pre>
671: *
672: * @return a lazy initialized Map that provides Lists of values from the XML content in the current locale
673: *
674: * @see #getLocaleValueList()
675: */
676: public Map getValueList() {
677:
678: return (Map) getLocaleValueList().get(m_locale);
679: }
680:
681: /**
682: * Returns an instance of a VFS access bean,
683: * initialized with the OpenCms user context this bean was created with.<p>
684: *
685: * @return an instance of a VFS access bean,
686: * initialized with the OpenCms user context this bean was created with
687: */
688: public CmsJspVfsAccessBean getVfs() {
689:
690: return CmsJspVfsAccessBean.create(m_cms);
691: }
692:
693: /**
694: * Initialize this instance.<p>
695: *
696: * @param cms the OpenCms context of the current user
697: * @param locale the Locale to use when accessing the content
698: * @param content the XML content to access
699: * @param resource the resource to create the content from
700: */
701: public void init(CmsObject cms, Locale locale,
702: I_CmsXmlDocument content, CmsResource resource) {
703:
704: m_cms = cms;
705: m_locale = locale;
706: m_content = content;
707: m_resource = resource;
708: }
709: }
|