Basic Web Application Setup

This web page documents the steps I use to set up a basic web application using Apache, Tomcat, Log4j, and Velocity on a Sun Solaris system. It covers only what I used for my applications and does not attempt to make a full documentation of all the features of any software product. It assumes that all systems have been downloaded and installed.

Author: Barbara Baughman, Systems Analyst, University of Texas at Dallas, baughman@utdallas.edu

What releases were used?

References

What permissions should be used for the files?

Tomcat Setup

The server.xml file - Configuring tomcat

The tomcat log files

Set up the tomcat lib subdirectory

Create application subdirectories

The web.xml file - Configuring the application

Velocity Setup

The velocity.properties file - Configuring Velocity

Servlets that use Velocity templates

Templates

General Comments

Templates for every application

Setting Up Log4j Logging

The Log4jServlet

Configuring Log4j loggers in the properties file.

Who added this...?


What releases were used for these instructions?

References

The home directory for tomcat is referred to as ${tomcat_home}.

The name of the directory that stores the application files is referred to as app_name.

The home directory for the application files is reffered to as ${app_home}, which is the same as ${tomcat_home}/webapps/app_name.

What permissions should be used for the files?
The files for the {tomcat_home} subdirectory have jakarta as the owner. The group permission should have userids that can read and/or write. There is no need to make anything world-readable/writeable/executable.

Tomcat Setup

Configuring tomcat

The server.xml file in $tomcat_home/conf contains instructions about setting up the tomcat-managed web applications. You may optionally add a <Context> element to the file for every web application, just to make sure the application will be setup as you like. Put them after the line for <Context path="/examples" ...</Context>

        <Context path="/jams" docBase="jams" debug="0"
                 reloadable="false" crossContext="false">
          <Logger className="org.apache.catalina.logger.FileLogger"
                     prefix="localhost_jams." suffix=".txt"
                  timestamp="true"/>
        </Context> 

The path refers to the path from $tomcat_home/webapps that holds the files related to this application. The docBase under my usual setup is the same as the path without the leading '/'.

Reloadable is true if you want the application to be reloaded when a java class file changes. Reloading essentially shuts down all sessions for the application and restarts the servlet. Since this can now be done with the only tomcat manager application, I would set this to false.

The crossContext indicates if the ServletContext for this application will be shared with other tomcat web applications. I make this false, since it is unnecessary for my applications.

The Logger is an optional statement that puts tomcat log messages for startup/shutdown for this application into a separate file. In this case, you can look for it under $tomcat_home/logs/localhost_jams.yyyy-mm-dd.txt.

Tomcat log files
If tomcat doesn't seem to startup correctly, or you application doesn't seem to startup, you can go to the tomcat logs to view error messages. See above for an example of setting up a separate log file for a given web application. Otherwise, the messages are in localhost_log.yyyy-mm-dd.txt. These log files should be purged periodically, since they do nothing but get more and more numerous.

Setup the tomcat shared/lib subdirectory
Under ${tomcat_home}/shared/lib, put the jar files for programs that will be needed for all applications. In particular, tomcat expects to find all oracle drivers and ldap-related jars in this directory. For any given web application, tomcat will include in its CLASSPATH the jars in this directory. The files should be owned by the same userid that will startup tomcat.

If you add new jars to this library, you must restart tomcat to have them included in the CLASSPATH.

Create application subdirectories
Make the directories/subdirectories for the application. First, create the subdirectory app_name under ${tomcat_home}/webapps, where app_name will be the name of your choice. All application files should go under ${tomcat_home}/webapps/app_name. Be sure that apache allows the ${app_home} subdirectory to be readable by a browser.

Under ${app_home}, create the subdirectories images, html, and WEB-INF. The images subdirectory contains image files that may be used in the application. The html subdirectory contains any HTML files that may be used in the application. The WEB-INF subdirectory contains everything else. Of course, you can have other subdirectories depending on how you wish to organize the application. Keep in mind that everything under the WEB-INF subdirectory will not be viewable from a web browser, and everything not under WEB-INF can be viewed from a web browser. Under WEB-INF, create the subdirectories lib, logs, templates, and classes.

The URL http://server.utdallas.edu/app_name/html/htmlfile.html will look for the file ${app_home}/html/htmlfile.html.

The lib subdirectory contains all jars that are needed for this particular application. Include the velocity jar here, log4j jars, and UTD-specific jars. All files in this subdirectory are in the tomcat CLASSPATH for this application only. If you add new jars to this library, you must restart tomcat to have them included in the CLASSPATH. If you put a new version of the jar in this subdirectory, you must reload the application or restart tomcat.

The logs subdirectory contains application logs.

The classes subdirectory contains java classes that are known in the tomcat CLASSPATH. It will contain any classes that are specific to this application.

The templates subdirectory will hold the Velocity templates for this application.

The web.xml file - Configuring the application
At application startup, Tomcat expects to find a file called web.xml in each application under ${app_home}/WEB-INF (although it does have a default in ${tomcat_home}/conf). ${tomcat_home}/webapps/examples/WEB-INF). Put an entry for every servlet that will be accessed under this application as follows:

    <servlet>
        <servlet-name>
            MAIN
        </servlet-name>
        <servlet-class>MainController</servlet-class>
        <init-param>
            <param-name>properties</param-name>
            <param-value>/WEB-INF/velocity.properties</param-value>
        </init-param>
        <load-on-startup>5</load-on-startup>
    </servlet>

This tells the web browser information about a particular servlet. It gives the name and then the class in the CLASSPATH that will run. The load-on-startup tells tomcat to run the init() method when tomcat starts up. The number is a simple sequence number to have multiple servlets in the application start in a particular order.

The example above includes an init-param for the servlet. Optionally, initializing parameters can also be defined as a context parameter, which makes it available to all servlets within the application. Parameters defined under the <servlet> are obtained through the ServletConfig object. Context parameters are available through the ServletContext object. During the servlet's init() method call:
getServletConfig().getInitParameter("properties");
to get an init-param under the servlet definition, or
getServletConfig().getServletContext().getInitParameter("properties");
to get a context parameter. Here properties is the param-name.

To set a context parameter, have the following code before the first <servlet>.

    <context-param>
        <param-name>properties</param-name>
        <param-value>/WEB-INF/app.properties<param-value>
        <description>Property values for this application
        </descrption>
    </context-param>

For every servlet that should be accessible to the user, you must also give the <servlet-mapping>, telling which URL's will be mapped to a particular servlet.

    <servlet-mapping>
        <servlet-name>MAIN</servlet-name>
        <url-pattern>/servlet/MAIN</url-pattern>
    </servlet-mapping>

The URL pattern refers to the characters that will follow the base URL that gets you to the application itself. For example, if the base application URL is https://netid.utdallas.edu/guam, the the mapping above will take all URL requests to https://netid.utdallas.edu/guam/servlet/MAIN to be processed by the class MainController. The servlets must all be defined in the web.xml file before the first servlet-mapping.

Finally, the web.xml file is where you can impose the maximum length of a user session to be idle before the session information goes away. The following example sets the session limit to 60 minutes.

    <session-config>
        <session-timeout>60</session-timeout>
    <session-config>

Velocity Setup

The velocity.properties file - Configuring Velocity
The application's properties file for any servlet that will have use Velocity must contain configuration parameters for the engine. In general, the only line needed is:
file.resource.loader.path=/WEB-INF/templates

This gives the location of template files. If more than one directory is used, separate the list of directories with a comma. Note that the path is relative to the app_home directory because of the way the method startVelocity() below initializes the VelocityEngine.

To use log4j to output the Velocity log file, also add something like the following line to the application properties file.
runtime.log.logsystem.log4j.category=VELOCITY

Then in the log4j properties file, define the log4j parameters for this category. Currently, Velocity's log4j link uses the deprecated Category class instead of the preferred Logger class.

The easiest way to create a servlet that has a builtin VelocityEngine is to create a class that extends edu.utdallas.ir.servlet.UTDServlet. The following method is used to create a VelocityEngine based on a Properties object created from the properties file. Call edu.utdallas.ir.util.WebAppProperties.getProperties(ServletConfig) to get this Properties object. This method is included in UTDServlet during init().

If you are not affiliated with UTD, then you'll want to create your own web application servlet that has some basic methods and does standard initialization.

    private VelocityEngine startVelocity(Properties p) {
        String m="";  
        VelocityEngine ve=new VelocityEngine();
        //Setup the file resource loader
        String
            path=p.getProperty(RuntimeConstants.FILE_RESOURCE_LOADER_PATH,
                    "/templates");
        path = getServletContext().getRealPath(  path );
        if ( path != null) {
            p.setProperty(
                    RuntimeConstants.FILE_RESOURCE_LOADER_PATH,path);
        }
        m=new StringBuffer(64)
         .append("Velocity templates in ").append(path).toString();
        msg.add(m);
        //Setup the velocity log
        String vellog=p.getProperty("RuntimeConstants.RUNTIME_LOG",
                      "/WEB-INF/logs/velocity.log");
        String log=getServletContext().getRealPath(vellog);
        if (log!=null) {
            p.setProperty(RuntimeConstants.RUNTIME_LOG,log);
        }
        try {
            ve.init(p);
        } catch (Exception e) {   
            m=new StringBuffer(64)
             .append("Unable to init the VelocityEngine.\n")
             .append(e).toString();
            msg.add(m);
            working= false;   
        }
        return ve; 
    }

Here msg is a Vector of startup messages and working is a boolean value that tells whether the servlet was properly initialized. These are private values defined for the class.

Following is a basic method for rendering a template.

    protected void renderTemplate(HttpServletResponse res,
            VelocityContext context, String template) {
        res.setContentType("text/html"); 
        try {
            ve.mergeTemplate(template, context, res.getWriter());   
        } catch (ResourceNotFoundException rnfe) {
        } catch (ParseErrorException pee) {
        } catch (MethodInvocationException mie) {
        } catch (Exception e) {
        } 
    }
Add your own handling of any exceptions. The exception if very seldom thrown. If there is a problem, look to velocity.log for the error message.

Other standard methods that I find helpful are:

protected Vector setServletParameters(Properties p);
This method is called during init(), right after the properties are obtained from the web application's properties file as designated in web.xml. The properties file, then, contains all the changeable parameters that would define the servlet workings. The Vector is a set of String messages about the value of the parameters as they are picked up.

protected VelocityContext setInitialContext(Properties p);
This method is called during init(), after the properties are obtained from the web application's properties file. It loads a VelocityContext object with objects that you want to make available to all templates, and which never change. You would do this by creating the template's context using a statement like:
VelocityContext ctx=new VelocityContext(initialContext);

Servlets that use Velocity templates.
There are several servlets already in edu.utdallas.ir.servlet which will make development of Velocity-based applications much easier. See the javadoc for the package edu.utdallas.ir.servlet for a list and description of each servlet.

Templates

General Comments
Template files are in the ${app_home}/WEB-INF/templates directory. The file extension is always .vm, although Velocity doesn't force any naming conventions for template files. The files may or may not contain Velocity directives, although HTML files that do not reference Velocity directives or references would generally be in the ${app_home}/html directory.

Templates for every application
Some templates show up in virtually all of my applications. Thus, templates with the same function always have the same name to help me with troubleshooting.

The error.vm template is called when the application fails in some crucial part of initialization.

The noserver.vm template gives a standard message to the user when a request cannot be processed because of a system error. The idea is to avoid sending stack traces to the poor user. Instead, send this screen to the user, and log the stack trace to a log file.

The login.vm template presents a standard login screen.

The welcome.vm template presents the "home page" screen for this application.

The head.vm template presents the standard top of a screen. You can use the Velocity directive #parse("head.vm") at the top of a template file to have this at the top of the screen. Changing the header then only involves changing this file. This is also a good place to setup a standard

statement, since all templates in the application will be directed to basically the same URL.

The tail.vm template presents a standard footer for a screen. You can use the Velocity directive #include("tail.vm") at the bottom of a template file to have this at the bottom of the screen. Changing the footer then only involves changing this file.

The end.vm template includes a standard footer with links to the UTD homepage and the IR homepage. These are mandated on all UTD web pages. However, for pages that are confidential in nature and should require a logout, these links should not be presented.

Setting Up Log4j Logging

The Log4jServlet
The servlet edu.utdallas.ir.servlet.Log4jServlet provides log4j logging. It will look for an init-param of "log4j" as the name of the Log4j properties file. Log4j logging will be setup according to this properties file. See the javadoc for edu.utdallas.ir.servlet.Log4jServlet for more information.

There does not need to be a <servlet-mapping> in web.xml for this servlet. The following should be placed in the list of <servlet> in web.xml. Note that <load-on-startup> is 1, so log4j logging is setup before any other servlets are called.

    <servlet>
        <servlet-name>Log4j</servlet-name>
        <servlet-class>edu.utdallas.ir.servlet.Log4jServlet
        </servlet-class>
        <init-param>log4j</init-param>
        <init-value>/WEB-INF/log4j.properties</init-value>
        <load-on-startup>1<load-on-startup>
    </servlet>
Configuring Log4j loggers in the properties file
See the documentation on setting up Log4j logging at http://jakarta for full details. Some common configurations are given below.

To setup the Velocity log file as a rolling appender file named velocity.log under WEB-INF/ use:

log4j.category.VELOCITY=DEBUG, VEL
log4j.appender.VEL=org.apache.log4j.RollingFileAppender
log4j.appender.VEL.File=${catalina.home}/webapps/appname/WEB-INF/logs/velocity.log
log4j.appender.VEL.MaxFileSize=10KB
log4j.appender.VEL.MaxBackupIndex=1
log4j.appender.VEL.layout=org.apache.log4j.PatternLayout
log4j.appender.VEL.layout.ConversionPattern=%d - %m%n

Here VELOCITY refers to the runtime.log.logsystem.log4j.category property in the properties file. When velocity.log fills to its maximum size of 10KB, the velocity.log will be written to velocity.log.1 and new messages will be written to velocity.log. In the ConversionPattern, %d is the date, %m is the message, %n is a newline. Be sure the log4j.appender File property points to the filename you want to use. Here the first line refers to log4j.category, which it must for Velocity. However, the application should be using the more recent Logger class, which means the first line would refer to log4j.logger.

To write to a system log:

log4j.logger.Login=DEBUG, Login
log4j.appender.Login=org.apache.log4j.net.SyslogAppender
log4j.appender.Login.SyslogHost=localhost
log4j.appender.Login.Facility=LOCAL0
log4j.appender.Login.layout=org.apache.log4j.PatternLayout
log4j.appender.Login.layout.ConversionPattern=%-5r %-5p [%t] %c{2} %x - %m\n

Here the SyslogHost will be the server name of the syslog or localhost for this server. LOCAL0 would be setup by the system administrator in configuring the syslog. Note that this uses the log4j.logger instead of log4j.category used for Velocity.

To setup a logger in the application, include the line
import org.apache.log4j.Logger;
among the import statements, and name the Logger when you name other class fields:
static Logger LOG=Logger.getLogger("Login");

Note that the Logger must be static. LOG is the name that will be used to program log statements (LOG.info("message");). "Login" is the reference that will be used in log4j.properties to define the Logger's properties, as in the example for Login above.

Setup an Oracle Connection Pool


A connection pool of connections to an Oracle database can be setup using the web.xml file and a properties file. The edu.utdallas.ir.oracle.ConnectionPool object is placed in the ServletContext as the attribute "oracleconnectionpool". After loading this servlet, an Oracle database connection pool is available to all servlets in the web application.

The following should be inserted in web.xml in the section on <servlet>'s. There is no need for a <servlet-mapping>

    <servlet>
        <servlet-name>OraclePool</servlet-name>
        <servlet-class>edu.utdallas.ir.OraclePoolServlet
        </servlet-class>
        <init-param>
            <param-name>properties</param-name>
            <param-value>WEB-INF/oracle.properties</param-value>
        </init-param>
        <load-on-startup>2</load-on-startup>
    </servlet>

Note that the init-param can be omitted if the properties file has been defined as a <context-param>. Also, this servlet should be loaded on startup of the web application after the Log4jServlet and before any servlet that will need to use the pool.

The properties that must be defined are:

OraDriver The driver class name
OraURL The URL to the database
OraSize The initial size of the pool
OraMax The maximum number of connections allowed
OraUse The number of uses before a connection is disconnected
OraTimeout Number of minutes of non-use before a connection times out

Setup an LDAP connection pool


A connection pool of connections to an LDAP server can be setup using the web.xml file and a properties file. This connection pool is placed in the ServletContext as attribute "ldapconnectionpool". After this servlet is initialized, the connection pool is available to all servlets within the web application.

The following should be inserted in web.xml in the section on <servlet>'s. There is no need for a <servlet-mapping>

    <servlet>
        <servlet-name>LDAPPool</servlet-name>
        <servlet-class>edu.utdallas.ir.LDAPPoolServlet
        </servlet-class>
        <init-param>
            <param-name>properties</param-name>
            <param-value>WEB-INF/ldap.properties</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet>

Note that the init-param can be omitted if the properties file has been defined as a <context-param>. Also, it should be loaded on startup of the web application after Log4jServlet and before any servlet that will need the connection pool.

The properties that must be defined are:
ldaphost The hostname of the ldap server
ldapport The port number on the host for the ldap server
ldapmin The minimum number of connections to hold in the pool
ldapmax The maximum number of connections to hold in the pool

The WebUser object


The class edu.utdallas.ir.util.WebUser is a convenient class to extend to contain information on the client user. It can be instantiated with as little as an IP address. With login and various lookups, it can be extended to carry other information. Check also UTDUser, which WebUser extends. It will lookup name information and has methods for hashing, comparing, and equals.

Many of the methods of edu.utdallas.ir.servlet.UTDAppServlet assume there will be a WebUser-type object in the HttpSession as attribute "user".

The WebLogin object


The class edu.utdallas.ir.ldap.WebLogin or edu.utdallas.ir.util.WebLoginLogged represent an object that has methods to handle login(), authenticate(), and logout(). This object is placed in the ServletContext by the login servlet. The edu.utdallas.ir.servlet package has several Login servlets. See the javadoc for details. That means that any servlet can use this object's method to send the user to the first screen of the application (login), send the user out of the application (logout), or authenticate a user.

All login servlets expect certain properties to be defined in the properties file. See the javadoc for details.

The log4j Logger CONNECT must be defined in the log4j.properties file to log messages at the time of login and logout.

User Authentication

If you are authenticating with the NetID/password or have an application that requires LDAP connections, you should have a connection pool.

In web.xml, include the servlet definition for the LDAP pool as described above. Also include a servlet definition for the Login servlet.

    <servlet>
        <servlet-name>Login</servlet-name>
        <servlet-class>edu.utdallas.ir.servlet.LoginServlet
        </servlet-class>
        <init-param>
            <param-name>login</param-name>
            <param-value>login.properties</param-value>
        </init-param>
        <load-on-startup>4</load-on-startup>
    </servlet>

Note that the init-param section can be omitted if the properties file is given in a context-param appearing before any servlet definition in web.xml. The servlet-name edu.utdallas.ir.servlet.LoginServlet may be replaced with another login-type servlet. For example, the servlet edu.utdallas.ir.servlet.SecureLogin does the authentication step and gets the functions the user is allowed to access.

Define the logger LOGIN in the log4j properties for login processing messages. Login servlets store a WebLogin object in the ServletContext.

Note that you will probably need a servlet mapping so you can use a line like <FORM ACTION="${url}/login"> to send the userid/password to the login servlet. Note: for edu.utdallas.ir.servlet.LoginServlet, it is assumed the HttpServletRequest parameters for netid and password are "userid" and "password". Add the following to the <servlet-mapping> part of the web.xml file. Note that you can provide more than one servlet mapping to the same servlet.

    <servlet-mapping>
        <servlet-name>Login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mappping>

The following properties
loginvm The template name of the entry screen to the application. Default is "login.vm".
logoutvm The template name to leave the application. Default is loginvm.
maxtries The maximum number of authentication tries allowed
noserver The template name to tell the user the LDAP server is not available
notloggedinvm The template name when the user is not authenticated
welcome The template name when the user is successfully authenticated