JaVa
   

Web app Project

The Web app is another subproject of the Model 2 Hello World app; it consists of a servlet, two JSPs, an HTML file, and a deployment descriptor. This section describes how to build a WAR file with a deployment descriptor. We also explain how to map servlets and JSPs to servlet elements in the deployment descriptor and how to map the servlet elements to URLs. In addition, this section breaks down the webapp project buildfile step by step, and shows how to use the buildfile to build and deploy the Web app.

Web app Project Directory Structure

The following are the files that we build into a Web app:

Web app root directory
| build.xml
|
+---JSP
| HelloWorld.jsp
| HelloApplet.jsp
|
+---src
| \---xptoolkit
| \---web
| HelloWorldServlet.java
|
+---HTML
| index.html
|
\---meta-data
 web.xml


Notice that the webapp project includes only six files. There are four subdirectories: JSP, src, HTML, and meta-data, and the root directory holds the build.xml file. The JSP directory contains two JSPs: HelloWorld.jsp and HelloApplet.jsp. Under the src directory is the Java source for the servlet xptoolkit.web.HelloWorldServlet.java. The web.xml file under the meta-data directory holds the deployment file for this Web app.

HelloWorldServlet.java

The servlet is contained in the class xptoolkit.web.HelloWorldServlet (see the next listing). Like the Java app, it uses the Greeting interface and the GreetingFactory class that are packaged in greetmodel.jar, the output of the model project.

package xptoolkit.web;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.ServletException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletContext;
import javax.servlet.RequestDispatcher;
/* import the classes to create a greeting object or type greeting */
import xptoolkit.model.GreetingFactory;
import xptoolkit.model.Greeting;
public class HelloWorldServlet extends HttpServlet{
 public void init(ServletConfig config) throws ServletException{
 super.init(config);
 /* Read in the greeting type that the factory should create */
 String clazz = config.getInitParameter("Greeting.class") ;
 if(clazz!=null)System.setProperty("Greeting.class",clazz);
 }
 
 public void doGet(HttpServletRequest request, HttpServletResponse response)
 throws ServletException{
 RequestDispatcher dispatch;
 ServletContext context;
 /*Get the session, create a greeting bean, map the greeting bean in the session, and redirect to the Hello World JSP.
 */
 try { /* Create the greeting bean and map it to the session. */
 HttpSession session = request.getSession(true);
 Greeting greet = (Greeting)
 GreetingFactory.getGreetingFactory().getGreeting();
 session.setAttribute("greeting", greet);
 /* Redirect to the HelloWorld.jsp */
 context = getServletContext();
 dispatch = context.getRequestDispatcher("/HelloWorldJSP");
 dispatch.forward(request, response);
 }catch(Exception e){
 throw new ServletException(e);
 }
 }
 /* Just call the doGet method */
 public void doPost(HttpServletRequest request, HttpServletResponse response)
 throws ServletException{
 doGet(request, response);
 }
}


Analyzing HelloWorldServlet

HelloWorldServlet is a simple servlet; it reads in the servlet initialization parameters in the init() method, as follows:

 String clazz = config.getInitParameter("Greeting.class") ;


It uses the value of the initialization parameter "Greeting.class" to set the System property "Greeting.class", as follows:

 System.setProperty("Greeting.class",clazz);


You will recall from that the GreetingFactory uses the system property "Greeting.class" to decide which implementation of the Greeting interface to load. Now let's get to the real action: the doGet() and doPost() methods. When the doGet() or doPost() method of the HelloWorldServlet is called, the servlet uses the GreetingFactory to create a greeting as follows:

 Greeting greet = (Greeting)
 GreetingFactory.getGreetingFactory().getGreeting();


The HelloWorldServlet then maps the greeting object into the current session (javax.servlet.http .HttpSession) under the name "greeting", as follows:

 session.setAttribute("greeting", greet);


Finally, the HelloWorldServlet forwards processing of this request to the JSP file HelloWorld.jsp by getting the request dispatcher for the HelloWorldServlet from the servlet's context, as follows:

 /* Redirect to the HelloWorld.jsp */
 context = getServletContext();
 dispatch = context.getRequestDispatcher("/HelloWorldJSP");
 dispatch.forward(request, response);


You may notice that the context.getRequestDispatcher call looks a little weird. This is the case because HelloWorld.jsp is mapped to /HelloWorldJSP in the deployment descriptor for the servlet. (We will discuss the deployment descriptor later.) Next, let's examine HelloWorld.jsp.

HelloWorld.jsp

HelloWorld.jsp exists to show the world the message it gets from the Greeting reference that the HelloWorldServlet mapped into session. The HelloWorld.jsp code is as follows:

<jsp:useBean type="xptoolkit.model.Greeting"
 scope="session"/>
<html>
<head>
<title>Hello World</title>
</head>
<body>
<h1><%=greeting.getGreeting()%></h1>
</body>


If you are a Web designer at heart, we understand if you are shocked and horrified by this HTML code. But for a moment, let's focus on the following two lines of code from the JSP:

<jsp:useBean type="xptoolkit.model.Greeting" scope="session"/>
<h1><%=greeting.getGreeting()%></h1>


Notice that the jsp:useBean action grabs the greeting reference that we put into the session with the HelloWorldServlet. Then, we print out the greeting with the JSP scriptlet expression <%=greeting.getGreeting()%>.

This sums up what the Model 2 Hello World Web app does. We will discuss the other JSP, HelloApplet.jsp, after we examine the applet subproject. For now, the next section explains why the servlet could forward HelloWorldJSP to the JSP HelloWorld.jsp.

Deployment Descriptor for the HelloWorld Web app

In order to configure the JSPs and servlets, we need a deployment descriptor. The following code defines a simple deployment descriptor that assigns names and mappings to the JSPs and servlet. Please note that the deployment descriptor goes in the web.xml file:

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
 PUBLIC "-//Oracle//DTD Web app 2.2//EN"
 "http://java.oracle.com/j2ee/dtds/web-app_2_2.dtd">
<web-app>
 <error-page>
 <error-code>404</error-code>
 <location>/HelloWorldServlet</location>
 </error-page>
 <servlet>
 <servlet-name>HelloWorldServlet</servlet-name>
 <servlet-class>xptoolkit.web.HelloWorldServlet</servlet-class>
 <init-param>
 <param-name>Greeting.class</param-name>
 <param-value>@Greeting.class@</param-value>
 </init-param>
 </servlet>
 <servlet>
 <servlet-name>HelloWorldJSP</servlet-name>
 <jsp-file>HelloWorld.jsp</jsp-file>
 </servlet>
 <servlet-mapping>
 <servlet-name>HelloWorldServlet</servlet-name>
 <url-pattern>/HelloWorldServlet</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
 <servlet-name>HelloWorldJSP</servlet-name>
 <url-pattern>/HelloWorldJSP</url-pattern>
 </servlet-mapping>
</web-app>


The deployment descriptor defines two servlet elements, one for the HelloWorldServlet and one for the HelloWorldJSP. If you are wondering why there is a servlet element for the HelloWorldJSP, remember that HelloWorld.jsp is compiled to a servlet before it is used for the first time. The HelloWorldServlet servlet element maps to the servlet (<servlet-class>xptoolkit.web.HelloWorldServlet</servlet-class>). The HelloWorldJSP element maps to the JSP file HelloWorld.jsp (<jsp-file>HelloWorld.jsp</jsp-file>). Then, the servlet mapping elements map the servlet element to specific URL patterns. Thus HelloWorldServlet maps to /HelloWorldServlet (<url-pattern>/HelloWorldServlet</url-pattern>); this is relative to the Web app location from the root of the server. And, the HelloWorldJSP servlet element is mapped to the /HelloWorldJSP URL pattern (<url-pattern>/HelloWorldJSP</url-pattern>).

The buildfile must deploy the descriptor to a place where the app server can find it. It does this by packaging the HTML files, JSP files, Java servlet, and deployment descriptor in a WAR file. The next section describes the buildfile for this project.

Buildfile for the HelloWorld Web app

This project has many more components than the other subprojects. As you would expect, the webapp project buildfile (see the next listing) is much more complex, but it builds on the foundation set by the model project—that is, the webapp project buildfile has the same base targets with the same meanings: setProps, init, clean, delete, prepare, mkdir, compile, package, and all. To the base targets, the webapp project's buildfile adds the prepare_metadata and deploy targets. The prepare_metadata target sets up the Ant filtering for the deployment descriptor (we talk about this in detail towards the end of this section). The deploy target adds the ability to deploy to both Resin and Tomcat Web app servers. The remaining details of this buildfile are covered in the applet and the enterprise beans sections later in this chapter.

<project default="all" >
 <target unless="setProps" description="setup the properites.">
 <property value="/tmp/app" /> </target>
 <target depends="setProps" description="initialize the properties.">
 <tstamp/>
 <property name="local_outdir" value="${outdir}/webapps" />
 <property value="${outdir}/lib" />
 <property value="${outdir}/dist" />
 <property value="${local_outdir}/webclasses" />
 <property value="${local_outdir}/meta" />
 <property name="deploy_resin" value="/resin/webapps" />
 <property name="deploy_tomcat" value="/tomcat/webapps" />
 <property name="build_lib" value="./../lib" />
 <property name="jsdk_lib" value="/resin/lib" />
 </target>
 <target name="clean_deploy" >
 <delete file="${deploy_resin}/hello.war" />
 <delete dir="${deploy_resin}/hello" />
 <delete file="${deploy_tomcat}/hello.war" />
 <delete dir="${deploy_tomcat}/hello" />
 </target>
 <target depends="init,clean_deploy" description="clean up the output directories.">
 <delete dir="${local_outdir}" />
 <delete file="${dist}/hello.war" />
 </target>
 <target depends="init" description="prepare the output directory.">
 <mkdir dir="${build}" />
 <mkdir dir="${dist}" />
 <mkdir dir="${build_lib}" /> </target>
 <target depends="prepare" description="compile the Java source.">
 <javac srcdir="./src" destdir="${build}">
 <classpath >
 <fileset dir="${lib}">
 <include name="**/*.jar"/>
 </fileset>
 <fileset dir="${jsdk_lib}"> <include name="**/*.jar"/>
 </fileset>
 <fileset dir="${build_lib}">
 <include name="**/*.jar"/>
 </fileset>
 </classpath>
 </javac>
 </target>
 <target name="prepare_meta_ejb" if="ejb">
 <filter token="Greeting.class"
 value="xptoolkit.model.GreetingShadow"/>
 </target>
 <target name="prepare_meta_noejb" unless="ejb">
 <filter token="Greeting.class" 
 value="xptoolkit.model.GreetingBean"/>
 </target>
 <target name="prepare_meta" depends="prepare_meta_ejb, prepare_meta_noejb">
 <copy todir="${meta}" filtering="true">
 <fileset dir="./meta-data"/>
 </copy>
 </target>
 <target depends="compile">
 <mkdir dir="${meta}" />
 <antcall target="prepare_meta" />
 <war warfile="${dist}/hello.war" webxml="${meta}/web.xml">
 <!-- Include the html and jsp files. Put the classes from the build into the classes directory of the war.
 /-->
 <fileset dir="./HTML" />
 <fileset dir="./JSP" />
 <classes dir="${build}" />
 <!-- Include the applet. /-->
 <fileset dir="${lib}" includes="helloapplet.jar" />
 <!-- Include all of the jar files except the ejbeans and applet. The other build files that create jars have to be run in the
 correct order. This is covered later.
 /-->
 <lib dir="${lib}" >
 <exclude name="greet-ejbs.jar"/>
 <exclude name="helloapplet.jar"/>
 </lib>
 </war>
 </target>
 <target depends="package">
 <copy file="${dist}/hello.war" todir="${deploy_resin}" />
 <copy file="${dist}/hello.war" todir="${deploy_tomcat}" />
 </target>
 <target depends="clean,package" description="perform all targets."/> </project>


The final output of the Web app project is a single WAR file. The WAR file is built (not surprisingly) by the package target. Here is the listing for the package target:

 <target depends="compile">
 <mkdir dir="${meta}" />
 <antcall target="prepare_meta" />
 <war warfile="${dist}/hello.war" webxml="${meta}/web.xml">
 <!-- Include the html and jsp files. Put the classes from the build into the classes directory of the war.
 /-->
 <fileset dir="./HTML" />
 <fileset dir="./JSP" />
 <classes dir="${build}" />
 <!-- Include the applet. /-->
 <fileset dir="${lib}" includes="helloapplet.jar" />
 <!-- Include all of the jar files except the ejbeans and applet. /-->
 <lib dir="${lib}" />
 </war>
 </target>


As you can see, this package target is much larger than the other two we've discussed (model and app). For now we'll defer a detailed discussion of the second and third lines of code:

 <mkdir dir="${meta}" />
 <antcall target="prepare_meta" />


These lines do some processing on the web.xml deployment descriptor file and put the file in the directory defined by ${meta} directory (note that the "meta" property is set in the init target). We explain the processing done to the deployment descriptor in the section "Enterprise JavaBeans" found later in this chapter. Next, the package target calls the war task, which is as follows:

 <war warfile="${dist}/hello.war" webxml="${meta}/web.xml">
 <fileset dir="./HTML" />
 <fileset dir="./JSP" />
 <classes dir="${build}" />
 <fileset dir="${lib}" includes="helloapplet.jar" />
 <lib dir="${lib}" />
 </war>


The WAR file hello.war is put in the distribution directory (dist), which is specified by the war task's "warfile" attribute (warfile="${dist}/hello.war"). The dist directory is another common directory that is used by the main project's buildfile later to build an enterprise archive (EAR) file; the "dist" property is defined in the init target. The "webxml" attribute of the war task defines the deployment descriptor to use; it's the one we processed at the beginning of the package target. The web.xml file is put in the WAR file's WEB-INF/ directory. In addition, the war task body specifies three file sets. One file set includes the helloapplet.jar file (which we discuss in the section "HelloWorld.jsp Applet Delivery" later in this chapter) and all the files in the HTML and JSP directories. The war task body also specifies where to locate the classes using <classes dir="${build}" />. This command puts the classes in the WEB-INF/classes directory. The webapp project's buildfile defines a slightly more complex compile target, as follows:

 <target depends="prepare" description="compile the Java source.">
 <javac srcdir="./src" destdir="${build}">
 <classpath >
 <fileset dir="${lib}">
 <include name="**/*.jar"/>
 </fileset>
 <fileset dir="${build_lib}">
 <include name="**/*.jar"/>
 </fileset>
 </classpath>
 </javac>
 </target>


Notice that this compile target defines two file sets. One file set (<fileset dir="${build_lib}">) is used to include the classes needed for servlets (such as import javax.servlet.*). The other file set (<fileset dir="${lib}">) is used to include the Greeting interfaces and the GreetingFactory class. The only real difference from the app compile target is the inclusion of the JAR file for servlets. The "build_lib" property is defined in the webapp project's init target, as follows:

<property name="build_lib" value="./../lib" />


The good thing about this approach is that if we need additional JAR files, we can put them in the build_lib. The second file set (<fileset dir="${build_lib}">) grabs all the JAR files in the ./../lib directory. The webapp project's buildfile adds a few convenience targets geared toward Web apps. The deploy target copies the WAR file that this buildfile generates to the webapps directory of Tomcat and Resin. (Tomcat is the reference implementation servlet engine of the Java specification. Resin is an easy-to-use Java app server that supports JSPs, EJBs, J2EE container specification, XSL, and so on.) Without further ado, here is the deploy target:

<target depends="package">
 <copy file="${dist}/hello.war" todir="${deploy_resin}" />
 <copy file="${dist}/hello.war" todir="${deploy_tomcat}" />
</target>


Both Tomcat and Resin pick up the WAR files automatically, in the interest of doing no harm and cleaning up after ourselves. The webapp project's buildfile also adds an extra clean_deploy target that deletes the WAR file it deployed and cleans up the generated directory, as follows:

 <target name="clean_deploy" >
 <delete file="${deploy_resin}/hello.war" />
 <delete dir="${deploy_resin}/hello" />
 <delete file="${deploy_tomcat}/hello.war" />
 <delete dir="${deploy_tomcat}/hello" />
 </target>


"Great," you say. "But what if the app server I am deploying to is on another server that is half way around the world?" No problem; use the following FTP task:

<ftp server="ftp.texas.austin.building7.eblox.org"
 remotedir="/deploy/resin/webapps"
 user 
 password="killMyLandLord"
 depends="yes"
 binary="yes"
>
 <fileset dir="${dist}">
 <include name="**/*.war"/>
 </fileset> </ftp>


Building and Deploying the Web app

This section explains how to build and deploy the Web app. The buildfile assumes that you have Resin and Tomcat installed in the root of your drive. You may need to make adjustments to the buildfile if you installed Resin or Tomcat in another directory or if you are using another J2EE-compliant Web app server. To build the Web app, follow these steps:

  1. Navigate to the Webapp directory, set up the environment, and then do the following at the command line:

    C:\CVS\...\MVCHelloWorld\Webapp>ant
    


    You will get the following output:

    Buildfile: build.xml setProps:
    
    init:
    clean_deploy:
     [delete] Could not find file C:\resin\webapps\hello.war to delete.
     [delete] Could not find file C:\tomcat\webapps\hello.war to delete clean:
     [delete] Could not find file C:\tmp\app\dist\hello.war to delete.
    prepare:
     [mkdir] Created dir: C:\tmp\app\webapps\webclasses
     [mkdir] Created dir: C:\tmp\app\dist compile:
     [javac] Compiling 1 source file to C:\tmp\app\webapps\webclasses package:
     [mkdir] Created dir: C:\tmp\app\webapps\meta prepare_meta_ejb:
    prepare_meta_noejb:
    prepare_meta:
     [copy] Copying 1 file to C:\tmp\app\webapps\meta
     [war] Building war: C:\tmp\app\dist\hello.war all:
    BUILD SUCCESSFUL
    


  2. Deploy the WAR files to the app server. If you install Resin or Tomcat off the root directory, then you can run the deploy target. Otherwise, modify the appropriate deploy properties defined in the init target. To deploy the app with Ant, do the following:
    C:\CVS\?.\MVCHelloWorld\Webapp>ant deploy Buildfile: build.xml
    ... ...
    deploy:
     [copy] Copying 1 file to C:\resin\webapps
     [copy] Copying 1 file to C:\tomcat\webapps BUILD SUCCESSFUL Total time: 0 seconds
    


  3. After we run the app, we start Resin or Tomcat, and then hit the site with our browser. (More on this subject later.) We can also clean out the directories when we are ready to deploy a new version, as follows:
    C:\CVS\...\MVCHelloWorld\Webapp>ant clean
    


    The output looks like the following:

    Buildfile: build.xml setProps:
    init:
    clean_deploy:
     [delete] Deleting: C:\resin\webapps\hello.war
     [delete] Deleting: C:\tomcat\webapps\hello.war clean:
     [delete] Deleting directory C:\tmp\app\webapps
     [delete] Deleting: C:\tmp\app\dist\hello.war BUILD SUCCESSFUL Total time: 0 seconds
    


    Notice that we delete the WAR files and the deployment directories. This is just good house-cleaning for when we do a build and deployIn the next section, we will run the webapp project.

Running the Web app

Now that we've built and deployed the webapp project, let's run it. We start our servlet engine and then open the site in our browser—for example, http://localhost/hello/HelloWorldServlet. (Resin's default setup is port 8080, so you may have to adjust the URL.) Here is what the Web app looks like when it's running:

Java Click To expand

You may notice a couple of things. The app URL is defined in a directory called hello (http:// localhost/hello/HelloWorldServlet). By default, Tomcat and Resin unjar our WAR file in a directory called <War file File Name>. Later, we will use the EAR file to override this default behavior in a neutral app server way. The HelloWorldServlet part of the app's URL is defined by a mapping in the deployment descriptor as follows:

 <servlet>
 <servlet-name>HelloWorldServlet</servlet-name>
 <servlet-class>xptoolkit.web.HelloWorldServlet</servlet-class>
 <init-param>
 <param-name>Greeting.class</param-name>
 <param-value>@Greeting.class@</param-value>
 </init-param>
 </servlet>
 <servlet-mapping>
 <servlet-name>HelloWorldServlet</servlet-name>
 <url-pattern>/HelloWorldServlet</url-pattern>
 </servlet-mapping>


The servlet tag declares the servlet and gives it a name. The servlet mapping assigns the HelloWorldServlet the URL pattern /HelloWorldServlet. We could change the URL pattern to /PeanutButter, and the URL http://localhost/hello/PeanutButter would work:

Java Click To expand

Actually, we mapped the 404 error to HelloWorldServlet as well, so the server sends any URL it does not recognize to HelloWorldServlet to process (for the benefit of people with fumble fingers).

The next section describes a simple applet project that integrates with the webapp project. Then, we will discuss Enterprise JavaBean deployment and enterprise archive files.

HelloWorld.jsp Applet Delivery

Now the applets JAR we built in becomes part of the Web app. It is put in the Web app where the browser can find it. The Web app has a JSP page, HelloApplet.jsp, which has a jsp:plugin tag that delivers the applet to the browser. The HelloApplet.jsp with the jsp:plugin action is listed as follows:

<html>
<head><title>Hello World Applet</title></head>
<body>
<jsp:plugin type="applet" code="xptoolkit.applet.HelloWorldApplet" archive="helloapplet.jar"
 
 align="center">
 <jsp:fallback> <!-- This fallback message will display if the plugin does not work. /-->
 <p> Java is cool. Get a browser that supports the plugin. </ br>
 Or we will hunt you down and melt your computer!
 </p>
 </jsp:fallback>
</jsp:plugin>
</body>
</html>


This shows how the applet is delivered to the browser. How is the applet included in the Web app's WAR file in the first place? We explain in the next section.

Including an Applet in a WAR File

If you look at the webapp project buildfile, you will note that the war task in the package target does the following:

 <war warfile="${dist}/hello.war" webxml="${meta}/web.xml">
 <fileset dir="./HTML" />
 <fileset dir="./JSP" />
 <classes dir="${build}" />
 <fileset dir="${lib}" includes="helloapplet.jar" />
 <lib dir="${lib}" />
 </war>


The fileset directive

<fileset dir="${lib}" includes="helloapplet.jar" />


tells the war task to include only the helloapplet.jar file from the lib directory. Because this file set is not a classes- or lib-type file set, helloapplet.jar goes to the root of the WAR file. In contrast, the special lib and classes file sets put their files in WEB-INF/lib and WEB-INF/classes, respectively. The end effect is that the browser is able to get the applet. After we build the applet, we go back and rebuild the Web app and then deploy it. We run Ant in the root of both the projects' home directories (if you get a compile error, be sure you have built the model, because the Web app depends on it). After everything compiles and the appropriate JAR and WAR files are built, we deploy the webapp project by using the deploy target of the webapp buildfile. Then we run the applet, as demonstrated in the following figure.

Java Click To expand

It's important to recap what we have done. We created a common Java library called model.jar. This model.jar is used by a Web app and a regular Java app that is a standalone executable Java app in an executable JAR file. We create an applet that is loaded with a JSP page that has the jsp:plugin action. Once the applet loads into the browser, the applet communicates over HTTP to the Web app's HelloWorldServlet. HelloWorldServlet calls the getGreeting() method on the GreetingFactory, which is contained in the model.jar file.

In the next section, we set up the GreetingFactory so that it talks to an enterprise session bean that in turn talks to an enterprise entity bean. The Web app buildfile is set up so that after we add one property file, it can talk to either the enterprise beans or to the local implementation in the model library.


JaVa
   
Comments