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.