Introducing JavaServer Pages

Based on servlet technology, and currently shaping up at breakneck speed, JavaServer Pages (JSP) is set to be one of the most important elements of Java server programming. It's by no means complete yet, but that will change as the Java 2 Enterprise Edition comes together.

So what are JavaServer Pages? Well, they combine markup (whether HTML or XML) with nuggets of Java code to produce a dynamic web page. Each page is automatically compiled to a servlet by the JSP engine, the first time it is requested, and then executed. JSP provides a variety of ways to talk to Java classes, servlets, applets and the web server. With it, you can split the functionality of your web applications into components with well-defined public interfaces glued together by a simple page.

This model allows tasks to be sub-divided - a developer builds custom components and the page designer assembles the application with a few judicious method calls. In this 'application assembly' model, the business logic is separated from the presentation of data.

To give you an idea of the future, this separation of logic and presentation may become yet more extreme with the use of custom tags slated for JSP 1.1.

JavaServer Pages is a specification that is already implemented by several web servers (for more details, see the JSP FAQ at http://www.esperanto.org.nz/jsp/jspfaq.html), on which your code will run without change, making it more portable and the server market more competitive than its rivals. Finally, it's nice and simple!

In this chapter, we will :

·  Discuss the JavaServer Pages (JSP) architecture

·  Look at the elements of a JSP file, and the tags used to represent them

·  Encapsulate logic in a JavaBean component and integrate it with JSP

·  Walk through a detailed example using JSP, showing a typical web application architecture

Architectural Overview

A JavaServer Page is a simple text file consisting of HTML or XML content along with JSP elements (a sort of shorthand for Java code). When a client requests a JSP page of the web server and it has not been run before, the page is first passed to a JSP engine which compiles the page to a servlet, runs it and returns the resulting content to the client. Thereafter, the web server's servlet engine will run the compiled page.

It should be no surprise, given the flexibility of the servlet model, that the current reference implementation of the JSP engine is itself a servlet.

It is possible to view the finished servlet code that is generated by locating it within the directory structure of the servlet engine. For example, with JRun, you can find the source code for your JSP files (in servlet form) in the jrun/jsm-default/services/jse/servlets/jsp directory. This is very helpful when trying to debug your JSP files.

If you take a look in the source files for the javax.servlet.jsp package, you'll find the following classes :

·  JSPPage

·  HttpJspPage

They define the interface for the compiled JSP page - namely that it must have three methods. Not surprisingly they are :

·  jspInit()

·  jspDestroy()

·  _jspService(HttpServletRequest request, HttpServletResponse response)

The first two methods can be defined by the JSP author (we'll see how in a moment), but the third is the compiled version of the JSP page, and its creation is the responsibility of the JSP engine.

It's time we saw a JSP file :

<html>
<head>
<title>Demo of a JSP page</title>
</head>
<body>
<!-- Set global information for the page -->
<%@ page language="java" %>
<!-- Declare the character variable -->
<%! char c = 0; %>
<!-- Scriptlet - Java code -->
<%
for (int i = 0; i < 26; i++)
{
for (int j = 0; j < 26; j++)
{
// Output capital letters of the alphabet, and change starting letter
c = (char)(0x41 + (26 - i + j)%26);
%>

Continued on Following Page

<!-- Output the value of c.toString() to the HTML page -->
<%= c %>
<%
}
%>
<br>
<%
}
%>
</body>
</html>

This page just outputs the alphabet 26 times and changes the starting letter. The HTML is self-explanatory and written the way it should be, rather than cluttering up methods of a servlet.

Elements of a JavaServer Page

The Java code in the page includes :

·  Directives – these provide global information to the page, for example, import statements, the page for error handling or whether the page is part of a session. In the above example we set the script language to Java.

·  Declaratives - these are for page-wide variable and method declarations.

·  Scriptlets - the Java code embedded in the page.

·  Expressions - formats the expression as a string for inclusion in the output of the page.

We will meet the last JSP element type, actions, soon. These elements follow an XML-like syntax, and perform a function behind the scenes. They provide the means to totally separate presentation from logic. A good example is <jsp:useBean .../> which finds or creates an instance of a bean with the given scope and name. With the tag extension mechanism to be introduced in JSP 1.1, you'll be able to define similar action tags and put their functionality in a tag library.

Now let's examine the basic elements of a JSP in a more complete fashion, before we code some more.

Something I've found very useful to have around while coding is the syntax crib sheet available at http://java.sun.com/products/jsp/syntax.html in PDF format. This has a concise summary of what we'll see here.

JSP Directives

A JSP directive is a statement that gives the JSP engine information for the page that follows. The general syntax of a JSP directive is <%@ directive { attribute=”value” } %>, where the directive may have a number of (optional) attributes. Each directive has an optional XML equivalent, but these are intended for future JSP tools, so we won't consider them here.

Possible directives in JSP 1.0 are :

·  Page – information for that page

·  Include – files to be included verbatim

·  Taglib – the URI for a library of tags that you'll use in the page (unimplemented at the time of writing)

As is to be expected, the page directive has many possible attributes. Specifying these is optional, as the mandatory ones have default values.

Attribute and possible values / Description
language=”java” / The language variable tells the server what language will be used in the file. Java is the only supported syntax for a JSP in the current specification.
Support for other scripting languages is available at http://www.plenix.org/polyjsp and http://www.caucho.com (JavaScript).
extends="package.class" / The extends variable defines the parent class of the generated servlet. It isn't normally necessary to use anything other than the provided base classes.
import="package.*,package.class" / The import variable is similar to the first section of any Java program. As such, it should always be placed at the top of the JSP file. The value of the import variable should be a comma-separated list of the packages and classes that you wish to import.
session="true|false" / By default, the session variable is true, meaning that session data is available to a page.
buffer="none|8kb|sizekb" / Determines if the output stream is buffered. By default it is set to 8kb. Use with autoFlush
autoFlush="true|false" / If set to true, flushes the output buffer when it's full, rather than raising an exception.

Continued on Following Page

Attribute and possible values / Description
isThreadSafe="true|false" / By default this is set true, signaling to the JSP engine that that multiple client requests can be dealt with at once. It's the JSP author's job to synchronize shared state, so that the page really is thread safe.
If isThreadSafe is set to false, the single thread model will be used, controlling client access to the page.
This doesn't let you off the hook, however, as servers may, at their discretion, have multiple instances of the page running to deal with the client request load. And there's no guarantee that consecutive requests from the same client will be directed to the same instance of JSP page. Any resources or state that are shared between page requests must therefore be synchronized.
info="text" / Information on the page that can be accessed through the page's Servlet.getServletInfo() method.
errorPage="pathToErrorPage" / Gives the relative path to the JSP page that will handle unhandled exceptions. That JSP page will have isErrorPage set to true
isErrorPage="true|false" / Marks the page as an error page. We'll see this in action later.
contentType="text/html;
charset=ISO-8859-1" / The mime type and character set of the JSP and the final page. This information must come early in the file, before any non-latin-1 characters appear in the file.

In the JSWDK-1.0-ea1 release there's a bug - the import statement needs to be imports to satisfy the JSP engine.

We'll see more of the include directive in a later example.


JSP Declarations

A JSP declaration can be thought of as the definition of class-level variables and methods that are to be used throughout the page. To define a declarative block, begin the block of code with <%! declaration.

<%!
String var1 = "x";
int count = 0;
private void incrementCount()
{
count++;
}
%>

Note that you put semi-colons after each variable declaration, just as if you were writing it in a class.

This is how you would define the optional jspInit() and jspDestroy() methods that we mentioned earlier.

JSP Scriptlets

Scriptlets are defined as any block of valid Java code that resides between <% and %> tags.

This code will be placed in the generated servlet's _jspService() method. Code that is defined within a scriptlet can access any variable and any beans that have been declared. There are also a host of implicit objects available to a scriptlet from the servlet environment.

Implicit Objects / Description
request / The client's request. This is usually a subclass of HttpServletRequest. This has the parameter list if there is one.
response / The JSP page's response, a subclass of HttpServletResponse.
pageContext / Page attributes and implicit objects (essentially what makes up the server environment in which the JSP runs) need to be accessible through a uniform API, to allow the JSP engine to compile pages. But each server will have specific implementations of these attributes and objects.
The solution to this problem is for the JSP engine to compile in code that uses a factory class to return the server's implementation of the PageContext class. That PageContext class has been initialized with the request and response objects and some of the attributes from the page directive (errorpage, session, buffer and autoflush) and provides the other implicit objects for the page request. We'll see more on this in a moment.
session / The HTTP session object associated with the request.
application / The servlet context returned by a call to getServletConfig().getContext() (see Chapter 5).
out / The object representing the output stream.
Implicit Objects / Description
config / The ServletConfig object for the page.
page / The page's way of referring to itself (as an alternative to this in any Java code).
exception / The uncaught subclass of Throwable that is passed to the errorpage URL.

The following snippet shows both how to get a named parameter from the request object, and how to pass a string to the output stream for the page.

<%
String var1 = request.getParameter("lname");
out.println(var1);
%>

Having discussed implicit objects, we're in a better position to understand the code featured in the comment for the PageContext source from the JSP 1.0 reference implementation. This shows the code that the JSP 1.0 reference engine injects into the JSP page's _jspService() method.

public void _jspService(HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
JspFactory factory = JspFactory.getDefaultFactory();
PageContext pageContext = factory.getPageContext(
this, // servlet
request,
response,
null, // errorPageURL
false, // needsSession
JspWriter.DEFAULT_BUFFER,
true // autoFlush
);
// Initialize implicit variables for scripting environment
HttpSession session = pageContext.getSession();
JspWriter out = pageContext.getOut();
Object page = this;
try {
// Body of translated JSP here...
} catch (Exception e)
{
out.clear();
pageContext.handlePageException(e);
} finally {
out.close();
factory.releasePageContext(pageContext);
}
}

JspFactory returns the pageContext implicit object, from which the other implicit objects are obtained for the duration of the _jspService() method.

JSP Expressions

A JSP expression is a very nice tool for embedding values within your HTML code. Anything between <%= and %> tags will be evaluated, converted to a string, and then displayed. Conversion from a primitive type to a string is handled automatically.

The current price of item A100 is
<%= request.getParameter("price") %>

Something you'll want to note is that the expression doesn't end with a semi-colon. That's because the JSP engine will put the expression within an out.println() call for you.

JSP expressions allow you to essentially parameterize HTML (just as you would parameterize a SQL query that differs by only a couple of values). Again and again, your code will set up conditions and loops using a one-line JSP scriptlet and then include the HTML code directly beneath it. Simply enclose the beginning and the ending of the condition or loop in separate pairs of <% and %> tags :

<% for (int i = 0; i < 10; i++)
{ %>
<br>
Counter value is <%= i %>
<% } %>

Coding JSP Pages

A big advantage in developing a JavaServer Page is that you can code the HTML without enclosing it in Java code, as you must do in a servlet. You can then take advantage of HTML editors to develop your content.

So from the drudgery of coding HTML output in servlets, we've arrived at the flexibility of coding Java snippets into the HTML page. But don't be dragged too far the other way. Heard of the people who can't fit their ASP files into Notepad? And if there's one problem with ASP and JSP, it's debugging the pages, making improvements to them, and untangling the meaning of that section you coded months back.

The "third way" is a mixture of presentation-based calls to a Bean or servlet, which components can be better tested, are well-encapsulated and good OOP citizens. This moves from embedding code to embedding components and action tags in the page.