When getting started with WebWork, I was hampered by the lack of really simple, basic documentation that even I could understand. This story is an attempt at addressing the issue, in the hope that it might make the process easier for others.
Joseph Ottinger has made a great start at a tutorial for WebWork, which can be found here. Read that as a 'how to make WebWork work' guide. Read this as a 'How I made WebWork work' anecdote.
On with the story. I'm lazy, and anything that takes me away from writing code and seeing it run is viewed with deep mistrust and suspicion. These things include: deployment descriptors, property files, and most other things that can't be compiled, tested, and executed. Therefore anything that saves me writing and maintaining these beasts is viewed with deep joy. For this reason I chose to combine WebWork with Ant and XDoclet 1.2 (beta). Okay, so I still had to produce the Ant script, but thankfully XDoclet had one that I cannabilised, so that wasn't too painful. WebWork has its own web.xml file, so that was one less task for me. XDoclet is a code generator. It can generate all sorts of things apart from code, including WebWork action descriptors. Pretty much all that was left for me to do was write code and run Ant. Rapture.
The 'heart' of WebWork is Actions. So that's where I started. The source code for my first Action class looks like this:
[TODO: Add source code]
My Ant file for autogenerating a Webwork-friendly WAR file can be found below. Paste the XML into a text file and save as build.xml.
Caveat: The build file works for me, it may not work for you. PLEASE NOTE, the basedir is the current directory! - Any pre-existing subdirs of the directory you place build.xml in called 'build' or 'dist' will be destroyed! The safest place to put the file is in a freshly created directory.
<?xml version="1.0" encoding="ISO-8859-1"?>
<project name="bloggi" default="dist" basedir=".">
<description>
Bloggi java weblogger
</description>
<!-- set global properties for this build -->
<property name="src.java" location="src/java"/>
<property name="src.jsp" location="src/jsp"/>
<property name="lib" location="lib"/>
<property name="build" location="build"/>
<property name="dist" location="dist"/>
<property name="webapp" location="${dist}/${ant.project.name}"/>
<property name="web-inf" location="${webapp}/WEB-INF"/>
<property name="webapp.classes" location="${web-inf}/classes"/>
<property name="webapp.lib" location="${web-inf}/lib"/>
<property name="resin.webapps" location="C:/java/resin-2.1.4/webapps"/>
<!-- =================================================================== -->
<!-- Define class path -->
<!-- =================================================================== -->
<path id="class.path">
<!-- todo the master script should move all compile-time libs here -->
<fileset dir="lib">
<include name="*.jar"/>
</fileset>
</path>
<!-- Define the XDoclet custom tasks -->
<taskdef
name="ejbdoclet"
classname="xdoclet.modules.ejb.EjbDocletTask"
classpathref="class.path"
/>
<taskdef
name="webdoclet"
classname="xdoclet.modules.web.WebDocletTask"
classpathref="class.path"
/>
<taskdef
name="castordoclet"
classname="xdoclet.modules.exolab.castor.ejb.CastorSubTask"
classpathref="class.path"
/>
<target name="init">
<!-- Create the time stamp -->
<tstamp/>
<!-- Create the build directory structure used by compile -->
<mkdir dir="${build}"/>
<mkdir dir="${build}/classes"/>
<!-- Create the distribution directories -->
<mkdir dir="${webapp}"/>
<mkdir dir="${webapp.classes}"/>
<mkdir dir="${webapp.lib}"/>
</target>
<target name="compile" depends="xdoclet"
description="compile the source ">
<!-- Compile the java code from ${src.java} into ${build} -->
<copy todir="${build}/src">
<fileset dir="${src.java}" includes="**/*.java" />
</copy>
<javac srcdir="${build}/src" destdir="${build}/classes" classpathref="class.path" compiler="modern"/>
</target>
<target name="xdoclet" depends="init">
<ejbdoclet destdir="${build}" verbose="false">
<fileset dir="${src.java}">
<include name="**/*.java"/>
</fileset>
<!--
<utilobject includeGUID="true"/>
<deploymentdescriptor destdir="${build}" validatexml="true"/>
-->
<castormapping destdir="${webapp}" validatexml="false"/>
</ejbdoclet>
<webdoclet
destdir="${build}/src"
mergedir="parent-fake-to-debug"
excludedtags="@version,@author,@todo"
addedtags="@xdoclet-generated at ${TODAY}, XDoclet,@version ${version}"
verbose="false"
>
<fileset dir="${src.java}">
<include name="**/*Servlet.java"/>
<include name="**/*Filter.java"/>
<include name="**/*Tag.java"/>
<include name="**/*Action.java"/>
</fileset>
<!--<deploymentdescriptor servletspec="2.3" destdir="${webapp}"/>-->
<webWorkConfigProperties destDir="${webapp.classes}"/>
</webdoclet>
</target>
<target name="dist" depends="compile"
description="generate the distribution">
<!-- Put everything in ${build} into the MyProject.jar file -->
<delete file="${dist}/{ant.project.name}/WEB-INF/lib/${ant.project.name}.jar"/>
<jar jarfile="${webapp.lib}/${ant.project.name}.jar" basedir="${build}/classes"/>
<!-- Copy runtime libraries to WEB-INF/lib -->
<copy file="${lib}/castor-0.9.3.21.jar" todir="${webapp.lib}"/>
<copy file="${lib}/webwork.jar" todir="${webapp.lib}"/>
<!-- Copy JSP's to webapp dir -->
<copy todir="${webapp}">
<fileset dir="${src.jsp}" includes="**/*.jsp"/>
</copy>
<!-- Copy WebWork properties -->
<copy file="webwork.properties" todir="${webapp.classes}"/>
<!-- Build the WAR -->
<war warfile="${dist}/${ant.project.name}.war" basedir="${dist}/${ant.project.name}" webxml="web.xml"/>
<!-- Laziness. Deploy the WAR to Resin for me -->
<copy file="${dist}/${ant.project.name}.war" todir="${resin.webapps}"/>
</target>
<target name="clean"
description="clean up">
<!-- Delete the ${build} and ${dist} directory trees -->
<delete dir="${build}"/>
<delete dir="${dist}"/>
</target>
</project>