KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cactus > extension > jsp > JspTagLifecycle


1 /*
2  * ========================================================================
3  *
4  * Copyright 2001-2003 The Apache Software Foundation.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * ========================================================================
19  */

20 package org.apache.cactus.extension.jsp;
21
22 import java.io.IOException JavaDoc;
23 import java.util.ArrayList JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.List JavaDoc;
26
27 import junit.framework.Assert;
28
29 import javax.servlet.jsp.JspException JavaDoc;
30 import javax.servlet.jsp.PageContext JavaDoc;
31 import javax.servlet.jsp.tagext.BodyContent JavaDoc;
32 import javax.servlet.jsp.tagext.BodyTag JavaDoc;
33 import javax.servlet.jsp.tagext.IterationTag JavaDoc;
34 import javax.servlet.jsp.tagext.Tag JavaDoc;
35 import javax.servlet.jsp.tagext.TryCatchFinally JavaDoc;
36
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39
40 /**
41  * Convenience class that supports the testing of JSP tag by managing the tag's
42  * lifecycle as required by the JSP specification.
43  *
44  * <p>
45  * This class is basically a stub implementation of the tag management
46  * facilities that an actual JSP container would provide. The implementation
47  * attempts to follow the specification as closely as possible, but the tag
48  * handling functionality of real JSP implementations may vary in some
49  * details.
50  * </p>
51  *
52  * <p>
53  * Although this class works quite well when used in the test methods of a
54  * {@link org.apache.cactus.JspTestCase JspTestCase}, it can also safely be
55  * used outside of the Cactus testing framework, for example when following
56  * a mock objects approach.
57  * </p>
58  *
59  * <h4>Testing Simple Tags</h4>
60  * <p>
61  * This is how you would use this class when testing the
62  * <code>&lt;c:set&gt;</code>-tag of the JSTL reference implementation:
63  * <blockquote><pre>
64   SetTag tag = new SetTag();
65   JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
66   tag.setVar("name");
67   tag.setValue("value");
68   lifecycle.invoke();
69   assertEquals("value", pageContext.findAttribute("name"));</pre>
70  * </blockquote>
71  * The order is important:
72  * <ol>
73  * <li>
74  * Instantiation of the tag under test
75  * </li>
76  * <li>
77  * Instantiation of the lifecycle helper, passing in the page context and
78  * the tag instance
79  * </li>
80  * <li>
81  * Set the tag's attributes
82  * </li>
83  * <li>
84  * Start the tag's lifecycle by calling
85  * {@link #invoke() JspTagLifecycle.invoke()}
86  * </li>
87  * <li>
88  * Make assertions
89  * </li>
90  * </ol>
91  * </p>
92  *
93  * <h4>Adding Expectations to the Lifecycle</h4>
94  * <p>
95  * <code>JspTagLifecycle</code> features a couple of methods that let you
96  * easily add expectations about the tag's lifecycle to the test. For example,
97  * the method {@link #expectBodySkipped expectBodySkipped()} can be used to
98  * verify that tag's body is not evaluated under the conditions set up by the
99  * test:
100  * <pre>
101  * IfTag tag = new IfTag();
102  * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
103  * tag.setTest("false");
104  * lifecycle.expectBodySkipped();
105  * lifecycle.invoke();</pre>
106  * </p>
107  * <p>
108  * An example of a more sophisticated expectationion is the
109  * {@link #expectScopedVariableExposed(String, Object[])}
110  * method, which can verify that a specific scoped variable gets exposed in
111  * the body of the tag, and that the exposed variable has a specific value in
112  * each iteration step:
113  * <pre>
114  * ForEachTag tag = new ForEachTag();
115  * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
116  * tag.setVar("item");
117  * tag.setItems("One,Two,Three");
118  * lifecycle.expectBodyEvaluated(3);
119  * lifecycle.expectScopedVariableExposed(
120  * "item", new Object[] {"One", "Two", "Three"});
121  * lifecycle.invoke();</pre>
122  * </p>
123  *
124  * <h4>Custom Expectations</h4>
125  * <p>
126  * In some cases, using the expectations offered by
127  * <code>JspTagLifecycle</code> does not suffice. In such cases, you need to
128  * use custom expectations. You can add custom expectations by creating a
129  * concrete subclass of the {@link JspTagLifecycle.Interceptor Interceptor}
130  * class, and adding it to the list of the tag lifecycles interceptors through
131  * {@link JspTagLifecycle#addInterceptor addInterceptor()}:
132  * <pre>
133  * ForEachTag tag = new ForEachTag();
134  * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
135  * tag.setVarStatus("status");
136  * tag.setBegin("0");
137  * tag.setEnd("2");
138  * lifecycle.addInterceptor(new JspTagLifecycle.Interceptor() {
139  * public void evalBody(int theIteration, BodyContent theBody) {
140  * LoopTagStatus status = (LoopTagStatus)
141  * pageContext.findAttribute("status");
142  * assertNotNull(status);
143  * if (theIteration == 0) {
144  * assertTrue(status.isFirst());
145  * assertFalse(status.isLast());
146  * }
147  * else if (theIteration == 1) {
148  * assertFalse(status.isFirst());
149  * assertFalse(status.isLast());
150  * }
151  * else if (theIteration == 2) {
152  * assertFalse(status.isFirst());
153  * assertTrue(status.isLast());
154  * }
155  * }
156  * });
157  * lifecycle.invoke();</pre>
158  * </p>
159  *
160  * <h4>Specifying Nested Content</h4>
161  * <p>
162  * <code>JspTagLifecycle</code> let's you add nested tempate text as well as
163  * nested tags to the tag under test. The most important use of this feature
164  * is testing of collaboration between tags, but it also allows you to easily
165  * check whether a tag correctly handles its body content.
166  * </p>
167  * <p>
168  * The following example demonstrates how to add nested template text to the
169  * tag, and how to assert that the body was written to the HTTP response on
170  * the client side:
171  * <pre>
172  * public void testOutTagDefaultBody() throws JspException, IOException {
173  * OutTag tag = new OutTag();
174  * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
175  * tag.setValue(null);
176  * lifecycle.addNestedText("Default");
177  * lifecycle.expectBodyEvaluated();
178  * lifecycle.invoke();
179  * }
180  * public void endOutTagDefaultBody(WebResponse theResponse) {
181  * String output = theResponse.getText();
182  * assertEquals("Default", output);
183  * }</pre>
184  * </p>
185  * <p>
186  * In sophisticated tag libraries, there will be many cases where tags need
187  * to collaborate with each other in some way. This is usually done by nesting
188  * such tags within eachother. <code>JspTagLifecycle</code> supports such
189  * scenarios by allowing you to add nested tags to an existing tag lifecycle.
190  * The nested tags can than be decorated with expectations themselves, as you
191  * can see in the following example:
192  * <pre>
193  * ChooseTag chooseTag = new ChooseTag();
194  * JspTagLifecycle chooseLifecycle =
195  * new JspTagLifecycle(pageContext, chooseTag);
196  * WhenTag whenTag = new WhenTag();
197  * JspTagLifecycle whenLifecycle =
198  * chooseLifecycle.addNestedTag(whenTag);
199  * whenTag.setTest("false");
200  * whenLifecycle.expectBodySkipped();
201  * OtherwiseTag otherwiseTag = new OtherwiseTag();
202  * JspTagLifecycle otherwiseLifecycle =
203  * chooseLifecycle.addNestedTag(otherwiseTag);
204  * otherwiseLifecycle.expectBodyEvaluated();
205  * chooseLifecycle.invoke();</pre>
206  * The code above creates a constellation of tags equivalent to the following
207  * JSP fragment:
208  * <pre>
209  * &lt;c:choose&gt;
210  * &lt;c:when test='false'&gt;
211  * &lt;%-- body content not significant for the test --%&gt;
212  * &lt;/c:when&gt;
213  * &lt;c:otherwise&gt;
214  * &lt;%-- body content not significant for the test --%&gt;
215  * &lt;/c:otherwise&gt;
216  * &lt;/c:choose&gt;</pre>
217  * </p>
218  *
219  * @since Cactus 1.5
220  *
221  * @version $Id: JspTagLifecycle.java,v 1.1 2004/05/22 11:34:48 vmassol Exp $
222  * @see org.apache.cactus.JspTestCase
223  */

224 public final class JspTagLifecycle
225 {
226     // Inner Classes -----------------------------------------------------------
227

228     /**
229      * Abstract class for intercepting the tag lifecycle. You can override any
230      * of the methods to insert expectations about the tag's behaviour while it
231      * is being executed.
232      *
233      * @since Cactus 1.5
234      */

235     public abstract static class Interceptor
236     {
237         
238         /**
239          * Method called when the body of the tag would be evaluated. Can be
240          * used in specific test cases to perform assertions.
241          *
242          * Please note that if you're testing a <code>BodyTag</code>, you
243          * should not write content to the
244          * {@link org.apache.cactus.JspTestCase#out} instance variable while
245          * the body is being evaluated. This is because the actual implicit
246          * object <code>out</code> in JSP pages gets replaced by the current
247          * nested <code>BodyContent</code>, whereas in <code>JspTestCase</code>
248          * the <code>out</code> variable always refers to the top level
249          * <code>JspWriter</code>. Instead, simply use the
250          * <code>BodyContent</code> parameter passed into the
251          * {@link JspTagLifecycle.Interceptor#evalBody evalBody()} method or
252          * the <code>JspWriter</code> retrieved by a call to
253          * {javax.servlet.jsp.PageContext#getOut pageContext.getOut()}.
254          *
255          * @param theIteration The number of times the body has been evaluated
256          * @param theBody The body content, or <tt>null</tt> if the tag isn't a
257          * <tt>BodyTag</tt>
258          * @throws JspException If thrown by a nested tag
259          * @throws IOException If an error occurs when reading or writing the
260          * body content
261          */

262         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
263             throws JspException JavaDoc, IOException JavaDoc
264         {
265             // default implementation does nothing
266
}
267         
268         /**
269          * Method called when the body of the tag would be skipped. Can be used
270          * in specific test cases to perform assertions.
271          */

272         public void skipBody()
273         {
274             // default implementation does nothing
275
}
276         
277     }
278     
279     /**
280      * A specialized interceptor that verifies that the tag's body is evaluated
281      * at least once.
282      *
283      * @since Cactus 1.5
284      */

285     private static class ExpectBodyEvaluatedInterceptor
286         extends Interceptor
287     {
288         /**
289          * The actual number of times the tag's body has been evaluated.
290          */

291         private int actualNumIterations;
292         
293         /**
294          * The number of times the tag's body is expected to be evaluated.
295          */

296         private int expectedNumIterations;
297         
298         /**
299          * Constructor.
300          *
301          * @param theNumIterations The number of iterations expected
302          */

303         public ExpectBodyEvaluatedInterceptor(int theNumIterations)
304         {
305             this.expectedNumIterations = theNumIterations;
306         }
307         
308         /**
309          * Overridden to assert that the body doesn't get evaluated more often
310          * than expected.
311          *
312          * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
313          */

314         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
315         {
316             actualNumIterations++;
317             if (actualNumIterations > expectedNumIterations)
318             {
319                 Assert.fail("Expected " + expectedNumIterations
320                     + " iterations, but was " + actualNumIterations);
321             }
322         }
323         
324         /**
325          * Overridden to assert that the body got evaluated as often as
326          * expected.
327          */

328         public void skipBody()
329         {
330             if (actualNumIterations < expectedNumIterations)
331             {
332                 Assert.fail("Expected " + expectedNumIterations
333                     + " iterations, but was " + actualNumIterations);
334             }
335         }
336     }
337     
338     /**
339      * A specialized interceptor that asserts that the tag's body is skipped.
340      *
341      * @since Cactus 1.5
342      */

343     private static class ExpectBodySkippedInterceptor
344         extends Interceptor
345     {
346         /**
347          * Overridden to assert that the body doesn't get evaluated.
348          *
349          * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
350          */

351         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
352         {
353             Assert.fail("Tag body should have been skipped");
354         }
355     }
356     
357     /**
358      * A specialized interceptor that checks whether a specific scoped variable
359      * is exposed in the body of the tag with a specific value.
360      *
361      * @since Cactus 1.5
362      */

363     private class ExpectScopedVariableExposedInterceptor
364         extends Interceptor
365     {
366         /**
367          * The name of the scoped variable.
368          */

369         private String JavaDoc name;
370         
371         /**
372          * The list of expected values of the variable.
373          */

374         private Object JavaDoc[] expectedValues;
375         
376         /**
377          * The scope in which the variable is stored.
378          */

379         private int scope;
380         
381         /**
382          * Constructor.
383          *
384          * @param theName The name of the scoped variable to check for
385          * @param theExpectedValues An array containing the expected values,
386          * one item for every iteration step
387          * @param theScope The scope to search for the scoped variable
388          */

389         public ExpectScopedVariableExposedInterceptor(String JavaDoc theName,
390             Object JavaDoc[] theExpectedValues, int theScope)
391         {
392             this.name = theName;
393             this.expectedValues = theExpectedValues;
394             this.scope = theScope;
395         }
396         
397         /**
398          * Overridden to assert that the scoped variable is exposed as expected.
399          *
400          * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
401          */

402         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
403         {
404             Assert.assertEquals(expectedValues[theIteration],
405                 pageContext.getAttribute(name, scope));
406         }
407     }
408     
409     /**
410      * A specialized interceptor that invokes the lifecycle of a nested tag.
411      *
412      * @since Cactus 1.5
413      */

414     private class NestedTagInterceptor
415         extends Interceptor
416     {
417         /**
418          * The lifecycle object of the nested tag.
419          */

420         private JspTagLifecycle lifecycle;
421         
422         /**
423          * Constructor.
424          *
425          * @param theLifecycle The lifecycle instance associated with the nested
426          * tag
427          */

428         public NestedTagInterceptor(JspTagLifecycle theLifecycle)
429         {
430             this.lifecycle = theLifecycle;
431         }
432         
433         /**
434          * Overridden to invoke the lifecycle of the nested tag.
435          *
436          * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
437          */

438         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
439             throws JspException JavaDoc, IOException JavaDoc
440         {
441             lifecycle.invoke();
442         }
443     }
444     
445     /**
446      * A specialized interceptor that prints nested template text when the tag's
447      * body is evaluated.
448      *
449      * @since Cactus 1.5
450      */

451     private class NestedTextInterceptor
452         extends Interceptor
453     {
454         /**
455          * The nested text.
456          */

457         private String JavaDoc text;
458         
459         /**
460          * Constructor.
461          *
462          * @param theText The nested text
463          */

464         public NestedTextInterceptor(String JavaDoc theText)
465         {
466             this.text = theText;
467         }
468         
469         /**
470          * Overridden to write the nested text to the current writer.
471          *
472          * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
473          */

474         public void evalBody(int theIteration, BodyContent JavaDoc theBody)
475             throws IOException JavaDoc
476         {
477             if (theBody != null)
478             {
479                 theBody.print(text);
480             }
481             else
482             {
483                 pageContext.getOut().print(text);
484             }
485         }
486     }
487     
488     // Class Variables ---------------------------------------------------------
489

490     /**
491      * The log target.
492      */

493     private static Log log = LogFactory.getLog(JspTagLifecycle.class);
494     
495     // Instance Variables ------------------------------------------------------
496

497     /**
498      * The JSP page context.
499      */

500     protected PageContext JavaDoc pageContext;
501     
502     /**
503      * The JSP tag handler.
504      */

505     private Tag JavaDoc tag;
506         
507     /**
508      * The interceptor chain.
509      */

510     private List JavaDoc interceptors;
511     
512     // Constructors ------------------------------------------------------------
513

514     /**
515      * Constructor.
516      *
517      * @param thePageContext The JSP page context
518      * @param theTag The JSP tag
519      */

520     public JspTagLifecycle(PageContext JavaDoc thePageContext, Tag JavaDoc theTag)
521     {
522         if ((thePageContext == null) || (theTag == null))
523         {
524             throw new NullPointerException JavaDoc();
525         }
526         this.tag = theTag;
527         this.pageContext = thePageContext;
528         this.tag.setPageContext(this.pageContext);
529     }
530     
531     // Public Methods ----------------------------------------------------------
532

533     /**
534      * Adds an interceptor to the interceptor chain.
535      *
536      * @param theInterceptor The interceptor to add
537      */

538     public void addInterceptor(Interceptor theInterceptor)
539     {
540         if (theInterceptor == null)
541         {
542             throw new NullPointerException JavaDoc();
543         }
544         if (this.interceptors == null)
545         {
546             this.interceptors = new ArrayList JavaDoc();
547         }
548         this.interceptors.add(theInterceptor);
549     }
550     
551     /**
552      * Adds a nested tag. The tag will be invoked when the body content of the
553      * enclosing tag is evaluated.
554      *
555      * @return The lifecycle wrapper for the nested tag, can be used to add
556      * expectations for the nested tag
557      * @param theNestedTag The tag to be nested
558      */

559     public JspTagLifecycle addNestedTag(Tag JavaDoc theNestedTag)
560     {
561         if (theNestedTag == null)
562         {
563             throw new NullPointerException JavaDoc();
564         }
565         JspTagLifecycle lifecycle =
566             new JspTagLifecycle(this.pageContext, theNestedTag);
567         theNestedTag.setParent(this.tag);
568         addInterceptor(new NestedTagInterceptor(lifecycle));
569         return lifecycle;
570     }
571     
572     /**
573      * Adds template text to nest inside the tag. The text will be printed to
574      * the body content when it is evaluated.
575      *
576      * @param theNestedText The string containing the template text
577      */

578     public void addNestedText(String JavaDoc theNestedText)
579     {
580         if (theNestedText == null)
581         {
582             throw new NullPointerException JavaDoc();
583         }
584         addInterceptor(new NestedTextInterceptor(theNestedText));
585     }
586     
587     /**
588      * Adds the expectation that the tag body must be evaluated once in the
589      * course of the tags lifecycle.
590      */

591     public void expectBodyEvaluated()
592     {
593         addInterceptor(new ExpectBodyEvaluatedInterceptor(1));
594     }
595     
596     /**
597      * Adds the expectation that the tag body must be evaluated a specific
598      * number of times in the course of the tags lifecycle.
599      *
600      * @param theNumIterations The number of times the body is expected to get
601      * evaluated
602      */

603     public void expectBodyEvaluated(int theNumIterations)
604     {
605         addInterceptor(new ExpectBodyEvaluatedInterceptor(theNumIterations));
606     }
607     
608     /**
609      * Adds the expectation that the tag body must be skipped. Essentially, this
610      * expectation verifies that the tag returns <code>SKIP_BODY</code> from
611      * <code>doStartTag()</code>.
612      */

613     public void expectBodySkipped()
614     {
615         addInterceptor(new ExpectBodySkippedInterceptor());
616     }
617     
618     /**
619      * Adds a special expectation that verifies that a specific scoped variable
620      * is exposed in the body of the tag.
621      *
622      * @param theName The name of the variable
623      * @param theExpectedValues An ordered list containing the expected values
624      * values of the scoped variable, one for each expected iteration
625      * step
626      */

627     public void expectScopedVariableExposed(String JavaDoc theName,
628         Object JavaDoc[] theExpectedValues)
629     {
630         expectScopedVariableExposed(theName, theExpectedValues,
631             PageContext.PAGE_SCOPE);
632     }
633     
634     /**
635      * Adds a special expectation that verifies that a specific scoped variable
636      * is exposed in the body of the tag.
637      *
638      * @param theName The name of the variable
639      * @param theExpectedValues An ordered list containing the expected values
640      * values of the scoped variable, one for each expected iteration
641      * step
642      * @param theScope The scope under which the variable is stored
643      */

644     public void expectScopedVariableExposed(String JavaDoc theName,
645         Object JavaDoc[] theExpectedValues, int theScope)
646     {
647         if ((theName == null) || (theExpectedValues == null))
648         {
649             throw new NullPointerException JavaDoc();
650         }
651         if (theExpectedValues.length == 0)
652         {
653             throw new IllegalArgumentException JavaDoc();
654         }
655         if ((theScope != PageContext.PAGE_SCOPE)
656          && (theScope != PageContext.REQUEST_SCOPE)
657          && (theScope != PageContext.SESSION_SCOPE)
658          && (theScope != PageContext.APPLICATION_SCOPE))
659         {
660             throw new IllegalArgumentException JavaDoc();
661         }
662         addInterceptor(
663             new ExpectScopedVariableExposedInterceptor(theName,
664                 theExpectedValues, theScope));
665     }
666     
667     /**
668      * Invokes the tag with the provided interceptor. The tag should have been
669      * populated with its properties before calling this method. The tag is not
670      * released after the tag's lifecycle is over.
671      *
672      * @throws JspException If the tag throws an exception
673      * @throws IOException If an error occurs when reading or writing the body
674      * content
675      */

676     public void invoke() throws JspException JavaDoc, IOException JavaDoc
677     {
678         if (this.tag instanceof TryCatchFinally JavaDoc)
679         {
680             TryCatchFinally JavaDoc tryCatchFinally = (TryCatchFinally JavaDoc) this.tag;
681             try
682             {
683                 invokeInternal();
684             }
685             catch (Throwable JavaDoc t1)
686             {
687                 try
688                 {
689                     tryCatchFinally.doCatch(t1);
690                 }
691                 catch (Throwable JavaDoc t2)
692                 {
693                     throw new JspException JavaDoc(t2.getMessage());
694                 }
695             }
696             finally
697             {
698                 tryCatchFinally.doFinally();
699             }
700         }
701         else
702         {
703             invokeInternal();
704         }
705     }
706     
707     // Private Methods ---------------------------------------------------------
708

709     /**
710      * Notify all interceptors about a body evaluation.
711      *
712      * @param theIteration The iteration
713      * @param theBody The body content
714      * @throws JspException If thrown by a nested tag
715      * @throws IOException If an error occurs when reading or writing the body
716      * content
717      */

718     private void fireEvalBody(int theIteration, BodyContent JavaDoc theBody)
719         throws JspException JavaDoc, IOException JavaDoc
720     {
721         if (this.interceptors != null)
722         {
723             for (Iterator JavaDoc i = this.interceptors.iterator(); i.hasNext();)
724             {
725                 ((Interceptor) i.next()).evalBody(theIteration, theBody);
726             }
727         }
728     }
729     
730     /**
731      * Notify all interceptors that the body has been skipped.
732      */

733     private void fireSkipBody()
734     {
735         if (this.interceptors != null)
736         {
737             for (Iterator JavaDoc i = this.interceptors.iterator(); i.hasNext();)
738             {
739                 ((Interceptor) i.next()).skipBody();
740             }
741         }
742     }
743     
744     /**
745      * Internal method to invoke a tag without doing exception handling.
746      *
747      * @throws JspException If the tag throws an exception
748      * @throws IOException If an error occurs when reading or writing the body
749      * content
750      */

751     private void invokeInternal()
752         throws JspException JavaDoc, IOException JavaDoc
753     {
754         int status = this.tag.doStartTag();
755         if (this.tag instanceof IterationTag JavaDoc)
756         {
757             if (status != Tag.SKIP_BODY)
758             {
759                 BodyContent JavaDoc body = null;
760                 try
761                 {
762                     IterationTag JavaDoc iterationTag = (IterationTag JavaDoc) this.tag;
763                     if ((status == BodyTag.EVAL_BODY_BUFFERED)
764                         && (this.tag instanceof BodyTag JavaDoc))
765                     {
766                         BodyTag JavaDoc bodyTag = (BodyTag JavaDoc) this.tag;
767                         body = pageContext.pushBody();
768                         if (log.isDebugEnabled())
769                         {
770                             log.debug("Pushed body content ["
771                                 + body.getString() + "]");
772                         }
773                         bodyTag.setBodyContent(body);
774                         bodyTag.doInitBody();
775                     }
776                     int iteration = 0;
777                     do
778                     {
779                         fireEvalBody(iteration, body);
780                         if (log.isDebugEnabled())
781                         {
782                             log.debug("Body evaluated for the ["
783                                 + iteration + "] time");
784                         }
785                         status = iterationTag.doAfterBody();
786                         iteration++;
787                     } while (status == IterationTag.EVAL_BODY_AGAIN);
788                     if (log.isDebugEnabled())
789                     {
790                         log.debug("Body skipped");
791                     }
792                     fireSkipBody();
793                 }
794                 finally
795                 {
796                     if (body != null)
797                     {
798                         if (log.isDebugEnabled())
799                         {
800                             log.debug("Popping body content ["
801                                 + body.getString() + "]");
802                         }
803                         pageContext.popBody();
804                         body = null;
805                     }
806                 }
807             }
808             else
809             {
810                 if (log.isDebugEnabled())
811                 {
812                     log.debug("Body skipped");
813                 }
814                 fireSkipBody();
815             }
816         }
817         status = tag.doEndTag();
818     }
819     
820 }
821
Popular Tags