JSPs and JavaBeans
Introduction
JavaServer Pages, or JSP, is a technology that is certain to
be very widely used. It has been a little slow in spreading because it has not
had a stable release until recently, and pre-release versions were not clear
about their overall direction. Clarity had to wait until the release of the XML
and Namespace Recommendations by W3C (see Appendices H and I). With that release, JSP started a rapid transition to
XML. As with several other technologies, including the XSLT recommendation, in
this book we're among the first to use an official stable release, JSP 1.0. We
refer to the specification, which we quote often, as JSP 1.0.
A JSP page is an HTML or XML page that contains JSP
elements. JSP elements are delimited by JSP tags. Some of these tags have
standard XML/Namespaces syntax, others have JSP-specific syntax reminiscent of
Processing Instructions. Beginning with version 1.0, all non-XML tags have
equivalent XML tags defined in the JSP DTD, so that a JSP page can be a valid XML page. JSP
1.0-compliant processors are not required to accept JSP pages in XML syntax,
but JSP 1.xcompliant processors are required to,
in effect, incorporate a validating XML parser. They are also required to
accept definitions of namespaces from a JSP (the taglib
feature), in addition to the default jsp:
namespace.
The largest challenge of JSP, as you will see throughout the
chapter, is to find a good way to structure the application into components: a
JSP page is so versatile that it is easy to try to make it do too much.
JavaBeans are a big help here. Instead of mixing Web content with unstructured
stretches of Java code, a JSP page can try to isolate its procedures into a
compiled Java bean, and use its JSP elements mostly to create and manipulate an
instance of such a bean. This is a clear direction of JSP evolution from
version 0.92 to versions 1.0 and 1.1.
Combining the two changes together, we can say that JSP
pages are moving towards becoming XML pages that have servlet functionality and
allow the incorporation of Java code.
Apart from JSP (and also the SAXMiniLanguage), there is one more way to
incorporate Java code in XML pages: through the "extension" mechanism
of an XSLT style sheet (see Chapter 13 for more details and an example). Although
not yet standardized, it is definitely on its way to becoming a standard; once
this happens, there will be a significant area of functional overlap between
XML+XSLT+(Java code) and JSP-as-XML. The version 1.1 specification, in an
appendix entitled "Future", makes it clear that its authors are aware
of the converging lines of development; the XML-Java team and the JSP team are
working closely together.
In outline, this chapter proceeds as follows:
Major features of JSP
A JSP example and the servlet it generates
Overview of JSP syntax and semantics
Design considerations
An example of a circular conversation between a page, a
bean and a browser
An
application with JavaMail, JSP and a database
In addition to an overview section in this chapter, Appendix F contains the syntactic
summary of JSP. As you will see, the syntax of JSP is small and intuitive, and
its semantics are easy to grasp for those who have a background in servlets.
The main challenge, with respect to JSPs, is to find good uses for their impressive
functionality. This is what this chapter will concentrate on.
Major features of JSP
Throughout this book, our distributed applications have had
at least these four separate components:
a servlet, to receive a request and map it to a
response
some backend code that the servlet invokes to do
backend work, e.g. run a database query
an HtmlWrapper class that produces the output
a template file for output that contains both static
template material and dynamic elements filled in by the servlet and backend
code
The great advantage of a JSP is that it can be all those
components at once. It has access to the same Request,
Response and Session
objects that a servlet does, and it has a PrintWriter
that writes to Response. It can contain arbitrary
amounts of Java code, and it can dynamically load Java beans. At the same time,
it is an HTML or an XML page with JSP elements inserted in it; beginning with
version 1.0, those JSP elements may themselves be well-formed XML, so the
entire JSP is a well-formed XML document, which can be validated against the
JSP DTD.
What Does it Look Like?
You have already seen a short example of JSP in Chapter 3;
here is another one, combined from examples in the GNU JSP 1.0 distribution and
our own embellishments:
<html>
<head>
<title>JSP example page</title>
<%! int
i=5,j=2; %>
<!-- a declaration -->
<%@ page
import="java.util.Date" %> <!-- a directive -->
</head>
<body>
<h1>The Famous JSP Hello Program</h1>
<%
String s = "GNU"+"JSP"; %> <!-- a code fragment -->
The following line should contain the text "Hello
GNUJSP World!".
<br>If thats not the case start debugging ...
<p>Hello <%= s %> World!<br> <!-- an expression
-->
The current date is <%= new Date()
%>.<br> <!--
another expression -->
The integer value is <%= ++i+j %> <!-- another expression
-->
<% if(i<12){ %> <!-- code fragment -->
<br>less than a dozen <!-- template data -->
<% }else %> <!-- code fragment -->
<br>a dozen or more <!-- template data -->
<% ;
%> <!-- code
fragment -->
</body>
</html>
If you have this document served to you by a JSP-enabled
server (i.e. a server that has a JSP engine) then this is what you will
see:
Click the Reload/Refresh
button several times, and you will reach the point where the message changes.
Our next task is to understand how this comes about. We are not aiming for a
systematic coverage at this point, but note that a JSP file consists of
template data, which is just HTML, and JSP elements of various kinds. The file
above shows a declaration, a directive, and several code fragments and
expressions. Each kind is indicated by a specific JSP tag.
How does it work?
JSP pages work within a request-response, client-server
protocol, such as HTTP. Although JSP 1.0 talks about JSP engines implementing
other protocols, for now it is HTTP that JSP engines implement, and that is the
context we assume: when we say "request" or "response", we
mean HTTP versions.
When a request for a JSP page comes from a client to a
JSP-enabled server (whether as a URL to load or a form action to execute), the
server passes it on to its JSP engine. The JSP engine delivers requests from a
client to a JSP page, and responses from the JSP page to the client.
Theoretically, JSP engines are free to implement "request" as they
wish, but in practice, this is what happens: deep down inside, a JSP page is a
servlet, and requests and responses are Java objects of type HttpServletRequest and HttpServletResponse.
How and when does a JSP page become a servlet? This is an
optimization trick that is not codified in a definitive way: the translation of
JSP text into servlet code can happen (to quote the specification)
"at any time between initial
deployment of the JSP page into the runtime environment of a JSP engine, and
the receipt and processing of a client request for the target JSP page."
(1.4)
Typically, during the "receipt and processing" of
the first request, the servlet class is compiled and loaded, so subsequent
requests return much faster than the first one. The class is not recompiled
until changes to the JSP pages are made, which may be a problem for pages that
dynamically load Java beans because if a bean is changed and recompiled, the
system won't notice unless you also "touch up" the JSP page to force
recompilation of the servlet.
Translating JSP into Servlet
Simplifying quite a bit, the translation process boils down
to this: the Java code of the page becomes the Java code of the underlying
servlet, while the template data gets rewritten as out.println()
statements. The way it is done depends on the JSP engine; we illustrate by
going through the code generated by jswdk-1.0 from the example above. We found
reading the code instructive.
Our JSP page is in the directory jswdk-1.0
\examples\jsp\; the Java code file is generated in jswdk-1.0\work\%3A8080%2Fexamples. (In the
text below, we will sometimes refer to the jswdk-1.0
directory as JSP_ROOT.) In addition to the code file, the
translation process also generates a binary data file in the same directory.
That file, as we will see shortly, contains the text of the JSP file, saved as
a two-dimensional array of characters. It also contains some data structure,
probably a Vector, that holds array indices for the beginning and end of each
JSP element.
In outline, the generated code consists of:
package and import statements
declarations
an initialization
method
a service
method
We will look at each of these in turn.
Package and Import Statements
The name of the package is generated from the path to the
directory containing the JSP page and, depending on your directory structure,
will look something like:
package D_0003a.jswdk_0002d_00031_0005f_00030.examples.jsp.ch_00031_00030;
The import statements show what JSP pages need to function.
We have rearranged their order to group related ones together, but we have not
moved the last one because its position is not random: this is the only one in
this example that has been generated from a directive in the page:
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
import com.sun.jsp.runtime.*;
import com.sun.jsp.JspException;
import java.io.PrintWriter;
import java.io.IOException;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.util.Vector;
import java.beans.*;
import java.util.Date; // generated from a page
directive
As you can see, there is a new kid on the block, the javax.servlet.jsp package. Let's take a
quick look at it.
javax.servlet.jsp
The package consists of two interfaces and four classes, all
of them abstract. The implementations and non-abstract extensions of them all
are in com.sun.jsp.runtime. We will see glimpses
of them as we read through the code.
Interfaces: HttpJspPage, JspPage
Classes:
JspEngineInfo,
JspFactory,
JspWriter,
PageContext
The JavaDoc API documentation explains what these do, and we
will see examples in the code. The main point is that the JspPage interface extends javax.servlet.Servlet, and HttpJspPage extends JspPage.
The servlet class generated from a JSP page extends HttpJspBase,
which implements HttpJspPage.
Declarations
Next come declarations, a null constructor, and a couple of
static variables. Note how every time Java code is extracted from JSP text, two
automatically generated comments indicate the beginning and end of the
extraction. (The // begin comment
unfortunately wraps around on a book page.)
public class exa3_jsp_1 extends HttpJspBase
{
static
char[][] _jspx_html_data = null;
// begin
[file="D:\\jswdk1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(3,11);to=(3,25)]
int
i=5,j=2; // both lines above are part
of the //begin comment
// end
public exa3_jsp_1( ) {}
private
static boolean _jspx_inited = false;
The static two-dimensional array of char
represents the text of the JSP file: rows are lines, and columns are columns.
The array is put to immediate use to copy the declarations of two integer
variables. The preceding // begin comment
gives the beginning and end point (from=(3,11);to=(3,25))
of where the declarations occur. If you check our JSP file, you will see that,
indeed, the two integer variables are declared on line 4, beginning at
character 12 and end on the same line at character 25.
The private static boolean is to keep track of
initialization. It is set to true once the initialization method is called from
the service method.
Initialization
The _jspx_init() method is final:
except for the name of the data file, it is the same for all applications. Its
main task is to open an ObjectInputStream
to the data file that contains the two-dimensional array of char, and read that array into a variable, _jspx_html_data:
public final void _jspx_init() throws JspException
{
ObjectInputStream oin = null;
int
numStrings = 0;
try
{
FileInputStream fin = new
FileInputStream("work\\%3A8080%2Fexamples
\\D_0003a.jswdk_0002d_00031_0005f_00030.
examples.jsp.ch_00031_00030exa3.dat");
oin =
new ObjectInputStream(fin);
_jspx_html_data = (char[][])
oin.readObject();
}
catch
(Exception ex)
{
throw
new JspException("Unable to open data file");
}
finally
{
if (oin
!= null)
try
{
oin.close();
}
catch
(IOException ignore)
{
}
}
}
This method is called from the service method that does all
the work.
Service
The service method is public, and it looks very much like a
servlet's service method:
public void _jspService(HttpServletRequest
request, HttpServletResponse
response) throws IOException, ServletException
{
The method starts by declaring and initializing all its
local variables, and running the _jspx_init()
method if it has not been run yet:
JspFactory _jspxFactory
= null;
PageContext pageContext = null;
HttpSession session = null;
ServletContext application = null;
ServletConfig config = null;
JspWriter out = null;
Object
page = this;
String _value = null;
try
{
if (_jspx_inited == false)
{
_jspx_init();
_jspx_inited = true;
}
The next thing we need is a pageContext
object. This is generated by a JspFactory:
_jspxFactory =
JspFactory.getDefaultFactory();
response.setContentType("text/html");
pageContext = _jspxFactory.getPageContext(this,
request,
response, "", true, 8192, true);
With a pageContext in
hand, we obtain the remaining objects we need:
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out
= pageContext.getOut();
Now we can start writing to out,
generating the response. If a line has only template material, we output it as
is. If there are JSP elements involved, they are dealt with appropriately,
according to their type. Every time a JSP element is processed, // begin and // end
comments are generated:
out.print(_jspx_html_data[0]);
out.print(_jspx_html_data[1]);
out.print(_jspx_html_data[2]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(9,3);to=(9,28)]
String s = "GNU" +
"JSP";
//
end
out.print(_jspx_html_data[3]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(13,12);to=(13,15)]
out.print( s );
//
end
out.print(_jspx_html_data[4]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(14,23);to=(14,35)]
out.print( new Date() );
//
end
out.print(_jspx_html_data[5]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(15,25);to=(15,32)]
out.print( ++i+j );
//
end
out.print(_jspx_html_data[6]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(17,2);to=(17,13)]
if(i < 12)
{
// end
out.print(_jspx_html_data[7]);
// begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(19,2);to=(19,9)]
}
else
//
end
out.print(_jspx_html_data[8]);
//
begin [file="D:\\jswdk-1.0\\examples\\jsp\\ch10\\exa3.jsp";
from=(21,2);to=(21,6)]
;
//
end
out.print(_jspx_html_data[9]);
}
catch (Throwable t)
{
if (out.getBufferSize() != 0)
{
out.clear();
}
throw new JspException("Unknown exception: ",
t);
}
finally
{
out.flush();
_jspxFactory.releasePageContext(pageContext);
}
}
}
Implicit Objects and Scope
One conclusion to draw from this is that a JSP page has some
implicit objects associated with it. They are: Request,
Response, a Writer,
a PageContext, a session,
a ServletConfig, and an application, which is a ServletContext.
If an exception is thrown but not caught by the implementing class of a JSP
page, and a special error page is specified by a page directive (see below),
that exception becomes an implicit object in the error page, referred to by the
name exception.
In addition to implicit objects, JSP page code can create
other objects as needed, or dynamically load objects; loading Javabeans is particularly easy. Section
1.4.1 of JSP 1.0 states: "The created objects have a scope attribute
defining where there is a reference to the object and when that reference is
removed." (In other words, it's both the scope and the temporal extent.)
The following scopes are supported (we quote from Section 1.4.1):
page – Objects
with page scope are accessible only within the page where they are created. All
references to such an object shall be released after the response is sent back
to the client from the JSP page or the request is forwarded somewhere else.
References to objects with page scope are stored in the PageContext object (see Chapter 2, Implicit Objects).
request –
Objects with request scope are accessible from pages processing the same
request where they were created. All references to the object shall be released
after the request is processed; in particular, if the request is forwarded to a
resource in the same runtime, the object is still reachable. References to
objects with request scope are stored in the request object.
session –
Objects with session scope are accessible from pages processing requests that
are in the same session as the one in which they were created. It is not legal
to define an object with session scope from within a page that is not
session-aware (see Section 2.7.1, "The page Directive"). All
references to the object shall be released after the associated session ends.
References to objects with session scope are stored in the session object
associated with the page activation.
application –
Objects with application scope are accessible from pages processing requests
that are in the same application as the one in which they were created. All
references to the object shall be released when the runtime environment
reclaims the ServletContext.
Objects with application scope can be defined (and reached) from pages that are
not session-aware (see Section 2.7.1, "The page Directive").
References to objects with application scope are stored in the application
object associated with a page activation.