Friday, August 15, 2008

A Simple JSP

Okay, playing with the examples can be fun (spoiler: the two colours you're looking for are Black and Cyan), but the real test is to set up a JSP of your own and make it run.


Open NotePad or your favourite text editor, and type in the following:


This example brought to you by JSP and SitePoint.com!


Save the file as theEnd.html in a new subdirectory of Tomcat's webapps directory called sitepoint. Create a second new file in NotePad and type in the following:


<%@ page language="Java" %>

<html>

<head>

<title>A Simple JSP</title>

</head>

<body>

<p>

 <% String num = request.getParameter("num");

    if (num == null) { // No number specified

      // Display the form

 %>

      <form action="<%= HttpUtils.getRequestURL(request) %>">

      What should I count to? <input type="text" size="2" name="num" />

      <input type="submit" />

      </form>

 <%

    } else for (int i=1; i<=Integer.parseInt(num); i++) {

 %>

      Counting: <%= i %><br />

 <% }

 %>

</p>



<%@ include file="theEnd.html" %>



</body>

</html>


Save this as count.jsp in your new sitepoint directory alongside theEnd.html.


Now, to make these two files visible, you need to create a Java Web application to contain them. Doing this is nice and simple. Create a subdirectory of your new sitepoint directory called WEB-INF. In that subdirectory, create a text file called web.xml and type the following into it:


<?xml version="1.0" encoding="ISO-8859-1"?>



<!DOCTYPE web-app

   PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"

   "http://java.sun.com/dtd/web-app_2_3.dtd">



<web-app>

</web-app>


Save the file and then restart Tomcat or reboot your system to allow Tomcat to become aware of the new Web application. You can then view the page through Tomcat with the URL http://localhost:8080/sitepoint/count.jsp.


To make your new Web application visible through Apache, simply restart Apache. When you restarted Tomcat, it created a new automatic configuration file for Apache; restarting Apache will read in this new config file and add your new Web application to the lineup. Whenever you add a new Web application to Tomcat you need to perform this "Restart Tomcat, Restart Apache" process; fortunately, this doesn't happen often.


Once Apache is back up and running, open http://localhost/sitepoint/count.jsp. There you have it: your first working JSP in Apache!

JSP Quick-Start Guide for Linux

Downloading and Installing Tomcat


Since Apache doesn't support JSP out of the box, we need to add something else to the mix to provide that support. Unfortunately, JSP is too complicated to be supported by a simple Apache module; thus, we need to install an entirely new program to provide that support, then instruct Apache to forward requests for JSP pages to that program (note: this may sound like CGI, but it isn't; just wait and see). The program we'll be using is called Tomcat, and is also written by the Apache Group.


Tomcat is in fact a simple Web server in its own right. It doesn't support any of the advanced features of Apache, however; that's not its job! By linking Tomcat and Apache together, you get a system that provides full support for JSP (thanks to Tomcat) while maintaining the performance and expandability (PHP, Perl, SSL, etc.) of Apache.


Your first step should be to download and install the Java 2 Software Development Kit (Java 2 SDK) from Sun. This is required both to run Tomcat (which is a Java program), and for Tomcat to be able to compile JSPs for use. The current version of the Java 2 SDK (also called the JDK) as of this writing is version 1.4.1_01, and is available for download here. Download the ~42MB "Linux self-extracting file" (be sure to download the SDK, not the JRE!). The filename should be j2sdk-1_4_1_01-linux-i586.bin. Extract this file into your /usr/local directory with this series of commands:


[kevin@sp kevin]$ su

Password: ********

[root@sp kevin]# chmod u+x j2sdk-1_4_1_01-linux-i586.bin

[root@sp kevin]# mv j2sdk-1_4_1_01-linux-i586.bin /usr/local/

[root@sp kevin]# cd /usr/local

[root@sp local]# ./j2sdk-1_4_1_01-linux-i586.bin


You can delete the j2sdk-1_4_1_01-linux-i586.bin file now, or put it someplace safe for future use; you're done with it.


Java is now installed, but you need to do a few things to settle it smoothly into your system. First, make a symbolic link so you can access the Java installation with the easier-to-type name /usr/local/java:


[root@sp local]# ln -s j2sdk1.4.1_01 java


Next, make links to the important programs that make up the Java SDK in the /usr/local/bin directory, so you can run them from anywhere:


[root@sp local]# ln -s java/bin/java /usr/local/bin/java

[root@sp local]# ln -s java/bin/javac /usr/local/bin/java

[root@sp local]# ln -s java/bin/jar /usr/local/bin/java


Now, we need to edit a couple of environment variables on your system. Still as root, open the /etc/profile on your system in your preferred text editor. Look for a line beginning with PATH=. When you type a program name at the command prompt, this line sets the directories that your system checks for that program. Check to make sure /usr/local/bin is in the list. If it isn't, add the following line right after the existing PATH= line:


PATH="$PATH:/usr/local/bin"


You also need to set the JAVA_HOME environment variable to point to your Java installation. To do this, scroll right down to the bottom of the file and add these two lines to the end:


JAVA_HOME="/usr/local/java"

export JAVA_HOME


Save the changes, log out, and then log back in. Java should now be nicely installed and integrated with your system. To test it, you can type java -version at the command prompt and make sure that it reports your Java version correctly.


Now you're ready to install Tomcat. Download the latest release from the Jakarta Project Web site. As of this writing, the latest version was 4.1.18, and was available at http://jakarta.apache.org/builds/jakarta-tomcat-4.0/release/v4.1.18/bin/. The file should be called jakarta-tomcat-4.1.18-LE-jdk14.tar.gz, and is about 5.1MB.


Once you've downloaded the file, move it to your /usr/local directory and extract it:


[kevin@sp kevin]$ su

Password: ********

[root@sp kevin]# mv jakarta-tomcat-4.1.18-LE-jdk14.tar.gz /usr/local/

[root@sp local]# tar xfz jakarta-tomcat-4.1.18-LE-jdk14.tar.gz


You can delete the jakarta-tomcat-4.1.18-LE-jdk14.tar.gz file now, or put it somewhere safe for future use; you're done with it.


As with the Java SDK, create a link to the installation directory with a neater name for convenience:


[root@sp local]# ln -s jakarta-tomcat-4.1.18-LE-jdk14 tomcat


Like Java, Tomcat requires an environment variable of its own to be set for it to run properly. Open up your /etc/profile file one more time and add these two lines to the end:


CATALINA_HOME="/usr/local/tomcat"

export CATALINA_HOME


Once again, save your changes, log out, then log back in for changes to take effect.


You're ready to start Tomcat! Log in as root and type the following command to launch it:


[root@sp kevin]# $CATALINA_HOME/bin/startup.sh


If all goes well, the startup.sh script should display the values of a few environment variables, and then Tomcat will launch quietly in the background. Congrats -- Tomcat is up and running!


As I said before, Tomcat provides its own simple Web server, and we can use this to test that it is working properly. Tomcat's Web server is set up to use port 8080 by default, so open your Web browser and load http://localhost:8080/. You should see the Tomcat home page, with links to some examples that come preinstalled on the server.


Have a play with these examples if you're curious, and notice how the JSP examples take considerable time to load the first time you use them, but then work very quickly upon subsequent accesses. This happens because the first time a JSP page is accessed, Tomcat needs to compile it into a Java Servlet, which is a piece of pure Java code that can be run very quickly to process requests. That Servlet is then held in memory to process subsequent requests for the same JSP at blazing speed.


When you're done playing with Tomcat, shut it down by running the shutdown.sh script the same way you ran the startup.sh script above ($CATALINA_HOME/bin/shutdown.sh). Tomcat will shut down after a few moments.


Running Tomcat Automatically

If you've got Apache running automatically at system start-up, you'll probably want to do the same for Tomcat. Start by copying (not linking) the catalina.sh script that came with Tomcat to your /etc/init.d/ directory:


[root@sp kevin]# cd /etc

[root@sp etc]# cp /usr/local/tomcat/bin/catalina.sh init.d/


This script relies on the JAVA_HOME and CATALINA_HOME environment variables we set earlier, but these variables do not exist while the system is starting up. We must therefore edit the script a little so that it can serve as a system startup script.


Open the file in your favourite text editor, and scroll down to the first blank line following the opening comments (any line that begins with a # is a comment). Add these two lines at that point:


JAVA_HOME="/usr/local/java"

CATALINA_HOME="/usr/local/tomcat"


This script actually makes an attempt at detecting CATALINA_HOME itself, but this attempt backfires if the script is not actually in the Tomcat directory (which in this case it isn't). Scroll down and look for a line that begins with CATALINA_HOME=. It should look like this:


CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`


Comment it out by putting a # at the start of that line:


#CATALINA_HOME=`cd "$PRGDIR/.." ; pwd`


That completes the adjustments to catalina.sh. You can now assign this as a start-up script in the various runlevels (operating modes) of your computer:


[root@sp etc]# ln -s init.d/catalina.sh rc2.d/S90tomcat

[root@sp etc]# ln -s init.d/catalina.sh rc3.d/S90tomcat

[root@sp etc]# ln -s init.d/catalina.sh rc4.d/S90tomcat

[root@sp etc]# ln -s init.d/catalina.sh rc5.d/S90tomcat

[root@sp etc]# ln -s init.d/catalina.sh rc0.d/K19tomcat


That should do it! To try it out, shut down your computer, start it back up again, and see if you can load the Tomcat home page at http://localhost:8080/.


 

Server-Side Java with the Struts Framework on Mac OS X

Struts helps you organize your Java-based web applications by providing a framework based on a version of the Model-View-Controller design pattern. With Struts (or more formally, the Jakarta Project’s Struts Framework), you can combine Servlets, JSP, custom Struts tag libraries and other components using a unified framework that helps you design, create, and deploy stable web applications quickly. It requires a bit more work initially, to set everything up, but the value of the framework is realized later, when the ordered and componentized nature of your code lets you maintain, update, and reuse it easily.

Design Patterns and the Model-View-Controller Pattern

Design patterns are conceptual structures that you can use to better organize how you think about, plan, and talk about your code. Many applications, especially web applications, have core elements in common. Design patterns give developers a shared vocabulary, can help keep us from re-inventing versions of the same solutions for each new application.

Apple’s development environments have used the Model-View-Controller pattern for many years. Apple’s documentation includes a discussion of how the Model-View-Controller applies to Cocoa applications.

The Model-View-Controller pattern is used (whether implicitly or explicitly) in nearly every sophisticated web application. It’s a sensible way to organize your application architecture. Simply put, the Model is your data and your application logic, the View corresponds to your presentation elements (HTML, JSP, display beans, etc.), and the Controller(s) handle the application’s flow.


Installing and Using Struts on Mac OS X

To complete the installation steps below, you’ll need items on the Apple Developer Tools CD. So if you haven’t installed it yet, do so now.

To obtain Struts, go to http://jakarta.apache.org/struts/acquiring.html. In these examples, I’m using the current binary distribution, which at the time of this writing is 1.1. If you’re using a later version, then, of course, you’ll have to change some of the paths in the commands below.

First, use curl to download the Struts archive:

liz@localhost:/usr/local/src> curl -O  
http://jakarta.apache.org/builds/jakarta-struts/release/v1.1/jakarta-struts-1.1.tar.gz

Next, extract the files using gnutar. The version of tar shipped with Mac OS X frequently does not work with tarfiles from the Apache project, but gnutar always will.

liz@localhost:/usr/local/src> gnutar -xzvf jakarta-struts-1.1.tar.gz

Before installing, check Jakarta’s list of prerequisites to make sure you have everything you need.

Struts requires a Java2 Java Development Kit - version 1.2 or later. Since you have installed the Apple Developer Tools, you’re all set. Struts also requires a servlet container. I’ve chosen to use the Apache Project’s Tomcat servlet container, and to run it as a stand-alone server for simplicity’s sake. At the time of this writing, the latest stable version was 4.1.24, although another major version is on the horizion. No matter which version you use, your installation process should be much like mine below.

Since the recent Developer Tools include a JDK greater than 1.4 (type java -version to find out which you have), I can install a lightweight version of Tomcat. I want the server to live under /usr/local/tomcat/, and the source tarball to stay in /usr/local/src.

liz@localhost:/usr/local/src> curl -O http://jakarta.apache.org/builds/jakarta-tomcat-4.0
/release/v4.1.24/bin/jakarta-tomcat-4.1.24-LE-jdk14.tar.gz
liz@localhost:/usr/local/src> gnutar -xzvf jakarta-tomcat-4.1.24-LE-jdk14.tar.gz
liz@localhost:/usr/local/src> sudo mkdir /usr/local/tomcat
Password:
liz@localhost:/usr/local/src> sudo mv jakarta-tomcat-4.1.24-LE-jdk14 /usr/local/tomcat
liz@localhost:/usr/local/src> export
CATALINA_HOME=/usr/local/tomcat/jakarta-tomcat-4.1.24-LE-jdk14
liz@localhost:/usr/local/src> cd $CATALINA_HOME/bin
liz@localhost:/usr/local/tomcat/jakarta-tomcat-4.1.24-LE-jdk14/bin> ./startup.sh

Now I can confirm that Tomcat is running on port 8080 on my local machine by going to http://localhost:8080 in a browser:

The next prerequisite is the Ant build system. Note that I’m still using gnutar to extract files, and not Apple’s standard tar executable. I’m installing Ant under /usr/local/ant, and adding its binary files directory to my $PATH environment variable.

liz@localhost:/usr/local/src> curl -O
http://apache.mirrorcentral.com/dist/ant/binaries/apache-ant-1.5.3-1-bin.tar.gz
liz@localhost:/usr/local/src> gnutar -xzvf apache-ant-1.5.3-1-bin.tar.gz
liz@localhost:/usr/local/src> sudo mkdir /usr/local/ant
liz@localhost:/usr/local/src> sudo mv apache-ant-1.5.3-1 /usr/local/ant/
liz@localhost:/usr/local/src> export ANT_HOME=/usr/local/ant/apache-ant-1.5.3-
liz@localhost:/usr/local/src> export PATH=$PATH:$ANT_HOME/bin/

At this point, if you’ve been following along with me, you’ve set up two environment variables ($CATALINA_HOME and $ANT_HOME) and changed one ($PATH). When you exit your terminal session, these variables will go away. No fun. You’ll probably want to set up a shell startup file that loads these variables for you on each new terminal session. Since I use the bash shell, my startup file lives in /Users/liz/.bash_profile and looks (in part) like this:

export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:/System/Library/CoreServices 
export JAVA_HOME=/usr
export PS1="\u@\h:\w> "

Since I wanted to keep the new environment variables for future use, I changed my .bash_profile to contain the lines below. You can also see that I added aliases for starting and stopping tomcat.

export ANT_HOME=/usr/local/ant/apache-ant-1.5.3-1 
export CATALINA_HOME=/usr/local/tomcat/jakarta-tomcat-4.1.24-LE-jdk14
export PATH=/bin:/sbin:/usr/bin:/usr/sbin:/usr/libexec:
/System/Library/CoreServices:$ANT_HOME/bin
export JAVA_HOME=/usr
alias start_tomcat='$CATALINA_HOME/bin/startup.sh'
alias stop_tomcat='$CATALINA_HOME/bin/shutdown.sh'

If you’re using the bash shell, you can copy and use this file as is. Otherwise, see the manpage for your favorite shell program (for example, man tcsh). To use bash and the .bash_profile file I’m using, open the Terminal application, click Preferences, and set your preferences to be like these:

It’s finally time to install Struts itself. The version of Tomcat I’m using comes with an integrated version of Struts. Still, there are some tag library descriptors and example files that I want to install. Note: If you aren’t using Tomcat (or if you’re using an older version of Tomcat without Struts), follow the Struts installation guide. You’ll just have to copy a few extra files - it’s not much harder.

Here are the commands I used to add the extra Struts files to my new Tomcat installation. Again, if you aren’t using Tomcat with Struts built-in, see the installation link in the line above.

liz@localhost:~> stop_tomcat 
liz@localhost:~> cd /usr/local/src/jakarta-struts-1.1
liz@localhost:/usr/local/src/jakarta-struts-1.1>
cp lib/*.tld $CATALINA_HOME/server/webapps/admin/WEB-INF/
liz@localhost:/usr/local/src/jakarta-struts-1.1>
cp webapps/*.war $CATALINA_HOME/webapps
liz@localhost:/usr/local/src/jakarta-struts-1.1> start_tomcat

With that step completed, you should be able to view the example applications (which came bundled in those .war files referenced above). For example, look at http://localhost:8080/struts-example/index.jsp

”Hello World”

Now we can build a “hello world” mini-application, using a few Struts components. Since the setup process is fairly complicated, this simple application won’t take advantage of many of Struts’ useful features. I’ll focus on those in the next section.

One of the .war files in your Struts source directory is called struts-blank.war. This file is meant to serve as a template for new Struts applications. I want to extract the archive so I can modify it to make my own simple “Hello World” application. So I copy struts-blank.war into a new empty folder, and type jar -xf struts-blank.war. Here are the contents:

You can see that the archive includes the struts.jar file (necessary for any Struts application), some tag libraries, the standard web.xml and manifest files, and a configuration file called struts-config.xml. This config file is actually functionally empty, but it includes lots of useful examples in commented sections.

Let’s look at the other two files in the archive. First, the index.jsp file that comes with the blank Struts application. In this file, you can see the Struts tag libraries in use. (If you aren’t familiar with the taglibs concept yet, you may want to read Sun’s explanation.) One interesting thing to note is that all the English text on the page is stored separately and presented via a custom tag. While this is by no means required in a Struts application, it does simplify Internationalization or text changes. You don’t need to touch any Java components in order to alter the page copy.

<%@ page language="java" %>   
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<html:html locale="true">
<head>
<title><bean:message key="index.title"/></title>
<html:base/> </head> <body bgcolor="white">
<logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application">
<font color="red">
ERROR: Application resources not loaded -- check servlet container
logs for error messages.
</font>
</logic:notPresent>
<h3><bean:message key="index.heading"/></h3>
<p><bean:message key="index.message"/></p>
</body>
</html:html>

The copy for the file above is stored in ApplicationResources.properties. Since I’m making my own application, I’ll start by altering that text. Here are the contents of my new properties file:

index.title=My Own Hello World, Using Struts  index.heading=Heya

Next, I want to make a simple Java Bean that my application can reference. It’s about as simple as a Bean gets - it stores a hard-coded Magic Number, and tells the user whether or not they guessed that number correctly.

package foo;   
public class GuessBean
{
public int magicNumber;
public GuessBean()
{
this.magicNumber = 2;
}
public String evaluateGuess(int g)
{
if (g == this.magicNumber)
{
return "You guessed it!";
}
else
{
return "Sorry, wrong number.";
}
}
}

Now I can edit the index.jsp file and add a basic form, and create a new file called guess.jsp which calls the bean’s evaluateGuess() method. (You can find those files in the hello.war archive.)

The final step is to create a build.xml file that Ant can use to bundle the all application’s files into a WAR archive, and deploy them to Tomcat. If you are using a Java IDE that can build WAR files for you, you won’t need to bother with this section. Otherwise, here’s the build file:

<project name="hello world" default="build-all" basedir=".">     
<property environment="env"/>
<property name="appname" value="hello"/>
<property name="src.dir" value="${basedir}/WEB-INF/src"/>
<property name="app.name" value="hello"/>
<property name="app.path" value="/${app.name}"/>
<property name="app.version" value="0.1-dev"/>
<property name="build.dir" value="${basedir}/build"/>
<property name="classes.dir" value="${basedir}/WEB-INF/classes"/>
<property name="tomcat.home" value="${env.CATALINA_HOME}"/>
<property name="servlet.jar" value="${tomcat.home}/common/lib/servlet.jar"/>
<property name="deploy.dir" value="${tomcat.home}/webapps"/>
<path id="build.path">
<fileset dir="./WEB-INF/lib/">
<include name="**/*.jar"/>
</fileset>
<pathelement path="${src.dir}"/>
<pathelement path="${servlet.jar}"/>
<pathelement path="${classes.dir}"/>
</path>
<target name="cleanlocal">
<delete dir="${build.dir}" includeEmptyDirs="true" />
<delete file="${appname}.war" />
<mkdir dir="${build.dir}"/>
</target>
<target name="compile">
<javac srcdir="${src.dir}" destdir="${classes.dir}" debug="on" deprecation="on">
<include name="**/*.java"/>
<classpath refid="build.path"/>
</javac>
</target>
<target name="cleanserver">
<delete file="${deploy.dir}/${appname}.war" />
<delete dir="${deploy.dir}/${appname}" includeEmptyDirs="true" />
</target>
<target name="war">
<war warfile="${appname}.war" webxml="./WEB-INF/web.xml">
<fileset dir="./" includes="**/*.*" excludes="*.war, **/*.nbattrs,
.xml, **/WEB-INF/**/*.*, **/project-files/**/*.*"/>
<webinf dir="./WEB-INF" includes="**/*" excludes="web.xml,
**/*.jar, **/*.class"/>
<lib dir="./WEB-INF/lib"/>
<classes dir="${classes.dir}" cludes="**/*.properties, **/*.class" />
</war>
</target>
<target name="build-all" depends="cleanlocal, cleanserver, compile, war">
<copy file="${appname}.war" todir="${tomcat.home}/webapps"/>
</target>
</project>

To deploy my new application, I simply need to run Ant and restart Tomcat.

liz@localhost:~/hello> ant  liz@localhost:~/hello> stop_tomcat 
liz@localhost:~/hello> start_tomcat

Sample Application: A RSS Newsfeed Consolidator

Many news sites and weblogs make their headlines available as RSS feeds. The RSS format is (more-or-less standardized) XML, generally made available over HTTP. You can read more about RSS, for example, on the O’Reilly xml.com site and the webreference.com site (and elsewhere).

In this section, I’ll show you how you can use Servlets, JSP, and Struts to create an application that will allow a user to log in, assemble a list of weblogs and/or news sites, and read headlines fetched and displayed by the application. Headlines are links to the remote content. For simplicity’s sake, I’ve left off several real-world aspects of the application, most notably the database backend. User data is simply stored in the session, and vanishes when the user closes their browser or you re-start Tomcat.

Let’s look at the application with the Model-View-Controller design paradigm in mind. In this case, the model is the session data plus the application logic. The view corresponds to the JSP pages and beans used for display, and the controller is a special SiteAction class. The SiteAction class is a subclass of a Struts Action class, and it is responsible for handling user input and dispatching requests to the correct places. Here’s an overview of the files which make up the application. (You can download the WAR file and a tarball of the whole application.)


In this application, I want to take advantage of a few of Struts’ cooler features. For instance, I can create custom Form Beans and tie them to Action objects. Let’s start with a Form Bean. The bean’s properties map to form fields, and each property has appropriately-named accessor methods.

package foo;   
import javax.servlet.http.HttpServletRequest;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionMapping;
public final class SiteForm extends ActionForm
{
private String index = null;
private String url = null;
private String title = null;
private String dispatch = null;
// accessor methods
public void setUrl(String url)
{
this.url = url;
}
public void setTitle(String title)
{
this.title = title;
}
public void setIndex(String index)
{
this.index = index;
}
public void setDispatch(String dispatch)
{
this.dispatch = dispatch;
}
public String getUrl()
{
return (this.url);
}
public String getTitle()
{
return (this.title);
}
public String getIndex()
{
return (this.index);
}
public String getDispatch()
{
return (this.dispatch);
}
public void reset(ActionMapping mapping, HttpServletRequest request)
{
this.url = null;
this.title = null;
this.index = null;
}
// for this application, we aren't validating user input, but you could easily extend
this method to do form validation public ActionErrors validate(ActionMapping mapping,
HttpServletRequest request)
{
// I'm leaving this example code in place so you can
see how form validation would be done using Struts
ActionErrors errors = new ActionErrors();
// if (url == null)
// errors.add("url", new ActionError("error.url.required"));
return errors;
}

One of the most interesting things about Struts is its set of Action classes. The code below extends the Struts Action class, and uses simple conditionals to dispatch user requests. There are other kinds of Action classes, notably DispatchAction, which you can read about in the Struts user guide and on Ted Husted’s husted.com.

// this controller responds to user input, handles it, and redirects  
// to a location specified in struts-config.xml package foo;
import java.io.IOException; import java.util.Vector;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionError;
import org.apache.struts.action.ActionErrors;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
public final class SiteAction extends Action
{
public ActionForward perform(ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws IOException, ServletException
{
ActionErrors errors = new ActionErrors();
// get the RSS Site List object from the session,
or create a new one if necessary
HttpSession session = request.getSession();
SiteList siteList = (SiteList)session.getAttribute("siteList");
if (siteList == null)
{
siteList = new SiteList();
}
String dispatch = ((SiteForm) form).getDispatch();
String forward = "alter";
if ("add".equals(dispatch))
{
String url = ((SiteForm) form).getUrl();
String title = ((SiteForm) form).getTitle();
if (url != null && title != null)
{
SiteListItem it = new SiteListItem();
it.setURL(url);
it.setTitle(title);
siteList.addSite(it);
}
}
else if ("show".equals(dispatch))
{
String index = ((SiteForm) form).getIndex();
if (index != null)
{
// put the selected site index in the
session for use by the next page
session.setAttribute("siteIndex",index);
forward = "view";
}
}
else if ("delete".equals(dispatch))
{
String index = ((SiteForm) form).getIndex();
if (index != null)
{
int ind = Integer.parseInt(index);
siteList.removeSite(ind);
}
}
// Forward to the specified success URL
return (mapping.findForward(forward));
}
}

At this point, we tie the Action and Form objects together using directives in struts-config.xml

<?xml version="1.0" encoding="ISO-8859-1" ?>   
<!DOCTYPE struts-config PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 1.0//EN"
"http://jakarta.apache.org/struts/dtds/struts-config_1_0.dtd">
<struts-config>
<!-- ========== Form Bean Definitions =================================== -->
<form-beans>
<!-- our SiteList controller -->
<form-bean name="SiteForm" type="foo.SiteForm"/>
</form-beans>
<!-- ========== Action Mapping Definitions ============================== -->
<action-mappings>
<action path="/siteAction" type="foo.SiteAction" name="SiteForm">
<forward name="alter" path="/index.jsp"/>
<forward name="view" path="/show.jsp"/>
</action>
</action-mappings>
</struts-config

Now we can use Struts to create a JSP page with user input elements that call the SiteAction object.

<%@ page language="java" %> 
<%@ page import="foo.SiteListItem" %>
<%@ taglib uri="/WEB-INF/struts-bean.tld" prefix="bean" %>
<%@ taglib uri="/WEB-INF/struts-html.tld" prefix="html" %>
<%@ taglib uri="/WEB-INF/struts-logic.tld" prefix="logic" %>
<head>
<title>Manage Sites</title>
<html:base/>
</head>
<body bgcolor="white">
<logic:notPresent name="org.apache.struts.action.MESSAGE" scope="application">
<font color="red">
ERROR: Application resources not loaded -- check servlet container
logs for error messages.</font>
</logic:notPresent> <br />
<jsp:useBean id="login" scope="session" class="foo.LoginBean" />
<jsp:useBean id="siteList" scope="session" class="foo.SiteList" />
<h1>RSS Site Manager</h1>
<%// user validation is being handled by a session bean if (login.validate() == false)
{
out.println("<script language=\"javascript\">
document.location='/headlines/login.jsp'</script>");
return;
}
int size = siteList.getSize();
for (int i=0; i < size; i++)
{
SiteListItem it = siteList.getItemAt(i);
out.println("<a href=\"/headlines/siteAction.do?dispatch=show&index="
+ i + "\">" + it.getTitle() + "
</a><br>");
}
%>
<br>
<hr>
<h2>Add a Site</h2>
<html:form type="foo.SiteAction" name="SiteForm" action="/siteAction.do" focus="url">
<table border="0"><tr>
<td>RSS URL</td>
<td><input type="text" name="url" size="60"/></td> </tr> <tr>
<td>Title</td> <td><input type="text" name="title" size="60"/></td>
</tr> <tr> <td colspan="2"> <input type="submit" value="Submit"/></td> </tr>
</table> <input type="hidden" name="dispatch" value="add"> </html:form> </body>
</html:html>

These files work together with beans that store and parse the list of RSS links and manage user login. Those helper objects are available in the tar archive. Note that in a production-quality application, user logins would have been handled by an Action object instead of the lightweight bean I’m using for example purposes.


With all these pieces assembled, you can compile and deploy the application using the same build.xml file referenced above. Just change the project name and appname at the top of the file, and you’re good to go. Here’s the RSS manager in action:


Conclusion, and Suggestions for Further Reading

This article has given you the information you need to get up and running with Struts on Mac OS X. Still, there’s much more to Struts than I can cover in one article. If you’re interested in learning more, visit the Struts User Guide. You might also want to pick up Programming Jakarta Struts, by Chuck Cavaness, or Struts in Action, by Ted Husted. Finally, I would be remiss in not recommending the now-classic book Design Patterns: Elements of Reusable Object-Oriented Software by Gamma, Helm, Johnson, and Vlissides.