|
|
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
Page 3 of 5
In general, a custom tag consists of three pieces:
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.
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:
write.
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.
destination is a mandatory attribute; message is an optional attribute.
<%= 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:
"jms://"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
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.