Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Add the power of asynchronous processing to your JSPs

Create custom JSP tags to use with JMS

  • Print
  • Feedback

Page 3 of 5

In general, a custom tag consists of three pieces:

  1. A tag library descriptor that maps the XML tag -- JSP -- to its implementation -- the tag handler class. For those of you familiar with CORBA, that step resembles creating IDL interfaces.
  2. A tag handler class that defines the tag's behavior. When the Web server comes across a custom tag, it relies on the tag's handler class to complete all the work. In CORBA, that step is comparable to coding the CORBA servers that implement the IDL interfaces defined in Step 1 above.
  3. JSP files that use the custom tag. In CORBA, that would be analogous to creating clients that use CORBA servers' services.


The tag developer creates the first two pieces only once. The JSP developer creates the last piece while designing the content and (re)uses the first two pieces.

Step 1: Define the tags

In this article, you will create two custom tags: write and read.

Write

The first tag, write, is for sending/publishing messages to a destination (i.e., a queue or topic). The definition of this tag is shown below:

    <tag>
        <name>write</name>
        <tagclass>JmsWriteTag</tagclass>
        <info>Send/Publish a message</info>
        <attribute>
               <name>destination</name>
               <required>true</required>
            <rtexprvalue>true</rtexprvalue>           
        </attribute>
        <attribute>
               <name>message</name>
               <required>false</required>
            <rtexprvalue>true</rtexprvalue>           
        </attribute>        
    </tag>       


The above tag definition provides the following information:

  • The tag name is write.
  • The tag handler class is JmsWriteTag, which is the tagclass element's value. JmsWriteTag must be the fully qualified class name of the tag handler implementation. I cover handler classes in the following section.
  • The tag has two attributes. destination is a mandatory attribute; message is an optional attribute.
  • Both the attributes can be JSP expressions of the form <%= expression %>, since the rtexprvalue element's value is true for both attributes.


The format of the destination attribute's value is especially noteworthy. Examine again the example I introduced earlier:

   <jms:write destination="jms://Queue/ModiQueue" message="Hello World"/>


Note the format of the destination attribute; it looks like a URL. Its value comprises three parts:

  1. The constant "jms://"
  2. The constant queue or topic, depending on the messaging model desired
  3. The name of the queue or topic to use


You can specify the message to be sent/published in two ways. The first, which is obvious from the above definition, is via the message attribute. You can also specify the message through the tag body. For example:

   <jms:write destination="jms://Queue/ModiQueue">
      Hello World
   </jms:write>


Note that in the latter case, I did not specify the message attribute. If I had done so, the tag handler would have ignored the body. Why? Because that's the way I coded the handler for that tag. I'll discuss the code later.

Read

The second tag, read, receives messages from a destination. Its definition follows:

    <tag>
        <name>read</name>
        <tagclass>JmsReadTag</tagclass>
        <info>Receive a message</info>
        <attribute>
               <name>destination</name>
               <required>true</required>      
            <rtexprvalue>true</rtexprvalue>     
        </attribute>
    </tag>


The above definition is a simpler version of write's. The handler implementation for the read tag is JmsReadTag. It only has one mandatory attribute, destination. Below you will find an example of how to use the read tag:

    <jms:read destination="jms://Queue/ModiQueue"/>


Listing 1 shows the entire tag library description.

Listing 1: Tag library description

Step 2: Implement the tags

Now that you've defined the tags, it's time to actually implement them. First, take a look at the tag handler class for the write tag. When the Web server comes across the write tag, it will call the tag handler class to complete all the work. As specified by JSP, a handler class must implement the javax.servlet.jsp.tagext.Tag interface by making the handler extend either the javax.servlet.jsp.tagext.TagSupport class or the javax.servlet.jsp.tagext.BodyTagSupport class. If the handler implementation needs to manipulate the tag body -- as it does in this case -- it needs to extend the BodyTagSupport class.

After creating a new instance (or reusing an old instance from a pool) of a handler class, the Web server informs the handler of all specified attributes. The handler class must follow the JavaBeans standard of naming property modifiers; that is, for an attribute called destination, the handler class must have a setDestination() method defined as follows:

    public void setDestination(String destination);


Accordingly, the handler implementation defines a setter method for each attribute. The handler also overrides the doAfterBody() method of the BodyTagSupport base class. The Web server calls that method when it is ready to process the custom tag's body. The implementation of doAfterBody() checks to see whether the message attribute has been specified and, if so, ignores the body. A message specified using the message attribute takes precedence over a message specified in the body of the write tag.

If no message attribute was specified, then the body becomes the message as shown below:

   // Was a message specified via the message attribute?
   if( message == null ) {
      // No.
      // Get the body content
      BodyContent body = getBodyContent();
      // Set the message equal to this content.
      message = body.getString();
   }


Next, the doAfterBody() calls the writeMessage() private method, which sends the message off to the specified destination.

That method proceeds as follows:

writeMessage parses the destination URL as shown below:

   String[] parts = parseDestination();


To parse the URL, the writeMessage() method calls the parseDestination() method, which returns a string array of two components: the destination type (queue or topic) and the destination name. If you do not format the destination according to the rules specified earlier in this article, a RuntimeException will result.

Depending on the type of destination, writeMessage will use the appropriate JMS messaging model (point-to-point or publish-and-subscribe).

For example, if the destination type is queue, the following code executes:

   QueueConnection connection = 
   JMSQueueConnectionFactory.getConnection();
   try
   {                     
      QueueSession session = connection.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
      Queue queue = session.createQueue(parts[1]);
      TextMessage msg = session.createTextMessage();
      msg.setText(message);
      QueueSender sender = session.createSender(queue);
      sender.send(msg);
      sender.close();
      session.close();
   }
   catch(Exception e)
   {
      e.printStackTrace();
   }
   finally
   {
      JMSQueueConnectionFactory.releaseConnection();
   }


Note the call to the static methods getConnection() and releaseConnection() on the JMSQueueConnectionFactory class. Those methods obtain and release a queue connection, respectively. Also note that the call to releaseConnection() appears within the finally section to ensure execution no matter what. For now, ignore those method calls. I will provide further details on the JMSQueueConnectionFactory class in a later section.

  • Print
  • Feedback

Resources