Friday, October 23, 2009

B.1 Servlet and JavaServer Pages Overview




I l@ve RuBoard










B.1 Servlet and JavaServer Pages Overview



Java
servlet technology is a means by which to execute Java programs
efficiently in a web environment. The Java Servlet Specification
defines the conventions of this environment, which may be summarized
briefly as follows:




  • Servlets run inside a servlet container, which itself either runs
    inside a web server or communicates with one. Servlet containers are
    also known as servlet engines.


  • The servlet container receives
    requests from the web server and executes the appropriate servlet to
    process the request. The container then receives the response from
    the servlet and gives it to the web server, which in turn returns it
    to the client. A servlet container thus provides the connection
    between servlets and the web server under which they run. The
    container acts as the servlet runtime environment, with
    responsibilities that include determining the mapping between client
    requests and the servlets that handle them, as well as loading,
    executing, and unloading servlets as necessary.


  • Servlets communicate with their container according to established
    conventions. Each servlet is expected to implement methods with
    well-known names to be called in response to various kinds of
    requests. For example, GET and
    POST requests are routed to methods named
    doGet( ) and doPost( ).


  • Servlets that can be run by a container are arranged into logical
    groupings called
    "contexts."
    (Contexts might correspond, for example, to subdirectories of the
    document tree that is managed by the container.) Contexts also can
    include resources other than servlets, such as HTML pages, images, or
    configuration files.


  • A context provides the basis for an
    "application,"
    that is, a group of related servlets that work together, without
    interference from other unrelated servlets. Servlets within a given
    application context can share information with each other, but
    servlets in different contexts cannot. For example, a gateway or
    login servlet might establish a user's credentials,
    which then are placed into the context environment to be shared with
    other servlets within the same context as proof that the user has
    logged in properly. Should those servlets find the proper credentials
    not to be present in the environment when they execute, they can
    redirect to the gateway servlet automatically to require the user to
    log in. Servlets in another context cannot gain access to these
    credentials. Contexts thus provide a measure of security by
    preventing one application from invading another. They also can
    insulate applications from the effects of another application
    crashing; the container can keep the non-crashed applications running
    while it restarts the one that failed.


  • Sharing of information between servlets may take place at several
    scope levels, which allows them to work together within the scope of
    a single request or across multiple requests.



The following listing shows what a simple servlet looks like.
It's a Java program that implements a
SimpleServlet class. The class has a doGet(
)

method to be invoked by the servlet container when it receives a
GET request for the servlet. It also has a
doPost( ) method to handle the possibility that a
POST request may be received instead;
it's simply a wrapper that invokes doGet(
)
. SimpleServlet produces a short HTML
page that includes some static text that is the same each time the
servlet runs, and two dynamic elements (the current date and client
IP address) that vary over time and for each client:



import java.io.*;
import java.util.*;
import javax.servlet.*;
import javax.servlet.http.*;

public class SimpleServlet extends HttpServlet
{
public void doGet (HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
PrintWriter out = response.getWriter ( );

response.setContentType ("text/html");
out.println ("<html>");
out.println ("<head>");
out.println ("<title>Simple Servlet</title>");
out.println ("</head>");
out.println ("<body bgcolor=\"white\">");
out.println ("<p>Hello.</p>");
out.println ("<p>The current date is "
+ new Date ( )
+ ".</p>");
out.println ("<p>Your IP address is "
+ request.getRemoteAddr ( )
+ ".</p>");
out.println ("</body>");
out.println ("</html>");
}

public void doPost (HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
doGet (request, response);
}
}


As you will no doubt observe, this
"simple" servlet really
isn't so simple! It requires a fair amount of
machinery to import the requisite classes and to establish the
doGet( ) and doPost( ) methods
that provide the standard interface to the servlet container.
Compare the servlet to the following
PHP script, which does the same thing in a much more concise fashion:



<html>
<head>
<title>Simple PHP Page</title>
</head>
<body bgcolor="white">

<p>Hello.</p>
<p>The current date is <?php print (date ("D M d H:i:s T Y")); ?>.</p>
<p>Your IP address is <?php print ($_SERVER["REMOTE_ADDR"]); ?>.</p>

</body>
</html>


The contrast between the Java servlet and the PHP script illustrates
one of the problems with writing servlets�the amount of
repetitious overhead:




  • A certain minimal set of classes must be imported into each servlet.


  • The framework for setting up the servlet class and the
    doGet( ) or doPost( ) methods
    is fairly stereotypical, often varying among servlets only in the
    servlet class name.


  • Each fragment of HTML is produced with an output statement.



The first two points can be addressed by using a prototype file that
you copy when beginning a new servlet. The third point (wrapping each
line of HTML within a print statement) is not so easily addressed and
is possibly the single most tedious aspect of servlet writing. It
also leads to another issue: a servlet's code may be
easy enough to read as Java, but it's sometimes
difficult to discern the structure of the HTML that the code
generates. The problem is that you're really trying
to write in two languages at once (i.e., you're
writing Java that writes HTML), which isn't really
optimal for either language.




B.1.1 JSP Pages�An Alternative to Servlets



One of the reasons for the invention
of JavaServer Pages was to relieve the burden involved in creating
web pages by means of lots of print statements. JSP uses a notational
approach that is similar to PHP: HTML is written literally without
being wrapped in print statements, and code to be executed is
embedded in the page within special markers. The following listing
shows a JSP page that is equivalent to the
SimpleServlet servlet, but looks much more like
the corresponding PHP script:



<html>
<head>
<title>Simple JSP Page</title>
</head>
<body bgcolor="white">

<p>Hello.</p>
<p>The current date is <%= new java.util.Date ( ) %>.</p>
<p>Your IP address is <%= request.getRemoteAddr ( ) %>.</p>

</body>
</html>


The JSP page is more concise than the servlet in several ways:




  • The standard set of classes required to run a servlet need not be
    imported.


  • The HTML is written more naturally, without using print statements.


  • No class definition is required, nor are any doGet(
    )
    or doPost( ) methods.


  • The response and out objects
    need not be declared, because they're set up for you
    and ready to use as implicit objects. In fact, the JSP page just
    shown doesn't refer to out
    explicitly at all, because its output-producing constructs write to
    out automatically.


  • The default content type is text/html;
    there's no need to specify it explicitly.


  • The script includes literal Java by placing it within special
    markers. The page just shown uses <%= and
    %>, which mean "evaluate the
    expression and produce its result." There are other
    markers as well, each of which has a specific purpose. (For a brief
    summary, see "Elements of JSP
    Pages" later in this appendix.)



When a servlet container receives a request for a JSP page, it treats
the page as a template containing literal text plus executable code
embedded within special markers. The container produces an output
page from the template to send to the client. Literal text from the
template is left unmodified, the executable code is replaced by any
output that it generates, and the combined result is returned to the
client as the response to the request. That's the
conceptual view of JSP processing, at least. What really happens when
a container processes a JSP
request is as follows:




  • The JSP page is translated into a servlet�that is, into an
    equivalent Java program. Instances of template text are converted to
    print statements that output the text literally. Instances of code
    are placed into the program so that they execute with the intended
    effect. This is all placed within a wrapper that provides a unique
    class name and that includes import statements to
    pull in the standard set of classes necessary for the servlet to run
    properly in a web environment.


  • The container compiles the servlet to produce an executable class
    file.


  • The container executes the class file to generate an output page,
    which is returned to the client as the response to the request.


  • The container also caches the executable class so that when the next
    request for the JSP page arrives, the container can execute the class
    directly and skip the translation and compilation phases. If the
    container notices that a JSP page has been modified the next time it
    is requested, it discards the cached class and recompiles the
    modified page into a new executable class.



Notationally, JSP pages provide a more natural way to write web pages
than do servlets. Operationally, the JSP engine provides the benefits
of automatic compilation after the page is installed in the document
tree or modified thereafter. When you write a servlet, any changes
require recompiling the servlet, unloading the old one, and loading
the new one. That can lead to an emphasis on messing with the servlet
itself rather than a focus on the servlet's purpose.
JSP reverses the emphasis so that you think more about what the page
does than about the mechanics of getting it compiled and loaded
properly.



The differences between servlets and JSP pages do not imply any
necessity of choosing to use only one or the other. Application
contexts in a servlet container can include both, and because JSP
pages are converted into servlets anyway, they can all
intercommunicate.



JSP is similar enough to certain other technologies that it can
provide a migration path away from them. For example, the JSP
approach is much like that used in Microsoft's Active
Server Pages (ASP). However, JSP is vendor and platform neutral,
whereas ASP is proprietary. JSP thus provides an attractive
alternative technology for anyone looking to move away from ASP.





B.1.2 Custom Actions and Tag Libraries



A servlet looks a lot like a Java program, because
that's what it is. The JSP approach encourages a
cleaner separation of HTML (presentation) and code, because you need
not generate HTML from within Java print statements. On the other
hand, JSP doesn't require
separation of HTML and code, so it's still possible
to end up with lots of embedded Java in a page if
you're not careful.



One way to avoid inclusion of literal Java in JSP pages is to use
another JSP feature known as custom actions. These take the form of
special tags that look a lot like HTML tags (because they are written
as XML elements). Custom actions allow tags to be defined that
perform tasks on behalf of the page in which they occur. For example,
a <sql:query> tag might communicate with a
database server to issue a query. Custom actions typically come in
groups, which are known as tag libraries and are designed as
follows:




  • The actions performed by the tags are implemented by a set of
    classes. These are just regular Java classes, except that they are
    written according to a set of interface conventions that allow the
    servlet container to communicate with them in a standard way. (The
    conventions define how tag attributes and body content are passed to
    tag handler classes, for example.) Typically, the set of classes is
    packaged into a JAR file.


  • The library includes a Tag Library Descriptor (TLD) file
    that specifies which tags are associated with which classes. This
    allows the JSP processor to determine which class to invoke for each
    custom tag that appears in a JSP page. The TLD file also indicates
    how each tag behaves, such as whether it has any required attributes.
    This information is used at page translation time to determine
    whether a JSP page uses the tags in the library correctly. For
    example, if a tag requires a particular attribute and the tag is used
    in a page without it, the JSP processor can detect that problem and
    issue an appropriate error message.



Tag libraries make it easier to write entire pages using tag notation
rather than switching between tags and Java code. The notation is
JSP-like, not Java-like, but the effect of placing a custom tag in a
JSP page is like making a method call. This is because a tag
reference in a JSP page maps onto a method invocation in the servlet
that the page is translated into.



To illustrate the difference between the embedded-Java and tag
library approaches, compare two JSP scripts that set up a connection
to a MySQL server and display a list of tables in the
cookbook database. The first one does so using
Java embedded within the page:



<%@ page import="java.sql.*" %>

<html>
<head>
<title>Tables in cookbook Database</title>
</head>
<body bgcolor="white">

<p>Tables in cookbook database:</p>

<%
Connection conn = null;
String url = "jdbc:mysql://localhost/cookbook";
String user = "cbuser";
String password = "cbpass";

Class.forName ("com.mysql.jdbc.Driver").newInstance ( );
conn = DriverManager.getConnection (url, user, password);

Statement s = conn.createStatement ( );
s.executeQuery ("SHOW TABLES");
ResultSet rs = s.getResultSet ( );
while (rs.next ( ))
out.println (rs.getString (1) + "<br />");
rs.close ( );
s.close ( );
conn.close ( );
%>

</body>
</html>


The same thing can be done using a tag library, such as the
JSP Standard Tag Library (JSTL). JSTL
consists of several tag sets grouped by function. Using its core and
database tags, the preceding JSP page can be converted as follows to
avoid entirely the use of literal Java:



<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>

<html>
<head>
<title>Tables in cookbook Database</title>
</head>
<body bgcolor="white">

<p>Tables in cookbook database:</p>

<sql:setDataSource var="conn"
driver="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost/cookbook"
user="cbuser" password="cbpass" />

<sql:query var="rs" dataSource="${conn}">SHOW TABLES</sql:query>
<c:forEach var="row" items="${rs.rowsByIndex}">
<c:out value="${row[0]}" /><br />
</c:forEach>

</body>
</html>


The taglib directives identify the TLD files that
the page uses and indicate that actions from the corresponding tag
sets will be identified by prefixes of c and
sql. (In effect, a prefix sets up a namespace for
a set of tags.) The <sql:dataSource> tag
sets up the parameters for connecting to the MySQL server,
<sql:query> issues a query,
<c:forEach> loops through the result, and
<c:out> adds each table name in the result
to the output page. (I'm glossing over details, of
course; the JSTL tags are described further in Recipe 16.4.)



If it's likely that you'd connect
to the database server the same way from most JSP pages in your
application context, a further simplification can be achieved by
moving the <sql:dataSource> tag to an
include file. If you name the file
jstl-mcb-setup.inc and place it in the
application's WEB-INF
directory,[B] any page
within the application context can set up the connection to the MySQL
server by accessing the file with an include
directive. Modifying the preceding page to use the include file
results in a script that looks like this:


[B] By convention, application contexts use
their WEB-INF directory for private
context-specific information. See Recipe B.3.



<%@ taglib uri="http://java.sun.com/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jstl/sql" prefix="sql" %>
<%@ include file="/WEB-INF/jstl-mcb-setup.inc" %>

<html>
<head>
<title>Tables in cookbook Database</title>
</head>
<body bgcolor="white">

<p>Tables in cookbook database:</p>

<sql:query var="rs" dataSource="${conn}">SHOW TABLES</sql:query>
<c:forEach var="row" items="${rs.rowsByIndex}">
<c:out value="${row[0]}" /><br />
</c:forEach>

</body>
</html>


You're still using Java when
you use a tag library, because tag actions map onto Java class
invocations. But the notation follows XML conventions, so
it's less like writing program code and more like
writing HTML page elements. If your organization produces web content
using a "separation of powers"
workflow, custom actions allow elements of the page that are produced
dynamically to be packaged in a way that is easier for designers and
other non-programmers to deal with. They don't have
to develop or work directly with the classes that implement tag
actions; that's left to the programmers that write
the classes that correspond to the tags.










    I l@ve RuBoard



    No comments:

    Post a Comment