KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > freemarker > ext > jsp > TagTransformModel


1 /*
2  * Copyright (c) 2003 The Visigoth Software Society. All rights
3  * reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  *
17  * 3. The end-user documentation included with the redistribution, if
18  * any, must include the following acknowledgement:
19  * "This product includes software developed by the
20  * Visigoth Software Society (http://www.visigoths.org/)."
21  * Alternately, this acknowledgement may appear in the software itself,
22  * if and wherever such third-party acknowledgements normally appear.
23  *
24  * 4. Neither the name "FreeMarker", "Visigoth", nor any of the names of the
25  * project contributors may be used to endorse or promote products derived
26  * from this software without prior written permission. For written
27  * permission, please contact visigoths@visigoths.org.
28  *
29  * 5. Products derived from this software may not be called "FreeMarker" or "Visigoth"
30  * nor may "FreeMarker" or "Visigoth" appear in their names
31  * without prior written permission of the Visigoth Software Society.
32  *
33  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
34  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
35  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
36  * DISCLAIMED. IN NO EVENT SHALL THE VISIGOTH SOFTWARE SOCIETY OR
37  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
38  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
39  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
40  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
41  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
42  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
43  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44  * SUCH DAMAGE.
45  * ====================================================================
46  *
47  * This software consists of voluntary contributions made by many
48  * individuals on behalf of the Visigoth Software Society. For more
49  * information on the Visigoth Software Society, please see
50  * http://www.visigoths.org/
51  */

52
53 package freemarker.ext.jsp;
54
55 import java.beans.BeanInfo JavaDoc;
56 import java.beans.IntrospectionException JavaDoc;
57 import java.beans.Introspector JavaDoc;
58 import java.beans.PropertyDescriptor JavaDoc;
59 import java.io.CharArrayReader JavaDoc;
60 import java.io.CharArrayWriter JavaDoc;
61 import java.io.IOException JavaDoc;
62 import java.io.Reader JavaDoc;
63 import java.io.Writer JavaDoc;
64 import java.lang.reflect.InvocationTargetException JavaDoc;
65 import java.lang.reflect.Method JavaDoc;
66 import java.util.HashMap JavaDoc;
67 import java.util.Iterator JavaDoc;
68 import java.util.Map JavaDoc;
69
70 import javax.servlet.jsp.JspException JavaDoc;
71 import javax.servlet.jsp.JspWriter JavaDoc;
72 import javax.servlet.jsp.tagext.BodyContent JavaDoc;
73 import javax.servlet.jsp.tagext.BodyTag JavaDoc;
74 import javax.servlet.jsp.tagext.IterationTag JavaDoc;
75 import javax.servlet.jsp.tagext.Tag JavaDoc;
76 import javax.servlet.jsp.tagext.TryCatchFinally JavaDoc;
77
78 import freemarker.ext.beans.BeansWrapper;
79 import freemarker.log.Logger;
80 import freemarker.template.ObjectWrapper;
81 import freemarker.template.TemplateModel;
82 import freemarker.template.TemplateModelException;
83 import freemarker.template.TemplateTransformModel;
84 import freemarker.template.TransformControl;
85 import freemarker.template.utility.SecurityUtilities;
86 import freemarker.template.utility.StringUtil;
87
88 /**
89  * @version $Id: TagTransformModel.java,v 1.16 2004/01/06 17:06:43 szegedia Exp $
90  * @author Attila Szegedi
91  */

92 class TagTransformModel implements TemplateTransformModel
93 {
94     private static final char[] NEWLINE = SecurityUtilities.getSystemProperty("line.separator").toCharArray();
95     
96     private static final Logger logger = Logger.getLogger("freemarker.servlet");
97     
98     private final Class JavaDoc tagClass;
99     private final Map JavaDoc propertySetters = new HashMap JavaDoc();
100     private final boolean isBodyTag;
101     private final boolean isIterationTag;
102     private final boolean isTryCatchFinally;
103             
104     public TagTransformModel(Class JavaDoc tagClass)
105     throws
106         IntrospectionException JavaDoc
107     {
108         if(!Tag JavaDoc.class.isAssignableFrom(tagClass)) {
109             throw new IllegalArgumentException JavaDoc(tagClass.getName() + " does not implement the " + Tag JavaDoc.class.getName() + " interface.");
110         }
111         isIterationTag = IterationTag JavaDoc.class.isAssignableFrom(tagClass);
112         isBodyTag = isIterationTag && BodyTag JavaDoc.class.isAssignableFrom(tagClass);
113         isTryCatchFinally = TryCatchFinally JavaDoc.class.isAssignableFrom(tagClass);
114                 
115         this.tagClass = tagClass;
116         BeanInfo JavaDoc bi = Introspector.getBeanInfo(tagClass);
117         PropertyDescriptor JavaDoc[] pda = bi.getPropertyDescriptors();
118         for (int i = 0; i < pda.length; i++)
119         {
120             PropertyDescriptor JavaDoc pd = pda[i];
121             Method JavaDoc m = pd.getWriteMethod();
122             if(m != null)
123             {
124                 propertySetters.put(pd.getName(), m);
125             }
126         }
127     }
128     
129     public Writer JavaDoc getWriter(Writer JavaDoc out, Map JavaDoc args) throws TemplateModelException
130     {
131         try {
132             Tag JavaDoc tag = getTagInstance();
133             FreeMarkerPageContext pageContext = FreeMarkerPageContext.getCurrentPageContext();
134             Tag JavaDoc parentTag = pageContext.peekTopTag();
135             tag.setParent(parentTag);
136             tag.setPageContext(pageContext);
137             setupTag(tag, args, pageContext.getObjectWrapper());
138             // If the parent of this writer is not a JspWriter itself, use
139
// a little Writer-to-JspWriter adapter...
140
boolean usesAdapter;
141             if(out instanceof JspWriter JavaDoc) {
142                 // This is just a sanity check. If it were JDK 1.4-only,
143
// we'd use an assert.
144
if(out != pageContext.getOut()) {
145                     throw new TemplateModelException(
146                         "out != pageContext.getOut(). Out is " +
147                         out + " pageContext.getOut() is " +
148                         pageContext.getOut());
149                 }
150                 usesAdapter = false;
151             }
152             else {
153                 out = new JspWriterAdapter(out);
154                 pageContext.pushWriter((JspWriter JavaDoc)out);
155                 usesAdapter = true;
156             }
157             JspWriter JavaDoc w = new TagWriter(out, tag, pageContext, usesAdapter);
158             pageContext.pushTopTag(tag);
159             pageContext.pushWriter(w);
160             return w;
161         }
162         catch(TemplateModelException e) {
163             throw e;
164         }
165         catch(Exception JavaDoc e) {
166             throw new TemplateModelException(e);
167         }
168     }
169
170     private Tag JavaDoc getTagInstance()
171     throws
172         IllegalAccessException JavaDoc,
173         InstantiationException JavaDoc
174     {
175         return (Tag JavaDoc)tagClass.newInstance();
176     }
177     
178     private void setupTag(Object JavaDoc tag, Map JavaDoc args, ObjectWrapper wrapper)
179     throws
180         TemplateModelException,
181         InvocationTargetException JavaDoc,
182         IllegalAccessException JavaDoc
183     {
184         BeansWrapper bwrapper =
185             wrapper instanceof BeansWrapper
186             ? (BeansWrapper)wrapper
187             : BeansWrapper.getDefaultInstance();
188         if(args != null && !args.isEmpty())
189         {
190             Object JavaDoc[] aarg = new Object JavaDoc[1];
191             for (Iterator JavaDoc iter = args.entrySet().iterator(); iter.hasNext();)
192             {
193                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iter.next();
194                 aarg[0] = bwrapper.unwrap((TemplateModel)entry.getValue());
195                 Method JavaDoc m = (Method JavaDoc)propertySetters.get(entry.getKey());
196                 if(m == null)
197                 {
198                     throw new TemplateModelException("Unknown property "
199                             + StringUtil.jQuote(entry.getKey().toString())
200                             + " on instance of " + tagClass.getName());
201                 }
202                 BeansWrapper.coerceBigDecimals(m, aarg);
203                 m.invoke(tag, aarg);
204             }
205         }
206     }
207
208     private class TagWriter extends BodyContent JavaDoc implements TransformControl
209     {
210         private final Tag JavaDoc tag;
211         private final FreeMarkerPageContext pageContext;
212         private CharArrayWriter JavaDoc buf;
213         private boolean needPop = true;
214         private final boolean needDoublePop;
215         
216         TagWriter(Writer JavaDoc out, Tag JavaDoc tag, FreeMarkerPageContext pageContext, boolean needDoublePop)
217         {
218             super((JspWriter JavaDoc)out);
219             this.needDoublePop = needDoublePop;
220             this.tag = tag;
221             this.pageContext = pageContext;
222         }
223         
224         public String JavaDoc toString() {
225             return "TagWriter for " + tag.getClass().getName() + " wrapping a " + getEnclosingWriter().toString();
226         }
227
228         Tag JavaDoc getTag()
229         {
230             return tag;
231         }
232         
233         FreeMarkerPageContext getPageContext()
234         {
235             return pageContext;
236         }
237         
238         public int onStart()
239         throws
240             TemplateModelException
241         {
242             try {
243                 int dst = tag.doStartTag();
244                 switch(dst) {
245                     case Tag.SKIP_BODY:
246                     // EVAL_PAGE is illegal actually, but some taglibs out there
247
// use it, and it seems most JSP compilers allow them to and
248
// treat it identically to SKIP_BODY, so we're going with
249
// the flow and we allow it too, altough strictly speaking
250
// it is in violation of the spec.
251
case Tag.EVAL_PAGE: {
252                         endEvaluation();
253                         return TransformControl.SKIP_BODY;
254                     }
255                     case BodyTag.EVAL_BODY_BUFFERED: {
256                         if(isBodyTag) {
257                             BodyTag JavaDoc btag = (BodyTag JavaDoc)tag;
258                             buf = new CharArrayWriter JavaDoc();
259                             btag.setBodyContent(this);
260                             btag.doInitBody();
261                         }
262                         else {
263                             throw new TemplateModelException("Can't buffer body since " + tag.getClass().getName() + " does not implement BodyTag.");
264                         }
265                         // Intentional fall-through
266
}
267                     case Tag.EVAL_BODY_INCLUDE: {
268                         return TransformControl.EVALUATE_BODY;
269                     }
270                     default: {
271                         throw new RuntimeException JavaDoc("Illegal return value " + dst + " from " + tag.getClass().getName() + ".doStartTag()");
272                     }
273                 }
274             }
275             catch(JspException JavaDoc e) {
276                 throw new TemplateModelException(e.getMessage(), e);
277             }
278         }
279         
280         public int afterBody()
281         throws
282             TemplateModelException
283         {
284             try {
285                 if(isIterationTag) {
286                     int dab = ((IterationTag JavaDoc)tag).doAfterBody();
287                     switch(dab) {
288                         case Tag.SKIP_BODY: {
289                             endEvaluation();
290                             return END_EVALUATION;
291                         }
292                         case IterationTag.EVAL_BODY_AGAIN: {
293                             return REPEAT_EVALUATION;
294                         }
295                         default: {
296                             throw new TemplateModelException("Unexpected return value " + dab + "from " + tag.getClass().getName() + ".doAfterBody()");
297                         }
298                     }
299                 }
300                 endEvaluation();
301                 return END_EVALUATION;
302             }
303             catch(JspException JavaDoc e) {
304                 throw new TemplateModelException(e);
305             }
306         }
307         
308         private void endEvaluation() throws JspException JavaDoc {
309             if(needPop) {
310                 pageContext.popWriter();
311                 needPop = false;
312             }
313             if(tag.doEndTag() == Tag.SKIP_PAGE) {
314                 logger.warn("Tag.SKIP_PAGE was ignored from a " + tag.getClass().getName() + " tag.");
315             }
316         }
317         
318         public void onError(Throwable JavaDoc t) throws Throwable JavaDoc {
319             if(isTryCatchFinally) {
320                 ((TryCatchFinally JavaDoc)tag).doCatch(t);
321             }
322             else {
323                 throw t;
324             }
325         }
326         
327         public void close() {
328             if(needPop) {
329                 pageContext.popWriter();
330             }
331             pageContext.popTopTag();
332             try {
333                 if(isTryCatchFinally) {
334                     ((TryCatchFinally JavaDoc)tag).doFinally();
335                 }
336                 // No pooling yet
337
tag.release();
338             }
339             finally {
340                 if(needDoublePop) {
341                     pageContext.popWriter();
342                 }
343             }
344         }
345         
346         public void flush() throws IOException JavaDoc {
347             if(buf == null) {
348                 getEnclosingWriter().flush();
349             }
350         }
351
352         public void clear() throws IOException JavaDoc {
353             if(buf != null) {
354                 buf = new CharArrayWriter JavaDoc();
355             }
356             else {
357                 throw new IOException JavaDoc("Can't clear");
358             }
359         }
360
361         public void clearBuffer() throws IOException JavaDoc {
362             if(buf != null) {
363                 buf = new CharArrayWriter JavaDoc();
364             }
365             else {
366                 throw new IOException JavaDoc("Can't clear");
367             }
368         }
369
370         public int getRemaining() {
371             return Integer.MAX_VALUE;
372         }
373
374         public void newLine() throws IOException JavaDoc {
375             write(NEWLINE);
376         }
377
378         public void print(boolean arg0) throws IOException JavaDoc {
379             write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
380         }
381
382         public void print(char arg0) throws IOException JavaDoc
383         {
384             write(arg0);
385         }
386
387         public void print(char[] arg0) throws IOException JavaDoc
388         {
389             write(arg0);
390         }
391
392         public void print(double arg0) throws IOException JavaDoc
393         {
394             write(Double.toString(arg0));
395         }
396
397         public void print(float arg0) throws IOException JavaDoc
398         {
399             write(Float.toString(arg0));
400         }
401
402         public void print(int arg0) throws IOException JavaDoc
403         {
404             write(Integer.toString(arg0));
405         }
406
407         public void print(long arg0) throws IOException JavaDoc
408         {
409             write(Long.toString(arg0));
410         }
411
412         public void print(Object JavaDoc arg0) throws IOException JavaDoc
413         {
414             write(arg0 == null ? "null" : arg0.toString());
415         }
416
417         public void print(String JavaDoc arg0) throws IOException JavaDoc
418         {
419             write(arg0);
420         }
421
422         public void println() throws IOException JavaDoc
423         {
424             newLine();
425         }
426
427         public void println(boolean arg0) throws IOException JavaDoc
428         {
429             print(arg0);
430             newLine();
431         }
432
433         public void println(char arg0) throws IOException JavaDoc
434         {
435             print(arg0);
436             newLine();
437         }
438
439         public void println(char[] arg0) throws IOException JavaDoc
440         {
441             print(arg0);
442             newLine();
443         }
444
445         public void println(double arg0) throws IOException JavaDoc
446         {
447             print(arg0);
448             newLine();
449         }
450
451         public void println(float arg0) throws IOException JavaDoc
452         {
453             print(arg0);
454             newLine();
455         }
456
457         public void println(int arg0) throws IOException JavaDoc
458         {
459             print(arg0);
460             newLine();
461         }
462
463         public void println(long arg0) throws IOException JavaDoc
464         {
465             print(arg0);
466             newLine();
467         }
468
469         public void println(Object JavaDoc arg0) throws IOException JavaDoc
470         {
471             print(arg0);
472             newLine();
473         }
474
475         public void println(String JavaDoc arg0) throws IOException JavaDoc
476         {
477             print(arg0);
478             newLine();
479         }
480
481         public void write(int c) throws IOException JavaDoc
482         {
483             if(buf != null) {
484                 buf.write(c);
485             }
486             else {
487                 getEnclosingWriter().write(c);
488             }
489         }
490
491         public void write(char[] cbuf, int off, int len) throws IOException JavaDoc
492         {
493             if(buf != null) {
494                 buf.write(cbuf, off, len);
495             }
496             else {
497                 getEnclosingWriter().write(cbuf, off, len);
498             }
499         }
500
501         public String JavaDoc getString() {
502             return buf.toString();
503         }
504         
505         public Reader JavaDoc getReader() {
506             return new CharArrayReader JavaDoc(buf.toCharArray());
507         }
508         
509         public void writeOut(Writer JavaDoc out) throws IOException JavaDoc {
510             buf.writeTo(out);
511         }
512     }
513
514     static class JspWriterAdapter extends JspWriter JavaDoc {
515         private final Writer JavaDoc out;
516         
517         JspWriterAdapter(Writer JavaDoc out) {
518             super(0, true);
519             this.out = out;
520         }
521         
522         public String JavaDoc toString() {
523             return "JspWriterAdapter wrapping a " + out.toString();
524         }
525         
526         public void clear() throws IOException JavaDoc {
527             throw new IOException JavaDoc("Can't clear");
528         }
529
530         public void clearBuffer() throws IOException JavaDoc {
531             throw new IOException JavaDoc("Can't clear");
532         }
533
534         public void close() throws IOException JavaDoc {
535             throw new IOException JavaDoc("Close not permitted.");
536         }
537
538         public void flush() throws IOException JavaDoc {
539             out.flush();
540         }
541
542         public int getRemaining() {
543             return 0;
544         }
545
546         public void newLine() throws IOException JavaDoc {
547             out.write(NEWLINE);
548         }
549
550         public void print(boolean arg0) throws IOException JavaDoc {
551             out.write(arg0 ? Boolean.TRUE.toString() : Boolean.FALSE.toString());
552         }
553
554         public void print(char arg0) throws IOException JavaDoc
555         {
556             out.write(arg0);
557         }
558
559         public void print(char[] arg0) throws IOException JavaDoc
560         {
561             out.write(arg0);
562         }
563
564         public void print(double arg0) throws IOException JavaDoc
565         {
566             out.write(Double.toString(arg0));
567         }
568
569         public void print(float arg0) throws IOException JavaDoc
570         {
571             out.write(Float.toString(arg0));
572         }
573
574         public void print(int arg0) throws IOException JavaDoc
575         {
576             out.write(Integer.toString(arg0));
577         }
578
579         public void print(long arg0) throws IOException JavaDoc
580         {
581             out.write(Long.toString(arg0));
582         }
583
584         public void print(Object JavaDoc arg0) throws IOException JavaDoc
585         {
586             out.write(arg0 == null ? "null" : arg0.toString());
587         }
588
589         public void print(String JavaDoc arg0) throws IOException JavaDoc
590         {
591             out.write(arg0);
592         }
593
594         public void println() throws IOException JavaDoc
595         {
596             newLine();
597         }
598
599         public void println(boolean arg0) throws IOException JavaDoc
600         {
601             print(arg0);
602             newLine();
603         }
604
605         public void println(char arg0) throws IOException JavaDoc
606         {
607             print(arg0);
608             newLine();
609         }
610
611         public void println(char[] arg0) throws IOException JavaDoc
612         {
613             print(arg0);
614             newLine();
615         }
616
617         public void println(double arg0) throws IOException JavaDoc
618         {
619             print(arg0);
620             newLine();
621         }
622
623         public void println(float arg0) throws IOException JavaDoc
624         {
625             print(arg0);
626             newLine();
627         }
628
629         public void println(int arg0) throws IOException JavaDoc
630         {
631             print(arg0);
632             newLine();
633         }
634
635         public void println(long arg0) throws IOException JavaDoc
636         {
637             print(arg0);
638             newLine();
639         }
640
641         public void println(Object JavaDoc arg0) throws IOException JavaDoc
642         {
643             print(arg0);
644             newLine();
645         }
646
647         public void println(String JavaDoc arg0) throws IOException JavaDoc
648         {
649             print(arg0);
650             newLine();
651         }
652
653         public void write(int c) throws IOException JavaDoc
654         {
655             out.write(c);
656         }
657         
658         public void write(char[] arg0, int arg1, int arg2)
659             throws IOException JavaDoc
660         {
661             out.write(arg0, arg1, arg2);
662         }
663     }
664 }
665
Popular Tags