View RSS Feed

Servlet

General Event Handling in Servlets Part 3

Rate this Entry
by , 11-28-2011 at 11:35 PM (1455 Views)
In the first two article on general event handling with servlets we have covered how to detect changes in the servlet context and monitoring the creation and destruction of the servlet context. In this last article of the series we will look into how to use listeners with tag libraries. If you have not seen the first two articles of this series, General Event Handling in Servlets, Part 1 and General Event Handling in Servlets, Part 2, then I would recommend that you review them before continuing with this article.

One of the key means of generating dynamic content inside a JSP page is to use custom tag libraries. The benefits of using custom tag libraries is that you can encapsulate complex presentation logic within a tag and make it available across all JavaServer Pages. This is a better and more coherent solution that attempting to express this logic in non Java code. The means to do this is to use the SimpleTag API which simplifies greatly the process of producing a powerful tag. In order to produce a custom tag, it is necessary to define three components:
  1. The tag handler for defining the tagís behaviour
  2. The TLD file for mapping XML elements to the tagís implementation
  3. The JSP file that uses the tag library


Although tags are an excellent means for encapsulating context that will be made accessible to multiple JSP pages, there are times when the content produced might be dependent on the lifecycle event listeners. To declare listeners using the listener and listener-class elements of web.xml would make tag library maintenance complicated. The normal means of deploying a tag library is to drop the JAR file in the WEB-INF/lib folder and putting the TLD file in the WEB-INF folder. In this situation it is necessary for the user to only have knowledge of the tags that the library defines not the individual classes in the library. In this article, we are going to look at how to package the listeners with Tag Libraries. The way in which this is done is to put the listener declarations in the TLD file rather than in the deployment descriptor. What happens is that when the application is loaded, the system automatically searches WEB-INF and all subdirectories for files using .tld extensions and uses all listener declarations it discovered. This is only possible because of changes to the JSP specification. In version 2.0 of the JSP specification, the validation of the TLD files was switched from using Document Type Definition (DTD) to XML Schema. Listing 1 shows the template of the JSP 2.0 TLD file.

Listing 1 - Template for JSP 2.0 TLD
Java Code:
<?xml version="1.0" encoding="UTF-8" ?> 
<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee 
http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd" version="2.0">

   <description> 
     Tag library documentation.
   </description> 
   <tlib-version>1.0</tlib-version> 
   <short-name>some name</short-name> 
   <uri>some uri</uri>
   <listener> 
      <listener-class>somePackage.someListener</listener-class>
   </listener>

   <tag> 
      <description>Tag documentation</description> 
      <name>tagName</name> 
      <tag-class>somePackage.someTagHandler</tag-class> 
      <body-content>...</body-content>
   </tag> 
</taglib>
 Now we will provide an example of how we to create custom tags that can be packaged with the Company Name Listeners. Below I will list out the functionality of each of the tags:
The first tag prints out the company name
Second tag determines whether to simply print the former company name or the print the company name inside parentheses The printout will appear in the following manner (e.g. acme-company.com) or (e.g., (formerly acme-company.com)).

In Listing 2 is shown the CompanyNameTag. This tag leverages the InitialCompanyNameListener that was initially created in part 1 of this series in order to obtain the actual company name. Similarly in Listing 3, the FormerCompanyNameTag leverages the InitialCompanyNameListener in order to obtain the former company name. Here we are going to modify the InitialCompanyNameListener by adding The TLD file for the tag library is shown in listing 5. As noted thanks to the change in the JSP 2.0 specification, we no longer need to discover the listeners by searching in the web.xml file , we are able to provide the listener elements directly in the TLD file. The TLD files is then placed into the WEB-INF folder.

Listing 2 - CompanyNameTag.java
Java Code:
package com.acme.webexample.tags; 
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import com.acme.webexample.listener.InitialCompanyNameListener;

public class CompanyNameTag extends SimpleTagSupport {

	@Override
	public void doTag() throws JspException, IOException {
	    PageContext pageContext = (PageContext) getJspContext();
	    ServletContext context = pageContext.getServletContext();
	    String companyName = 
	      InitialCompanyNameListener.getCompanyName(context);
	    JspWriter out = pageContext.getOut();
	    out.print(companyName);
	}

}
Listing 3 - FormerCompanyNameTag.java
Java Code:
package com.acme.webexample.tags; 
import java.io.IOException;
import javax.servlet.ServletContext;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.JspWriter;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.SimpleTagSupport;

import com.acme.webexample.listener.InitialCompanyNameListener;

public class FormerCompanyNameTag extends SimpleTagSupport {
	private boolean useFullDescription = false;

	@Override
	public void doTag() throws JspException, IOException {
		PageContext pageContext = (PageContext) getJspContext();
		ServletContext context = pageContext.getServletContext();
		String formerCompanyName = InitialCompanyNameListener
				.getFormerCompanyName(context);
		JspWriter out = pageContext.getOut();
		if (useFullDescription) {
			String formerCompanyDescription = "";
			if (!formerCompanyName.equals("")) {
				formerCompanyDescription = "(formerly " + formerCompanyName
						+ ")";
			}
			out.print(formerCompanyDescription);
		} else {
			out.print(formerCompanyName);
		}
	}

	  /** If the user supplies a fullDescription attribute
	   *  with the value "true" (upper, lower, or mixed case),
	   *  set the useFullDescription instance variable to true.
	   *  Otherwise, leave it false.
	   */
	public void setFullDescription(String flag) {
		if (flag.equalsIgnoreCase("true")) {
			useFullDescription = true;
		}
	}

}
Next we show the TLD file for the tag library, company-name-taglib.tld in Listing 4. Note the inclusion of the listeners which provide the tag library with notifications of changes in the relevant information.

Listing 4 - company-name-taglib.tld
Java Code:
<?xml version="1.0" encoding="UTF-8"?>
<taglib version="2.0" xmlns="http://java.sun.com/xml/ns/j2ee"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee   http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd">
 
 <description>A tag library to print out the current and former company names (Monitored by event listeners). 
	   http://webexamples.acme.com</description>
 <tlib-version>1.0</tlib-version>
 <short-name>company-name-tags</short-name>
 <uri>http://acme.com/listeners</uri>
 <!-- Register the listener that sets up the initial company name. -->
 <listener>
  <listener-class>com.acme.webexample.listener.InitialCompanyNameListener</listener-class>
 </listener>
 <!-- Register the listener that monitors changes to the company name. -->
 <listener>
  <listener-class>com.acme.webexample.listener.ChangedCompanyNameListener</listener-class>
 </listener>
 <!-- Define a tag that prints out the current name. -->
 <tag>
  <description>The current company name</description>
  <name>companyName</name>
  <tag-class>com.acme.webexample.tags.CompanyNameTag</tag-class>
  <body-content>empty</body-content>
 </tag>
<!-- Define a tag that prints out the previous name. -->
<tag>
<description>The previous company name</description>
<name>formerCompanyName</name>
<tag-class>com.acme.webexample.tags.FormerCompanyNameTa g</tag-class>
<body-content>empty</body-content>
<attribute>
<name>fullDescription</name>
<rtexprvalue>false</rtexprvalue>
</attribute>
</tag>
</taglib>

In the next listing is the company home page in Listing 5. Note how it is reworked with the custom tags. In listing 7 is it new version of the InitialCompanyNameListener with static methods that permit access to the current and former company names. Handling this situation is the job of servlet context attribute listeners.

Listing 5 - index.jsp
XML Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
	<HEAD>
		<%@ taglib uri="http://acme.com/listeners" prefix="acwjsp"%>
		<TITLE><acwjsp:companyName />
		</TITLE>
		<LINK REL=STYLESHEET HREF="events-styles.css" TYPE="text/css">
	</HEAD>
	<BODY>
		<TABLE BORDER=5 ALIGN="CENTER">
			<TR>
				<TH CLASS="TITLE">
					<acwjsp:companyName />
					<BR>
					<acwjsp:formerCompanyName fullDescription="true" />
		</TABLE>
		<P>
			Welcome to the rebranded page of
			<B><acwjsp:companyName />
			</B>
			<acwjsp:formerCompanyName fullDescription="true" />
		<P>
			<B><acwjsp:companyName />
			</B> is a fast moving internet company. Perfectly positioned to take
			advantage of the many opportunities on the internet!
		<P>
			Click
			<A HREF="company-info2.jsp">here</A> for more information.
	</BODY>
</HTML>
Finally there is the companyinfo.jsp shown in Listing 6. It too uses the custom tags.

Listing 6 - companyinfo.jsp
XML Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
	<HEAD>
		<%@ taglib uri="http://acme.com/listeners" prefix="acwjsp"%>
		<TITLE><acwjsp:companyName />
		</TITLE>
		<LINK REL=STYLESHEET HREF="events-styles.css" TYPE="text/css">
	</HEAD>
	<BODY>
		<TABLE BORDER=5 ALIGN="CENTER">
			<TR>
				<TH CLASS="TITLE">
					<acwjsp:companyName />
					<BR>
					<acwjsp:formerCompanyName fullDescription="true" />
		</TABLE>
		<P>
			Learn more about
			<B><acwjsp:companyName />
			</B>
			<acwjsp:formerCompanyName fullDescription="true" />
		<UL>
			<LI>
				<A HREF="products.jsp"><acwjsp:companyName /> products</A>
			<LI>
				<A HREF="services.jsp"><acwjsp:companyName /> services</A>
			<LI>
				<A HREF="history.jsp"><acwjsp:companyName /> history</A>
			<LI>
				<A HREF="invest.jsp">investing in <acwjsp:companyName />
				</A>
			<LI>
				<A HREF="contact.jsp">contacting <acwjsp:companyName />
				</A>
		</UL>
	</BODY>
</HTML>
Listing 7 - InitialCompanyNameListener.java
Java Code:
package com.acme.webexample.listeners;
import javax.servlet.ServletContext;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

public class InitialCompanyNameListener implements ServletContextListener {

	private static final String DEFAULT_NAME = "MISSING-COMPANY-NAME";

	public void contextDestroyed(ServletContextEvent arg0) { }

	public void contextInitialized(ServletContextEvent event) {
		ServletContext context = event.getServletContext();
		setInitialAttribute(context, "companyName", DEFAULT_NAME);
		setInitialAttribute(context, "formerCompanyName", "");
	}

	private void setInitialAttribute(ServletContext context,
			String initParamName, String defaultValue) {
		String initialValue = context.getInitParameter(initParamName);
		if (initialValue != null) {
			context.setAttribute(initParamName, initialValue);
		} else {
			context.setAttribute(initParamName, defaultValue);
		}
	}

	  /** Static method that returns the servlet context
	   *  attribute named "companyName" if it is available.
	   *  Returns a default value if the attribute is
	   *  unavailable.
	   */
	  public static String getCompanyName(ServletContext context) {
	    String name =
	      (String)context.getAttribute("companyName");
	    if (name == null) {
	      name = DEFAULT_NAME;
	    }
	    return(name);
	  }
	  
	  /** Static method that returns the servlet context
	   *  attribute named "formerCompanyName" if it is available.
	   *  Returns an empty string if the attribute is
	   *  unavailable.
	   */
	  public static String getFormerCompanyName
	                                     (ServletContext context) {
	    String name =
	      (String)context.getAttribute("formerCompanyName");
	    if (name == null) {
	      name = "";
	    }
	    return(name);
	  }
}
OK. Thatís it. When you run the application, the custom tag will print out the new and former names of the company. Of course this is a simple example but it shows you the power of how event handling came provide rich functionality to your applications.

Submit "General Event Handling in Servlets Part 3" to Facebook Submit "General Event Handling in Servlets Part 3" to Digg Submit "General Event Handling in Servlets Part 3" to del.icio.us Submit "General Event Handling in Servlets Part 3" to StumbleUpon Submit "General Event Handling in Servlets Part 3" to Google

Updated 12-09-2011 at 04:16 PM by Servlet

Categories
Tutorial , Web , Listener , ServletContextListener

Comments