First Java program First applet Abstraction
in Java
Servlet basics JavaServer Pages JavaBeans
As we saw in Chapters 12 and 13, the
learning curve for getting started with the MySQL APIs for PHP and Perl is
remarkably short and quick. Those welcome facts have played very big parts indeed
in the growth of MySQL's popularity as the preferable database for data-driven
webapps. Java is a different story altogether. To get started with MySQL-driven
Java webapps, you have to assemble, and become familiar with, half a dozen
large and complex software elements. There are hundreds of megabytes of
software and documentation, and lots of gotchas on the path.
This appendix is for MySQL users starting
with Java at square zero, and for those who need a bit of a Java refresher on Applet,
Servlet and JavaServer Page (JSP) basics. It assumes successful
installation of Java 2 Standard Edition (J2SE), Java 2 Enterprise Edition
(J2EE), and Tomcat, as described at the beginning of Chapter
14 and here.
Create a directory for ad hoc Java source files. To ensure that test program source files survive installations of new Java versions, you might want to put this directory not under $JAVA_HOME, but somewhere that is convenient for access and backup. Here we refer to the location of ad hoc source files as $JAVA_DEVEL. Remembering that Java filenames, object names and code are case-sensitive, type or copy this code into your text editor:
/* HelloWorldApp writes a greeting to the standard output */
public class HelloWorldApp {
public static void main( String[] args ) {
String s = "Hello World from Java!";
System.out.println( s );
}
}
Save it as HelloWorldApp.java in $JAVA_DEVEL.
Windows Tip: In Explorer, right-click on the .java file you have just created.
If the popup menu does not include an edit option, from the top menu select
Tools, Folder Options, then select the File Types tab, and look for 'Java' in
the list. If you don't find it, select New; otherwise select Edit; then click
on the New button at the bottom of the dialog, set Action to 'Edit' and set
Application to the full path to your text editor.
Comments are between /* and */. Anything after // on a line is also a comment.
Blocks of code are marked off, as in C, C# and C++, by curly braces {}.
A class may be
· public: the entity is available to the entire Java system.
· private: accessible to class members only,
· protected: accessible to subclasses, or
· private protected: combining private and protected.
The class defined by the .java file is the name following public class, which must be exactly the same as the name of the file it is in. Think of a class as a template that specifies the data and behaviour of instances of that class. The class HelloWorldApp must be public to be visible to the Java system.
void means that the method does not return a value. For example, writing the word long in that position, instead of void, would indicate misleadingly that main returns a long value.
static defines a variable or method as the only copy for all instances of the class in which it is declared.
main: The Java interpreter starts execution of an application by calling the class's main method, which in turn calls all the other methods required to run your application. The main method of an applet must be public in order to be visible to the entire Java system, and accepts a single argument: an array of elements of type String, conventionally named args:
public static void main( String[] args )
Instance variables and methods: Methods and variables that are not class methods or class variables are instance methods and variables. For example, when the application loads the System class, it instantiates PrintStream and assigns it to the out class variable. Once you have an instance of a class, you can call one of its instance methods.
Dot notation: As an object-oriented language, Java is hierarchical. Its contents are somewhat like a collection of Russian dolls¾classes within other classes, methods and variables within the classes. Dot notation is for accessing the available contents of those container hierarchies. It reads left to right, for example
objectName.varName.varState
objectName.object2Name.methodName( ... )
Other classes and their methods provide the details of what main is to do. In HelloWorldApp, the only class referenced is System, the only variable of the System class referenced is the variable named out, and the only System method used is println. The System class is part of the java.lang package; everything in java.lang is automatically imported into every Java program, so there is no need to declare System.
The Java compiler is javac.exe. On the command line issue …
javac HellpWorldApp.java
Then check to see that the compiler has written the file HelloWorldApp.class.
The Java bytecode executor is java.exe. In the same directory, type
java HelloWorldApp
and you should see
Hello World from Java!
Note that if you type
java HelloWorldApp.class
the bytecode executor responds ...
Exception in thread "main" java.lang.NoClassDefFoundError: HelloWorldApp/class
because Java is uncompromisingly literal about matching the name of the application file with the name of the public class it finds in that file. This literalness can take surprising twists. Even if you typed your program name correctly, there are two situations where you will get Java calls NoClassDefError. One occurs when your .class file isn't in the current directory; if that is the case, switch to that directory and try again. The other occurs when the environment CLASSPATH variable is not set correctly for what you are now doing. If your .class file is in your current directory and you still receive NoClassDefError, enter this command at your shell prompt:
set classpath=
to clear the CLASSPATH environment variable, and again ask Java to run your program. If it runs, you have shown the problem was the content of CLASSPATH. Surprising as it may seem, even if your .class file is in the current directory,
If you leave this arrangement as is, you will have to put all your .class files, even transient ones, in a directory named in CLASSPATH. Not ideal. The simplest workaround is to set CLASSPATH to always include the current directory, whatever it is, for example under Windows
set classpath=.;%classpath%
Type or copy this Java code into your text editor:
/* HelloWorld.java */
import java.applet.*;
import java.awt.*;
// HelloWorld applet class
public class HelloWorld extends Applet {
String msg = "Hello world from a Java applet!";
public void paint(Graphics g) {
g.drawString( msg, 5, 5);
}
}
and save it in your $JAVA_DEVEL folder as HelloWorld.java. Then type or paste this HTML code into your text editor:
<HTML>
<HEAD>
<TITLE>First Applet</TITLE>
</HEAD>
<BODY>
<FONT COLOR="blue">Message from HelloWorld java applet:
<APPLET CODE="HelloWorld.class" WIDTH=3000 HEIGHT=25>
</APPLET></FONT>
</BODY>
</HTML>
and save it as Hello.html in the same directory. There are several points to note:
import: Import directives at the top of the Java listing tell the compiler which packages of classes to use. Without them, the code would have to be a little more verbose, making all inheritances explicit:
public class HelloWorld extends java.applet.Applet {
public void paint( java.awt.Graphics g ) {
String s = "Hello world from a Java applet!";
g.drawString( s, 5, 5);
}
}
The savings in time and typing are small for this miniature program; they grow quickly for large ones.
Subclassing: Newcomers to object-oriented programming are often intimidated by subclassing. No need. Subclassing is how you customise basic classes like Applet into working objects, like HelloWorld, and how you extend class and object functionality. In our little HelloWorld applet, the keyword that performs this magic is extend in:
public class HelloWorld extends Applet {
HelloWorld extends Applet, which is of course is a useful class to have because applets know how to respond to browser requests. Our HelloWorld inherits all this knowledge because we wrote that one line of code.
paint: In a Java program like HelloWorldApp, as in C programs, a main method controls program execution. A Java applet, however, executes in a graphical context which has been provided by the appletâs host, for example a web browser, so the HelloWorld applet executes via the Java paint method, calling into a Java representation of the appletâs drawing context, java.awt.Graphics. The first argument to the Graphics.drawString method is the string to draw, in this case the instance variable s. The remaining arguments are the x and y position of the lower left corner of the text's rectangle, where (0,0) is the top left corner of the applet's display area.
You compile an applet just as you compile Java applications. In the directory where you saved HelloWorld.java and Hello.html, type ...
javac HelloWorld.java
and again check the directory to see that the Java compiler has created HelloWorld.class.
You can test your applet with the Java applet viewer. Type
appletviewer Hello.html
and the Java applet viewer will open a little window which merely says "Hello World from a Java applet!" However, applets are meant to run, not by themselves, but in browsers, To run your applet in your browser, have your browser open Hello.html.
Java classes are templates for building objects. They may contain data, they may implement methods, they may inherit from a superclass, and they may have as many subclasses as you need.
Sometimes we need to abstract only methods and specifications, then share those methods with other classes, or with hierarchies of classes. The Java device for this is the interface, which is a named collection of method and data specifications without implementations. So interfaces are not in the class hierarchy.
A class implements methods. Interfaces specify classes, so interfaces are implicitly public and abstract. An interface definition has two parts: declaration, and body. In
public interface priceLookup {
void getAmount( string sItem, double dPrice );
}
the declaration is the text before the left curly brace, and the body is the text between the two curly braces. Of course if we have PriceLookup we can also have ...
public interface housePriceLookup extends PriceLookup { ... };
but though a class can have just one superclass, an interface can have any number of super-interfaces, so in an interface definition, the keyword implements may be followed by a comma-separated list.
A class adopts an interface and implements it by declaring that fact, so we can write ...
public class priceSet extends Applet implements priceLookup{ ... };
Either the class must implement all methods declared in the interface and its superinterfaces, or the class must be declared abstract.
Interfaces are user-defined datatypes. Like other datatypes, if they are changed after code that uses them has been written, that code is almost certainly broken. So you have a choice: try to anticipate all interface methods up front¾ almost impossible¾or be satisfied with extending your interfaces when unanticipated needs arise.
You use Java to solve a problem as you would use any object-oriented language: you model the problem as a set of classes which encapsulate methods and data, you write and test the classes, then you write and test the application.
A Java program does three basic things:
The baby programs HelloWorldApp and HelloWorld illustrate these basic tasks:
What these baby programs leave out is interface implementation, which is what applets and servlets must do when they need to extend base class functionality. Unfortunately you will have to at least nominally implement all methods in the interface. Fortunately you can stub out the methods you do not need.
Web applications often must be threaded, so they often have to implement the Java Runnable interface, and instantiate the Thread Class.
A single-threaded program is a single sequence of actions with a beginning, a middle, and an end. A multi-threaded program is a collection of these sequences where each sequence is a thread, also sometimes called an execution context or lightweight process, which runs concurrently.
Well, not quite concurrently, since many machines on which these programs run have single CPUs. On these machines, threads follow deterministic priority scheduling to provide the illusion of concurrency. A thread inherits priority from the thread that created it, and can change it with a setPriority method. Obviously then, you can write gracious or piggish threads. Threads can also be locked, unlocked, grouped, and synchronisd.
A thread is made to run by
Which way to go? Java does not have multiple inheritance, so if a class already extends another class, as any applet or servlet must, Runnable is the only choice.
As a manageably small example, imagine a toy program which displays accumulated exponential growth in a population of imaginary animals as a function of the time an applet runs. The pseudocode is:
data to track
years, populationSize, litterSize, deathRate, LitterRate
stop button
running thread
output string
methods
start
iterate through defined timespan
while running, poll mouse for click
stop if user clicks or if timespan is done
calculate population size
paint output string
catch errors
Inspecting the methods, we find four processes:
In many applets that must respond to user events, you will have to poll for mouse clicks and movements. The Java MouseListener interface requires that we implement five methods:
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mousePressed( MouseEvent e ){}
public void mouseReleased(MouseEvent e){}
only one of which¾the fourth¾our applet will actually use.
In most applets that must start and stop in response to events, you will have to implement the Runnable interface, which requires implementation of start, run and stop methods.
We have our applet implement the interface by adding the keyword implements after the word Applet, followed by the name of the interface we are implementing (or a list of them). Then we must do what our declaration advertises.
A start method does what it says¾it calls the thread's constructor, and the JVM starts it running. It can hibernated via sleep or wait methods, or via I/O blocking. The isAlive method returns true if the thread has started and not yet died.
You will see much of this construct in Java code¾it's how you handle code failure. Its three keywords mean exactly what they say: try this, catch any exceptions (errors) which may be thrown in the try block, and finally clean up.
For any try block there may be multiple catch blocks, each referencing a different exception object that can report error info. None of these exception objects can catch an exception whose superclass has already been caught. An exception method you will soon tire of seeing executed is printStackTrace, whose listings, you hope, will illuminate bugs you have written. The finally block will be executed no matter what exceptions have occurred and no matter what return statements have executed elsewhere in the method.
Type or copy this code into Wabbits.java:
/* Wabbits.java */
import java.applet.*;
import java.awt.*;
import java.awt.event.*;
public class Wabbits
extends Applet implements MouseListener, Runnable {
long yrs, wabbits, deathPct = 30, litterRate, litterSize;
// INITIALISE BUTTON
Button wabbitButton = new Button( "Stop the Wabbits!" );
// THREAD
Thread silk;
// INITIALISE FONT, OUTPUT STRING
Font thisFont = new Font( "Arial", Font.ITALIC, 12 );
String thisRpt;
// SET UP
public void init() {
add( wabbitButton );
wabbitButton.addMouseListener( this );
}
// IMPLEMENT RUNNABLE
public void start() {
if( silk == null ) {
silk = new Thread( this );
silk.start();
}
}
public void stop() {
wabbitButton.setLabel( "Whew" );
repaint();
silk = null;
}
// IMPLEMENT MOUSELISTENER
public void mousePressed( MouseEvent e ) {
if( e.getSource() == wabbitButton )
stop();
}
public void mouseClicked(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseExited(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
// CALCULATE POPULATION GROWTH
public void malthus() {
wabbits = exponentiate( wabbits );
}
long exponentiate( long num ) {
num += ( litterSize * litterRate * ( num < 3 ? 2 : num/3 ) );
num -= ( num * deathPct / 100 );
return num;
}
// RUN
public void run() {
Thread thisThread = Thread.currentThread();
Wabbits w = new Wabbits();
w.wabbits = 2;
w.litterSize = 5;
w.litterRate = 2;
while( silk == thisThread && w.yrs < 25 ) {
w.yrs++;
w.malthus();
thisRpt = w.yrs + " years, " + w.wabbits + " wabbits!";
repaint();
try {
thisThread.sleep( 1000 );
}
catch( InterruptedException e ) {
}
}
}
// PAINT
public void paint( Graphics g ) {
g.setFont( thisFont );
g.drawString( thisRpt, 30, 60 );
}
}
The applet implements methods required by the Runnable interface:
The applet's implementation of MouseListener.MousePressed is as simple as can be: it calls the applet's Runnable.stop method. Other MouseListener methods are empty.
The applet also uses two Java words we have not seen before: this , which refers to the current object, and new, which is the Java class constructor, as in:
Font thisFont = new Font( "Arial", Font.BOLD, 12 );
which says: construct a new instance of the Font class, name the instance thisFont, and send the indicated arguments to the constructor.
Methods have access to variables declared above them in the class. Subsequently assigning, to another variable, a name which is already in use, creates subtle dereferencing bugs. Given a reference to a variable, Java looks for its definition,
So giving a local variable the same name as another class or superclass or instance variable can hide the higher variable and give rise to bugs that are difficult to trace:
There once was a VARIABLE named FOO,
which FIDDLE (and FARKLE)
owned (too).
When FOO was dereferenced,
FIDDLE's
was preferenced,
but FARKLE's
FOO answered the cue.
Consider one or both these rules of thumb: do not re-use variable names within classes, and when there is any doubt, reference variables as this.varName.
Compile Wabbits.java with this command:
javac Wabbits.java
Type or copy this HTML code for calling the applet into Wabbits.html:
<HTML>
<HEAD><TITLE>Wabbits</TITLE></HEAD>
<BODY>
<FONT COLOR="blue">
<APPLET CODE="Wabbits.class" WIDTH=400 HEIGHT=200></APPLET>
</FONT>
</BODY>
</HTML>
save it, and run Wabbits.html either in the Java applet viewer or in your browser. It will stop when it gets to 25 "years" or when you click on stop button, whichever first occurs.
A package is a collection of related classes and interfaces providing access protection and namespace management. To create a package, you put a class or an interface in it, and you do that simply by writing a package statement at the top of the source file where the class or the interface is defined, like the following code in java.sql.date.java:
package java.sql;
public class Date extends java.util.Date { ... }
If developers all over the world are to use each other's Java packages, naming conflicts are inevitable, so a convention has arisen: Organisations use their reversed Internet domain name as package names, for example com.ArtfulSoftware.thisPackage. Within an organization, further conventions are required to avoid name collisions.
Only public package members are accessible outside the package that defines them. To use a public package member from outside its package, you must refer to its fully qualified name, import the package member, or import the whole package.
A Java servlet is a Java module which runs not on a client machine, not in a client browser, but in a container on a web server as a generic extension to a Java-enabled server.
The servlet runs entirely within the Java Virtual Machine, receiving and responding to HTTP, FTP or custom-protocol client requests. Because it is running on the server, it need not be browser-compatible. Like any other Java module, it has access to all Java APIs, including JDBC. Its basic framework is in javax.servlet; extensions for HTTP server response are in javax.servlet.http.
As an alternative to Common Gateway Interface (CGI) modules written in Perl and PHP, the Java servlet has the advantages of not requiring a separate process, of thus being able to persist in memory between invocations, thus of being able to track state information, and of being isolatable in what is called a sandbox, a context which restricts what a servlet may do (usually for security purposes).
You call servlets explicitly in two ways¾directly, and from HTML pages. The Java servlet is also the final execution pathway of the JavaServer Page (JSP), so to be complete, servlets run
· directly and explicitly, or
· explicitly from HTML, or
· silently or implicitly from JSPs.
In general, servlets are useful for ...
Servlets are not ideal for generating HTML content: every change would require recompilation. Common servlet uses include the application logic of shopping carts, e-commerce storefronts, access to legacy databases, and tunnelling through firewalls using HTTP tunnelling to provide access to objects which may be anywhere on the network
A servlet execution environment is a container in which a servlet runs. The container is an HTTP web server plug-in. In this book we use Tomcat, which can run standalone or as an Apache process. Until recently, methods of deploying servlets and JSPs differed widely from server to server, often from one servlet container version to another. Starting with version 2.2 of the Servlet API Specification, web applications are deployed in a standard directory hierachy. The hierarchy may be raw, or packed in a web archive (.war) file. Once a system administrator assigns a context path for a web application, that context path is the applicationâs document root, the folder for an applicationâs HTML, JSP, Javascript, stylesheet and image files. Off this document root there are these files and folders:
There are two basic Java servlet packages:
The kernel of servlet architecture is the javax.servlet.Servlet interface, which defines five methods:
A servlet must implement this interface, and javax.servlet.ServletConfig¾directly as in the case of javax.servlet.genericServlet, or via subclassing as in the case of javax.servlet.http.HttpServlet, from which in turn you will subclass all your web application servlets.
A servlet's life cycle is simple. On construction, its init method initialises required data and resources in the servlet's ServletConfig object. While alive, it services requests, which come to the servlet with a request and a response parameter. On being shut down, its destroy method frees the memory it occupied.
Here is the simplest servlet you can write. Type or copy it into $JAVA_DEVEL/HelloWorldServlet.java.
/* HelloWorldServlet.java */
import javax.servlet.http.*;
import java.io.*;
public class HelloWorldServlet extends HttpServlet {
public void service( HttpServletRequest request,
HttpServletResponse response )
throws IOException {
PrintWriter out = response.getWriter();
out.println( "</html><body><h1>Hello World from a Servlet!” +
“</h1></body></html>" );
}
}
This ultra-simple servlet class does just three things: (i) it extends HttpServlet, and (ii) implements a service method by (iii) ignoring HttpServletRequest content to merely print a canned greeting to System.out.
Servlets compile like applets, so to compile this servlet issue the command
javac -classpath $j2ee_home/lib/j2ee.jar HelloWorldServlet.java
The command-line classpath setting is required if the systemâs CLASSPATH does not include the path to j2ee.jar. If compilation yields an error message like …
javax.servlet.http does not exist,
correct the environmental setting $J2EE_HOME and try again.
Tip: You can test the CLASSPATH environment setting with
the command-line instruction…
javap -classpath $CLASSPATH javax.servlet.Servlet
If javap cannot find javax.servlet.Servlet, correct CLASSPATH to include the fully
qualified path to j2ee.jar. If javap can find it but javac still cannot find the
servlet packages, CLASSPATH is not being set correctly:
see the section earlier in this chapter on compiling Java applets.
If you were to compile the servlet in $JAVA_DEVEL and simply leave the .class file there, what could you type into a browser's location/address field to run the servlet? Nothing. Amongst the ways to run a servlet, one is not to put it in any directory you like, then ask your browser to run it from there. It has to run in a server context, so running it requires:
· moving the servlet .class file to a place that the servlet container knows about,
· telling the server about the servlet, and
· restarting the server.
The details of how to execute these steps vary from server to server.
Tomcat 5 looks for its web applications in $CATALINA_HOME/webapps/, so creating a webapps subfolder defines a web application context. Tomcat will run servlets from the WEB-INF/classes subfolder of such a named folder under webapps/. To make small-scale testing as convenient as possible, Tomcat installs a nameless default application in $CATALINA_HOME/webapps/ROOT. So deploying HelloWorldServlet.class to run under Tomcat requires just these steps:
· copy HelloWorldServlet.class to $CATALINA_HOME/webapps/ROOT/WEB-INF/classes,
· edit $CATALINA_HOME/webapps/ROOT/WEB-INF/web.xml with a text editor, and within the <web-app>…</web-app> tags add:
<servlet>
<servlet-name>HelloWorldServlet</servlet-name>
<servlet-class>HelloWorldServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet</servlet-name>
<url-pattern>/servlet/HelloWorldServlet</url-pattern>
</servlet-mapping>
· restart Tomcat.
Now just browse http://localhost:8080/servlet/HelloWorldServlet.
Could we have called that servlet from a HTML page? Yes, directly and simply by writing an HTML page which submits it. Type or copy HelloWorldServlet.html into $TOMCAT_HOME/webapps/ROOT:
<html>
<head><title>HelloWorldServlet</title></head>
<body>
<font color=blue>
<form action = "http://localhost:8080/servlet/HelloWorldServlet">
<p>Click on <b>Go</b> to invoke HelloWorldServlet</p>
<input type = submit value = " Go ">
</font>
</body>
</html>
save the file, type http:/localhost/HelloWorldServlet.html into your browser's address/location field, and voilà.
Servlets service requests. They live for it.
An HTML page calls a Java servlet just as it calls a CGI script¾via a URL in a FORM ACTION tag. The abstract class HttpServlet is designed for handling such requests, and provides a cleaner interface than CGI by hiding some servicing details, for example the management and parsing of command-line script arguments.
An HttpServlet subclass often overrides
The next HTML/servlet pair shows how to code for Post and Get requests. Just as HelloWorldServlet.html called HelloWorldServlet.class, GetPostServlet.html calls GetPostServlet.class. A call to the servlet occurs when the user clicks one of two submit buttons. The simple data in these buttons describes how they do what they do¾each submit button named "method" tells the Java servlet, in its value, whether it is sending data via a Post or a Get.
Type or copy this HTML code...
<html>
<head><title>GetPostServlet.html</title></head>
<body>
<font color=blue>
<br>This page has two ultra-simple forms, each with one button<br>
which invokes either the Post or Get service of a servlet.<br>
<!-- FORM FOR A POST -->
<form action = "http://localhost:8080/servlet/GetPostServlet"
method=POST>
<p>Click on <b>Post</b> to invoke GetPostServlet's
doPost service</p>
<input type = submit name = "method" value = " Post ">
</form>
<!-- FORM FOR A GET -->
<form action = "http://localhost:8080/servlet/GetPostServlet"
method=GET>
<p>Click on <b>Get</b> to invoke GetPostServlet's doGet
service</p>
<input type = submit name = "method" value = " Get ">
</form>
</font>
</body>
</html>
to $TOMCAT_HOME/webapps/ROOT/GetPostServlet.html, then type or copy this Java code into $JAVA_DEVEL/GetPostServlet.java ...
/* GetPostServlet.java */
import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;
import java.util.*;
public class GetPostServlet extends HttpServlet {
String htmlStart =
"<html>\n<head><title>GetPostServlet</title></head>\n<body>";
String goBackMsg =
"Click on your browser's Back button to return to the form.\n";
public void init( ServletConfig cfg ) throws ServletException {
super.init( cfg );
}
// POST
public void doPost( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException {
respond( req, res );
}
// GET
public void doGet( HttpServletRequest req, HttpServletResponse res )
throws ServletException, IOException {
respond( req, res );
}
private void respond(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException {
res.setContentType( "text/html" );
PrintWriter out = res.getWriter();
out.println( htmlStart );
out.println( getServletInfo() + " got a " + req.getMethod() +
" request from " + req.getRemoteAddr() +
", saying it uses a " + req.getParameter( "method" ) +
".<br><br>" );
out.println( goBackMsg );
out.println( "</body></html>" );
out.close();
}
// INFO
public String getServletInfo() {
return "Y'r obedient servlet";
}
}
The servlet initialises itself via its parent init method. Its doPost and doGet methods delegate request processing to a private method that makes three HttpServletRequest calls¾getMethod to find how the request was sent, getRemoteAddr to find where the request came from, and getParameter for the value of the HTML form field named method¾ then generates a simple HTML page reporting what it found. Compile the file with
javac GetPostServlet.java
and copy GetPostServlet.class to $CATALINA_HOME/webapps/ROOT/WEB-INF/classes.
To run this page on your server, you have to tell Tomcat about the servlet it calls. Within the <web-app>…</web-app> tags of <CATALINA_HOME>/webapps/ROOT/web.xml, add this:
<servlet>
<servlet-name>GetPostServlet</servlet-name>
<servlet-class>GetPostServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>GetPostServlet</servlet-name>
<url-pattern>/servlet/GetPostServlet</url-pattern>
</servlet-mapping>
Bring down and restart Tomcat, then run http://localhost/GetPostServlet.html. Try clicking on each of the page's buttons.
Think about the architecture of this for a moment. You wrote
You are now writing server-side Java-based dynamic web content.
The servlet is not ideal for HTML generation. What is better? The JavaServer Page (JSP). The JSP specification defines the interfaces that servlet-container vendors can implement to support dynamic Web pages. A JSP, defined in java.servlet.jsp and java.servlet.jsp.tagext, is a page with extension .jsp which contains both HTML and Java code. One of its reasons for existence is to provide a convenient shorthand way to combine, yet distinguish within the one document, both HTML user interface code and Java content generation code. A servlet container will interpret the JSP, creating a workhorse servlet which it then compiles to respond to HTTP requests.
Another reason for its existence is the JavaBean.
A JavaServer Page is thus an interesting hybrid: an XML document, a partly-HTML file, an extension of Java servlets, a mechanism for generating dynamic HTML content, a container for Java objects, and a source file to be compiled from scratch at runtime. So it can be thought of
The first time a JSP is called, the servlet container compiles it, and sends the result to the requesting client, to run in the client's JVM. On subsequent calls, the server checks to see if the .jsp file has changed; if not, it invokes the previously compiled servlet object; if so, it recompiles and again sends the result to the client. Though the JSP resembles Microsoftâs Active Server Page (ASP) in many respects, here is one striking difference in favour of the JSP, which need not be parsed and compiled each time the user loads the page.
In a JSP, XML-like tags and Java scriptlets encapsulate content-generation logic, and access application logic which has been encapsulated in server-based resources like JavaBeans. HTML and XML formatting tags are passed back to the response page.
A JavaBean is a Java class which
It is often useful to encapsulate database-driven content generation within JavaBeans, so JavaBeans are often embedded in JavaServer Pages, which have features designed for just that purpose.
Type or copy this into HelloFromJSP.jsp in your $JAVA_DEVEL directory:
<HTML>
<HEAD><TITLE>HelloFromJSP.jsp</TITLE></HEAD>
<BODY>
<font color="blue">
<H1>Hello World from a Java Server Page!</H1>
On this server it is now <%= new java.util.Date() %>
</font>
</BODY>
</HTML>
To deploy a JSP under Tomcat, you need not edit web.xml; you need only put the page in the appropriate folder, and since Tomcat defines a default web application context ROOT, you need only copy the .jsp file to <CATALINA_HOME>/webapps/ROOT. To run it, browse http://localhost:8080/HelloFromJSP.jsp. If the server reports that it cannot find the file, re-check where you put it.
HelloFromJSP.jsp contains just one element which is not standard HTML:
<%= new java.util.Date() %>
The <%= ... %> tags enclose a scriptlet. These scriptlet tags tell the server that here is an expression requiring Java compilation. The resulting String will be inserted in the output stream at the expression's referenced position in the .jsp file. If the result cannot be converted into a string, a translation error will occur. If the translation cannot be detected during translation, a ClassCastException will be thrown.
When a servlet container encounters a JSP, it expands it into a .java file, a workhorse servlet. Tomcat writes it to <CATALINA_HOME>/work/Catalina/<hostname>/_/org/apache. The servlet container then compiles it into a .class file. If there is an error in the code, the servlet container will report the error on the browser page, complete with line numbers which reference the auto-generated workhorse source file.
A JSP may contain four kinds of Java components:
A JSP directive has the form
<%@ directive {thisAttribute="thisValue"} %>
which tells the compiler that on this page, thisAttribute has thisValue. There are three possible directives: include, page and taglib. , and several subdirectives:
Table
D-1: JSP Directives
Type |
Attribute |
Meaning |
include |
<%@ include file="relativeUrlSpec"%> |
Another
HTML file or JSP to be evaluated at translation time |
page |
<%@ page language="scriptLang"%> |
Language
to use compiling the JSP ("Java") |
page |
<%@ page extends="className"%> |
Name
of parent class that this JSP extends |
page |
<%@ page import="importList"%> |
Comma-separated
list of packages to import |
page |
<%@ page session="true|false"%> |
Is
session data available to this page? Default true |
page |
<%@ page buffer="none|Kb"%> |
Whether
output is to be buffered. Default 8kb |
page |
<%@ page autoFlush="true|false"%> |
When
full, should buffer automatically flush or raise an exception? |
page |
<%@ page isThreadSafe="true|false"%> |
Can
JSP service multiple threads simultaneously? Default true |
page |
<%@ page info="text"%> |
Text
information about this JSP |
page |
<%@ page errorPage="errorUrl"%> |
Relative
URL to error-handling page |
page |
<%@ page isErrorPage="true|false"%> |
Is
this an error page? Default false |
page |
<%@ page contentType="ctInfo"%> |
Response
MIME type and character set |
taglib |
<%@ taglib uri"tagLibraryURI" prefix="tagPrefix" %> |
URI
of the tag library that defines custom tags, and the prefix used to identify
them |
There are six JSP actions: useBean, setProperty, getProperty, include, forward and plugin. They generally create or do something to objects, often JavaBeans.
useBean
This declares and finds a bean, or, if it cannot find the bean, instantiates the bean from the specified class or serialized template. The syntax is
<jsp:useBean
id=”name”
scope=”page|request|session|application”
class=”className” type=”typeName” |
beanName=”beanName” type=”typeName” |
type=”typename”>
…
</jsp:useBean>
You can specify type alone to attach a local name to a bean defined elsewhere, or also specify class and/or beanName in any order, for example
<jsp:useBean id="bean1" scope="application" class=”Counter” />
setProperty
This sets a bean property, for example from submitted form data. You must first have declared the bean with useBean. Then with the syntax
<jsp:setProperty name="beanName" property="*" />
you set all bean properties with matching names to user values in the form, that is, with request parameters in the object. This saves time if your bean's variable names exactly match field names in your form. This syntax…
<jsp:setProperty name="beanName" property="propertyName" />
sets the bean property named propertyName to the value of the form field with that name. The syntax
<jsp:setProperty name="beanName"
property="propertyName" param="
paramName"
/>
or
<jsp:setProperty name="beanName"
property="propertyName" value="
paramValue | <%= expression %>"
/>
sets the parameter or the value¾you cannot do both in one directive¾of the named property of the named bean.
getProperty
This inserts a stringified bean property value into the output stream:
<jsp:getProperty name="id" property="propertyName" />
include
Minimal include syntax,
<jsp:include page="urlSpec" flush="true|false" />
tells the JSP to include the named page. The extended include syntax
<jsp:include page="urlSpec" flush="true|false" >
<jsp:param>
<jsp:param name="paramName" value="paramValue" >
</jsp:param>
</jsp:include>
supports inclusion parameters as shown.
forward
This sends a client request to an HTML file, JSP file, or servlet for processing. The syntax is
<jsp:forward page="{relativeURL | <%= expression %>}" />
or
<jsp:forward page="{relativeURL | <%= expression %>}" >
<jsp:param name="parameterName"
value="{parameterValue | <%= expression %>}" />
</jsp:forward>
plugin
This executes an applet or bean. If necessary for execution, it downloads a Java plug-in to the client. The syntax is
<jsp:plugin
type="bean|applet"
code="classFileName"
codebase="classFileDirectoryName"
[ name="instanceName" ]
[ archive="URIToArchive, ..." ]
[ align="bottom|top|middle|left|right" ]
[ height="displayPixels" ]
[ width="displayPixels" ]
[ hspace="leftRightPixels" ]
[ vspace="topBottomPixels" ]
[ jreversion="JREVersionNumber | 1.1" ]
[ nspluginurl="URLToPlugIn" ]
[ iepluginurl="URLToPlugIn" ] >
[ <jsp:params>
[ <jsp:param name="parameterName"
value="{parameterValue | <%= expression %>}" /> ]+
</jsp:params> ]
[ <jsp:fallback> text message for user </jsp:fallback> ]
</jsp:plugin>
The JSP silently pre-declares and initializes eight objects for programmatic use (Table D-2).
Table
D-2: Undeclared objects in a JavaServer Page
Object |
Scope |
Class |
Description |
application |
application |
javax.servlet.ServletContext |
Servlet
context returned from getServletConfig() |
config |
page |
javax.servlet.ServletConfig |
Initialisation
info for the JSP's servlet |
exception |
page |
java.lang.Throwable |
Accessible
from an error page only |
out |
page |
javax.servlet.jsp.JspWriter |
Write
to output stream |
page |
page |
java.lang.Object |
This
JSP instance |
pageContext |
page |
javax.servlet.jsp.PageContext |
API
for managing scoped attributes |
request |
request |
Subtype
of javax.servlet.Servlet.Request or javax.servlet.HttpServlet.Request |
Request
object that triggered the request |
response |
page |
Subtype
of javax.servlet.Servlet.Response or javax.servlet.HttpServletResponse |
Response
to be returned to the client |
session |
session |
javax.servlet.http.HttpSession |
Session
object for the client |
JSP scripting embeds Java code into an HTML page, and has three elements: declarations, expressions and scriptlets.
JSP Scripting Declarations
These declare variables and methods. The syntax is
<%! declaration %>
for example
<%! String composer = new String( "Bach,J.S" ); %>
declares the variable composer and assigns "Bach,J.S." to it, and
<%! public String getComposer() { return composer; } %>
declares a public access method for it.
JSP Scripting Expressions
A JSP expression is evaluated, then converted to a string at the time of the HTTP request. For example having declared the method getComposer() above, writing
<%= getComposer() %>
will cause the page to insert the value returned by that function.
JSP Scriptlets
A JSP scriptlet may contain any code that is valid for the language declared in the page language directive. Its syntax is simply
<% scriptlet source %>
As we saw with the toy page HelloWorldFromJSP.jsp, the servlet container compiles the page into servlet code, then executes it.
Without JavaBeans, the JSP is an interesting convenience for writing dynamic web content, but remains a stateless device responding to stateless requests¾useful, but not a stunning advance. But JavaBeans encapsulate data persistence, and JSPs define the scope of that data persistence, so the JavaServer Page with embedded JavaBeans is a powerful and flexible object-oriented environment for managing requests, responses to those requests, and the data which makes those requests and responses worth processing.
A JavaBean is essentially a Java class which provides data access via set and get methods, and which uses java.io.Serializable.
We begin with a toy bean DataBean.java that does just four things:
Compile DataBean.java, and copy the resulting .class file to $CATALINA_HOME/webapps/ROOT/WEB-INF/classes:
import java.io.Serializable;
public class DataBean implements Serializable {
private int counter = 0;
private String data = new String( "original value" );
public DataBean () {}
public String getData() {
return data;
}
public void setData( String str ) {
counter++;
data = "Setting #" + counter + ": " + str;
}
}
A JSP which is to use this bean must first declare it, then may access its data either via setProperty and getProperty JSP actions, or via direct calls to DataBean.setData and DataBean.getData. In AccessDataBean.jsp, the line
<%@ page import="DataBean" %>
simply imports our packageless DataBean class, and
<jsp:useBean id="databean" scope="session" class="DataBean" />
declares it with session scope. The code uses setProperty and getProperty to get and set data. Type or copy this into $TOMCAT_HOME/webapps/ROOT/AccessDataBean.jsp:
<%@ page language="java" %>
<%@ page import="DataBean" %>
<jsp:useBean id="databean" scope="session" class="DataBean" />
<html><body><font color="blue">
GET original DataBean value<br>
DataBean.data is:
<font color="red"><jsp:getProperty name="databean"
property="data" /><br></font>
SET DataBean.data:
<font color="red">
<jsp:setProperty name="databean" property="data"
value="This is a new setting" />
</font>
GET modified DataBean value<br>
DataBean.data is now:
<font color="red"><jsp:getProperty name="databean"
property="data" /></font>
</font></body></html>
Browse http://localhost:8080/AccessDataBean.jsp. and click on the browser Refresh button a few times. Each time you click, the JSP fires the bean's setData method to increment the counter. Load a different URL, then go back to AccessDataBean, and hit Refresh again. DataBean remembers. Shut down your browser and open it again, and the counter restarts: while you stay within the scope defined in this JSP¾session¾the data values persist; once you leave that scope, persistence is over.
Like servlets, EJBs are distributed server-side components, but there are two big differences: servlets cannot handle distributed transactions, and EJBs cannot accept HTTP requests so cannot service requests from web browsers.
An EJB must have
· A remote interface that exposes the methods the enterprise bean supports,
· A home interface that provides life cycle methods for the enterprise bean,
· An implementation class, including the business logic it needs.
Consider EJBs if your application has any of these requirements:
Sun MicroSystems Inc, “JavaServer Pages Syntax Reference”, http://java.sun.com/products/jsp/tags/11/tags11.html