Introduction to Web Application
Archives
by Peter Darrah, Lutris Support Engineer
This FAQ describes how to set up the directory structure of a
Web archive or WAR to deploy Java servlets, Java Server Pages
(JSPs), and static content. This description assumes that you have
already written some JSPs or servlets and that you are trying to
figure out how to run them on the server. Under servlet 2.2, JSPs
and servlets are put into a directory structure referred to as a
Web application archive or WAR. When the WAR is finished, you can
compress it into a file with a .war extension, but setting up the
files to compress is the hard part. One advantage to the WAR construct
is that once a WAR is set up, it can be moved from server to server
without further configuration. A good way to begin understanding
how to construct a war is to look at a simple example.
A Simple WAR Example
Assume that you have a JSP called Hello.jsp and a
servlet called Hello.java and that you want to deploy
them. You could set up the following directory structure:
The directory structure begins with a document root directory
that has an arbitrary name, in this case, webApp . The
JSP page can either be in the document root directory or in any
of its subdirectories. In this example, it's in an arbitrary subdirectory
named myJspDir . The one required subdirectory is called
WEB-INF . This special directory contains the configuration
file web.xml and a directory called classes
that contains the compiled servlet classes. If you are only using
JSPs, you do not need a classes subdirectory. The servlet
server adds the classes directory to its CLASSPATH,
so the server automatically finds servlets you placed in that directory.
The last required file is the web.xml file. It contains
deployment information like name mappings, parameters, and default
file mappings. The web.xml file in this simple example
could contain the following essentially empty file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<!-- configuration options would go here -->
</web-app>
Once you register your web application with your servlet runner,
you access the above pages with the following URL's:
The http://your_host section of the URL gets you to your host.
When you configure the servlet runner to run the Web application,
you tell it the path to the document root is /tmp/webApp
an the URL prefix is some arbitrary string like /myPrefix. Therefore,
every request with the prefix myPrefix will be forwarded to the
servlet runner which, in turn, looks into your application. The
remainder of the URL for the JSP page corresponds to the directory
structure. You can put *.html files in the same directory
and request them in a similar manner. The call to the servlet requires
using the reserved word "servlet" in the url. When the servlet server
sees the word "servlet" in the URL, it knows to look for the corresponding
class in the classes subdirectory of the WEB-INF
directory.
Good Resources
Once you get a simple WAR example working, you will probably want
to see a more complicated example. There is an example that goes
along with this document. Your servlet server probably also comes
with an example WAR. Another good source of information about configuring
a WAR is the Servlet 2.2 specification. It's easy to read and includes
examples. You can download it from the following URL:
http://java.sun.com/products/servlet/download.html
A More Interesting web.xml File
As mentioned above, the web.xml file describes a
number of configuration parameters. The web.xml file
in the example above is empty. It contains no configuration parameters.
The following web.xml file shows how to do some common
configuration tasks. The tasks are describes by comments in bold.
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE web-app
PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.2//EN"
"http://java.sun.com/j2ee/dtds/web-app_2.2.dtd">
<web-app>
<!-- The next two sections define name/class mappings. -->
<servlet>
<servlet-name>BasicHello</servlet-name>
<servlet-class>Hello</servlet-class>
<init-param>
<param-name>SomeParameter</param-name>
<param-value>Parameterized hello from the web.xml file.</param-value>
</init-param>
</servlet>
<servlet>
<servlet-name>PackagedHello</servlet-name>
<servlet-class>a.b.c.HelloPackage</servlet-class>
</servlet>
<!-- The next two sections define name/url mappings. -->
<servlet-mapping>
<servlet-name>BasicHello</servlet-name>
<url-pattern>/Hello</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>PackagedHello</servlet-name>
<url-pattern>/Howdy/*</url-pattern>
</servlet-mapping>
<!-- The next two sections define welcome files and the error page. -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>index.html</welcome-file>
<welcome-file>myFunkyIndex.htm</welcome-file>
</welcome-file-list>
<error-page>
<error-code>404</error-code>
<location>/aDirectory/myFavoriteErrorPage.html</location>
</error-page>
<!-- This application wide parameter mapping is used to map the / to a page.
This parameter is used by the index.jsp page in this example. -->
<context-param>
<param-name>welcomeServlet</param-name>
<param-value>/Hello</param-value>
</context-param>
</web-app>
Mapping Servlets to URLs
The first lines in the web.xml file map servlet classes
to arbitrary names. For example, the Hello servlet
class is mapped to the name BasicHello. In another example, the
mapped class is in a package. The class file for the HelloPackage
servlet is located at /someDir/webApps/webApp/WEB-INF/classes/a/b/c/HelloPackage.class .
Once the servlet classes are mapped to names, the names can link
the classes with arbitrary URL mappings. For example, the HelloPackage
servlet is mapped to /Howdy/*, so the following URL brings up the
servlet:
http://localhost:8010/myPrefix/Howdy/aBigHello
Notice there is no use of the reserved word "servlet" in the URL.
Frequently, every servlet in a web application is mapped to a corresponding
URL to avoid using the word servlet. This example uses the wildcard
* (asterisk), but you can map to specific names. The pattern-matching
rules are described in more detail in the servlet specification.
For security reasons, a single * is the only supported wildcard.
Everything in this section refers to servlets, but JSPs can be
mapped to URLs in the same way. Just use the jsp-file tag instead
of the servlet-class tag when you define the servlet.
Mapping Default and Error Pages
This section of the web.xml file defines default
pages and the error page. The welcome-file-list section lists the
default pages. There are three entries there: index.jsp, index.html,
and myFunkyIndex.htm. If a URL is called without a page specified,
these are the default pages. As an example, assume a WAR has the
following configuration:
-
A /tmp/webApp/aDirectory containing a file index.html .
-
The root of the web application is mapped to /tmp/webApp .
-
The URL prefix is mapped to "/myPrefix".
In this case, a call to the following URL would return the contents
of index.html :
http://localhost:8010/myPrefix/aDirectory
If there was another subdirectory webApp/anotherDir
with the file myFunkyIndex.htm , a call to the following
would return the contents of myFunkyIndex.htm :
http://localhost:8010/myPrefix/anotherDirectory
The next section defines the default error page. In this case,
the 404 File Not Found error is mapped to a page called myFavoriteErrorPage.html
in the directory aDirectory . Bogus URLs will map to
this page.
Defining parameters used by the application
Virtually every application uses parameters that are set in a
configuration file. In the servlet 2.2 model, the parameters used
by an application are included in the web.xml file.
This example web.xml file includes one parameter set
for a servlet and one parameter set for the entire Web application.
The Hello servlet includes a parameter defined in the block beginning
with the init-param tag. The servlet then gets that value with the
following call:
getInitParameter("SomeParameter")
The application-wide parameter is defined in the block beginning
with the tag context-param. This value can be accessed by any servlet
or JSP with the following method call:
getServletContext().getInitParameter( "welcomeServlet" )
Servlets talk to each other through the servlet context in a similar
manner. For example, if you have a factory class you instantiate
on startup and place in the servlet context, then all other servlets
can access that factory object through servlet context. A full discussion
of JNDI, security, and servlet/EJB communication is beyond the scope
of this document, but you should be aware that they are an integral
part of servlet 2.2.
Using the load-on-startup tag
While it is not used in this example, the load-on-startup tag
is very useful. Virtually all large Web applications start at least
one servlet that manages services for the rest of the application.
That central servlet might start a database connection pool manager,
verify that an email server is working, test a credit card verification
service, or instantiate objects used by the rest of the servlets.
This tag takes a positive integer as an argument. The number determines
what order the servlets are started in. For more information, see
the web.xml DTD in the servlet specification. The DTD
includes descriptions of other tags not used here, including tags
that control the security context and references to Enterprise Java
Beans.
Mapping the slash to a servlet welcome
page
Mapping the slash to a servlet is an apparently simple problem
that requires a somewhat complicated solution. It's a very common
task to map the opening page of an application to a servlet. In
which case a request to the URL http://foo.com/myPrefix is forwarded
to the servlet mapped to http://foo.com/myPrefix/Hello. Note that
your application prefix can just be / if you want http://foo.com
to go to http://foo.com/Hello.
The most intuitive answer is to simply define a URL mapping to
the URL "/". If you take this approach, the mapping appears to act
like mapping "/*" and every URL not defined in the web.xml
file appears to get the default page. Files like foo.html
are no longer served. This behavior comes from the fact that mapping
the slash takes over the default servlet. This behavior is defined
in the servlet specfication. Because *.html, *.wml, and other static
files are handled by the default servlet, the returned request looks
like the page you mapped to slash.
One good solution to this problem is to use a JSP page in the
document root that forwards the request to your welcome servlet.
The server receives the request for the slash and looks for the
welcome-file mappings. It finds an index.jsp file and
calls it. That JSP file then forwards the request to your welcome
servlet. The advantage to this approach is that it leaves the default
servlet that comes with the server in place. It also takes advantage
of the welcome-file approach defined in the servlet 2.2 specification.
An example of this approach is included in the accompanying WAR
example. The index.jsp in the example can be copied
to any subdirectory and it will forward the request to the default
servlet defined in the web.xml file.
An important point to note with this approach is the possible
security risk of the default servlet showing directory listings.
The Tomcat default servlet will show a directory listing if an URL
refers to a directory that does not contain a welcome file. If a
directory listing will compromise your site's security, verify that
you put an index.jsp or index.html in
every directory. For example, assume you have a webApp/media
directory containing your site's images. Without a welcome file,
a call to http://foo.com/myPrefix/media returns a directory listing
of all the images. If you do not want a user to see that listing,
put an index.jsp or index.html file in
the media subdirectory.
The "behind the scenes" web.xml
file
By now you may be wondering if there is some "behind the scenes"
web.xml file that defines default mappings. Yes there
is. In Tomcat this file is org/apache/tomcat/deployment/web.xml
in the JAR file. In Enhydra, this file can be found in the enhydra.jar .
You can extract the file from the JAR file using a zip utility or
jar itself. Reading this web.xml file
is instructive. For example, there is a mapping for "/servlet/*"
to the ServletInvoker servlet. If you want to see what the default
welcome mappings are, they are listed at the bottom of the file.
Adding MIME types for WAP/WML
While the default web.xml file defines hundreds of
MIME mappings, it does not define the MIME mappings used by the
WAP protocol. WAP is the protocol used to transmit content to the
micro-browsers in cellular telephones. If your WAR contains *.wml
and *.wbmp files, you will want to add the wireless
MIME types to your web.xml file. The mappings are given
in the web.xml file in the demonstration WAR that accompanies
this example. With the example running, you can access the following
URL from a cellular phone emulator:
http://localhost:8010/myPrefix/wapPages/Hello.wml
Adding other *.jar files to a Web application
To this point, this FAQ has only described how to add servlets
or other classes to the classes subdirectory in the
WEB-INF directory. JAR files your application uses
are put in the lib subdirectory of the WEB-INF
directory. The name lib is a reserved word. From the application
server's point of view, it simply adds the WEB-INF/classes
directory and every *.jar file in WEB-INF/lib
to its CLASSPATH. Servlets do not have to be in the classes
subdirectory. They can be anywhere on the application server's CLASSPATH
if they are mapped in the web.xml file. Deploying your
Web application's servlets in a JAR file in the lib
directory is very common.
The images directory
Frequently, a web application has an images or media
subdirectory that contains all of the *.gif or *.jpg
files. How do you manage this directory during development and deployment?
During development you want the images to be part of your WAR, but
at deployment time you want the Web server to serve them. Although
images and static files can be served from a WAR, the Web server
will serve them more efficiently because Web servers are written
in native code and are optimized to serve static content.
The following steps describe a possible scenario for serving static
content from the WAR during development and the Web server's htdocs
directory after deployment.
-
During development, put your images in an images
subdirectory of the top-level Web application directory.
-
Make links in your HTML relative to "/". For example, the HTML
your servlets return contains the following:
<img src="/images/Enhydra.gif">
-
During development, use an URL prefix of "/" so all requests
go to the Web application.
-
At deployment time, move all static content from your WAR to
the Web server's document directory.
-
When you configure the Web server and application server, use
an URL prefix like myPrefix for your WAR. Images are then served
by the Web server, and URLs like /myPrefix/Hello are forwarded
to the application server.
Running the example
A WAR example is included with
this FAQ. The example is designed to run "out of the box" with Enhydra
3.x. To run the example, follow these steps:
-
Create a WARConfig directory:
mkdir /tmp/WARconfig
-
Download WARconfig.war
to /tmp/WARConig .
-
Change directories to WARConfig :
cd /tmp/WARconfig
-
Uncompress the WAR with the following command:
jar xf WARconfig.war
-
Edit the top two lines in the Makefile to point
to your JDK and Enhydra installation.
-
Run make .
-
Change directories multiserver installation make created:
cd ../multiserver
-
Start the server:
./start
-
Browse to http://localhost:8010/myPrefix
to see the WAR.
This demo runs on the following ports:
8000 MultiserverAdmin
8010 HTTP connection to demo WAR
8020 Enhydra Director connection to demo WAR
Here are interesting URL's you might want to check out:
Enhydra Issues
The previous information applies to any servlet/JSP container
that is servlet 2.2-compliant. This section describes issues that
are specific to the Enhydra Multiserver servlet runner.
-
You may wonder how to configure a Web application to run under
the Enhydra Multiserver. The basic steps are described here:
-
Run the Multiserver Administration Console.
-
Choose the Add button and select the WAR radio button.
-
Fill in the name, Document Root path, and select Servlet
Invoker if you intend to use the /servlet/* syntax.
-
Once the application is added, select the Connections tab.
Choose a port and URL prefix.
-
Start the application by clicking the Start button.
-
Classic presentation object style Enhydra applications are
easy to add to a WAR. You can use an Enhydra application, JSPs,
and servlets in the same application. Enhydra applications deploy
as a single servlet. You can run a classic Enhydra application
in any 2.2 servlet server by adding the application's JAR file
to the lib directory, entering the Enhdyra Servlet
in the web.xml file, and supplying the application's
configuration file as an argument. If you are using another
application server, be sure to put Enhydra's classes in your
CLASSPATH after the server's classes or they will conflict.
Here is an example of the web.xml settings:
<servlet>
<servlet-name>welcome</servlet-name>
<servlet-class>org.enhydra.Servlet</servlet-class>
<init-param>
<param-name>ConfFile</param-name>
<param-value>/WelcomeWar/apps/welcome.conf</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
-
A bug in the 3.x releases prevents you from deploying a WAR
in a JAR file. You have to expand the JAR on the file system.
There are actually no performance benefits to deploying WAR
files because Tomcat just expands WARs files to the file system.
Copyright (C) 1997-2000 Lutris Technologies
|