KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > mmbase > bridge > jsp > taglib > ContextReferrerTag


1 /*
2
3 This software is OSI Certified Open Source Software.
4 OSI Certified is a certification mark of the Open Source Initiative.
5
6 The license (Mozilla version 1.0) can be read at the MMBase site.
7 See http://www.MMBase.org/license
8
9 */

10 package org.mmbase.bridge.jsp.taglib;
11
12 import javax.servlet.http.HttpServletRequest JavaDoc;
13 import javax.servlet.jsp.*;
14 import javax.servlet.jsp.tagext.*;
15 import javax.servlet.jsp.jstl.core.*;
16
17 import java.io.*;
18
19 import org.mmbase.bridge.jsp.taglib.util.Attribute;
20 import org.mmbase.bridge.jsp.taglib.containers.QueryContainer;
21 import org.mmbase.util.Casting;
22 import org.mmbase.util.logging.*;
23 import org.mmbase.util.functions.Parameter;
24 import org.mmbase.util.functions.Parameters;
25
26 import java.util.*;
27
28 /**
29  * If you want to have attributes which obtain the value from a
30  * parameter or other context variable, or if you want to be able to
31  * refer to other tags, then your tag can extend from this one.
32  *
33  *
34  * @author Michiel Meeuwissen
35  * @version $Id: ContextReferrerTag.java,v 1.90.2.2 2006/12/05 21:43:23 michiel Exp $
36  * @see ContextTag
37  */

38
39 public abstract class ContextReferrerTag extends BodyTagSupport implements TryCatchFinally {
40
41     /**
42      * EVAL_BODY is EVAL_BODY_INCLUDE or EVAL_BODY_BUFFERED. It wants to be EVAL_BODY_INCLUDE, but
43      * because that often not works, it on default is EVAL_BODY_BUFFERED.
44      *
45      * This configurable constant might become deprecated, because it is a bit experimental.
46      *
47      */

48     public static int EVAL_BODY = -1;
49     // should be EVAL_BODY_INCLUDE. But
50
// 1. Completely unsupported by orion 1.6.0
51
// 2. Buggy supported by tomcat < 4.1.19
52

53
54     private static final Logger log = Logging.getLoggerInstance(ContextReferrerTag.class);
55
56     private static final Logger pageLog = Logging.getLoggerInstance(Logging.PAGE_CATEGORY);
57
58
59
60     protected static String JavaDoc getTaglibVersion() {
61         try {
62             ClassLoader JavaDoc cl = ContextReferrerTag.class.getClassLoader();
63             InputStream is = cl.getResourceAsStream("org/mmbase/taglib/version");
64             if (is == null) {
65                 return "1.1";
66             }
67             BufferedReader r = new BufferedReader(new InputStreamReader(is));
68             return r.readLine();
69         } catch (IOException io) {
70             // should not happen
71
return "1.0";
72         }
73     }
74
75
76
77     protected ContextTag pageContextTag = null;
78
79     protected Attribute contextId = Attribute.NULL; // context to which this tagg is referring to.
80
protected Attribute referid = Attribute.NULL;
81
82     protected Attribute id = Attribute.NULL; // hides String id of TagSupport
83

84     private String JavaDoc thisPage = null;
85
86     void setPageContextOnly(PageContext pc) {
87         super.setPageContext(pc);
88         // the 'page' Context
89
}
90
91
92     public PageContext getPageContext() {
93         return pageContext;
94     }
95
96     /**
97      * @since MMBase-1.7.4
98      */

99     protected ContextTag getPageContextTag() {
100         if (pageContextTag == null) {
101
102             pageContextTag = (ContextTag) pageContext.getAttribute(ContextTag.CONTEXTTAG_KEY);
103
104
105             if (pageContextTag == null) { // not yet put
106
log.debug("No pageContextTag found in pagecontext, creating..");
107                 if (pageLog.isServiceEnabled()) {
108                     HttpServletRequest JavaDoc request = ((HttpServletRequest JavaDoc)pageContext.getRequest());
109                     //thisPage = request.getRequestURI();
110
String JavaDoc queryString = ((HttpServletRequest JavaDoc)pageContext.getRequest()).getQueryString();
111                     String JavaDoc includedPage = (String JavaDoc) request.getAttribute("javax.servlet.include.servlet_path");
112                     thisPage = (includedPage == null ? "" : includedPage + " for ") + request.getRequestURI();
113                     pageLog.service("Parsing JSP page: " + thisPage +
114                                     (queryString != null ? "?" + queryString : ""));
115                 }
116                 pageContextTag = new ContextTag();
117                 pageContextTag.setId(null);
118
119                 // page context has no id, this also avoids that it tries
120
// registering itself in the parent (which it is itself)
121
// so don't change this!
122

123                 pageContextTag.setPageContextOnly(pageContext);
124
125                 // set the pageContextTag, before fillVars otherwise the page is not set in the fillVars
126
// register also the tag itself under __context.
127
// _must_ set __context before calling setPageContext otherwise in infinite loop.
128
pageContextTag.createContainer(null);
129                 pageContextTag.pageContextTag = pageContextTag; // the 'parent' of pageContextTag is itself..
130
pageContext.setAttribute(ContextTag.CONTEXTTAG_KEY, pageContextTag);
131
132                 // there is one implicit ContextTag in every page.
133
// its id is null, it is registered in the pageContext as __context.
134
//
135
// it is called pageContext, because it is similar to the pageContext, but not the same.
136
}
137         }
138         return pageContextTag;
139     }
140
141     public void setPageContext(PageContext pc) {
142         if (EVAL_BODY == -1) { // as yet unset
143
EVAL_BODY = "true".equals(pc.getServletContext().getInitParameter("mmbase.taglib.eval_body_include")) ?
144                 EVAL_BODY_INCLUDE : EVAL_BODY_BUFFERED;
145             log.info("Using " + (EVAL_BODY == EVAL_BODY_BUFFERED ? " EVAL_BODY_BUFFERED (If you use a modern app-server, which supports it, you prefer EVAL_BODY_INCLUDE. See web.xml)" : "EVAL_BODY_INCLUDE"));
146         }
147
148         if (log.isDebugEnabled()) {
149             log.debug("setting page context: " + this.getClass().getName());
150         }
151         setPageContextOnly(pc); // make pageContext availabe
152
pageContextTag = null;
153         getPageContextTag();
154
155     }
156
157     /**
158      * ContextReferrers normally can have the attribute 'referid'. If
159      * a ContextReferrer has the 'id' attribute it registers its
160      * output in the surrounding Context. With 'referid' you can 'repeat' a
161      * tag which had the 'id' attribute.
162      */

163
164     public void setReferid(String JavaDoc r) throws JspTagException {
165         referid = getAttribute(r);
166     }
167
168     public void setId(String JavaDoc i) {
169         try {
170             if ("_".equals(i)) {
171                 throw new RuntimeException JavaDoc("'_' is not a valid id (it is reserved for the 'current writer')");
172             }
173             id = getAttribute(i);
174         } catch (JspTagException j) {
175             throw new RuntimeException JavaDoc(j);
176         }
177     }
178
179     public String JavaDoc getId() {
180         try {
181             return (String JavaDoc) id.getValue(this);
182         } catch (JspTagException j) {
183             throw new RuntimeException JavaDoc(j);
184         }
185     }
186
187     protected String JavaDoc getReferid() throws JspTagException {
188         return (String JavaDoc) referid.getValue(this);
189     }
190
191     /*
192      * The writerreferrer functionality is here, though not every conterreferrer is a writerreferrer.
193      * So contextreferrer does not implement Writerreferrer. It is enough tough to 'implement WriterReferrer'
194      * for every ContextReferrer to become a real WriterReferrer;
195      */

196     /**
197      * Which writer to use.
198      */

199     protected Attribute writerid = Attribute.NULL;
200
201
202     /**
203      * Find the parent writer tag. It also calls haveBody on this
204      * parent tag, so that this knows that it has a body. If a
205      * write-tag has a body, then on default it will not write itself,
206      * but only communicate itself tot the body's tags.
207      */

208     public Writer findWriter() throws JspTagException {
209         return findWriter(true);
210
211     }
212     /**
213      * @since MMBase-1.6.2
214      */

215     public Writer findWriter(boolean th) throws JspTagException {
216         Writer w = (Writer) findParentTag(Writer.class, (String JavaDoc) writerid.getValue(this), th);
217         if (w != null) {
218             w.haveBody();
219         }
220         return w;
221     }
222
223
224
225     /**
226      * Sets the writer attribute.
227      */

228     public void setWriter(String JavaDoc w) throws JspTagException {
229         writerid = getAttribute(w);
230
231     }
232
233     public int doEndTag() throws JspTagException {
234         return EVAL_PAGE;
235     }
236
237     public void doFinally() {
238         helper.doFinally();
239         thisPage = null;
240         pageContextTag = null;
241         writerid = Attribute.NULL;
242     }
243
244     public void doCatch(Throwable JavaDoc e) throws Throwable JavaDoc {
245         log.debug("Caught throwable: " + e.getMessage());
246         throw e;
247     }
248
249     /**
250      * Release all allocated resources.
251      */

252     public void release() {
253         super.release();
254         if (log.isDebugEnabled()) {
255             log.debug("releasing context-referrer " + this.getClass().getName());
256         }
257         if (thisPage != null) {
258             pageLog.debug("END Parsing JSP page: " + thisPage);
259             thisPage = null;
260         }
261         pageContextTag = null;
262         /*
263         id = null;
264         referid = Attribute.NULL;
265         contextId = Attribute.NULL;
266         */

267     }
268
269
270     /**
271      * Refer to a specific context. With this you can refer to, and
272      * write in, another context then the direct parent (but is must
273      * be an ancestor). This is for analogy with other attributes
274      * like this.
275      *
276      */

277
278     public void setContext(String JavaDoc c) throws JspTagException {
279         contextId = getAttribute(c);
280     }
281
282     /**
283      * Call this function in your set-attribute function. It makes it
284      * possible for the user of the taglib to include ids of values stored in
285      * the context.
286      *
287      * The method replaces all occurrences of ${x} and $x, where x is a reference to
288      * a attribute value, possibly prefixed with context names. The
289      * end of the variable if determined by the closing bracket (${x})
290      * or by the first non ContextIndentifierChar or end of string ($x).
291      *
292      * Simple aritmetic is possible with ${+...}, and since you can
293      * even use $-vars inside ${}, you can do in this way some
294      * arithmetic on variables.
295      *
296      * @deprecated Call getAttribute in the set-method and 'toString(tag)' when using
297      * it. This is better for perfomrnace and makes sure the impl. works in all servlet
298      * containers.
299      */

300
301     public String JavaDoc getAttributeValue(String JavaDoc attribute) throws JspTagException {
302         if (attribute == null) return null;
303         return getAttribute(attribute).getString(this);
304     }
305     /**
306      * @since MMBase-1.6.1
307      */

308     public Attribute getAttribute(String JavaDoc attribute) throws JspTagException {
309         return Attribute.getAttribute(attribute);
310     }
311
312     /**
313      * Like getAttributeValue but converts the result to a Boolean,
314      * and throws an exception if this cannot be done.
315      **/

316
317     protected Boolean JavaDoc getAttributeBoolean(String JavaDoc b) throws JspTagException {
318         String JavaDoc r = getAttributeValue(b).toLowerCase();
319         if ("true".equals(r)) {
320             return Boolean.TRUE;
321         } else if ("false".equals(r)) {
322             return Boolean.FALSE;
323         } else {
324             throw new JspTagException("'" + r + "' cannot be converted to a boolean");
325         }
326     }
327     /**
328      * Like getAttributeValue but converts the result to an Integer,
329      * and throws an exception if this cannot be done. It the incoming string evaluates to an empty string, then
330      * it will return 0, unless the second optional parameter specifies another default value;
331      **/

332
333     protected Integer JavaDoc getAttributeInteger(String JavaDoc i) throws JspTagException {
334         return getAttributeInteger(i, 0);
335     }
336     protected Integer JavaDoc getAttributeInteger(String JavaDoc i, int def) throws JspTagException {
337         try {
338             i = getAttributeValue(i);
339             if (i.equals("")) return new Integer JavaDoc(def);
340             return new Integer JavaDoc(i);
341         } catch (NumberFormatException JavaDoc e) { // try first if it was a float
342
try {
343                 return new Integer JavaDoc(new java.math.BigDecimal JavaDoc(i).intValue());
344             } catch (NumberFormatException JavaDoc e2) {
345                 throw new TaglibException(i + " is not an integer value ", e2);
346             }
347         }
348     }
349
350     /**
351      * @see #findParentTag(Class, String, boolean)
352      * @deprecated
353      */

354
355     final protected TagSupport findParentTag(String JavaDoc classname, String JavaDoc id, boolean exception) throws JspTagException {
356         Class JavaDoc clazz ;
357         try {
358             clazz = Class.forName(classname);
359         } catch (java.lang.ClassNotFoundException JavaDoc e) {
360             throw new TaglibException ("Could not find " + classname + " class", e);
361         }
362         return findParentTag(clazz, id, exception);
363     }
364
365     /**
366      * Finds a parent tag by class and id. This is a base function for
367      * 'getContext', but it is handy in itself, so also available for
368      * extended classes.
369      *
370      * @param clazz the class of the Tag to find.
371      * @param tagId the id of the Tag to find.
372      * @param exception if it has to throw an exception if the parent can not be found (default: yes).
373      * @since MMBase-1.7
374      */

375
376     final public TagSupport findParentTag(Class JavaDoc clazz, String JavaDoc tagId, boolean exception) throws JspTagException {
377         TagSupport cTag = (TagSupport) findAncestorWithClass(this, clazz);
378         if (cTag == null) {
379             if (exception) {
380                 throw new JspTagException ("Could not find parent of type " + clazz.getName());
381             } else {
382                 if (log.isDebugEnabled()) {
383                     log.debug("Could not find parent of type " + clazz.getName());
384                 }
385                 return null;
386             }
387         }
388
389         if (tagId != null) { // search further, if necessary
390
if (log.isDebugEnabled()) {
391                 log.debug(" with id (" + tagId + ")");
392             }
393             while (! tagId.equals(cTag.getId())) {
394                 cTag = (TagSupport) findAncestorWithClass(cTag, clazz);
395                 if (cTag == null) {
396                     if (exception) {
397                         throw new JspTagException ("Could not find parent Tag of type " + clazz.getName() + " with id " + tagId);
398                     } else {
399                         return null;
400                     }
401                 }
402             }
403         }
404         return cTag;
405
406     }
407
408     /**
409      * @since MMBase-1.8
410      */

411     public Tag findLoopOrQuery(String JavaDoc tagId, boolean exception) throws JspTagException {
412         Tag tag = getParent();
413         while (tag != null) {
414             if (tag instanceof LoopTag) {
415                 if (tagId == null) return tag;
416             } else if (tag instanceof QueryContainer) {
417                 if (tagId == null || ((QueryContainer) tag).getId().equals(tagId)) return tag;
418             }
419             tag = tag.getParent();
420         }
421         throw new JspTagException("Cloud not find parent Tag of LoopTag or QueryContainer type");
422     }
423     /**
424      * @deprecated
425      */

426     final protected TagSupport findParentTag(String JavaDoc classname, String JavaDoc id) throws JspTagException {
427         return findParentTag(classname, id, true);
428     }
429     /**
430      * @since MMBase-1.7
431      */

432     final protected TagSupport findParentTag(Class JavaDoc clazz, String JavaDoc id) throws JspTagException {
433         return findParentTag(clazz, id, true);
434     }
435
436     /**
437      * Finds the parent context provider.
438      * @since MMBase-1.7
439      */

440
441     public ContextProvider getContextProvider() throws JspTagException {
442         return getContextProvider((String JavaDoc) contextId.getValue(this), ContextProvider.class);
443     }
444
445     /**
446      * Finds the parent context tag. In MMBase 1.7 and higher,
447      * normally you would like to use getContextProvider in stead.
448      *
449      */

450
451     public ContextTag getContextTag() throws JspTagException {
452         return (ContextTag) getContextProvider((String JavaDoc) contextId.getValue(this), ContextTag.class);
453     }
454
455     /**
456      * Finds a parent context tag using an id, and a class. The class
457      * is ContextProvider or ContextTag.
458      * @since MMBase-1.7
459      */

460
461     private ContextProvider getContextProvider(String JavaDoc contextid, Class JavaDoc cl) throws JspTagException {
462
463         if(log.isDebugEnabled()) {
464             log.debug("Searching context " + contextid);
465         }
466         ContextProvider contextTag = (ContextProvider) findParentTag(cl, contextid, false);
467         if (contextTag == null ||
468             // doesn't count becase it is on a different page, (this tag e.g. is in a tag-file)
469
// necessary in tomcat > 5.5.20 only.
470
// See http://issues.apache.org/bugzilla/show_bug.cgi?id=31804
471
contextTag.getContextContainer().getPageContext() != pageContext) {
472
473             log.debug("Didn't find one, take the pageContextTag");
474             contextTag = getPageContextTag();
475             if (contextTag == null) {
476                 throw new RuntimeException JavaDoc("Did not find pageContextTag!");
477             }
478             if (contextid != null) {
479                 if(! contextid.equals(contextTag.getId())) {
480                     throw new JspTagException("Could not find context tag with id " + contextid + " (page context has id " + contextTag.getId() + ")");
481                 }
482             }
483         }
484         if (log.isDebugEnabled()) {
485             log.debug("found a context with ID= " + contextTag.getId());
486         }
487         return contextTag;
488     }
489
490     /**
491      * Gets an object from the Context.
492      *
493      */

494     public Object JavaDoc getObject(String JavaDoc key) throws JspTagException {
495         // does the key contain '.', then start searching on pageContextTag, otherwise in parent.
496
if (log.isDebugEnabled()) {
497             log.debug("Getting object '" + key + "' from '" + getContextProvider().getId() + "'");
498         }
499         Object JavaDoc r = getContextProvider().getContextContainer().getObject(key);
500         if (r == null) {
501             log.debug("Not found, returning empty string");
502             return "";
503         } else {
504             if (log.isDebugEnabled()) log.debug("found: '" + r + "'");
505         }
506         return r;
507     }
508
509     /**
510      * Support '[key]?', which returns the object with name [key] if it is present, or simply null otherwise.
511      * If not ends with ?, it simply behaves like {@link #getObject(String)}.
512      * @since MMBase-1.8.1
513      */

514     public Object JavaDoc getObjectConditional(String JavaDoc key) throws JspTagException {
515         if (key.endsWith("?")) {
516             key = key.substring(0, key.length() - 1);
517             return getContextProvider().getContextContainer().get(key);
518         } else {
519             return getObject(key);
520         }
521     }
522     /**
523      * Gets an object from the Context, and returns it as a
524      * String. This is not always a simple 'toString'. For example a
525      * getString on a Node will return the number, which also uniquely
526      * identifies it.
527      *
528      * If the object is 'not present' then it returns an empty string.
529      */

530
531     protected String JavaDoc getString(String JavaDoc key) throws JspTagException {
532         return Casting.toString(getObject(key));
533     }
534
535     /**
536      * Returns the content-tag in which this context-referrer is in,
537      * or a default (compatible with MMBase 1.6) if there is none.
538      * @since MMBase-1.7
539      */

540
541     public ContentTag getContentTag() throws JspTagException {
542         ContentTag ct = (ContentTag) findParentTag(ContentTag.class, null, false);
543         if (ct == null) {
544             return ContentTag.DEFAULT;
545         } else {
546             return ct;
547         }
548     }
549
550     /**
551      * Get the locale which is defined by surrounding tags or the cloud
552      * @return a locale when defined or otherwise the mmbase locale.
553      * @throws JspTagException
554
555      * @since MMBase-1.7.1
556      */

557     public Locale getLocale() throws JspTagException {
558         Locale locale = getLocaleFromContext();
559         if (locale == null) {
560             locale = getDefaultLocale();
561         }
562         return locale;
563     }
564
565     /**
566      * Get the locale which is defined by surrounding tags or the cloud
567      * @return a locale when defined or otherwise <code>null</code>
568      * @throws JspTagException
569      *
570      * @since MMBase-1.8.1
571      */

572     public Locale getLocaleFromContext() throws JspTagException {
573         // is this correct?
574
LocaleTag localeTag = (LocaleTag)findParentTag(LocaleTag.class, null, false);
575         if (localeTag != null) {
576             Locale locale = localeTag.getLocale();
577             if (locale != null) {
578                 return locale;
579             }
580         }
581         ContextReferrerTag contextReferrerTag = (ContextReferrerTag)findParentTag(ContextReferrerTag.class, null, false);
582         if (contextReferrerTag != null) {
583             Locale locale = contextReferrerTag.getLocale();
584             if (locale != null) {
585                 return locale;
586             }
587         }
588         {
589             Locale locale = (Locale) pageContext.getAttribute(LocaleTag.KEY, LocaleTag.SCOPE);
590             if (locale != null) {
591                 return locale;
592             }
593         }
594         return null;
595     }
596     
597     /**
598      * Get the default locale which is set in mmbase.
599      *
600      * @since MMBase-1.8.1
601      */

602     public Locale getDefaultLocale() {
603         return org.mmbase.bridge.ContextProvider.getDefaultCloudContext().getDefaultLocale();
604     }
605
606     /**
607      * @since MMBase-1.8
608      */

609     public TimeZone getTimeZone() {
610         TimeZone timeZone = (TimeZone) pageContext.getAttribute(LocaleTag.TZ_KEY, LocaleTag.SCOPE);
611         if (timeZone != null) return timeZone;
612         return org.mmbase.bridge.ContextProvider.getDefaultCloudContext().getDefaultTimeZone();
613     }
614     /**
615      * @since MMBase-1.7.4
616      */

617     protected void fillStandardParameters(Parameters p) throws JspTagException {
618         log.debug("Filling standard parameters");
619         p.setIfDefined(Parameter.RESPONSE, pageContext.getResponse());
620         p.setIfDefined(Parameter.REQUEST, pageContext.getRequest());
621         // locale parameters
622
java.util.Locale JavaDoc locale = getLocale();
623         if (locale != null) {
624             p.setIfDefined(Parameter.LANGUAGE, locale.getLanguage());
625             p.setIfDefined(Parameter.LOCALE, locale);
626         }
627     }
628
629
630
631     // Writer Implmentation
632
// Not all ContextReferrerTags are actually Writers, but no m.i. in java.
633

634     /**
635      * The helper member is only used by 'Writer' extensions.
636      */

637
638     final protected WriterHelper helper = new WriterHelper(this);
639     // sigh, we would of course prefer to extend, but no multiple inheritance possible in Java..
640

641     public void setVartype(String JavaDoc t) throws JspTagException {
642         helper.setVartype(t);
643     }
644     /**
645      * @since MMBase-1.8
646      */

647     final public void setListdelimiter(String JavaDoc l) throws JspTagException {
648         helper.setListdelimiter(getAttribute(l));
649     }
650     public void setJspvar(String JavaDoc j) {
651         helper.setJspvar(j);
652     }
653     final public void setWrite(String JavaDoc w) throws JspTagException {
654         helper.setWrite(getAttribute(w));
655     }
656
657     final public void setEscape(String JavaDoc e) throws JspTagException {
658         helper.setEscape(getAttribute(e));
659     }
660
661     final public Object JavaDoc getWriterValue() {
662         return helper.getValue();
663     }
664     final public void haveBody() { helper.haveBody(); }
665
666     /**
667      * Returns the escaped value associated with this tag, but only if the escape attribute was set explicitely (so not when only inherited from content-tag).
668      * @since MMBase-1.8
669      */

670     protected Object JavaDoc getEscapedValue(Object JavaDoc value) throws JspTagException {
671         if (helper.getEscape() == null) {
672             return value;
673         } else {
674             org.mmbase.util.transformers.CharTransformer ct = ContentTag.getCharTransformer(helper.getEscape(), this);
675             if (ct != null) {
676                 return ct.transform(Casting.toString(value));
677             } else {
678                 return value;
679             }
680         }
681     }
682
683
684 }
685
Popular Tags