Back Contents Next

 


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.x-compliant 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:

 

q       Major features of JSP

q       A JSP example and the servlet it generates

q       Overview of JSP syntax and semantics

q       Design considerations

q       An example of a circular conversation between a page, a bean and a browser

q       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:

 

q       a servlet, to receive a request and map it to a response

q       some backend code that the servlet invokes to do backend work, e.g. run a database query

q       an HtmlWrapper class that produces the output

q       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:

 

q       package and import statements

q       declarations

q       an initialization method

q       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.

 

q       Interfaces: HttpJspPage, JspPage

q       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):

 

q       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).

q       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.

q       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.

q       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.


 


Back Contents Next
©1999 Wrox Press Limited, US and UK.