All the servlets you've seen so far generate full HTML pages. If this were all that servlets could do, it would still be plenty. Servlets, however, can also be embedded inside HTML pages with something called server-side include (SSI)functionality.
In many servers that support servlets, a page can be preprocessed by the server to include output from servlets at certain points inside the page. The tags used for a server-side include look similar to those used for applets:[4]
[4] Currently, the <SERVLET> tag syntax varies across server implementations. This section describes the syntax appropriate for the Java Web Server.
<SERVLET CODE=ServletName CODEBASE=http://server:port/dir initParam1=initValue1 initParam2=initValue2> <PARAM NAME=param1 VALUE=value1> <PARAM NAME=param2 VALUE=value2> If you see this text, it means that the web server providing this page does not support the SERVLET tag. </SERVLET>
The CODE attribute specifies the class name or registered name of the servlet to invoke. The CODEBASE attribute is optional. It can refer to a remote location from which the servlet should be loaded. Without a CODEBASE attribute, the servlet is assumed to be local.
Any number of parameters may be passed to the servlet using the <PARAM> tag. The servlet can retrieve the parameter values using the getParameter() method of ServletRequest. Any number of initialization (init) parameters may also be passed to the servlet appended to the end of the <SERVLET> tag. We'll cover init parameters in Chapter 3, "The Servlet Life Cycle".
A server that supports SSI detects the <SERVLET> tag in the process of returning the page and substitutes in its place the output from the servlet (as shown in Figure 2-7). The server does not parse every page it returns, just those that are specially tagged. The Java Web Server, by default, parses only pages with an .shtml extension. Note that with the <SERVLET> tag, unlike the <APPLET> tag, the client browser never sees anything between <SERVLET> and </SERVLET>--unless the server does not support SSI, in which case the client receives the content, ignores the unrecognized tags, and displays the descriptive text.
Server-side includes are useful when a page is primarily static but contains a few distinct dynamic portions. For a simple example, let's assume we have several pages that need to display the current time. As an extra challenge, let's assume that sometimes we need the current time in time zones other than our own.
The problem is easy with server-side includes. Each page can be written as a static HTML page with one or more SSI directives that call Java code to provide the times. The HTML could look something like this, saved to a file with an .shtmlextension:
<HTML> <HEAD><TITLE>Times!</TITLE></HEAD> <BODY> The current time here is: <SERVLET CODE=CurrentTime> </SERVLET> <P> The current time in London is: <SERVLET CODE=CurrentTime> <PARAM NAME=zone VALUE=GMT> </SERVLET> <P> And the current time in New York is: <SERVLET CODE=CurrentTime> <PARAM NAME=zone VALUE=EST> </SERVLET> <P> </BODY> </HTML>
The servlet named CurrentTime can be plugged into any page that needs a time display. The name can be either the servlet's class name or its registered name. The servlet code is shown in Example 2-4.
import java.io.*; import java.text.*; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; public class CurrentTime extends HttpServlet { public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException { PrintWriter out = res.getWriter(); Date date = new Date(); DateFormat df = DateFormat.getInstance(); String zone = req.getParameter("zone"); if (zone != null) { TimeZone tz = TimeZone.getTimeZone(zone); df.setTimeZone(tz); } out.println(df.format(date)); } }
The CurrentTime servlet looks strikingly similar to the Hello servlet. This is not a coincidence. There is no real difference between a servlet that handles full-page GET requests and one that is embedded in a page, except that embedded servlets have limited response capabilities. For example, an embedded servlet cannot set HTTP headers.
The only method CurrentTime implements is the doGet() method. All SSI servlets use either doGet() or service() to handle requests. Inside the method, the servlet first retrieves its PrintWriter.[5] This early retrieval is perhaps unnecessary; it could be retrieved as late as the next to last line. Still, we recommend fetching it first thing. It will save time later when you find you need to begin sending output sooner than you expected.
[5]The Java Web Server 1.1.1 has a bug where the PrintWriter returned by the getWriter() method of ServletRequest does not generate output for a servlet used as a server side include. This means that to run the SSI examples shown in the book you need to use another servlet engine; or you can change the examples to manually create a PrintWriter as follows: PrintWriter out = new PrintWriter(res.getOutputStream(), true);
Then the servlet gets the current Date and a DateFormat instance with which to display the time. This servlet's ability to hop time zones is based on functionality in DateFormat. The servlet simply tells the DateFormat which time zone to use, and the date is displayed appropriately.
The time zone is specified by the <PARAM> tag in the HTML file. The servlet gains access to this parameter with the getParameter() method of HttpServletRequest. This technique is identical to the one we used to retrieve form data. The servlet uses the value of the "zone" parameter to create a TimeZone object that can be passed to the DateFormat object. If the "zone" parameter is not specified, as is the case with the first SSI example on our page, getParameter() returns null and the DateFormat uses the default time zone. Finally, the servlet outputs the String created when the DateFormat object formats the current date. The output of the HTML page is shown in Figure 2-8.
Copyright © 2001 O'Reilly & Associates. All rights reserved.