Servlet Collaboration by R4R Team

Servlet Collaboration:
The Servlet collaboration is all about sharing information among the servlets. Collaborating servlets is to pass the common information that is to be shared directly by one servlet to another through various invocations of the methods. To perform these operations, each servlet need to know the other servlet with which it is collaborated. Here are several ways to communicate with one another:

Using RequestDispatchers include() and forward() method;
Using HttpServletResponse sendRedirect() method;
Using ServletContext setAttribute() and getAttribute() methods;
Using Java's system-wide Properties list;
Using singleton class object.

Servlets running together in the same server have several ways to communicate with one another. There are two main styles of servlet collaboration:

1)Sharing information:

This involves two or more servlets sharing state or resources. For example, a set of servlets managing an online store could share the store's product inventory count or share a database connection. Session tracking is a special case of sharing information.

2)Sharing control:

This involves two or more servlets sharing control of the request. For example, one servlet could receive the request but let another servlet handle some or all of the request-handling responsibilities.
In the past (before Servlet API 2.1) we would have listed another style of collaboration: direct manipulation . With this style of collaboration, a servlet could obtain a direct reference to another through the getServlet( ) method and invoke methods on the other servlet. This style of collaboration is no longer supported; the getServlet( ) method has been deprecated and defined to return null for API 2.1 and later. The reason: a servlet may be destroyed by the web server at any time, so nothing but the server should hold a direct reference to a servlet. Everything that could be done with getServlet( ) can be accomplished better and safer using the alternatives we'll learn about in this topic.

Collaboration Through the System Properties List:

One simple way for servlets to share information is by using Java's system-wide Properties list, found in the java.lang.System class. This Properties list holds the standard system properties, such as java.version and path.separator, but it can also hold application-specific properties. Servlets can use the properties list to hold the information they need to share. A servlet can add (or change) a property by calling:

System.getProperties().put("key", "value");
That servlet, or another servlet running in the same JVM, can later get the value of the property by calling:

String value = System.getProperty("key");
The property can be removed by calling:

System.getProperties().remove("key");

It's best if the key for a property includes a prefix that contains the name of the servlet's package and the name of the collaboration group. For example, "com.oreilly.servlet.ShoppingCart".

The Properties class is intended to be String based, meaning that each key and value is supposed to be a String. This limitation, though, isn't commonly enforced and can (although it's quite a hack) be ignored by servlets that want to store and retrieve non-String objects. Such servlets can take advantage of the fact that the Properties class extends the Hashtable class, so the Properties list can (quite rudely) be treated as a Hashtable when storing keys and values. For example, a servlet can add or change a property object by calling:

System.getProperties().put(keyObject, valueObject);
It can retrieve the property object by calling:

SomeObject valueObject = (SomeObject)System.getProperties().get(keyObject);
It can remove the property object by calling:

System.getProperties().remove(keyObject);
This misuse of the Properties list causes the getProperty(), list() and save() methods of the Properties class to throw ClassCastException objects when they naturally--but erroneously--assume each key and value to be a String. For this reason, if there's any chance these methods might be called, you should instead use one of the techniques for servlet collaboration we describe later in the chapter. Also, remember the class files for keyObject and valueObject should be found in the server's classpath, not in the default servlet directory where they would be loaded, and perhaps reloaded, by the special servlet class loaders.

There are three more caveats to using the system Properties list for servlet collaboration: the information isn't naturally persistent between server restarts, the information can be viewed (and modified or deleted) by other classes executing in the servlet's JVM, and some servlet security managers may not grant servlets access to the system property list.


Using properties to sell burritos:


Despite the stern warnings, servlet collaboration through the system-wide Properties list works well for servlets that are sharing insensitive, noncritical, easily replaceable information. 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 using the following code:

System.getProperties().put("com.LaCostena.special.burrito", "r4r");

System.getProperties().put("r4r.in.special.day", new Date());

Thereafter, every other servlet on the server can access the special and display it with code like this:

String burrito = System.getProperty(r4rin.special.burrito");

Date day = (Date)System.getProperties().get("r4r.in.special.day");

DateFormat df = DateFormat.getDateInstance(DateFormat.SHORT);

String today = df.format(day);

out.println("Our burrito special today (" + today + ") is: " + burrito);

Faster image chaining:

Servlets performing image effects in a servlet chain can boost their speed dramatically by using the system Properties list to pass their images.  we saw the standard method by which the servlets in a chain pass images from link to link. The first servlet takes an Image object, encodes it to a stream of bytes, and passes the bytes to the next servlet. The receiving servlet decodes the bytes back into the original Image object. The technique works fine, but it can be prohibitively slow for large images. An alternative solution is for the first servlet to save the Image object itself in the system-wide Properties list, then pass on a small unique key by which the next servlet in the chain can locate the Image. In a sense, the old approach works by shoving an entire elephant through the small portal between servlets.

demonstrates exactly how a servlet passes on a key to an Image object saved in the system Properties list.

Passing an Image through the Properties list:

 

import java.awt.*;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class ChainImageSource extends HttpServlet {

int keynum = 0; // used to create a unique key

public void doGet(HttpServletRequest req, HttpServletResponse res)

throws ServletException, IOException {

// Get an Image

String imageFile = req.getRealPath("/system/images/serverduke.gif");

Image image = Toolkit.getDefaultToolkit().getImage(imageFile);

// Create a unique key under which to store the image

String key = "com.oreilly.servlet.ChainImageSource." + keynum++;

// Store the image in the system Properties list using that key

System.getProperties().put(key, image);

// Tell the next servlet to expect an image key

res.setContentType("java-internal/image-key");

PrintWriter out = res.getWriter();

// Send the key

out.println(key);

}}

Notice how the servlet generates its unique key. It prefixes the key with the string "com.oreilly.servlet.ChainImageSource", something no other servlet is likely to use. Then it appends a different integer value for each image. Also notice how this servlet uses the custom content type "java-internal/image-key" to indicate that it's passing on an image key.

Example shows the other half of this servlet chain--a servlet that uses the key to fetch the original Image object.

Example Fetching an image passed through the Properties list
 

import java.awt.*;

import java.io.*;

import javax.servlet.*;

import javax.servlet.http.*;

public class ChainImageSink extends HttpServlet {

public void doGet(HttpServletRequest req, HttpServletResponse res)

throws ServletException, IOException {

// See what content type we're receiving

String contentType = req.getContentType();

Image image = null;

// An "image/*" content type means to expect the image as an encoded

// byte stream

if (contentType != null && contentType.startsWith("image")) {

}

// A "java-internal/image-key" content type means to expect a key

else if ("java-internal/image-key".equals(contentType)) {

// Read the first line of content to get the key

String key = req.getReader().readLine();

// Retrieve the Image stored under that key

image = (Image)System.getProperties().get(key);

// Always remove the Image, to avoid a memory leak

System.getProperties().remove(key);

}

// Other content types cannot be handled

else {

throw new ServletException("Incoming content type must be " +

"\"image/*\" or \"java-internal/image-key\"");

}

// Proceed to use the image as appropriate...

res.setContentType("text/plain");

PrintWriter out = res.getWriter();

out.println("Received the image: " + image);

}}


The most important thing to notice with this example is that the receiving servlet bears the responsibility of removing the Image from the system Properties list to avoid a potentially large memory leak.

This leash-passing technique works only when the source servlet can be absolutely sure its key is being sent to another servlet, not to a dumbfounded user who expected an image. This can be ensured if every chain has as its final servlet a special servlet whose sole purpose is to accept an image key and emit that Image's encoded byte stream.

Collaboration Through a Shared Object:

Another way for servlets to share information is through a shared object. A shared object can hold the pool of shared information and make it available to each servlet as needed. In a sense, the system Properties list is a special case example of a shared object. By generalizing the technique into sharing any sort of object, however, a servlet is able to use whatever shared object best solves its particular problem.

Often the shared object incorporates a fair amount of business logic or rules for manipulating the object's data. This business logic protects the shared object's actual data by making it available only through well-defined methods. It can enforce data integrity, trigger events to handle certain conditions, and basically abstract lots of little data manipulations into a single method invocation. This capability isn't available with the Properties list.

There's one thing to watch out for when collaborating through a shared object: the garbage collector. It can reclaim the shared object if at any time the object isn't referenced by a loaded servlet. To keep the garbage collector at bay, it's wise for every servlet using a shared object to save a reference to the object.

Leave a Comment: