Now we are going to think about programming web applications so we need a few more development tools. Download XAMPP from http://www.apachefriends.org/en/xampp.html and the tomcat addon.

Get familar with the software and make sure you can do the following:

1) access http://localhost and https://localhost

2) access http://localhost:8080/

Got it (or access to similar facilities on a server)? If not, don't proceed.

Now make directories for JP/src/main/webapp and JP/src/main/webapp/WEB-INF and add servlet-api.jar to JP/lib

Create the following servlet: InfoServlet.java

package net.wsor.osterman.javapersistence.util;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import net.wsor.utils.file.FileOperator;
import net.wsor.utils.file.PropertiesFile;
import net.wsor.utils.logging.Loggable;
import net.wsor.utils.logging.Logger;
import net.wsor.utils.logging.Logger.LOG_LEVEL;
import net.wsor.utils.web.html.MapBlock;

/**
 * <code>InfoServlet</code> is designed to format the local
 * environment into a page that can be easily viewed.
 * <p>
 * requires servlet-api.jar
 * @author <a href="mailto:travis@wsor.net">Travis Osterman</a>
 * @see net.wsor.utils.web.html.MapBlock
 * @see net.wsor.utils.file.PropertiesFile
 * @since Nov 5, 2007 9:41:57 PM
 * @todo complete javadoc for InfoServlet
 */

public class InfoServlet extends HttpServlet implements Loggable{

    private static final long serialVersionUID = 1L;

    /**
     * Provides a utiltiy for logging through the variable
     * <code>log</code>.
     */

    protected static Logger log = new Logger (InfoServlet.class, LOG_LEVEL.TRACE);
   
    protected void doGet(HttpServletRequest httpServletRequest,
    HttpServletResponse httpServletResponse)
        throws ServletException, IOException {

        log.trace("starting InfoServlet");
        httpServletResponse.setContentType("text/html");
        PrintWriter out = httpServletResponse.getWriter();
        String content = createContent(httpServletRequest,httpServletResponse);
        //out.println("Hello World!");
        out.println(content);
        out.close();
        log.trace("content written");
       
        log.trace("trace");
        log.debug("debug");
        log.info("info");
        log.warn("warn");
        log.error("error");
        log.fatal("fatal");
    }

    /**
     * @param httpServletRequest
     * @param httpServletResponse
     * @return html to be written to the response
     */

    protected String createContent(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
       
        log.trace("creating content");
       
        String out = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"DTD/xhtml1-transitional.dtd\">\n" +
                     "<html>\n" +
                     "\t<head>\n" +
                     "\t\t<title>InfoServlet</title>\n" +
                     "\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"/debug/debug.css\">\n" +
                     "\t</head>\n" +
                     "\t<body>\n";
       
        List<MapBlock> blocks = new ArrayList<MapBlock>();
       
        /*
         * Example output
         * Host: localhost:8080
         * User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.7) Gecko/20070914 Firefox/2.0.0.7
         * Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*\/*;q=0.5
         * Accept-Language: en-us,en;q=0.5
         * Accept-Encoding: gzip,deflate
         * Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
         * Keep-Alive: 300
         * Connection: keep-alive
         * Cookie: JSESSIONID=s0bzbijiqhtl
         */

       
        // out += "\n\nHeaders\n";
        MapBlock headers = new MapBlock("Headers");
        Enumeration headerNames = httpServletRequest.getHeaderNames();
        while(headerNames.hasMoreElements()) {
            String key   = (String) headerNames.nextElement();
            String value = httpServletRequest.getHeader(key);
           
            // System.out.println(key + ": " + value);
            // out += key + ": " + value + "\n";
            headers.add(key, value);
        }
        blocks.add(headers);
       
        /*
         * this is broken with https
         *
        out += "\n\nAttributes\n";
        Enumeration attribNames = httpServletRequest.getAttributeNames();
        while(attribNames.hasMoreElements()) {
            String key   = (String) attribNames.nextElement();
            String value = (String) httpServletRequest.getAttribute(key);
           
            // System.out.println(key + ": " + value);
            out += key + ": " + value + "\n";
        }
        */

       
        MapBlock requestData = new MapBlock("Request Data");
        requestData.add("Auth Type", httpServletRequest.getAuthType());
        requestData.add("Char Encoding", httpServletRequest.getCharacterEncoding());
        requestData.add("Content type", httpServletRequest.getContentType());
        requestData.add("Context path", httpServletRequest.getContextPath());
        requestData.add("Local address", httpServletRequest.getLocalAddr());
        requestData.add("Local name", httpServletRequest.getLocalName());
        requestData.add("Local port", new Integer(httpServletRequest.getLocalPort()).toString());
        requestData.add("Method", httpServletRequest.getMethod());
        requestData.add("Path info", httpServletRequest.getPathInfo());
        requestData.add("Path translated", httpServletRequest.getPathTranslated());
        requestData.add("Protocol", httpServletRequest.getProtocol());
        requestData.add("Query string", httpServletRequest.getQueryString());
        requestData.add("Remote address", httpServletRequest.getRemoteAddr());
        requestData.add("Remote host", httpServletRequest.getRemoteHost());
        requestData.add("Remote port", new Integer(httpServletRequest.getRemotePort()).toString());
        requestData.add("Remote user", httpServletRequest.getRemoteUser());
        requestData.add("Requested session id", httpServletRequest.getRequestedSessionId());
        requestData.add("Requested URI", httpServletRequest.getRequestURI());
        blocks.add(requestData);
       
        MapBlock sessionBlock = new MapBlock("Http Session");
        HttpSession session = httpServletRequest.getSession();
       
        Enumeration sessionAttrib = session.getAttributeNames();
        while(sessionAttrib.hasMoreElements()) {
            String key   = (String) sessionAttrib.nextElement();
            String value = (String) session.getAttribute(key);
           
            // System.out.println(key + ": " + value);
            // out += key + ": " + value + "\n";
            sessionBlock.add(key, value);
        }
        blocks.add(sessionBlock);
       
       
        // out += "\n\nEnvironmental vars\n";
        MapBlock envBlock = new MapBlock("Environmental Vars");
        Map<String, String> env = System.getenv();
        Set<String> keys = env.keySet();
       
        Iterator<String> i = keys.iterator();
        while(i.hasNext()) {
            String key = i.next();
            String value = env.get(key);
           
            // out += key + ": " + value + "\n";
            envBlock.add(key, value);
        }
        blocks.add(envBlock);
       
       
        // out += "\n\nEnvironmental vars\n";
        MapBlock propBlock = new MapBlock("Environmental Properties");
        Properties props = System.getProperties();
        Set<Object> propKey = props.keySet();
       
        Iterator propIterator = propKey.iterator();
        while(propIterator.hasNext()) {
            String key = (String) propIterator.next();
            String value = props.getProperty(key);
           
            // out += key + ": " + value + "\n";
            propBlock.add(key, value);
        }
        blocks.add(propBlock);
       
        Iterator<MapBlock> j = blocks.iterator();
        while(j.hasNext())         
            out += j.next().toHTML();
       
        MapBlock threadBlock = new MapBlock("Current Threads");
        listThreads(threadBlock);
        out += threadBlock.toHTML();
       
        out += getConfigInfo("runtime.properties").toHTML();
       
        out += getJVMInfo().toHTML();
       
        out += "\t</body>\n</html>";
       
        log.debug("debugging finished writing html");
        log.trace("trace finished writing html");
       
        return out;
    }
   
    private MapBlock getJVMInfo() {
        log.trace("getting JVM info");
        Runtime rt = Runtime.getRuntime();
        MapBlock map = new MapBlock("Virtual Machine Data");
       
        map.add("processors ", (new Integer(rt.availableProcessors()).toString()));
        map.add("free memory", FileOperator.getFormattedFileSizeString(rt.freeMemory()));
        map.add("max memory", FileOperator.getFormattedFileSizeString(rt.maxMemory()));
        map.add("total memory", FileOperator.getFormattedFileSizeString(rt.totalMemory()));
       
        return map;
    }

    /**
     * Based on code from <a href="http://safari.oreilly.com/0768668255/ch15lev1sec6">O'Reilly Publishing</a>
     * @param mapBlock
     */

    public static void listThreads(MapBlock mapBlock) {
   
    log.trace("getting Thread info");
   
    ThreadGroup root = Thread.currentThread().getThreadGroup().getParent();
    while (root.getParent() != null) {
        root = root.getParent();
    }
        visitGroup(root, 0, mapBlock);
    }

    /**
     * Based on code from <a href="http://safari.oreilly.com/0768668255/ch15lev1sec6">O'Reilly Publishing</a>
     * @param mapBlock
     */

        public static void visitGroup(ThreadGroup group, int
        level, MapBlock mapBlock) {
           int numThreads = group.activeCount();
           Thread[] threads = new Thread[numThreads];
           group.enumerate(threads, false);
           for (int i=0; i<numThreads; i++) {
              Thread thread = threads[i];
              printThreadInfo(thread, mapBlock);
           }

           int numGroups = group.activeGroupCount();
           ThreadGroup[] groups = new
        ThreadGroup[numGroups];
           numGroups = group.enumerate(groups, false);

           for (int i=0; i<numGroups; i++) {
              visitGroup(groups[i], level+1, mapBlock);
           }
        }
       
        /**
         * @author <a href="http://safari.oreilly.com/0768668255/ch15lev1sec6">O'Reilly Publishing</a>
         * @param mapBlock
         */
   
        private static void printThreadInfo(Thread t, MapBlock mapBlock) {
           
            /*
            System.out.println("Thread: " + t.getName( ) +
                       " Priority: " + t.getPriority( ) +
                       (t.isDaemon( )?" Daemon":"") +
                       (t.isAlive( )?"":" Not Alive"));
            */

            if(t != null) {
                mapBlock.add(t.getName()," Priority: " + t.getPriority( ) +
                       (t.isDaemon( )?" Daemon":"") +
                       (t.isAlive( )?"":" Not Alive"));
            }
        }
        private static MapBlock getConfigInfo(String config) {
           
            log.trace("getting runtime.properties info");
            PropertiesFile propFile = null;
            try {
                propFile = new PropertiesFile();
                propFile.load(new FileInputStream(config));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            } catch (IOException e) {
                e.printStackTrace();
            }
           
            Set<Object> keyObject = propFile.keySet();
            Iterator<Object> i = keyObject.iterator();
            MapBlock configData = new MapBlock(config + " contents");
           
            while(i.hasNext()) {
                String key = (String) i.next();
                String value = propFile.getString(key);
                configData.add(key, value);
            }
           
            return configData;
        }
                             
}

Create a (very simple) web.xml file that will just point to our servlet

    <?xml version="1.0" encoding="UTF-8"?>
    <!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>
      <servlet>
        <servlet-name>InfoServlet</servlet-name>
        <servlet-class>net.wsor.osterman.javapersistence.util.InfoServlet</servlet-class>
      </servlet>
      <servlet-mapping>
        <servlet-name>InfoServlet</servlet-name>
        <url-pattern>/</url-pattern>
      </servlet-mapping>
    </web-app>

To prepare the war tasks, add these to the build.properties

dir.jsp.source = ${basedir}/src/main/webapp
dir.build.war = ${dir.build}/war
webapp.name = ${ant.project.name}.war
webapp.webxml.file = ${dir.jsp.source}/WEB-INF/web.xml

Add a 'war' target in the build file

    <!-- ==========================================================
       
             war
             create a war file from classes, libraries, config files,
             and other components
       
         ========================================================== -->    
    <target name="war" depends="compile" description="create a deployable war file">

        <echo level="info">
    ***********************************************************************
    *
    * Creating deployable webapp ${webapp.name}
    *
    ***********************************************************************
        </echo>    
       
        <!-- include all files except metadata (which will be specifically listed
             and hidden files -->
        <fileset id="war.fileset" dir="${dir.jsp.source}">
            <exclude name="metadata/**"/>
            <exclude name=".*/**"/>
            <exclude name="**/web.xml"/>
        </fileset>
       
        <delete dir="${dir.build.war}"/>
        <mkdir dir="${dir.build.war}"/>
       
        <war destfile="${dir.build.war}/${webapp.name}" webxml="${webapp.webxml.file}">
            <fileset refid="war.fileset"/>
            <lib dir="${dir.lib}"/>
            <classes dir="${dir.build.source}"/>
        </war>
       
    </target>
> war

Inside the war file you should see a META-INF folder containing a manifest file and a WEB-INF with several things inside of it. Now log into the tomcat manager with username: xampp password: xampp at http://localhost:8080/manager/html choose "Select WAR file to upload" and upload it to the server.

Now access http://localhost:8080/JavaPersistence/ with your favorite browser. You should see a bunch of system information.

> svn inc.build.minor

commit