To build a successful web application, you often need to know a lot about the environment in which it is running. You may need to find out about the server that is executing your servlets or the specifics of the client that is sending requests. And no matter what kind of environment the application is running in, you most certainly need information about the requests that the application is handling.
Servlets have a number of methods available to gain access to this information. For the most part, each method returns one specific result. If you compare this to the way environment variables are used to pass a CGI program its information, the servlet approach has several advantages:
Stronger type checking. In other words, more help from the compiler in catching errors. A CGI program uses one function to retrieve its environment variables. Many errors cannot be found until they cause runtime problems. Let's look at how both a CGI program and a servlet find the port on which its server is running.
A CGI script written in Perl calls:
$port = $ENV{'SERVER_PORT'};
where $port is an untyped variable. A CGI program written in C calls:
char *port = getenv("SERVER_PORT");
where port is a pointer to a character string. The chance for accidental errors is high. The environment variable name could be misspelled (it happens often enough) or the data type might not match what the environment variable returns.
A servlet, on the other hand, calls:
int port = req.getServerPort()
This eliminates a lot of accidental errors because the compiler can guarantee there are no misspellings and each return type is as it should be.
Delayed calculation. When a server launches a CGI program, the value for each and every environment variable must be precalculated and passed, whether the CGI program uses it or not. A server launching a servlet has the option to improve performance by delaying these calculations and performing them on demand as needed.
More interaction with the server. Once a CGI program begins execution, it is untethered from its server. The only communication path available to the program is its standard output. A servlet, however, can work with the server. As discussed in the last chapter, a servlet operates either within the server (when possible) or as a connected process outside the server (when necessary). Using this connectivity, a servlet can make ad hoc requests for calculated information that only the server can provide. For example, a servlet can have its server do arbitrary path translations, taking into consideration the server's aliases and virtual paths.
If you're coming to servlets from CGI, Table 4-1 is a "cheat sheet" you can use for your migration. It lists each CGI environment variable and the corresponding HTTP servlet method.
CGI Environment Variable |
HTTP Servlet Method |
---|---|
SERVER_NAME |
req.getServerName() |
SERVER_SOFTWARE |
getServletContext().getServerInfo() |
SERVER_PROTOCOL |
req.getProtocol() |
SERVER_PORT |
req.getServerPort() |
REQUEST_METHOD |
req.getMethod() |
PATH_INFO |
req.getPathInfo() |
PATH_TRANSLATED |
req.getPathTranslated() |
SCRIPT_NAME |
req.getServletPath() |
DOCUMENT_ROOT |
req.getRealPath("/") |
QUERY_STRING |
req.getQueryString() |
REMOTE_HOST |
req.getRemoteHost() |
REMOTE_ADDR |
req.getRemoteAddr() |
AUTH_TYPE |
req.getAuthType() |
REMOTE_USER |
req.getRemoteUser() |
CONTENT_TYPE |
req.getContentType() |
CONTENT_LENGTH |
req.getContentLength() |
HTTP_ACCEPT |
req.getHeader("Accept") |
HTTP_USER_AGENT |
req.getHeader("User-Agent") |
HTTP_REFERER |
req.getHeader("Referer") |
In the rest of this chapter, we'll see how and when to use these methods--and several other methods that have no CGI counterparts. Along the way, we'll put the methods to use in some real servlets.
Each registered servlet name can have specific initialization (init) parameters associated with it. Init parameters are available to the servlet at any time; they are often used in init() to set initial or default values for a servlet or to customize the servlet's behavior in some way. Init parameters are more fully explained in Chapter 3, "The Servlet Life Cycle".
A servlet uses the getInitParameter() method to get access to its init parameters:
public String ServletConfig.getInitParameter(String name)
This method returns the value of the named init parameter or null if it does not exist. The return value is always a single String. It is up to the servlet to interpret the value.
The GenericServlet class implements the ServletConfig interface and thus provides direct access to the getInitParameter() method.[1] The method is usually called like this:
[1] The servlet must call super.init(config) in its init() method to get this functionality.
public void init(ServletConfig config) throws ServletException { super.init(config); String greeting = getInitParameter("greeting"); }
A servlet that needs to establish a connection to a database can use its init parameters to define the details of the connection. We can assume a custom establishConnection() method to abstract away the details of JDBC, as shown in Example 4-1.
java.sql.Connection con = null; public void init(ServletConfig config) throws ServletException { super.init(config); String host = getInitParameter("host"); int port = Integer.parseInt(getInitParameter("port")); String db = getInitParameter("db"); String user = getInitParameter("user"); String password = getInitParameter("password"); String proxy = getInitParameter("proxy"); con = establishConnection(host, port, db, user, password, proxy); }
A servlet can examine all its init parameters using getInitParameterNames() :
public Enumeration ServletConfig.getInitParameterNames()
This method returns the names of all the servlet's init parameters as an Enumeration of String objects or an empty Enumeration if no parameters exist. It's most often used for debugging.
The GenericServlet class also makes this method directly available to servlets. Example 4-2 shows a servlet that prints the name and value for all of its init parameters.
import java.io.*; import java.util.*; import javax.servlet.*; public class InitSnoop extends GenericServlet { // No init() method needed public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { res.setContentType("text/plain"); PrintWriter out = res.getWriter(); out.println("Init Parameters:"); Enumeration enum = getInitParameterNames(); while (enum.hasMoreElements()) { String name = (String) enum.nextElement(); out.println(name + ": " + getInitParameter(name)); } } }
Notice that this servlet directly subclasses GenericServlet, showing that init parameters are available to servlets that aren't HTTP servlets. A generic servlet can be used in a web server even though it lacks any support for HTTP-specific functionality.
Unfortunately, there's no server-independent way for a servlet to ask for its registered name or its class file location. This information may be added in a future version of the Servlet API. Until then, although it's not pretty, this information can be passed using init parameters where necessary. Also, some servers--including the Java Web Server--provide a back door whereby a servlet can get its registered name. If a servlet defines a method with the following signature, the server calls it and passes it the servlet's registered name at initialization:
public void setServletName(String name);
The servlet can save the passed-in name and use it later. You'll notice this back door was built without changing the Servlet API, a necessary requirement because, by the time it was added, the Servlet API 2.0 had already been frozen.
Copyright © 2001 O'Reilly & Associates. All rights reserved.
This HTML Help has been published using the chm2web software. |