<taglib:tutorial lesson="14"/>

In this part of the tutorial, we will look at what a Validator is and then implement one for our Taglibrary

1 Lesson 14, Writing Validators

    In this part of the tutorial, we will look at what a Validator is, and develop a Validator that can be used to ban scriptlets from all pages that uses the Taglibrary. We will continue to use the setup previously defined for this tutorial. At the end of this tutorial, you will have created and properly described a Validator. In order to try it out, you will also have written a JSP page.

2 What is a Validator?

    Back in JSP 1.1, Tag developers could put translation-time validation into the isValid() method of a TEI class (see lesson 5), and that method could use the information held by the TagData given to it to validate the tag usage. But now, thanks to JSP 1.2, Tag library descriptor now allows for a TagLibraryValidator class to be specified for a Tag library, so that this validator is invoked as soon as a page is compiled that utilizes the Tag Library that the validator is part of.


    Figure 1. The abstract TagLibraryValidator class

    When a Taglibrary that contains TagLibraryValidators is utilized, the Container will instantiate (or reuse a pooled instance) of the defined TagLibraryValidators, initialize them with any configured properties through their init method and then invoke their validate() method.

    The validate() method is called with the used prefix and uri of the Taglibrary together with a PageData object that holds the translation-time XML view of the JSP page (this is refered to as the JSP Document). The validate() method may return an array of ValidationMessages if an error occured. If no errors occured, then the validate() method should return null or a single length array of ValidationMessages.


    Figure 2. The abstract PageData class and the ValidationMessage class

    As will be exemplified in our TagLibraryValidator implementation later on, the PageData object can be used with a suitable parser to retreive any element of the JSP Document that is available at translation time. Sun has a very nice reference card that can be used to find out the available tags and elements (or read appendix B1 in the JSP 1.2 Specification).

    After that the Container has invoked the validate() method of the TagLibraryValidator it will call its release() method. If the TagLibraryValidator has to close any used resources or such before it is used again, this is where the implementator should put such instructions. The Container might reuse the instance, but before invoking its validate() method the Container will always initialize the intstance by running its init() method.

    Now lets leave the introductions behind and get implementing.

3 Writing the ScriptletBanningValidator TagLibraryValidator

    We will now create a TagLibraryValidator that will behave sort of like the <scripting-invalid> Web-module descriptor tag of JSP 2.0/Servlet 2.4.


    Figure 3: The ScriptletBanningValidator class

    When the Container comes across a JSP that is utilizing our Taglibrary, it will instantiate and invoke our implementation. Our code will then go thorugh the JSP Document and look for any <jsp:scriptlet> nodes. If found, we will return a ValidationMessage with a complaint regarding this.

    But nomather how nice it would be to get rid of all scriptlets once and for all, we will take advantage of the possibility to pass in parameters to our TagLibraryValidator implementation that will tell it if it should consider itself enabled or not.

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


      package com.acme.tag.validator;

      import org.w3c.dom.Document;
      import org.w3c.dom.Node;
      import org.w3c.dom.NodeList;

      import javax.servlet.jsp.tagext.TagLibraryValidator;
      import javax.servlet.jsp.tagext.ValidationMessage;
      import javax.servlet.jsp.tagext.PageData;
      import javax.xml.parsers.DocumentBuilderFactory;
      import java.util.Map;

      public class ScriptletBanningValidator extends TagLibraryValidator
      {
      private boolean enabled;
      Listing 1: Define the variables that the tag will need.

      The boolean variable above will be used to determine if our class should consider itself enabled or not.

    2. Define an accessor:


      public void setEnabled(boolean enabled)
      {
      this.enabled = enabled;
      }
      Listing 2: Adding the accessor for the boolean variable endabled

    3. Now, add the following method:


      public void setInitParameters(Map map)
      {
      Boolean value=new Boolean((String)map.get("enabled"));
      setEnabled(value.booleanValue());
      }
      Listing 3: Implementing the nitialization method

      Our Container will call the method above to initialize the TagLibraryValidator with any properties configured in the Taglibrary descriptor. As seen in the listing above, we will accept a boolean property to tell us if our Validator should be enabled or not.

    4. After that, we should have this method:


      public ValidationMessage[] validate(String prefix, String uri, PageData page)
      {
      if(enabled)
      {
      try
      {
      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
      Document document = factory.newDocumentBuilder().parse(page.getInputStream());
      String message = traverse(document.getFirstChild());
      if(message != null)
      {
      return new ValidationMessage[]{new ValidationMessage(uri, message)};
      }
      }
      catch(Exception e)
      {
      return new ValidationMessage[]{new ValidationMessage(uri, e.getMessage())};
      }
      }
      return null;
      }
      Listing 4: Adding the validate() method.

      The method above will be called by the Container at translation-time to validate the usage of the Taglibrary in a JSP page. Our implementation will use a XML DocumentBuilder to generate a Document out of the PageData hanled to us by the Container. We will then traverse all Nodes of the Document and make sure that we dont run into any scriptlets. If we encounter any scriptlets then we will return an errormessage in the ValidationMessage array that the method returns.

    5. Continue with the actual handing of the Document Node traversal


      public String traverse(Node node)
      {
      String message = null;
      try
      {
      NodeList nodes=node.getChildNodes();
      for(int n=0; n<nodes.getLength();n++)
      {
      Node child=nodes.item(n);
      String name=child.getNodeName();
      if(name.equals("jsp:scriptlet"))
      {
      message="Scriptlets detected";
      }
      else
      {
      message=traverse(child);
      }
      if(message!=null)
      {
      return message;
      }
      }
      }
      catch(Throwable t)
      {
      return "Error in ScriptletBanningValidator: "+t;
      }
      return message;
      }
      }
      Listing 5: Adding a mehtod to handle the Document Node traversal.

      This method will go through the subnodes of the current Node and look for scriptlet Nodes. If no scriptlet Node is found in the current subnode, we will try and traverse the subnodes of this subode until there aren't any more subnodes.

      By now, your ScriptletBanningValidator.java should look like this.

    6. Compile the Class.

4 Update the Tag Library Descriptor

    We should now describe our new TagLibraryValidator in the previously created Tag library descriptor.

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

    2. Edit the TagLibrary descriptor so that it includes the validator-tag as in listing 6 below.


      <?xml version="1.0" ?>
      <!DOCTYPE taglib PUBLIC "-//Sun Microsystems, Inc.//DTD JSP Tag Library 1.2//EN" "http://java.sun.com/dtd/web-jsptaglibrary_1_2.dtd">
      <taglib>
      <tlib-version>1.0</tlib-version>
      <jsp-version>1.2</jsp-version>
      <short-name>mt2</short-name>
      <uri>http://www.orionserver.com/tutorials/mytags2</uri>
      <description>My Second Tag library</description>
      <validator>
      <validator-class>com.acme.tag.validator.ScriptletBanningValidator</validator-class>
      <init-param>
      <param-name>enabled</param-name>
      <param-value>true</param-value>
      <description>turning the validator on or off</description>
      </init-param>
      <description>a sample validator</description>
      </validator>
      <listener>
      <listener-class>com.acme.tag.listener.SimpleContextListener</listener-class>
      </listener>
      Listing 6: The modified Taglibrary descriptor.

      Notice that the validator-tag we added above holds just not only the validator-class tag that points out our implementation, but also a init-param subtag that describes the parameter we want the Container to pass to our TagLibraryValidator when initializing it.

    Your taglib.tld should now look like this.

5 Testing your new TagLibraryValidator

    We are now ready to test our new TagLibraryValidator and will do so by calling the JSP page

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

    Continue with lesson 15, "Simple Tag Handlers".

Copyright © 2005 IronFlare AB