|
This chapter shows how to access resources of the Web Server and communicate
with Servlets and other kinds of active resources (e.g.
JSP
documents,
CGI
programs). The examples in this chapter are often only fragments of Java
source code and not necessarily complete Servlets.
This section shows how to
-
call a method of another Servlet
The inter-Servlet communication method which is described in this section can
only be used with Servlet engines which implement version 1.0 or 2.0 of the
Servlet API. It will not work with Servlet engines which comply strictly to
version 2.1. The new way of doing inter-Servlet communication which was
introduced in the 2.1 API is described in detail in sections
3.2
and
3.5.
Servlets are not alone in a Web Server. They have access to other Servlets in
the same Servlet Context (usually a Servlet directory), represented
by an instance of javax.servlet.ServletContext. The ServletContext is available through the ServletConfig object's
getServletContext method.
A Servlet can get a list of all other Servlets in the Servlet Context by
calling getServletNames on the ServletContext object. A Servlet for a known name (probably
obtained through getServletNames) is returned by getServlet. Note that this method can throw
a ServletException because it may need to load and initialize the requested Servlet if
this was not already done.
After obtaining the reference to another Servlet that Servlet's methods can be
called. Methods which are not declared in javax.servlet.Servlet but in a subclass thereof can
be called by casting the returned object to the required class type.
Note that in Java the identity of a class is not only defined by the class
name but also by the ClassLoader by which it was loaded. Web servers usually load
each Servlet with a different class loader. This is necessary to reload
Servlets on the fly because single classes cannot be replaced in the running
JVM.
Only a ClassLoader object with all loaded classes can be replaced.
This means that classes which are loaded by a Servlet class loader cannot be
used for inter-Servlet communication. A class literal FooServlet (as used in a type
cast like "FooServlet foo = (FooServlet)context.getServlet("FooServlet")") which is used in class BarServlet is different from the class
literal FooServlet as used in FooServlet itself.
A way to overcome this problem is using a superclass or an interface which is
loaded by the system loader and thus shared by all Servlets. In a Web Server
which is written in Java those classes are usually located in the class path
(as defined by the CLASSPATH environment variable).
Example. Servlet FooServlet wants to call the method public void bar() of
Servlet BarServlet. Both Servlets should be reloadable so the Servlet classes
cannot be loaded by the system loader. Instead we define an interface BarInterface
which defines the callable method and is loaded by the system loader. BarServlet
implements this interface. The Servlets are placed into the Servlet directory
and the interface into a directory in the class path.
1: public class FooServlet extends HttpServlet 2: { 3: protected void doGet(HttpServletRequest req, 4: HttpServletResponse res) 5: throws ServletException, IOException 6: { 7: ... 8: ServletContext context = getServletConfig().getServletContext(); 9: BarInterface bar = (BarInterface)context.getServlet("BarServlet"); 10: bar.bar(); 11: .. 12: } 13: 14: ... 15: }
1: public interface BarInterface 2: { 3: public void bar(); 4: }
1: public class BarServlet extends HttpServlet implements BarInterface 2: { 3: public void bar() 4: { 5: System.err.println(""bar() called""); 6: } 7: 8: ... 9: }
This section shows how to
-
call another Servlet (or any other kind of active resource) to process a
request
A Servlet can make a request to an active resource on the web server just like
a client can (by requesting a URL). The Servlet API supports a more direct way
of accessing server resources from within a Servlet which is running in the
server than opening a socket connection back to the server. A Servlet can
either hand off a request to a different resource or include the response
which is created by that resource in its own response. It is also possible to
supply user-defined data when calling an active resource which provides for an
elegant way of doing inter-Servlet communication.
See section
3.1
for an inter-Servlet communication method which can be used with Servlet API
versions 1.0 and 2.0.
Example. We're building an online shop with an ItemServlet which
takes an argument item=number and returns a paragraph of HTML text with a
description of the item which is retrieved from a database.
A second Servlet, the PresentationServlet, takes the same argument and creates a complete
HTML page which includes the output of the ItemServlet. If the item argument is
missing, the request is delegated to an ErrorServlet which returns a formatted error
message.
public class PresentationServlet extends HttpServlet { private static class ItemNotFoundException extends Exception { ItemNotFoundException() { super("Item not found"); } }
protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { String item = req.getParameter("item"); if(item == null) { req.setAttibute("exception", new ItemNotFoundException()); getServletContext() .getRequestDispatcher("/servlet/ErrorServlet") .forward(req, res); } else { res.setContentType("text/html"); PrintWriter out = res.getWriter(); out.print("<HTML><HEAD><TITLE>Item " + item + "</TITLE>"+ "</HEAD><BODY>Item " + item + ":<P>"); getServletContext() .getRequestDispatcher("/servlet/ItemServlet?item="+item) .include(req, res); out.print("</BODY></HTML>"); } } }
In the doGet method we first check for the existence of the item argument. If
it is present (second branch of the if statement) the Servlet is responding
with an HTML document in the usual way. In the middle of the document the
response body of the ItemServlet is included by asking the ItemServlet's RequestDispatcher (whis is
obtained through the ServletContext) to perform that operation.
If no item attribute was specified, the request is delegated to the ErrorServlet in
a similar way. Note that this time we are using the RequestDispatcher's forward method
(instead of include). This method can be called only once and only if neither
getOutputStream nor getWriter has been called, but it allows the included Servlet to set
headers and the response code (which is required to create a proper HTTP error
response message).
The ItemServlet gets its item argument from the query string. That way it can also
be accessed directly via an HTTP request, but argument values have to be
represented as url-encoded strings (which is no problem in this case). The
ErrorServlet takes an exception argument of type java.lang.Exception which is provided as a request
attribute. The ErrorServlet uses the ServletRequest method getAttribute to read the attribute.
Note that a server which supports load balancing could run the Servlets on
different
JVMs.
All custom request attributes should be serializable to allow them to
be moved from one JVM to another.
This section shows how to
-
access a resource in the server's document tree
Passive server resources (e.g. static HTML pages which are stored in local
files) are not accessed with RequestDispatcher objects. The ServletContext method getResource(String path) returns a
URL object for a resource specified by a local URI (e.g. "/" for the
server's document root) which can be used to examine the resource.
If you only want to read the resource's body you can directly ask the ServletContext
for an InputStream with the getResourceAsStream(String path) method.
In Servlets which have to use version 1.0 or 2.0 of the Servlet API you can
use the ServletContext method getRealPath(String path) to find a path in the local file system to a
resource. This method is less general than the one described above because it
doesn't allow you to access resources which are not stored in local files.
This section shows how to
-
access resources which belong to a Servlet
A Servlet may need to access additional resources like configuration files
whose locations should not need to be specified in init parameters. Those
resources can be accessed with the methods getResource(String name) and getResourceAsStream(String name) of the java.lang.Class object
which represents the Servlet's class.
Example. The following code gets an InputStream for a configuration
file named myservlet.cfg which resides in the same directory as the class in which the
code is executed:
InputStream confIn = getClass().getResourceAsStream("myservlet.cfg");
Note that the Servlet engine's Servlet class loader must implement the getResource
and getResourceAsStream methods in order for this to work. This may not be the case with
all Servlet engines.
This section shows how to
-
share data between Servlets
Version 2.1 of the Servlet API offers a new way of sharing named objects
between all the Servlets in a Servlet context (and also other contexts, as
you'll see below) by binding the objects to the ServletContext object which is shared
by several Servlets.
The ServletContext class has several methods for accessing the shared objects:
-
public void setAttribute(String name,
Object object) adds a new object or replaces an old object by the specified name.
The attribute name should follow the same naming convention as a package
name (e.g. a Servlet com.foo.fooservlet.FooServlet could have an attribute com.foo.fooservlet.bar).
Just like a custom ServletRequest attribute, an object which is stored as a ServletContext
attribute should also be serializable to allow attributes to be
shared by Servlets which are running in different
JVMs
on different machines in a load-balancing server environment.
-
public Object getAttribute(String name) returns the named object or null if the attribute does not exist.
In addition to the user-defined attributes there may also be predefined
attributes which are specific to the Servlet engine and provide additional
information about a Servlet(Context)'s environment.
-
public Enumeration getAttributeNames() returns an Enumeration of the names of all available attributes.
-
public void removeAttribute(String name) removes the attribute with the specified name if it exists.
The separation of Servlets into Servlet contexts depends on the Servlet
engine. The ServletContext object of a Servlet with a known local URI can be retrieved
with the method public ServletContext getContext(String uripath) of the Servlet's own ServletContext. This method returns null if
there is no Servlet for the specified path or if this Servlet is not allowed
to get the ServletContext for the specified path due to security restrictions.
|