<taglib:tutorial lesson="11">

In this lesson, we will take advantage of the new TryCatchFinally interface and how we can utilize that as Tag developers.

1 Lesson 11, Taking advantage of TryCatchFinally

    In this lesson, we will learn how to take advantage of the new TryCatchFinally interface and have a look at how we can utilize this new interface as Tag developers. We will then write an Exception catching Tag in order to show how we can utilize this new interface to catch Exceptions thrown in parts of a page, which could prove to be a useful addition to our Tag libraries.

    Throughout this lesson, we will continue to use the setup previously defined for this tutorial. You should feel comfortable about the Tag interface, the TagSupport class and BodyTags before starting on this lesson.

2 What is the TryCatchFinally interface?

    The TryCatchFinally interface is another addition made to the Taglibrary API in JSP 1.2. Any Tag or BodyTag implementation might extend this interface in order to be given the features required to properly handle its resources in the event of an unhandled situation.


    Figure 1. The TryCatchFinally interface

    In figure 1 above it can be seen that the interface adds the methods doCatch and doFinally. Whenever an Exception occurs inside the body of the Tag implementing this interface, the doCatch() method will be called. The same goes for any Exceptions thrown from within the Tag.doStartTag(), Tag.doEndTag(), IterationTag.doAfterBody() and BodyTag.doInitBody() methods.


    Figure 2: A sequence diagram showing the interaction between the Container and a Tag implementing the TryCatchFinally interface.

    As seen in figure 2 above, when a JSP page is parsed and a Tag implementing the TryCatchFinally interface is encountered, the Container will:

    1. Use the setPageContext() method of the Tag to set the current PageContext for it to use.

    2. Use the setParent() method to set any parent of the encountered Tag (or null if none).

    3. Set any attributes defined to be given to the Tag.

    4. Start the try{} statement.

    5. Call the doStartTag() method. This method can either return EVAL_BODY_INCLUDE (EVAL_BODY_BUFFERED for BodyTags) or SKIP_BODY. If EVAL_BODY_INCLUDE is returned, the Tags body will be evaluated. If SKIP_BODY is returned, the Container will not evaluate the body of the Tag.

    6. Call the doAfterBody() method after every body evaluation. This method can either return EVAL_BODY_AGAIN or SKIP_BODY. If EVAL_BODY_AGAIN is returned, the Tags body will be re-evaluated. If SKIP_BODY is returned, the Container will not re-evaluate the body of the Tag, but call doEndTag instead.

    7. Call the doEndTag() method. This method can either return EVAL_PAGE or SKIP_PAGE. IF EVAL_PAGE is returned, the Container will continue to evaluate the JSP page when done with this Tag. If SKIP_PAGE is returned, the Container will stop evaluating the page when it's done with this Tag.

    8. If any exception was thrown, call the doCatch() method. This method might throw the caught or another Throwable onwards up the chain.

    9. Call the doFinally() method. This method will always get called for a Tag implementing the TryCatchFinally interface, Exception thrown or not.

    10. Call the release() method. This method can be used by the Tag developer to release any resources that the Tag was using. Please notice that it is up to the Container to call the release() method when seemed fit, so you can't rely on this method being called at any specific time. In theory, this method could be called 12 days after the Tag was used. For this reason, any code that must be executed at the end of the Tag usage should be called from the doEndTag() method (see 7 above).

    This new interface comes in very handy when dealing with resources such as DataSource connections and such, where some method must always be called at the end to free up limited resources.

    Although this new interface gives us a number of new possibilities, there isn't that much more to say about it. We will therefore end this introduction to the TryCatchFinally interface so that we can get down to using it instead. If you want to learn more or get a deeper understanding about the TryCatchFinally class, consult the JSP 1.2 API or the JSP 1.2 specification.

3 Writing the Exception-catching Tag

    The Tag we will now write will be able to catch any Exception thrown in its body and then replace the body content with a message passed in as a parameter. By default, the Tag will log the Exception, but by making this a parameter this behaviour can be controlled by the page author.

    This could for instance be used in a page that includes a number of other pages from different locations/resources, so that if the included page fails to be included, a previously defined message can be displayed instead.


    Figure 4: The ErrorTag class extends BodyTagSupport class and implements the TryCatchFinally interface

    The ErrorTag shown in figure 4 above extends a normal BodyTagSupport class in order to utilize its standard Tag behaviour without overriding a single method. We need to extend BodyTagSupport instead of TagSupport as our new Tag will modify its body content. The part of interest is the implementation of the TryCatchFinally interface and its doCatch() and doFinally() methods. As will be covered in greater detail below, the doCatch() method will be used to catch and optionally log any Exception thrown in the body of the Tag, while the doFinally() method will be used to clear the body content of the Tag and instead write a message that will be passed in as a parameter, if and only if an Exception has been caught.

    1. In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'ErrorTag.java' with the following content:


      package com.acme.tag;

      import javax.servlet.jsp.*;
      import javax.servlet.jsp.tagext.*;
      import java.util.*;

      public class ErrorTag extends BodyTagSupport implements TryCatchFinally
      {
      private String message;
      private boolean log=true;
      private boolean exceptionThrown;
      Listing 1: Define the variables that the tag will need.

      Above we define the two variables message and log. The former will be used to specify a message to display instead the body content of the tag where the Exception originated, while the later will tell our Tag if it should write the Exception to the log or not.

      The third variable will be used to remember if an Exception has been thrown or not.

    2. Add the following method:


      public void setMessage(String message)
      {
      this.message = message;
      }
      Listing 2: Adding the setMessage() method.

      The JSP container calls the method above to set the message attribute with the value that the author has given.

    3. Add the following method:


      public void setLog(boolean log)
      {
      this.log=log;
      }
      Listing 3: Adding the setLog() method.

      The JSP container calls the method above to set the log attribute with the value that the author has given.

    4. Continue with the following method:


      public void doCatch(Throwable throwable) throws Throwable
      {
      if(log)
      this.pageContext.getServletContext().log("Exception caught in "+((HttpServletRequest)this.pageContext.getRequest()).getRequestURL(),throwable);
      exceptionThrown = true;

      }
      Listing 4: Adding the doCatch method.

      In the implementation of the doCatch() method of the TryCatchFinally interface in listing 4 above we write the thrown Exception to the log, but only if the log attribute is true.

    5. Continue with the last method:


      public void doFinally()
      {
      if(exceptionThrown)
      {
      try
      {
      bodyContent.clearBody();
      bodyContent.write(message);
      bodyContent.writeOut(bodyContent.getEnclosingWriter());
      }
      catch(IOException e)
      {
      this.pageContext.getServletContext().log("Exception within ErrorTag", e);
      }
      }
      message = null;
      log = true;
      exceptionThrown = false;
      }
      }
      Listing 5: Adding the last method.

      In the implementation of the doFinally() method above, we first check if an Exception has been thrown or not. If this is the case, then we first clear any existing body content before we add the message passed in as a parameter to the Tag by the page author.

      Finally, we make sure to reset our variables, and that should be it!

      If you've typed this in correctly, your ErrorTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as ErrorTag.java

    6. Compile the Tag.

4 Creating an Exception to use

    In order to see your new Tag in action we need a situation where an Exception is thrown from the body of the Tag. While a scriptlet could be used for now, we are probably better off going the extra distance and make a Tag for it that we can reuse in the future.

    1. In the '/WEB-INF/classes/com/acme/tag/' directory, create a new class called 'ExceptionThrowingTag.java' with the following content:

      package com.acme.tag;

      import javax.servlet.jsp.tagext.TagSupport;
      import javax.servlet.jsp.JspException;
      import java.io.IOException;


      public class ExceptionThrowingTag extends TagSupport
      {

      public int doStartTag() throws JspException {
      if(true)
      throw new JspException("This was totally unexpected!");
      return EVAL_BODY_INCLUDE;

      Listing 6: The ExceptionThrowingTag.

      In the listing above we define a Tag thats sole purpose is to throw an JspException for us.

      By now, your ExceptionThrowingTag.java should look like this. Store the sourcecode in the /WEB-INF/classes/com/acme/tag/ directory as ExceptionThrowingTag.java

    2. Compile the Tag. If needed, details are given here. The result should be a file named ExceptionThrowingTag.class in the /WEB-INF/classes/com/acme/tag/ directory.

5 Update the Tag Library Descriptor

    We now need to tell our JSP Container about our new Tags.

    1. Open your 'taglib1.2.tld' from your '/WEB-INF/' directory with your favourite editor.

    2. Add the following description for your new Tag:


      <tag>
      <name>catch</name>
      <tag-class>com.acme.tag.ErrorTag</tag-class>
      <body-content>JSP</body-content>
      <description>A simple Error handling Tag</description>
      <attribute>
      <name>message</name>
      <required>false</required>
      </attribute>
      <attribute>
      <name>log</name>
      <required>false</required>
      </attribute>
      </tag>
      Listing 7: Adding the Tag to the descriptor.

    3. Now add the ExceptionThrowingTag too:


      <tag>
      <name>throw</name>
      <tag-class>com.acme.tag.SExceptionThrowingTag</tag-class>
      <body-content>empty</body-content>
      </tag>
      Listing 8: Adding the other Tag to the descriptor.

    By now, your taglib1.2.tld should look like this. Store the descriptor in the /WEB-INF/ directory as taglib1.2.tld.

6 Presenting the new Tag

    In order to use your new Tag so that you can see your ErrorTag in action, you will need a JSP page that uses it to wrap an exception. To generate the Exception we will use the Exception throwing Tag we created above.

    1. Create a file called errorTag.jsp and add the following lines:


      <%@ taglib uri="mytags2" prefix="mt" %>
      <HTML>
      <HEAD>
      <TITLE>Page with error on it</TITLE>
      </HEAD>
      <BODY>
      <h1>before</h1>
      <mt:catch message="<h2>Displaying this instead of an error</h2>" log="true">
      <hr>
      <mt:throw/>
      <hr>
      </mt:catch>
      <h1>after</h1>
      </BODY>
      </HTML>
      Listing 9: A sample JSP page.

    The page above will use the ErrorTag (mt:catch) to surround an inclusion of a page that doesn't exist, and that will therefore throw an IOException that the ErrorTag will catch. The ErrorTag will then replace whatever got written into its body with the "Displaying this instead of a page" message that was provided as a parameter to it.

    By now, your ErrorTag.jsp should look like this. Store the file in the taglib-tutorial-web/ directory as ErrorTag.jsp.

7 Using your new Tag

    We are now ready to use our Tag.

    Open the URL http://localhost/taglib/errorTag.jsp in a normal web browser. Hopefully the result looks like this.

    Continue with lesson 12, "Changes to the TLD".

Copyright © 2005 IronFlare AB