KickJava   Java API By Example, From Geeks To Geeks.

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


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 import javax.servlet.jsp.*;
12 import javax.servlet.jsp.tagext.BodyContent JavaDoc;
13 import java.io.IOException JavaDoc;
14
15 import java.util.*;
16
17 import org.mmbase.util.transformers.CharTransformer;
18 import org.mmbase.bridge.jsp.taglib.util.*;
19
20 import org.mmbase.util.logging.Logger;
21 import org.mmbase.util.logging.Logging;
22
23 import org.mmbase.util.Casting; // not used enough
24

25 /**
26  * Tags that are Writers can use the this class. It's a pitty that
27  * they can't extend, but that's life.
28  *
29  * @author Michiel Meeuwissen
30  * @version $Id: WriterHelper.java,v 1.88.2.1 2006/11/13 14:59:22 michiel Exp $
31  */

32
33 public class WriterHelper {
34
35     private static final Logger log = Logging.getLoggerInstance(WriterHelper.class);
36     public static final boolean NOIMPLICITLIST = true;
37     public static final boolean IMPLICITLIST = false;
38
39     public static final String JavaDoc STACK_ATTRIBUTE = "org.mmbase.bridge.jsp.taglib._Stack";
40
41     static final int TYPE_UNKNOWN = -10;
42     static final int TYPE_UNSET = -1;
43     static final int TYPE_OBJECT = 0;
44     static final int TYPE_LIST = 1;
45     static final int TYPE_VECTOR = 2;
46     static final int TYPE_INTEGER = 3;
47     public static final int TYPE_STRING = 4;
48     static final int TYPE_BYTES = 6;
49     static final int TYPE_DOUBLE = 7;
50     static final int TYPE_LONG = 8;
51     static final int TYPE_FLOAT = 9;
52     static final int TYPE_DECIMAL = 10;
53     static final int TYPE_DATE = 11;
54
55
56     static final int TYPE_NODE = 20;
57     static final int TYPE_CLOUD = 21;
58     static final int TYPE_TRANSACTION = 22;
59     static final int TYPE_FIELD = 23;
60     static final int TYPE_FIELDVALUE = 24;
61     static final int TYPE_BOOLEAN = 25;
62     static final int TYPE_CHARSEQUENCE = 26;
63     static final int TYPE_FILEITEM = 27;
64
65
66     static final int stringToType(String JavaDoc tt) {
67         String JavaDoc t = tt.toLowerCase();
68         if ("string".equals(t)) {
69             return TYPE_STRING;
70         } else if ("node".equals(t)) {
71             return TYPE_NODE;
72         } else if ("cloud".equals(t)) {
73             return TYPE_CLOUD;
74         } else if ("transaction".equals(t)) {
75             return TYPE_TRANSACTION;
76         } else if ("decimal".equals(t)) {
77             return TYPE_DECIMAL;
78         } else if ("integer".equals(t)) {
79             return TYPE_INTEGER;
80         } else if ("long".equals(t)) {
81             return TYPE_LONG;
82         } else if ("double".equals(t)) {
83             return TYPE_DOUBLE;
84         } else if ("float".equals(t)) {
85             return TYPE_FLOAT;
86         } else if ("vector".equals(t)) {
87             return TYPE_VECTOR;
88         } else if ("list".equals(t)) {
89             return TYPE_LIST;
90         } else if ("bytes".equals(t)) {
91             return TYPE_BYTES;
92         } else if ("fileitem".equals(t)) {
93             return TYPE_FILEITEM;
94         } else if ("object".equals(t)) {
95             return TYPE_OBJECT;
96         } else if ("date".equals(t)) {
97             return TYPE_DATE;
98         } else if ("field".equals(t)) {
99             return TYPE_FIELD;
100         } else if ("fieldvalue".equals(t)) {
101             return TYPE_FIELDVALUE;
102         } else if ("boolean".equals(t)) {
103             return TYPE_BOOLEAN;
104         } else if ("charsequence".equals(t)) {
105             return TYPE_CHARSEQUENCE;
106         } else {
107             return TYPE_UNKNOWN;
108         }
109     }
110
111     private Object JavaDoc value = null;
112
113     private String JavaDoc jspvar = null;
114     private Attribute write = Attribute.NULL;
115     private Attribute escape = Attribute.NULL;
116     private Boolean JavaDoc overrideWrite = null;
117     private int vartype = TYPE_UNSET;
118     private Attribute listDelimiter = Attribute.NULL;
119
120     private ContextReferrerTag thisTag = null;
121
122     private BodyContent JavaDoc bodyContent;
123
124
125     /**
126      * 'underscore' stack, containing the values for '_'.
127      * @since MMBase_1.8
128      */

129     private Stack _Stack;
130     // whether this tag pushed something on the stack already.
131
private boolean pushed = false;
132
133     private boolean hasBody = false;
134
135     private boolean useEscaper = true;
136
137
138     public WriterHelper(ContextReferrerTag tag) {
139         thisTag = tag;
140     }
141
142     /**
143      * For implementation of the write attribute.
144      */

145     public void setWrite(Attribute w) {
146         if (log.isDebugEnabled()) {
147             log.debug("Setting write to " + w);
148         }
149         write = w;
150     }
151
152     /**
153      * @since MMBase-1.7
154      */

155     public Attribute getWrite() {
156         return write;
157     }
158
159     /**
160      * For implementation of the escape attribute.
161      * @since MMBase-1.7
162      */

163
164     public void setEscape(Attribute e) {
165         if (log.isDebugEnabled()) {
166             log.debug("Setting escape to " + e);
167         }
168         escape = e;
169     }
170
171     /**
172      * @deprecated Use setWrite(Attribute)
173      */

174     public void setWrite(Boolean JavaDoc b) {
175         try {
176             write = Attribute.getAttribute(b.toString());
177         } catch (JspTagException e) {
178             log.error(e.toString());
179         }
180     }
181
182     /**
183      * @since MMBase-1.7.4
184      */

185     private boolean overrideNoImplicitList = false;
186     public void overrideNoImplicitList() {
187          overrideNoImplicitList = true;
188      }
189
190
191     /**
192      * There is a default behavior for what should happen if the 'write' attribute is not set.
193      * if you want to override this, then call this function.
194      */

195     public void overrideWrite(boolean w) {
196         overrideWrite = w ? Boolean.TRUE : Boolean.FALSE;
197     }
198
199     /**
200      * Some writer tags produce very specific content, and take care
201      * of escaping themselves (UrlTag). They turn off escaping (on default).
202      */

203
204     public void useEscaper(boolean ue) {
205         useEscaper = ue;
206     }
207
208     public boolean isWrite() throws JspTagException {
209         if (write == Attribute.NULL) {
210             if (log.isDebugEnabled()) {
211                 log.debug("write is unset, using default " + overrideWrite + " with body == '" + getString() + "' and hasBody (which is determined by childs) = " + hasBody);
212             }
213             if (overrideWrite != null) {
214                 log.debug("override-write was used --> " + overrideWrite);
215                 return overrideWrite.booleanValue();
216             }
217             boolean result = "".equals(getString()) && (! hasBody);
218             log.debug("Result " + result + " with body-string '" + getString() + "' and hasbody " + hasBody);
219             return result;
220         } else {
221             if (log.isDebugEnabled()) {
222                 log.debug("Write: " + write);
223             }
224             return write.getBoolean(thisTag, true);
225         }
226     }
227
228     public void setJspvar(String JavaDoc j) {
229         jspvar = j;
230     }
231
232     /**
233      * @deprecated jspvar will be set by setValue then
234      */

235     public void setJspvar(PageContext p) throws JspTagException {
236         setJspvar();
237     }
238
239     public String JavaDoc getJspvar() {
240         return jspvar;
241     }
242
243     /**
244      * Sets the vartype for this variable (used for jspvar as well as for taglib var).
245      *
246      * Some 'casting' functionality is present here.
247      */

248
249     public void setValue(Object JavaDoc v) throws JspTagException {
250         setValue(v, IMPLICITLIST);
251     }
252
253     /**
254      * Gets specified escaper (as a string) or null (if not set)
255      * @since MMBase-1.7
256      */

257
258     public String JavaDoc getEscape() throws JspTagException {
259         String JavaDoc e = (String JavaDoc) escape.getValue(thisTag);
260         if ("".equals(e)) return null;
261         return e;
262     }
263
264
265     /**
266      * @since MMBase-1.8
267      */

268     public CharTransformer getEscaper() throws JspTagException {
269         if (useEscaper || escape != Attribute.NULL) {
270             String JavaDoc e = getEscape();
271             if (e == null) {
272                 return (CharTransformer) thisTag.getPageContext().findAttribute(ContentTag.ESCAPER_KEY);
273             } else {
274                 return ContentTag.getCharTransformer((String JavaDoc) e, thisTag);
275             }
276         } else {
277             return null;
278         }
279     }
280
281
282     /**
283      * Sets only the value in the helper, withouth setting the _Stack
284      * @since MMBase-1.8
285      */

286     public void setValueOnly(Object JavaDoc v, boolean noImplicitList) throws JspTagException {
287         value = null;
288         if (noImplicitList && ! overrideNoImplicitList && vartype != TYPE_LIST && vartype != TYPE_VECTOR) {
289             // Take one element of list if vartype defined not to be a list.
290
// this is usefull when using mm:includes and passing a var which also can be on the request
291
if (v instanceof List) {
292                 List l = (List) v;
293                 if (l.size() > 0) {
294                     // v = l.get(l.size() - 1); // last element
295
v = l.get(0); // first element, allows for 'overriding'.
296
} else {
297                     v = null;
298                 }
299             }
300         }
301         if (v != null || vartype == TYPE_LIST || vartype == TYPE_VECTOR) {
302             switch (vartype) {
303                 // these accept a value == null (meaning that they are empty)
304
case TYPE_LIST:
305                 if (! (v instanceof List)) {
306                     if ("".equals(v)) {
307                         v = new ArrayList();
308                     } else {
309                         v = Casting.toList(v, listDelimiter.getString(thisTag));
310                     }
311                 }
312                 break;
313             case TYPE_VECTOR: // I think the type Vector should be deprecated?
314
if (v == null) {
315                     // if a vector is requested, but the value is not present,
316
// make a vector of size 0.
317
v = new Vector();
318                 } else if (! (v instanceof Vector)) {
319                     // if a vector is requested, but the value is not a vector,
320
if (! (v instanceof Collection)) {
321                         // not even a Collection!
322
// make a vector of size 1.
323
Vector vector = new Vector();
324                         vector.add(v);
325                         v = vector;
326                     } else {
327                         v = new Vector((Collection)v);
328                     }
329                 }
330                 break;
331             case TYPE_UNSET:
332                 break;
333             case TYPE_INTEGER:
334                 if (! (v instanceof Integer JavaDoc)) {
335                     v = Casting.toInteger(v);
336                 }
337                     break;
338             case TYPE_DOUBLE:
339                 if (! (v instanceof Double JavaDoc)) {
340                     v = new Double JavaDoc(Casting.toDouble(v));
341                 }
342                 break;
343             case TYPE_LONG:
344                 if (! (v instanceof Long JavaDoc)) {
345                     v = new Long JavaDoc(Casting.toLong(v));
346                 }
347                 break;
348             case TYPE_FLOAT:
349                 if (! (v instanceof Float JavaDoc)) {
350                     v = new Float JavaDoc(Casting.toFloat(v));
351                 }
352                 break;
353             case TYPE_DECIMAL:
354                 if (! (v instanceof java.math.BigDecimal JavaDoc)) {
355                     v = new java.math.BigDecimal JavaDoc(v.toString());
356                 }
357                 break;
358             case TYPE_STRING:
359                 if (! (v instanceof String JavaDoc)) {
360                     v = Casting.toString(v);
361                 }
362                 break;
363             case TYPE_CHARSEQUENCE:
364                 if (! (v instanceof CharSequence JavaDoc)) {
365                     v = Casting.toString(v);
366                 }
367                 break;
368             case TYPE_DATE:
369                 if (! (v instanceof Date)) {
370                     v = Casting.toDate(v);
371                 }
372                 break;
373             case TYPE_BOOLEAN:
374                 if (! (v instanceof Boolean JavaDoc)) {
375                     v = Boolean.valueOf(Casting.toBoolean(v));
376                 }
377                 break;
378             case TYPE_NODE:
379                 if (! (v instanceof org.mmbase.bridge.Node)) {
380                     throw new JspTagException("Variable is not of type Node, but of type " + v.getClass().getName() + ". Conversion is not yet supported by this Tag");
381                 }
382                 break;
383             case TYPE_BYTES:
384                 if (! (v instanceof byte[])) {
385                     v = Casting.toByte(v);
386                 }
387                 break;
388             case TYPE_FILEITEM:
389                 if (! (v instanceof org.apache.commons.fileupload.FileItem)) {
390                     throw new JspTagException("Variable is not of type FileItem, but of type " + v.getClass().getName() + ". Conversion is not yet supported by this Tag");
391                 }
392                 break;
393             default:
394                 log.debug("Unknown vartype" + vartype);
395                 break;
396             }
397             value = v;
398         }
399
400     }
401     public void setValue(Object JavaDoc v, boolean noImplicitList) throws JspTagException {
402         setValueOnly(v, noImplicitList);
403
404         PageContext pageContext = thisTag.getPageContext();
405
406         _Stack = (Stack) pageContext.getAttribute(STACK_ATTRIBUTE);
407         if (_Stack == null) {
408             _Stack = new Stack();
409             pushed = false;
410             pageContext.setAttribute(STACK_ATTRIBUTE, _Stack);
411         }
412
413         setJspvar();
414         if (pushed) {
415             if (log.isDebugEnabled()) {
416                 log.debug("Value was already pushed by this tag");
417             }
418             _Stack.set(_Stack.size() - 1, value);
419         } else {
420             _Stack.push(value);
421             pushed = true;
422         }
423         pageContext.setAttribute("_", Casting.wrap(value, getEscaper()));
424         if (log.isDebugEnabled()) {
425             log.debug("pushed " + value + " on _stack, for " + thisTag.getClass().getName() + " now " + _Stack);
426             log.debug("Escaper: " + getEscaper());
427             log.debug("_:" + pageContext.getAttribute("_"));
428         }
429     }
430
431
432     public Object JavaDoc getValue() {
433         return value;
434     }
435
436
437     /**
438      * Don't forget to call 'setValue' first!
439      */

440
441     private void setJspvar() throws JspTagException {
442         if (jspvar == null) return;
443
444         if (log.isDebugEnabled()) {
445             log.debug("Setting variable " + jspvar + " to " + value + "(" + (value != null ? value.getClass().getName() : "" ) + ")");
446         }
447
448         // If this tag explicitely specified an escaper, and also a jspvar attribute, then use it too for the jspvar value itself:
449
String JavaDoc e = getEscape();
450         CharTransformer ct = e == null ? null : ContentTag.getCharTransformer((String JavaDoc) e, thisTag);
451         Object JavaDoc jspValue = ct != null ? Casting.wrap(value, ct) : value;
452         thisTag.getContextProvider().getContextContainer().setJspVar(thisTag.getPageContext(), jspvar, vartype, jspValue);
453     }
454
455
456     public void setVartype(String JavaDoc t) throws JspTagException {
457         vartype = stringToType(t);
458         if (vartype == TYPE_UNKNOWN) {
459             throw new JspTagException("Type " + t + " is not known");
460         }
461     }
462
463
464     /**
465      * @since MMBase-1.8
466      */

467     final public void setListdelimiter(Attribute l) {
468         listDelimiter = l;
469     }
470
471     public int getVartype() {
472         return vartype;
473     }
474
475     /**
476      * Returns a string which can be written to the page.
477      */

478
479     protected java.io.Writer JavaDoc getPageString(java.io.Writer JavaDoc w) throws JspTagException, IOException JavaDoc {
480         if (value == null) return w;
481
482         Object JavaDoc writeValue = thisTag.getPageContext().getAttribute("_");
483         if (writeValue == value) {
484             if (value instanceof byte[]) {
485                 // writing bytes to the page?? We write base64 encoded...
486
// this is an ondocumented feature...
487
value = org.mmbase.util.Encode.encode("BASE64", (byte[]) value);
488             } else {
489                 // perhaps this could not be decently wrapped, and it was not wrapped.
490
CharTransformer ct = getEscaper();
491                 if (ct != null) {
492                     writeValue = ct.transform(Casting.toString(value));
493                 }
494             }
495         }
496         if (writeValue == null) writeValue = "";
497         w.write(writeValue.toString());
498         return w;
499     }
500
501     /**
502      * To be called by subtags. Even if they don't produce output,
503      * they say that the tag had a body.
504      */

505     public void haveBody() {
506         hasBody = true;
507     }
508
509
510     public String JavaDoc getString() {
511         if (bodyContent != null) {
512             return bodyContent.getString();
513         } else {
514             log.debug("bodycontent is null, returning empty string");
515             return "";
516         }
517     }
518
519     /**
520      * Pops one value of the _-stack, if not yet happend, if stack exists.
521      * Puts the value of peek in "_" then, if not the stack is empty now, in which case "_" is removed.
522      * @since MMBase-1.8
523      */

524     private void pop_Stack() throws JspTagException {
525         if (_Stack != null) {
526             Object JavaDoc pop = _Stack.pop();
527             if (log.isDebugEnabled()) {
528                 log.debug("Removed " + pop + "( " + (pop == null ? "NULL" : pop.getClass().getName()) + ") from _stack for " + thisTag.getClass().getName() + " now: " + _Stack);
529             }
530             if (_Stack.empty()) {
531                 thisTag.getPageContext().removeAttribute("_");
532             } else {
533                 thisTag.getPageContext().setAttribute("_", Casting.wrap(_Stack.peek(), getEscaper()));
534             }
535             _Stack = null;
536             pushed = false;
537
538         }
539     }
540
541     /**
542      * @since MMBase-1.7
543      */

544     public int doAfterBody() throws JspTagException {
545         bodyContent = thisTag.getBodyContent();
546         return javax.servlet.jsp.tagext.Tag.SKIP_BODY;
547     }
548
549     /**
550      * A basic doEndTag for Writers.
551      *
552      * It decides if to write or not, and then does that or not.
553      * It also pops the _-stack, and releases the members for gc.
554      */

555     public int doEndTag() throws JspTagException {
556         log.debug("doEndTag of WriterHelper");
557         try {
558             String JavaDoc body = getString();
559             if (isWrite()) {
560                 log.debug("Must write to page");
561                 if (bodyContent != null) bodyContent.clearBody(); // clear all space and so on
562
getPageString(thisTag.getPageContext().getOut()).write(body);
563             } else {
564                 log.debug("not writing to page");
565             }
566             if (bodyContent != null) {
567                 // if this writer (still) has body, it should be written out.
568
bodyContent.writeOut(bodyContent.getEnclosingWriter());
569             }
570         } catch (IOException JavaDoc ioe){
571             throw new TaglibException(ioe);
572         }
573         pop_Stack();
574         _Stack = null;
575         pushed = false;
576         bodyContent = null;
577         value = null;
578         log.debug("End of doEndTag");
579         return javax.servlet.jsp.tagext.Tag.EVAL_PAGE;
580     }
581
582     public void doFinally() {
583         overrideWrite = null; // for use next time
584
hasBody = false;
585         value = null;
586         _Stack = null;
587         pushed = false;
588         bodyContent = null;
589     }
590 }
591
Popular Tags