11.1 Sharing Information

Java Servlet Programming, 2nd Edition > 11. Servlet Collaboration > 11.1 Sharing Information

 
< BACKCONTINUE >

11.1 Sharing Information

Oftentimes servlets cooperate by sharing some information. The information may be state information, a shared resource, a resource factory, or anything. In Servlet API 2.0 and earlier there were no built-in mechanisms by which servlets could share information, and in the first edition of this book (written against API 2.0) we had to demonstrate several creative workarounds including putting information in the System properties list! Fortunately such workarounds are no longer necessary, because beginning with Servlet API 2.1 the ServletContext class has been enhanced to act as a shared information repository.

11.1.1 Sharing with the ServletContext

A servlet retrieves the ServletContext for its web application using the getServletContext( ) call. A servlet may use the context as if it were a Hashtable or Map, with the following methods.

public void ServletContext.setAttribute(String name, Object o) public Object ServletContext.getAttribute(String name) public Enumeration ServletContext.getAttributeNames() public void ServletContext.removeAttribute(String name)

The setAttribute( ) method binds an object under a given name. Any existing binding with the same name is replaced. Attribute names should follow the same convention as package names to avoid overwriting one another. The package names java.*, javax.*, and com.sun.* are reserved.

The getAttribute( ) method retrieves the object bound under the given name or null if the attribute does not exist. The call may also retrieve server-specific hard-coded attributes (for example, javax.servlet.context.tempdir) as discussed in Chapter 4.

The getAttributeNames( ) method returns an Enumeration, which contains the names of all the bound attributes or an empty Enumeration if there are no bindings.

The removeAttribute( ) method removes the object bound under the given name or does nothing if the attribute does not exist. It's a good idea to remove attributes that are no longer needed to reduce memory bloat.

11.1.1.1 Using the context to sell burritos

As a fun example, imagine a set of servlets that sell burritos and share a special of the day. An administrative servlet could set the special of the day as shown in Example 11-1.

Example 11-1. Me Gustan Burritos
import java.io.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SpecialSetter extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/plain");     PrintWriter out = res.getWriter();     ServletContext context = getServletContext();     context.setAttribute("com.costena.special.burrito", "Pollo Adobado");     context.setAttribute("com.costena.special.day", new Date());     out.println("The burrito special has been set.");   } }

Thereafter, every other servlet on the server can access the special and display it using the code in Example 11-2.

Example 11-2. Especial Del D a
import java.io.*; import java.text.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class SpecialGetter extends HttpServlet {   public void doGet(HttpServletRequest req, HttpServletResponse res)                                throws ServletException, IOException {     res.setContentType("text/html");     PrintWriter out = res.getWriter();     ServletContext context = getServletContext();     String burrito = (String)       context.getAttribute("com.costena.special.burrito");     Date day = (Date)       context.getAttribute("com.costena.special.day");     DateFormat df = DateFormat.getDateInstance(DateFormat.MEDIUM);     String today = df.format(day);     out.println("Our burrito special today (" + today + ") is: " + burrito);   } }

11.1.2 Sharing with Another ServletContext

Using the ServletContext to share information has the beneficial effect that each web application has its own unique information store. There's no risk of accidental name collisions or even name collisions from the same application deployed twice on a server. However, sometimes information needs to be shared between web contexts. In this situation, there are two choices. First, use an external information repository such as a singleton or database, or, second, use special hooks to directly access another context. We'll explore the latter.

A servlet can obtain a handle to another context on the same server using the getContext( ) hook in its own context:

public ServletContext ServletContext.getContext(String uripath)

This method returns the ServletContext containing the specified URI path. The given path must be absolute (beginning with /) and is interpreted based on the server's document root. This method allows a servlet to gain access to a context outside its own. In a security-conscious or distributed environment (see Chapter 12 ), the servlet container may return null for any and all paths.

To demonstrate, assume a servlet outside the burrito store context needs access to the special of the day. Furthermore, assume the burrito store context is rooted at /burritostore. And finally, assume the server hasn't turned on security controls to disallow intercontext communication. Under these conditions the following code allows any servlet on the server to retrieve the special of the day from the burrito store application:

ServletContext myContext = getServletContext(); ServletContext otherContext = myContext.getContext("/burritostore/index.html"); String burrito = otherContext.getAttribute("com.costena.special.burrito"); Date day = (Date)otherContext.getAttribute("com.costena.special.day");

Currently the only way to obtain a reference to a different context is by path lookup, so our example here will break should the burrito store move to a different URL. In the future there may be a way to obtain a context by name.

11.1.2.1 Class loader issues

If the object placed into the context is a custom object, sharing the object between contexts becomes much more difficult due to class loader issues. Remember that each web application has its classes under WEB-INF loaded by a different class loader. Also remember that the class loader from one application cannot locate the classes stored within a different application. The unfortunate result: an object whose .class file exists only within WEB-INF/classes or WEB-INF/lib won't be easily usable from any other application. Any attempt to cast the object to its proper type results in a NoClassDefFoundError.

The solution of copying the .class file into both applications doesn't work either. Classes loaded by different class loaders are not the same class, even if their definitions match. If you try this, you'll only replace the NoClassDefFoundError with a ClassCastException.

There are three possible workarounds. First, copy the .class file for the shared object into the server's standard classpath (for Tomcat that's server_root/classes). This allows it to be found by the primordial class loader shared by all web applications. Second, avoid casting the returned object and invoke its methods using reflection (a technique whereby a Java class can inspect and manipulate itself at runtime). This isn't as elegant but works if you don't have full control over the server. Third, cast the returned object to an interface that declares the pertinent methods and place the interface in the server's standard classpath. Every class but the interface can remain in the individual web applications. This requires refactoring the shared object's class but works well if the implementation needs to remain in the original web applications.


Last updated on 3/20/2003
Java Servlet Programming, 2nd Edition, © 2001 O'Reilly

< BACKCONTINUE >


Java servlet programming
Java Servlet Programming (Java Series)
ISBN: 0596000405
EAN: 2147483647
Year: 2000
Pages: 223

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net