At this point I’d like to point out that all of the source code for this book, including ready-to-run WAR files for all the projects, can be downloaded from the Apress web site at www.apress.com. Once there, click the Source Code/Download link and find this book in the list, which will bring you to the download page.
Please note that this is not just a suggestion, it is all but required to move forward! From this point out, I will assume that you have downloaded the source code, have unzipped it, and therefore have it available to refer to. This will not only save you oodles of time and pain from typing far more than you should have to, but it will also all but assure that the code you’re trying to run is in good working order.
A Simple Webapp to Get Us Started
Our first order of business at this point is to throw together a quick, simple little webapp that we’ll add some DWR to in the next section. The complete app, including DWR, is included in the source download package, but if you’d like to build it from scratch (and this is one of the few times I’d suggest doing that instead of using the prebuilt code), follow along here, it’s nothing complicated.
Getting the Lay of the Land: Directory Structure
First, go into the <TOMCAT>/webappsdirectory and create a new directory named simpleapp. In that directory, create a directory named WEB-INF. This is, of course, the typical Java webapp directory structure, which should be old hat to you for sure, but we’ll go through it just the same to be certain.
Inside the WEB-INFdirectory, create a directory named liband another named src. The directory libis where our JAR files that the app depends on to run are located, and the src directory is where the server-side source code for the app will go. Lastly, inside the srcdirec- tory, create another directory named app, which is where our Java source files will be.
By the end of this, you should have the directory structure shown in Figure 2-5 under- neath <TOMCAT>/webapps.
Figure 2-5.Directory structure of our first webapp (eventually) using DWR
The next thing we need to do is get the JAR files this application will need and add them.
First, when we want to compile the source code for the application, we’ll need access to the Servlet APIs. These are present in a JAR file named, not surprisingly, servlet-api.jar. This can be found in the <TOMCAT>/libdirectory. Copy that JAR file over into simpleapp/WEB-INF/src (we don’t want to put it in simpleapp/WEB-INF/libbecause it’s provided to our webapp via Tomcat, so it would be redundant if added to the classpath for the application and could actu- ally cause conflicts).
From Code to Executable: Ant Build Script
The next step is to create an Ant build script file that we can use to compile our source code (which we haven’t written yet, of course). The build script can be seen in Listing 2-1. You should save this to a file named build.xmland save it to simpleapp/WEB-INF/src.
Listing 2-1.The Ant Build Script for the Application
<project name="simpleapp" basedir="." default="build">
<!-- Classpath for build. -->
<path id="classpath">
<pathelement path="servlet-api.jar" />
</path>
<!-- The default target. Compile source, build WAR. -->
<target name="build">
<delete dir="../classes/com" />
<mkdir dir="../classes/com" />
<javac srcdir="." destdir="../classes" debug="true"
debuglevel="lines,vars,source">
<compilerarg value="-Xlint:unchecked" />
<classpath refid="classpath" />
</javac>
<delete file="simpleapp.war" />
<jar destfile="simpleapp.war" basedir="../../" />
</target>
</project>
This is a very simple build script that performs two simple tasks. First, it compiles the source code found in simpleapp/WEB-INF/src/appand puts the resultant Java .classfiles in simpleapp/WEB-INF/classes. Second, it creates a WAR file for deployment to a servlet con- tainer. If this is your first exposure to Ant, I suggest taking a few moments to read the documentation available on the Ant web site since that’s a bit out of the scope of this book.
The scripts for the projects to come won’t be a whole lot more complicated than this one, but they will in fact be somewhat more so, and while you can get away without ever looking at them, it’s better to understand it all for the sake of completeness.
The <delete>and <mkdir>tasks you’ll notice don’t delete WEB-INF/classes, they delete WEB-INF/
classes/com. The reason is that in many of the applications in this book, there are files in WEB-INF/
classesthat can’t be deleted if the application is to function properly.
Application Configuration: web.xml
Now that we’ve essentially put together the infrastructure for the application, let’s get to the application components themselves. First up is the web.xmlfile, as shown in Listing 2-2. Save this to simpleapp/WEB-INF.
Listing 2-2.The web.xmlFile for the Application
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app id="simpleapp" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<!-- Our servlet, the target of the form submission. -->
<servlet>
<servlet-name>MathServlet</servlet-name>
<servlet-class>app.MathServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>MathServlet</servlet-name>
<url-pattern>/MathServlet</url-pattern>
</servlet-mapping>
<!-- Default page to load in context. -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
As you can see, there’s not much going on here. In fact, it’s only two things: a default docu- ment declaration so that when we access http://localhost:8080/simpleapp, which will be the URL to use to try this out, we’ll get index.jspright away, and a servlet declaration, which will be the target of the form submission that we’ll see soon. In case you haven’t noticed by now, by creating this directory structure directly in <TOMCAT>/webapps, we’re effectively deploying the application automatically. We don’t need to do anything else to make this application available via Tomcat. This is a fast, efficient way to work on a webapp that can really save you time dur- ing the development process. However, you’ll also notice that the build script creates a WAR file. So, if you prefer not working directly in the Tomcat directory structure, you can simply do all this elsewhere, and copy the WAR file into <TOMCAT>/webapps. On startup, Tomcat will see this WAR file and unpack and deploy your application automatically (in fact, Tomcat by default is configured to unpack and deploy WAR files on the fly, so even if Tomcat is running, assuming you haven’t disabled automatic deployment, a WAR file dropped in this directory will be deployed automatically). I’m all about choice, so however you’re more comfortable, feel free!
The Markup: index.jsp
Next up is our single page, index.jsp, as shown in Listing 2-3. Please save this to the simpleapp directory.
Listing 2-3.The index.jspPage
<html>
<head>
<title>simpleapp</title>
</head>
<body>
<%
Integer answer = (Integer)request.getAttribute("answer");
// If there's an answer attribute in request, we just performed an // operation, so display the result.
if (answer != null) {
Integer a = (Integer)request.getAttribute("a");
String op = (String)request.getAttribute("op");
Integer b = (Integer)request.getAttribute("b");
%>
<span><h1>Result: <%=a%> <%=op%> <%=b%> = <%=answer%></h1></span>
<%
}
%>
Please enter two numbers, select an operation, and click the equals button:
<br><br>
<form action="MathServlet" method="post">
<input type="text" name="a" size="4">
<select name="op">
<option value="add">+</option>
<option value="subtract">-</option>
<option value="multiply">*</option>
<option value="divide">/</option>
</select>
<input type="text" name="b" size="4">
<input type="submit" value="=">
</form>
</body>
</html>
As long as this isn’t your first exposure to JSPs, this should be readily understandable to you. Notice that I’m using a scriplet block instead of JSTL or something more elegant because this is frankly very simple code, and I felt it was cleaner to not bring in extra dependencies and have more to talk about. To explain the code you see quickly: when the form is submitted, it will hit the MathServlet, which we’ll see next. That will call the MathDelegateclass, which is what does the actual math. The servlet then puts a number of attributes into the request object, including the two numbers (the attributes aand b) the user submitted, as well as the mathematical symbol for the operation the user requested (the opattribute), and of course the answer. So, if the answerattribute is found, then we grab the two numbers and the operation from the request object. Then, we just output the result, which is the complete expression, answer and all. Certainly not rocket science!
On the Server Side: MathServlet.java
Only one step remains, and that’s to create the Java classes for the MathServletand the MathDelegatethat the preceding JSP makes use of. Please save Listing 2-4 and Listing 2-5 (the latter shown in the next section) to the simpleapp/WEB-INF/src/appdirectory.
Listing 2-4.The MathServletClass package app;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
/**
* This servlet is the target of the form submission. It dispatches to the
* MathDelegate class to do the actual work, then forwards to index.jsp.
*/
public class MathServlet extends HttpServlet {
/**
* The typical doPost() method of a servlet.
*
* @param request The request object.
* @param response The response object.
* @throws ServletException If anything goes wrong.
* @throws IOException If anything goes wrong.
*/
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Get the numbers to operate on, and the operation to perform, as // specified by the caller.
int a = Integer.parseInt(request.getParameter("a"));
int b = Integer.parseInt(request.getParameter("b"));
String op = request.getParameter("op");
MathDelegate mathDelegate = new MathDelegate();
int answer = 0;
// Call the MathDelegate to perform the appropriate operation, and store // a math symbol representing the operation in request.
if (op.equalsIgnoreCase("add")) { answer = mathDelegate.add(a, b);
request.setAttribute("op", "+");
} else if (op.equalsIgnoreCase("subtract")) { answer = mathDelegate.subtract(a, b);
request.setAttribute("op", "-");
} else if (op.equalsIgnoreCase("multiply")) { answer = mathDelegate.multiply(a, b);
request.setAttribute("op", "*");
} else if (op.equalsIgnoreCase("divide")) { answer = mathDelegate.divide(a, b);
request.setAttribute("op", "/");
}
// Add the two numbers and the answer to request, so our JSP can display it.
request.setAttribute("a", new Integer(a));
request.setAttribute("b", new Integer(b));
request.setAttribute("answer", new Integer(answer));
// Forward to index.jsp.
RequestDispatcher dispatcher =
getServletContext().getRequestDispatcher("/index.jsp");
dispatcher.forward(request, response);
} /// End doPost().
} // End class.
This is a pretty ordinary servlet really. You’ll quickly note that this isn’t exactly production- quality code! All of the checks you’d perform to avoid errors are left out, among other things, but that is just for the sake of keeping the listing relatively short in print. In any case, you should get the general gist of it in short order. It grabs the two numbers the user submitted, along with the operation the user selected, and calls on the MathDelegateclass to perform the desired operation. It then puts the numbers, the operation, and the answer in the request object as attributes, and finally forwards back to index.jsp, which as we’ve seen already will display the result.
The Workhorse: MathDelegate.java
The MathDelegateclass, which MathServletcalls on, is our next stop, and it’s very simplistic, even more so than the servlet. For those of you who prefer a more visual approach to learning, Figure 2-6 shows the UML class diagram for the MathDelegateclass.
Figure 2-6.UML diagram of the MathDelegateclass
In Listing 2-5, you can see the code for the class in its entirety.
Listing 2-5.The MathDelegateClass package app;
/**
* A class to perform basic mathematical operations on two numbers.
*/
public class MathDelegate {
/**
* Add two numbers.
*
* @param a The first number.
* @param b The second number.
* @return The result of the operation.
*/
public int add(int a, int b) { return a + b;
} // End add().
/**
* Subtract two numbers.
*
* @param a The first number.
* @param b The second number.
* @return The result of the operation.
*/
public int subtract(int a, int b) { return a - b;
} // End subtract().
/**
* Multiply two numbers.
*
* @param a The first number.
* @param b The second number.
* @return The result of the operation.
*/
public int multiply(int a, int b) { return a * b;
} // End multiply().
/**
* Divide two numbers.
*
* @param a The first number.
* @param b The second number.
* @return The result of the operation.
*/
public int divide(int a, int b) { if (b != 0) {
return a + b;
} else { return 0;
}
} // End divide().
} // End class.
Four simple methods, one for each of our four basic math operations, and that’s it. Again, not exactly robust code: the only check is the obvious divide-by-zero possibility; otherwise we let everything go through. And again, it’s all about making a simple, clean example app (and besides, mathematics and I haven’t frequently been on speaking terms, and this is about as advanced as I’m willing to get!).
It’s Alive: Seeing It in Action
At this point we have ourselves a complete webapp. Well, nearly so: we still need to build it. To do so, go to a command prompt in the simpleapp/WEB-INF/srcdirectory, enter ant, and press Return. Ant should execute the build script in that directory, compiling the MathServletand MathDelegateclasses and creating a WAR file.
Once you are ready, just start Tomcat as previously described in the section “Getting Ready for the Fun: Your DWR Development Environment” and navigate to the URL http://
localhost:8080/simpleapp, and you should see the page shown in Figure 2-7.
Figure 2-7.Our simple webapp in action, simple as it is!
At this point, you can enter two numbers (or not, and get an exception if you prefer . . . this isn’t robust production-quality code by any stretch!), select an operation, and click the equals button. Note that the page refreshes with each click. It is being rendered each and every time. Clearly, this is a perfect place for Ajax, and what’s that I hear? Is that the pitter- patter of horse hooves? Yes, indeed it is, it’s DWR to the rescue, 299 Spartans in tow!3
Adding DWR to the Mix
So, we have a simple little webapp, and we have one problem with it: that annoying page refresh. You also may not so much like the fact that there’s a little more server-side code than you might like, i.e., that servlet in the mix. Let’s add DWR to this thing and see how the for- mula changes.
The first step you should take is to copy the entire simpleappdirectory and rename the copy to firstdwr. You’ll have a new webapp to hack without messing up what you just created.
The next thing you’ll need to do is add the DWR JAR itself. This too is included in the source code download archive, or you can download it from the DWR web site at http://
getahead.org/dwr. Copy the dwr.jarfile into firstdwr/WEB-INF/lib(this one is needed at run- time as well as compile time, so it has to be on the application’s classpath, and hence in the libdirectory).