Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.extension.jsp » [javadoc | source]
    1   /* 
    2    * ========================================================================
    3    * 
    4    * Licensed to the Apache Software Foundation (ASF) under one or more
    5    * contributor license agreements.  See the NOTICE file distributed with
    6    * this work for additional information regarding copyright ownership.
    7    * The ASF licenses this file to You under the Apache License, Version 2.0
    8    * (the "License"); you may not use this file except in compliance with
    9    * the License.  You may obtain a copy of the License at
   10    * 
   11    *   http://www.apache.org/licenses/LICENSE-2.0
   12    * 
   13    * Unless required by applicable law or agreed to in writing, software
   14    * distributed under the License is distributed on an "AS IS" BASIS,
   15    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   16    * See the License for the specific language governing permissions and
   17    * limitations under the License.
   18    * 
   19    * ========================================================================
   20    */
   21   package org.apache.cactus.extension.jsp;
   22   
   23   import java.io.IOException;
   24   import java.util.ArrayList;
   25   import java.util.Iterator;
   26   import java.util.List;
   27   
   28   import junit.framework.Assert;
   29   
   30   import javax.servlet.jsp.JspException;
   31   import javax.servlet.jsp.PageContext;
   32   import javax.servlet.jsp.tagext.BodyContent;
   33   import javax.servlet.jsp.tagext.BodyTag;
   34   import javax.servlet.jsp.tagext.IterationTag;
   35   import javax.servlet.jsp.tagext.Tag;
   36   import javax.servlet.jsp.tagext.TryCatchFinally;
   37   
   38   import org.apache.commons.logging.Log;
   39   import org.apache.commons.logging.LogFactory;
   40   
   41   /**
   42    * Convenience class that supports the testing of JSP tag by managing the tag's
   43    * lifecycle as required by the JSP specification.
   44    * 
   45    * <p>
   46    *   This class is basically a stub implementation of the tag management
   47    *   facilities that an actual JSP container would provide. The implementation
   48    *   attempts to follow the specification as closely as possible, but the tag
   49    *   handling functionality of real JSP implementations may vary in some
   50    *   details.
   51    * </p>
   52    * 
   53    * <p>
   54    *   Although this class works quite well when used in the test methods of a 
   55    *   {@link org.apache.cactus.JspTestCase JspTestCase}, it can also safely be
   56    *   used outside of the Cactus testing framework, for example when following
   57    *   a mock objects approach.
   58    * </p>
   59    * 
   60    * <h4>Testing Simple Tags</h4>
   61    * <p>
   62    *   This is how you would use this class when testing the
   63    *   <code>&lt;c:set&gt;</code>-tag of the JSTL reference implementation:
   64    *   <blockquote><pre>
   65     SetTag tag = new SetTag();
   66     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
   67     tag.setVar("name");
   68     tag.setValue("value");
   69     lifecycle.invoke();
   70     assertEquals("value", pageContext.findAttribute("name"));</pre>
   71    *   </blockquote>
   72    *   The order is important:
   73    *   <ol>
   74    *     <li>
   75    *       Instantiation of the tag under test
   76    *     </li>
   77    *     <li>
   78    *       Instantiation of the lifecycle helper, passing in the page context and
   79    *       the tag instance
   80    *     </li>
   81    *     <li>
   82    *       Set the tag's attributes
   83    *     </li>
   84    *     <li>
   85    *       Start the tag's lifecycle by calling
   86    *       {@link #invoke() JspTagLifecycle.invoke()}
   87    *     </li>
   88    *     <li>
   89    *       Make assertions
   90    *     </li>
   91    *   </ol>
   92    * </p>
   93    * 
   94    * <h4>Adding Expectations to the Lifecycle</h4>
   95    * <p>
   96    *   <code>JspTagLifecycle</code> features a couple of methods that let you 
   97    *   easily add expectations about the tag's lifecycle to the test. For example,
   98    *   the method {@link #expectBodySkipped expectBodySkipped()} can be used to 
   99    *   verify that tag's body is not evaluated under the conditions set up by the
  100    *   test:
  101    *   <pre>
  102    * IfTag tag = new IfTag();
  103    * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
  104    * tag.setTest("false");
  105    * lifecycle.expectBodySkipped();
  106    * lifecycle.invoke();</pre>
  107    * </p>
  108    * <p>
  109    *   An example of a more sophisticated expectationion is the
  110    *   {@link #expectScopedVariableExposed(String, Object[])}
  111    *   method, which can verify that a specific scoped variable gets exposed in
  112    *   the body of the tag, and that the exposed variable has a specific value in
  113    *   each iteration step:
  114    *   <pre>
  115    * ForEachTag tag = new ForEachTag();
  116    * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
  117    * tag.setVar("item");
  118    * tag.setItems("One,Two,Three");
  119    * lifecycle.expectBodyEvaluated(3);
  120    * lifecycle.expectScopedVariableExposed(
  121    *     "item", new Object[] {"One", "Two", "Three"});
  122    * lifecycle.invoke();</pre>
  123    * </p>
  124    * 
  125    * <h4>Custom Expectations</h4>
  126    * <p>
  127    *   In some cases, using the expectations offered by 
  128    *   <code>JspTagLifecycle</code> does not suffice. In such cases, you need to 
  129    *   use custom expectations. You can add custom expectations by creating a 
  130    *   concrete subclass of the {@link JspTagLifecycle.Interceptor Interceptor}
  131    *   class, and adding it to the list of the tag lifecycles interceptors through
  132    *   {@link JspTagLifecycle#addInterceptor addInterceptor()}:
  133    *   <pre>
  134    * ForEachTag tag = new ForEachTag();
  135    * JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
  136    * tag.setVarStatus("status");
  137    * tag.setBegin("0");
  138    * tag.setEnd("2");
  139    * lifecycle.addInterceptor(new JspTagLifecycle.Interceptor() {
  140    *     public void evalBody(int theIteration, BodyContent theBody) {
  141    *         LoopTagStatus status = (LoopTagStatus)
  142    *             pageContext.findAttribute("status");
  143    *         assertNotNull(status);
  144    *         if (theIteration == 0) {
  145    *             assertTrue(status.isFirst());
  146    *             assertFalse(status.isLast());
  147    *         }
  148    *         else if (theIteration == 1) {
  149    *             assertFalse(status.isFirst());
  150    *             assertFalse(status.isLast());
  151    *         }
  152    *         else if (theIteration == 2) {
  153    *             assertFalse(status.isFirst());
  154    *             assertTrue(status.isLast());
  155    *         }
  156    *     }
  157    * });
  158    * lifecycle.invoke();</pre>
  159    * </p>
  160    * 
  161    * <h4>Specifying Nested Content</h4>
  162    * <p>
  163    *   <code>JspTagLifecycle</code> let's you add nested tempate text as well as 
  164    *   nested tags to the tag under test. The most important use of this feature 
  165    *   is testing of collaboration between tags, but it also allows you to easily
  166    *   check whether a tag correctly handles its body content.
  167    * </p>
  168    * <p>
  169    *   The following example demonstrates how to add nested template text to the 
  170    *   tag, and how to assert that the body was written to the HTTP response on
  171    *   the client side:
  172    *   <pre>
  173    * public void testOutTagDefaultBody() throws JspException, IOException {
  174    *     OutTag tag = new OutTag();
  175    *     JspTagLifecycle lifecycle = new JspTagLifecycle(pageContext, tag);
  176    *     tag.setValue(null);
  177    *     lifecycle.addNestedText("Default");
  178    *     lifecycle.expectBodyEvaluated();
  179    *     lifecycle.invoke();
  180    * }
  181    * public void endOutTagDefaultBody(WebResponse theResponse) {
  182    *     String output = theResponse.getText();
  183    *     assertEquals("Default", output);
  184    * }</pre>
  185    * </p>
  186    * <p>
  187    *   In sophisticated tag libraries, there will be many cases where tags need 
  188    *   to collaborate with each other in some way. This is usually done by nesting
  189    *   such tags within eachother. <code>JspTagLifecycle</code> supports such 
  190    *   scenarios by allowing you to add nested tags to an existing tag lifecycle.
  191    *   The nested tags can than be decorated with expectations themselves, as you
  192    *   can see in the following example:
  193    *   <pre>
  194    * ChooseTag chooseTag = new ChooseTag();
  195    * JspTagLifecycle chooseLifecycle =
  196    *     new JspTagLifecycle(pageContext, chooseTag);
  197    * WhenTag whenTag = new WhenTag();
  198    * JspTagLifecycle whenLifecycle =
  199    *     chooseLifecycle.addNestedTag(whenTag);
  200    * whenTag.setTest("false");
  201    * whenLifecycle.expectBodySkipped();
  202    * OtherwiseTag otherwiseTag = new OtherwiseTag();
  203    * JspTagLifecycle otherwiseLifecycle =
  204    *     chooseLifecycle.addNestedTag(otherwiseTag);
  205    * otherwiseLifecycle.expectBodyEvaluated();
  206    * chooseLifecycle.invoke();</pre>
  207    *   The code above creates a constellation of tags equivalent to the following
  208    *   JSP fragment:
  209    *   <pre>
  210    * &lt;c:choose&gt;
  211    *  &lt;c:when test='false'&gt;
  212    *   &lt;%-- body content not significant for the test --%&gt;
  213    *  &lt;/c:when&gt;
  214    *  &lt;c:otherwise&gt;
  215    *   &lt;%-- body content not significant for the test --%&gt;
  216    *  &lt;/c:otherwise&gt;
  217    * &lt;/c:choose&gt;</pre>
  218    * </p>
  219    * 
  220    * @since Cactus 1.5
  221    * 
  222    * @version $Id: JspTagLifecycle.java 238991 2004-05-22 11:34:50Z vmassol $
  223    * @see org.apache.cactus.JspTestCase
  224    */
  225   public final class JspTagLifecycle
  226   {   
  227       // Inner Classes -----------------------------------------------------------
  228       
  229       /**
  230        * Abstract class for intercepting the tag lifecycle. You can override any
  231        * of the methods to insert expectations about the tag's behaviour while it
  232        * is being executed.
  233        * 
  234        * @since Cactus 1.5
  235        */
  236       public abstract static class Interceptor
  237       {
  238           
  239           /**
  240            * Method called when the body of the tag would be evaluated. Can be
  241            * used in specific test cases to perform assertions.
  242            * 
  243            * Please note that if you're testing a <code>BodyTag</code>, you
  244            * should not write content to the
  245            * {@link org.apache.cactus.JspTestCase#out} instance variable while 
  246            * the body is being evaluated. This is because the actual implicit
  247            * object <code>out</code> in JSP pages gets replaced by the current 
  248            * nested <code>BodyContent</code>, whereas in <code>JspTestCase</code>
  249            * the <code>out</code> variable always refers to the top level
  250            * <code>JspWriter</code>. Instead, simply use the 
  251            * <code>BodyContent</code> parameter passed into the
  252            * {@link JspTagLifecycle.Interceptor#evalBody evalBody()} method or 
  253            * the <code>JspWriter</code> retrieved by a call to 
  254            * {javax.servlet.jsp.PageContext#getOut pageContext.getOut()}. 
  255            * 
  256            * @param theIteration The number of times the body has been evaluated
  257            * @param theBody The body content, or <tt>null</tt> if the tag isn't a
  258            *        <tt>BodyTag</tt>
  259            * @throws JspException If thrown by a nested tag
  260            * @throws IOException If an error occurs when reading or writing the
  261            *         body content
  262            */
  263           public void evalBody(int theIteration, BodyContent theBody)
  264               throws JspException, IOException
  265           {
  266               // default implementation does nothing
  267           }
  268           
  269           /**
  270            * Method called when the body of the tag would be skipped. Can be used 
  271            * in specific test cases to perform assertions.
  272            */
  273           public void skipBody()
  274           {
  275               // default implementation does nothing
  276           }
  277           
  278       }
  279       
  280       /**
  281        * A specialized interceptor that verifies that the tag's body is evaluated
  282        * at least once.
  283        * 
  284        * @since Cactus 1.5
  285        */
  286       private static class ExpectBodyEvaluatedInterceptor
  287           extends Interceptor
  288       {
  289           /**
  290            * The actual number of times the tag's body has been evaluated.
  291            */
  292           private int actualNumIterations;
  293           
  294           /**
  295            * The number of times the tag's body is expected to be evaluated.
  296            */
  297           private int expectedNumIterations;
  298           
  299           /**
  300            * Constructor.
  301            * 
  302            * @param theNumIterations The number of iterations expected
  303            */
  304           public ExpectBodyEvaluatedInterceptor(int theNumIterations)
  305           {
  306               this.expectedNumIterations = theNumIterations;
  307           }
  308           
  309           /**
  310            * Overridden to assert that the body doesn't get evaluated more often
  311            * than expected.
  312            * 
  313            * {@inheritDoc}
  314            * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
  315            */
  316           public void evalBody(int theIteration, BodyContent theBody)
  317           {
  318               actualNumIterations++;
  319               if (actualNumIterations > expectedNumIterations)
  320               {
  321                   Assert.fail("Expected " + expectedNumIterations
  322                       + " iterations, but was " + actualNumIterations);
  323               }
  324           }
  325           
  326           /**
  327            * Overridden to assert that the body got evaluated as often as
  328            * expected.
  329            */
  330           public void skipBody()
  331           {
  332               if (actualNumIterations < expectedNumIterations)
  333               {
  334                   Assert.fail("Expected " + expectedNumIterations
  335                       + " iterations, but was " + actualNumIterations);
  336               }
  337           }
  338       }
  339       
  340       /**
  341        * A specialized interceptor that asserts that the tag's body is skipped.
  342        * 
  343        * @since Cactus 1.5
  344        */
  345       private static class ExpectBodySkippedInterceptor
  346           extends Interceptor
  347       {
  348           /**
  349            * Overridden to assert that the body doesn't get evaluated.
  350            * 
  351            * {@inheritDoc}
  352            * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
  353            */
  354           public void evalBody(int theIteration, BodyContent theBody)
  355           {
  356               Assert.fail("Tag body should have been skipped");
  357           }
  358       }
  359       
  360       /**
  361        * A specialized interceptor that checks whether a specific scoped variable
  362        * is exposed in the body of the tag with a specific value.
  363        * 
  364        * @since Cactus 1.5
  365        */
  366       private class ExpectScopedVariableExposedInterceptor
  367           extends Interceptor
  368       {
  369           /**
  370            * The name of the scoped variable.
  371            */
  372           private String name;
  373           
  374           /**
  375            * The list of expected values of the variable.
  376            */
  377           private Object[] expectedValues;
  378           
  379           /**
  380            * The scope in which the variable is stored.
  381            */
  382           private int scope;
  383           
  384           /**
  385            * Constructor.
  386            * 
  387            * @param theName The name of the scoped variable to check for
  388            * @param theExpectedValues An array containing the expected values, 
  389            *        one item for every iteration step
  390            * @param theScope The scope to search for the scoped variable
  391            */
  392           public ExpectScopedVariableExposedInterceptor(String theName,
  393               Object[] theExpectedValues, int theScope)
  394           {
  395               this.name = theName;
  396               this.expectedValues = theExpectedValues;
  397               this.scope = theScope;
  398           }
  399           
  400           /**
  401            * Overridden to assert that the scoped variable is exposed as expected.
  402            * 
  403            * {@inheritDoc}
  404            * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
  405            */
  406           public void evalBody(int theIteration, BodyContent theBody)
  407           {
  408               Assert.assertEquals(expectedValues[theIteration],
  409                   pageContext.getAttribute(name, scope));
  410           }
  411       }
  412       
  413       /**
  414        * A specialized interceptor that invokes the lifecycle of a nested tag.
  415        * 
  416        * @since Cactus 1.5
  417        */
  418       private class NestedTagInterceptor
  419           extends Interceptor
  420       {
  421           /**
  422            * The lifecycle object of the nested tag.
  423            */
  424           private JspTagLifecycle lifecycle;
  425           
  426           /**
  427            * Constructor.
  428            * 
  429            * @param theLifecycle The lifecycle instance associated with the nested
  430            *        tag
  431            */
  432           public NestedTagInterceptor(JspTagLifecycle theLifecycle)
  433           {
  434               this.lifecycle = theLifecycle;
  435           }
  436           
  437           /**
  438            * Overridden to invoke the lifecycle of the nested tag.
  439            * 
  440            * {@inheritDoc}
  441            * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
  442            */
  443           public void evalBody(int theIteration, BodyContent theBody)
  444               throws JspException, IOException
  445           {
  446               lifecycle.invoke();
  447           }
  448       }
  449       
  450       /**
  451        * A specialized interceptor that prints nested template text when the tag's
  452        * body is evaluated.
  453        * 
  454        * @since Cactus 1.5
  455        */
  456       private class NestedTextInterceptor
  457           extends Interceptor
  458       {
  459           /**
  460            * The nested text.
  461            */
  462           private String text;
  463           
  464           /**
  465            * Constructor.
  466            * 
  467            * @param theText The nested text
  468            */
  469           public NestedTextInterceptor(String theText)
  470           {
  471               this.text = theText;
  472           }
  473           
  474           /**
  475            * Overridden to write the nested text to the current writer.
  476            * 
  477            * {@inheritDoc}
  478            * @see JspTagLifecycle.Interceptor#evalBody(int,BodyContent)
  479            */
  480           public void evalBody(int theIteration, BodyContent theBody)
  481               throws IOException
  482           {
  483               if (theBody != null)
  484               {
  485                   theBody.print(text);
  486               }
  487               else
  488               {
  489                   pageContext.getOut().print(text);
  490               }
  491           }
  492       }
  493       
  494       // Class Variables ---------------------------------------------------------
  495       
  496       /**
  497        * The log target.
  498        */
  499       private static Log log = LogFactory.getLog(JspTagLifecycle.class);
  500       
  501       // Instance Variables ------------------------------------------------------
  502       
  503       /**
  504        * The JSP page context.
  505        */
  506       protected PageContext pageContext;
  507       
  508       /**
  509        * The JSP tag handler.
  510        */
  511       private Tag tag;
  512           
  513       /**
  514        * The interceptor chain.
  515        */
  516       private List interceptors;
  517       
  518       // Constructors ------------------------------------------------------------
  519       
  520       /**
  521        * Constructor.
  522        * 
  523        * @param thePageContext The JSP page context
  524        * @param theTag The JSP tag
  525        */
  526       public JspTagLifecycle(PageContext thePageContext, Tag theTag)
  527       {
  528           if ((thePageContext == null) || (theTag == null))
  529           {
  530               throw new NullPointerException();
  531           }
  532           this.tag = theTag;
  533           this.pageContext = thePageContext;
  534           this.tag.setPageContext(this.pageContext);
  535       }
  536       
  537       // Public Methods ----------------------------------------------------------
  538       
  539       /**
  540        * Adds an interceptor to the interceptor chain.
  541        * 
  542        * @param theInterceptor The interceptor to add
  543        */
  544       public void addInterceptor(Interceptor theInterceptor)
  545       {
  546           if (theInterceptor == null)
  547           {
  548               throw new NullPointerException();
  549           }
  550           if (this.interceptors == null)
  551           {
  552               this.interceptors = new ArrayList();
  553           }
  554           this.interceptors.add(theInterceptor);
  555       }
  556       
  557       /**
  558        * Adds a nested tag. The tag will be invoked when the body content of the
  559        * enclosing tag is evaluated.
  560        * 
  561        * @return The lifecycle wrapper for the nested tag, can be used to add 
  562        *         expectations for the nested tag
  563        * @param theNestedTag The tag to be nested
  564        */
  565       public JspTagLifecycle addNestedTag(Tag theNestedTag)
  566       {
  567           if (theNestedTag == null)
  568           {
  569               throw new NullPointerException();
  570           }
  571           JspTagLifecycle lifecycle =
  572               new JspTagLifecycle(this.pageContext, theNestedTag);
  573           theNestedTag.setParent(this.tag);
  574           addInterceptor(new NestedTagInterceptor(lifecycle));
  575           return lifecycle;
  576       }
  577       
  578       /**
  579        * Adds template text to nest inside the tag. The text will be printed to 
  580        * the body content when it is evaluated.
  581        * 
  582        * @param theNestedText The string containing the template text
  583        */
  584       public void addNestedText(String theNestedText)
  585       {
  586           if (theNestedText == null)
  587           {
  588               throw new NullPointerException();
  589           }
  590           addInterceptor(new NestedTextInterceptor(theNestedText));
  591       }
  592       
  593       /**
  594        * Adds the expectation that the tag body must be evaluated once in the 
  595        * course of the tags lifecycle.
  596        */
  597       public void expectBodyEvaluated()
  598       {
  599           addInterceptor(new ExpectBodyEvaluatedInterceptor(1));
  600       }
  601       
  602       /**
  603        * Adds the expectation that the tag body must be evaluated a specific
  604        * number of times in the course of the tags lifecycle.
  605        * 
  606        * @param theNumIterations The number of times the body is expected to get 
  607        *        evaluated
  608        */
  609       public void expectBodyEvaluated(int theNumIterations)
  610       {
  611           addInterceptor(new ExpectBodyEvaluatedInterceptor(theNumIterations));
  612       }
  613       
  614       /**
  615        * Adds the expectation that the tag body must be skipped. Essentially, this
  616        * expectation verifies that the tag returns <code>SKIP_BODY</code> from
  617        * <code>doStartTag()</code>.
  618        */
  619       public void expectBodySkipped()
  620       {
  621           addInterceptor(new ExpectBodySkippedInterceptor());
  622       }
  623       
  624       /**
  625        * Adds a special expectation that verifies that a specific scoped variable
  626        * is exposed in the body of the tag.
  627        * 
  628        * @param theName The name of the variable
  629        * @param theExpectedValues An ordered list containing the expected values 
  630        *        values of the scoped variable, one for each expected iteration
  631        *        step
  632        */
  633       public void expectScopedVariableExposed(String theName,
  634           Object[] theExpectedValues)
  635       {
  636           expectScopedVariableExposed(theName, theExpectedValues,
  637               PageContext.PAGE_SCOPE);
  638       }
  639       
  640       /**
  641        * Adds a special expectation that verifies that a specific scoped variable
  642        * is exposed in the body of the tag.
  643        * 
  644        * @param theName The name of the variable
  645        * @param theExpectedValues An ordered list containing the expected values 
  646        *        values of the scoped variable, one for each expected iteration
  647        *        step
  648        * @param theScope The scope under which the variable is stored
  649        */
  650       public void expectScopedVariableExposed(String theName,
  651           Object[] theExpectedValues, int theScope)
  652       {
  653           if ((theName == null) || (theExpectedValues == null))
  654           {
  655               throw new NullPointerException();
  656           }
  657           if (theExpectedValues.length == 0)
  658           {
  659               throw new IllegalArgumentException();
  660           }
  661           if ((theScope != PageContext.PAGE_SCOPE)
  662            && (theScope != PageContext.REQUEST_SCOPE)
  663            && (theScope != PageContext.SESSION_SCOPE)
  664            && (theScope != PageContext.APPLICATION_SCOPE))
  665           {
  666               throw new IllegalArgumentException();
  667           }
  668           addInterceptor(
  669               new ExpectScopedVariableExposedInterceptor(theName,
  670                   theExpectedValues, theScope));
  671       }
  672       
  673       /**
  674        * Invokes the tag with the provided interceptor. The tag should have been
  675        * populated with its properties before calling this method. The tag is not
  676        * released after the tag's lifecycle is over.
  677        * 
  678        * @throws JspException If the tag throws an exception
  679        * @throws IOException If an error occurs when reading or writing the body
  680        *         content
  681        */
  682       public void invoke() throws JspException, IOException
  683       {
  684           if (this.tag instanceof TryCatchFinally)
  685           {
  686               TryCatchFinally tryCatchFinally = (TryCatchFinally) this.tag;
  687               try
  688               {
  689                   invokeInternal();
  690               }
  691               catch (Throwable t1)
  692               {
  693                   try
  694                   {
  695                       tryCatchFinally.doCatch(t1);
  696                   }
  697                   catch (Throwable t2)
  698                   {
  699                       throw new JspException(t2.getMessage());
  700                   }
  701               }
  702               finally
  703               {
  704                   tryCatchFinally.doFinally();
  705               }
  706           }
  707           else
  708           {
  709               invokeInternal();
  710           }
  711       }
  712       
  713       // Private Methods ---------------------------------------------------------
  714       
  715       /**
  716        * Notify all interceptors about a body evaluation.
  717        * 
  718        * @param theIteration The iteration
  719        * @param theBody The body content
  720        * @throws JspException If thrown by a nested tag
  721        * @throws IOException If an error occurs when reading or writing the body
  722        *         content
  723        */
  724       private void fireEvalBody(int theIteration, BodyContent theBody)
  725           throws JspException, IOException
  726       {
  727           if (this.interceptors != null)
  728           {
  729               for (Iterator i = this.interceptors.iterator(); i.hasNext();)
  730               {
  731                   ((Interceptor) i.next()).evalBody(theIteration, theBody);
  732               }
  733           }
  734       }
  735       
  736       /**
  737        * Notify all interceptors that the body has been skipped.
  738        */
  739       private void fireSkipBody()
  740       {
  741           if (this.interceptors != null)
  742           {
  743               for (Iterator i = this.interceptors.iterator(); i.hasNext();)
  744               {
  745                   ((Interceptor) i.next()).skipBody();
  746               }
  747           }
  748       }
  749       
  750       /**
  751        * Internal method to invoke a tag without doing exception handling.
  752        * 
  753        * @throws JspException If the tag throws an exception
  754        * @throws IOException If an error occurs when reading or writing the body
  755        *         content
  756        */
  757       private void invokeInternal()
  758           throws JspException, IOException
  759       {
  760           int status = this.tag.doStartTag();
  761           if (this.tag instanceof IterationTag)
  762           {
  763               if (status != Tag.SKIP_BODY)
  764               {
  765                   BodyContent body = null;
  766                   try
  767                   {
  768                       IterationTag iterationTag = (IterationTag) this.tag;
  769                       if ((status == BodyTag.EVAL_BODY_BUFFERED)
  770                           && (this.tag instanceof BodyTag))
  771                       {
  772                           BodyTag bodyTag = (BodyTag) this.tag;
  773                           body = pageContext.pushBody();
  774                           if (log.isDebugEnabled())
  775                           {
  776                               log.debug("Pushed body content ["
  777                                   + body.getString() + "]");
  778                           }
  779                           bodyTag.setBodyContent(body);
  780                           bodyTag.doInitBody();
  781                       }
  782                       int iteration = 0;
  783                       do
  784                       {
  785                           fireEvalBody(iteration, body);
  786                           if (log.isDebugEnabled())
  787                           {
  788                               log.debug("Body evaluated for the ["
  789                                   + iteration + "] time");
  790                           }
  791                           status = iterationTag.doAfterBody();
  792                           iteration++;
  793                       } while (status == IterationTag.EVAL_BODY_AGAIN);
  794                       if (log.isDebugEnabled())
  795                       {
  796                           log.debug("Body skipped");
  797                       }
  798                       fireSkipBody();
  799                   }
  800                   finally
  801                   {
  802                       if (body != null)
  803                       {
  804                           if (log.isDebugEnabled())
  805                           {
  806                               log.debug("Popping body content ["
  807                                   + body.getString() + "]");
  808                           }
  809                           pageContext.popBody();
  810                           body = null;
  811                       }
  812                   }
  813               }
  814               else
  815               {
  816                   if (log.isDebugEnabled())
  817                   {
  818                       log.debug("Body skipped");
  819                   }
  820                   fireSkipBody();
  821               }
  822           }
  823           status = tag.doEndTag();
  824       }
  825       
  826   }

Save This Page
Home » cactus-1.8.0-src » org.apache.cactus.extension.jsp » [javadoc | source]