Scott Snyder is a Software Engineer at IBM and part of the team responsible for the performance
of the IBM WebSphere family of e-business software servers. He can be contacted at
[email protected].
THE SERVLET API allows Web developers to use the Java programming language as a development
environment for dynamic Web page creation, execution of complex business logic, and communication
with third-tier data sources. However, these three activities are very distinct from each other and
require different types of software development skills.
Web page creators are generally more concerned with the aesthetic aspects of the page (i.e., the placement
and design of pictures, backgrounds, and frames) and less concerned about the source of the dynamic data
and the data manipulation required to get it into the form required by the client request. Also there
are times when information about the request is needed, such as the browser type, so that
client- or request-specific content can be provided in the Web page. It would be nice to allow Web
page designers to have access to this information without requiring them to learn Java, write servlets,
compile them, and deploy them on their Web servers.
To give designers access to the Servlet API without them going through the write, compile, deploy cycle,
Sun has defined JavaServer Pages to enable Java as a server side scripting language.
JavaServer Page Technology
The JavaServer Pages (JSP) technology uses standard HTML pages with special tags that are defined by the
JSP specification. JSP uses <% and %> tags
to delimit a JSP scriptlet—a set of Java code that is compiled and run as if it were in the service
method of a servlet (which, in fact, it will be). Any Java code can be placed within a scriptlet, so the
entire Java language can be used for scripting. In addition, the JSP specification predefines the
following variables available for use in a JSP page:
- request—An instance of javax.servlet.http.
HttpServletRequest set
to the client request.
- response—An instance of javax.servlet.http.
HttpServletResponse set
to the client response.
- in—An instance of java.io.BufferedReader set
to the servlet input.
- out—An instance of java.io.PrintWriter set to
the servlet output.
As an example, Listing 1 is a simple
JSP page that can detect the type of browser that the client is using and send the appropriate HTML content.
Because there is no standard for Dynamic HTML, it may be necessary to test for the type of browser so that
advanced features of each browser can be exploited. It is more efficient to determine the type of browser
on the server than have to send all the page variations to the client and have some client-side script
interpret the appropriate page information.
In Listing 1, a string variable is initialized with the value of the user-agent obtained using the
getHeader method of the request object, and then searched for the appropriate
strings to identify the Netscape or the Internet Explorer browser. Instead of returning anything fancy,
a string is sent to the servlet output indicating the client type, or if it is an unknown client,
the useragent string. Dynamic content is sent to the client by sending
strings to the out output stream object, which is a PrintWriter predefined
to correspond to the servlet output.
To output an individual expression, one can more conveniently use the JSP expression tags
<%= and %>. To see how they could be used
to further personalize this JSP page, see
Listing 2.
At the top of the page, expression tags are used to evaluate the address of the remote host as well as the
day and time. The processing of the JSP expression implicitly calls out.print() for the expression being
evaluated as well as doing the string conversion using a toString method as seen in the
<%=today%> call.
This in place expression evaluation can be used like the original server-side include (SSI) variables,
and most third-party servers that support JSP still support the legacy NCSA tags used for SSI. But JSP
technology can do more than simple SSI. Using the BEAN tag, several JSP pages
can reuse business logic encapsulated in a JavaBean. But first, let's see how JSP pages are processed.
JSP Under The Covers
JSP files are usually processed by servlet-enabled Web Servers through a step called Page Compilation.
Typically, when a file with the extension *.jsp
(or *.shtml for legacy SSI files) is requested a page compile servlet is
called with the JSP file as a parameter. The JSP file is read off the disk, parsed, and the static
portions stored. Then a servlet is dynamically constructed, the output of which will contain the
appropriate client response. This servlet is compiled by the server and if the compilation is successful,
it is loaded by the class loader just like any other servlet on the server. The next time the JSP file
is requested, the page compile servlet confirms that the file has not changed on disk and executes the
already loaded servlet. This makes JSP significantly faster than traditional SSI because the source
document is parsed only once. Once compiled, processing of JSP files is as efficient as any other servlet.
By default, the scriptlets and JSP expressions are placed in the service method of the dynamically
constructed servlet (which I will abbreviate DCS). But the name of the method of the DCS that the
scriptlets and JSP expressions are placed in can be specified using JSP directive tags. JSP directives
use the general syntax <@>@>directive_name = "string_value" %>,
where currently the valid directive names are:
- language—The scripting language used in the file. Currently the only valid language, and
the default, is "java".
- method—The method that scriptlets and JSP expressions are placed in the DCS.
- import—A comma-delimited list of packages that the DCS imports.
- content_type—The MIME type of the DCS response. The default is "text/html".
- implements—A comma-delimited list of Java interfaces that the DCS inherits from.
- extends—The Java class that the DCS inherits from. This can be any valid Java class.
Class-wide variables and methods can also be declared using the tag.
The syntax for the SCRIPT tag is
The runat=server is required to indicate that this tag is for server-side processing and not
to be passed on to the browser.
As this syntax indicates, almost any servlet functionality can be added to the DCS through the use of
JSP directives, expressions, scriptlets, and SCRIPT tags. While this flexibility is powerful for
dynamically constructing a stand-alone servlet, the real power of JavaServer Pages is in how they
can be used to interact with other servlets and beans on the server.
Separating Business Logic From Display
The most powerful form of dynamic page composition that JSP supports is by using the
BEAN tag. Using this tag, JSP pages can access instances of JavaBeans
that were created from a class file, referred to from an HTTP session, or passed in by a servlet.
The BEAN tag has several attributes controlling its name, datatype,
whether introspection will be used, whether the bean needs to be dynamically constructed, and so
on; see the 0.91 JSP draft specification1 for full details.
Listing 3 and Listing 4 show examples of the power of using JavaBeans
with JSP. Mortgage_direct.jsp.
Listing 3
is essentially an HTML form with a BEAN tag that instantiates the
MortgageBean class
(Listing 4).
In this example, the user types in loan amount, interest rate, and loan duration and the bean calculates
the monthly payment and inserts the result into the page.
When the form is submitted, an instance of the bean is looked for in the context of the DCS. If one is
not available and the create attribute is set, the DCS will create an instance of the bean of a type
specified by the type attribute. When the introspect attribute of the BEAN
tag is equal to "yes", the set methods of the instantiated bean that correspond to the form's name
variables will be run. This allows the form data to be brought into the bean and affect the results
of the bean's methods. In this example, the named fields are amount,
interestPerPeriod, and numberOfPayperiods, and the form button name is action.
Figure 1 shows a pictorial representation of the JSP file in a browser and the connection between the
three form fields, the reply and the form button, and the bean methods that are called when the button
is pressed. Because bean methods can be invoked directly from the JSP page,
mortgage_direct.jsp has an explicit call to
getReply() to get the monthly payment. Notice that the
MortgageBean (containing the formula for calculating monthly loan payback)
must still know the format of the data as it is entered into the form, thus linking the business logic
to the Web page display.
Figure 1. Pictorial representation of the JSP file in a browser and the connections called when a
button is pressed.
Up until now, the examples of the Java-Server Page technology have used JSP as a scripted version of SSI
where the client requests the JSP page and content is dynamically filled in for you. This model is fine
for simple environments where the amount of dynamic content is limited or the interaction with the
business logic is not that extensive. However it forces the Web page designer to work with and
manipulate potentially large amounts of Java code. What would be more typical on large Web sites is
that servlets would be used to contain some form of business logic. This could include calculations,
database access to mainframe or legacy systems, or anything that servlets would normally be used for,
but should not include generation of the client response. The design of the client response
(the dynamically constructed HTML page) is essentially an aesthetic one, requiring graphic artists,
or Web page designers, and should not be hardcoded into the servlet. Page designers need to have
access to HTML design tools that can work on page content independently of the source of the dynamic
content. By separating the presentation from the business logic, the look and organization of Web
sites can be updated without requiring modifications of the servlets driving the response.
Figure 2. Diagram of the JSP request model.
Figure 2 is a diagram of the JSP request model. In it a client request is made to a servlet. This servlet
implements the appropriate business logic and places the data that needs to be sent to the output in an
instance of a bean. This bean can be used for any purpose required by the application, including possibly
JDBC access to databases, but must include public accessor (get) methods to
get the private bean data that needs to be accessible to the JSP page. If the bean can be made
accessible to a JSP file designated as the output, then BEAN tags can be
used to access the required dynamic content. To support this functionality, Sun has defined two new
interface API's.
- com.sun.server.http.HttpServiceRequest implements the
javax.servlet.http.HttpServletRequest interface and adds a
setAttribute method that allows an object and a key to be stored with the request.
- com.sun.server.http.HttpServiceResponse implements the javax.servlet.http.HttpServlet
Response interface and adds a callPage method that passes a JSP page
(or HTML page) to the response for output.
Listings 5-8 show the mortgage calculator implemented with a servlet invocation. This application follows
the JSP request model diagram in Figure 2 except that it does not access a database as shown in the figure.
Initially, the client fills out a regular HTML form
(Listing 5),
which submits a POST request to MortgageServlet
(Listing 6);
in Figure 2 this is the Request arrow pointing to the servlet at position 1.
The doGet and doPost methods call a
performTask method, which takes the form attributes, does the appropriate
scaling, instantiates the MortgageBean
(Listing 7),
and sends the scaled form parameters to the bean to be processed; this is position 2 in Figure 2.
The MortgageBean is not instantiated in the standard way using the
new() method but as:
myMortgageBean = (MortgageBean)
java.beans.Beans.instantiate(getClass().getClass-
Loader(), "MortgageBean");
This is because the new() method uses the default system class loader,
which may not be the same as the servlet class loader. Because the instance of the
MortgageBean (myMortgageBean) must be accessible to the servlet constructed
from the JSP page via the pagecompile process, it must be instantiated with
the servlet class loader so that it will be visible to the DCS.
When the performTask method of the servlet is finished updating
myMortgageBean, it calls the setAttribute method
of HttpServiceRequest to store the bean instance with the request and then
uses the callPage method of HttpServiceResponse to
send a JSP file as the client response; this is position 3 in Figure 2. The JSP page
(Listing 8)
returns the mortgage information and fills out a duplicate of the original static form so that additional
requests can be made.
Notice that the MortgageBean can now be implemented more generally because it
does not have to know how the form attributes are being sent; it leaves that to the servlet. This
aids reuse as different servlets can use the MortgageBean to calculate
mortgages without any concern about how the input to the mortgage calculation is obtained.
In a way, the bean definition acts as a contract between the servlet writer and the Web page designer.
The Web page designer is guaranteed to have access to certain state information and methods by the servlet
writer; he is generally unconcerned as to how that information is obtained, and cares only that it is
available when required. The servlet writer is not concerned with how the bean information will be
presented to the client; only that he fulfill the interface requirements of the bean.
This Just In
JSP draft specification 0.922 was released on October 7, 1998. Most JSP implementations are
based on the 0.91 draft specification as in the above discussion. Some changes introduced in the 0.92
JSP draft specification are:
- The BEAN tag has been renamed to USEBEAN.
- The INTROSPECT attribute of the BEAN tag is
now a separate tag called SETFROMREQUEST.
- The CREATE attribute of the BEAN tag is now a
separate tag called SETONCREATE.
- The com.sun.server.http.HttpServiceResponse.call Page(String uri,
HttpServletRequest request) method has been replaced by javax.servlet.
ServletContext.getRequestDispatcher(String uripath) and the
com.sun.server.http.HttpServiceRequest. setAttribute(String key, Object o)
method have been replaced by javax.servlet. ServletRequest.
setAttribute (String key, Object o) with the new Java Servlet Development Kit 2.0 (JSDK 2.0)
specification.
- Hierarchical naming was introduced in referring to bean properties so that one could say
MyBean:myProperty instead of MyBean.my Property or
as in the original 0.91 specification <%= MyBean.getMyProperty() %>.
- A tag was introduced so that bean properties could be
accessed directly without explicitly using the get method for that property i.e.,
<%= MyBean.getMy
Property() %>.
- A tag has been added to support the display of multivalued
properties using the above hierarchical naming with both implicit and explicit loop indices (used in
conjunction with the DISPLAY tag above).
- Conditional inclusion of statements with the and
tags.
- Implicit beans, exception and request environment, are created, which are used to hold error information
and request information, respectively.
- Beans can now exist for the life of an application, as well as for the original request and session.
- The METHOD, IMPLEMENTS, and EXTENDS directives
have been removed.
What can we infer from these changes? The bean attributes have been promoted to full tags, perhaps as a
way of applying them to container objects other than beans. The hierarchical naming as well as the
DISPLAY and LOOP tags also seem to support
this because they remove the Java-specific syntax to property access.
Servlets are being promoted as being part of a Web application, a "set of cooperating resources...that
share information to achieve some end functionality."2
The removal of the METHOD, IMPLEMENTS, and EXTENDS
directives seems to indicate that Sun is encouraging developers not to place too much business logic
within the JSP page, but to encapsulate it within a bean or a servlet.
JavaServer Pages is an exciting and rapidly evolving technology for server side Java, as you can see
from the number of changes in the specification from 0.91 to 0.92, and will be a key component,
along with Enterprise JavaBeans, in Sun's positioning of Java as the premier tool for server and
enterprise level computing.
References
- The 0.91 JSP draft specification is no longer available on the Sun Web site. Check any third-party
server vendor that supports JSP e.g., IBM's WebSphere Application Server documentation at
www.software.ibm.com/webservers/appserv/doc/guide/asgl1mst.html.
- The 0.92 draft specification is available from Sun at
java.sun.com/products/jsp/jsp092.html.