Chapter 1 Introduction

Everything should be made as simple as possible, but not one bit simpler.

Albert Einstein

Welcome to Stripes!

Stripes is a framework that makes developing Java web applications easier. How? By eliminating much of the configuration that traditionally has been associated with Java web development. Goodbye, XML hell!

When Tim Fennell created Stripes in 2005, he decided to leverage the features introduced in Java 5, such as annotations and generic types, to remove the need for XML configuration files. In fact, the only XML file that you'll need is the standard web.xml file which kick-starts any Java web application.

But Stripes isn't just about reducing configuration. Have you ever used a framework and felt that you had to do too much work for the framework compared to what the framework gave you in return? Have you ever received very reasonable requirements from a client, but then had to fight with the framework to get the application to meet those requirements? Have you ever stopped and thought, “it's not normal for these things to be so complicated”?

Stripes is about making things simple for you, the programmer. While you develop your application, you'll notice how Stripes adapts to your code---a lot more than you have to adapt your code to Stripes. You spend your time writing your application, not reshaping your code in strange ways just to meet a framework's restrictions. Stripes is about making your work more enjoyable. Tim's tagline for Stripes says it all: “Java web development doesn't have to suck.”

Everything in Stripes aims to be as straightforward and practical as possible. Web development inevitably involves many repetitive low-level tasks; Stripes takes care of those so that you can concentrate instead on writing clear, concise, readable, and maintainable code.

Let's briefly discuss some of the characteristics of Stripes.

An MVC (Model-View-Controller) framework, Stripes is mostly present the Controller and View parts. Stripes interacts with your Model but does not intrude---your Model stays independent of anything Stripes-specific. Stripes happily transfers data between your Model and the Controller/View without asking you to describe anything in some configuration file or do any other form of “framework hand-holding.”

Stripes is not a “full-stack” framework; it works with your model but lets you decide how to map your model to a database. Plenty of high-quality frameworks exist for that, and the Stripes developers do not see value in duplicating those efforts. Moreover, not only do you probably already have a favorite solution for model-database mapping, but perhaps you even use different frameworks depending on the application. Stripes sees the value in that and does not tie you to a single solution. Stripes is very lightweight that way---it doesn't reinvent the wheel for everything, and it won't require that you learn a completely different paradigm. Stripes just focuses on the web part of web application development.

Stripes developers are very careful to avoid the “scope creep” pitfall. It's easily understandable that you'd want to add every single feature requested by users---you want to please them. In the long run, you're actually doing users a disservice because the number of features explodes, leading to a bloated, hard-to-understand and hard-to-maintain framework. With a never-ending list of classes and methods, too many tags, and a ton of attributes, a framework becomes very tedious to use. Stripes stays focused on a core set of features. At the same time, Stripes is very simple to extend so that you can easily add anything you need.

Stripes is an action-based framework. It acknowledges the stateless nature of the HTTP protocol and does its best to get the most out of it. HTTP is based on a request-response cycle: when the user clicks on something in the browser, a request is made to the web application which does its work and provides a response. The browser is refreshed with the results, and the cycle is complete. Stripes shapes itself to fit into this request-response cycle. A request is translated into an action, which triggers a Java method that does the work and returns a result. The framework interprets the result and provides the appropriate response. By using plain requests and responses, Stripes stays transparent and makes it easy to plug in third-party libraries and AJAX frameworks.

Another nice thing about Stripes is that you only need to learn a few basic concepts to get started. You can go a long way with a small set of features, and can leave the advanced stuff for later. When your applications become more sophisticated, you can learn how to get more out of Stripes. This cuts down on complexity when you start using the framework, because you don't need to learn too many things at once before you get some gratification.

What truly makes Stripes a joy to work with is that it helps you without getting in your way. You can actually wrap your head around the framework and understand what it is doing. When you run into a situation where you need something special, you can tap in and tinker to get the required result. Stripes is not a big magic black box that works “only if used as intended” and for which the warranty is void if you tear off the sticker and open the box.

What can Stripes do for you?

So if Stripes is so small and simple, what does it actually do? Plenty. Here's a quick feature summary:

Smart binding. Stripes goes a long way to bind URLs, parameters, and events from HTTP to Java so that your code remains simple and straightforward. The names in your view templates match the names of your Java classes, methods and properties, so the association between the two is very clear.

Autoloading. Stripes automatically discovers and loads your Stripes-related classes, so you can add, rename, and remove classes without worrying about keeping any configuration files (XML or otherwise) in sync.

Validation. Stripes provides a powerful validation mechanism based on annotations.

Type Conversion and Formatting. Stripes gives you strong type support by automatically converting between Strings and common Java types, and making it easy to add your own data types to its conversion system.

Layouts. With three tags from its tag library, Stripes gives you a simple and powerful reusable layout mechanism. You guessed it---no configuration files involved here either.

Localization. Stripes tags have a default resource bundle lookup strategy, so that localization is simply a matter of following the convention and adding key-label pairs in a resource bundle.

Exception handling. When an exception goes all the way up the stack without being handled, the servlet container shows a big ugly exception page. You don't want your users to see that! Stripes lets you show specific error pages for the exception types that you care about, and have a general “catch-all” error page for all other exceptions.

Interceptors. When handling a request, Stripes goes through several lifecycle stages before providing a response. Interceptors let you write code that is called before or after any of these stages, making it easy to alter the flow, change the data, and so on. Interceptors are a great way of plugging in custom behavior.

Customizable URLs. Stripes takes care of all the URL binding for you, so you can write your whole application without ever bothering with URLs. However, if you need specific URL patterns, Stripes lets you do that too.

Easy AJAX integration. With the simple and transparent request-response nature of Stripes, you can AJAXify your applications by using your favorite AJAX framework as a frontend and Stripes as a backend.

Testing. Stripes comes with a built-in set of mock objects that help you write automated unit tests to make sure your application works as expected.

Easy extension and customization. Stripes is designed in a modular fashion with many areas to hook into. You can plug in different behavior for any part of the framework. Extensibility is an area where Stripes really shines, and if you're not used to being able to easily insert custom code into a framework, you're in for a real treat.

Getting the most out of this book

Here is some information that will help you get the most out of this book.

What you should already know

I assume that you know the basics of Java web application development, including compiling Java code, creating a web application, packaging a WAR file, and deploying to a servlet container. You should also be familiar with JSPs and the Expression Language (EL).

If you need a refresher, you'll find a myriad of tutorials and examples on the 'Net. Here are a few good places to start:

The Java Tutorial

http://java.sun.com/javaee5/docs/tutorial/doc/bnadr.html

The web application section of the Java Tutorial.

JSP Syntax Reference

http://java.sun.com/products/jsp/syntax/2.0/syntaxref20.html

Handy reference on JSP syntax, EL expressions, directives, and standard JSP tags.

Java with Passion!

http://www.javapassion.com/j2ee

Sang Shin's online course for learning Java web application development.

NetBeans Tutorial

http://www.netbeans.org/kb/trails/web.html

A tutorial for creating web applications with the NetBeans IDE.

Eclipse Tutorial

http://www.eclipse.org/webtools/community/tutorials/BuildJ2EEWebApp/BuildJ2EEWebApp.html

A tutorial for creating web applications with the Eclipse IDE.

Getting the source code

This book comes with a lot of source code so that you can learn Stripes by example. Of course, the text contains code snippets along with explanations. Although I've done my best to include enough context around the code shown in the book so that it makes sense, I didn't want to bombard you with pages upon pages of code listings. When you want to see the full source and navigate through the code at your mind's desire, the best thing to do is to download the source package and use your favorite text editor or IDE. While you're at it, there's a good chance you'll want to try a few things of your own. Go ahead---that's a great way to learn.

You can download the source code from:

http://www.pragprog.com/titles/fdstr/source_code

Conventions

I use a few simple conventions in this book, which you'll recognize if you've read other books by The Pragmatic Programmers.

Live Code

The majority of code snippets in the book are extracted from fully functional examples. When that's the case, a bar above the code contains the path to the source file. For example:

getting_started/web/WEB-INF/jsp/hello.jsp

 <p>

   Date and time: ${actionBean.date}

 </p>

If you've downloaded the source code package, you'll find the file using that path. If you're reading the PDF version of this book with a PDF viewer that supports hyperlinks, it's even easier: just click on the bar and the code will appear in a browser window. If your browser mistakenly tries to interpret the file as HTML, just view the page source and you'll see the real code.

Joe Asks...

Joe, the mythical developer, sometimes pops up to ask questions about what I'm discussing in the text. I answer these questions as I go along.

Tim Says...

Tim Fennell, who created Stripes, has some wisdom to share every now and then. Look for these Tim Says... sidebars to read his rationales, recommendations, and colour (he's English so he spells it with a “u”) commentary.

Road map

This book is organized in three parts. Part I is about learning the different parts of Stripes and how they work. After setting up a development environment and getting a “Hello world” example running to make sure everything works, you start building the sample application that you'll keep improving throughout the book. In Part II, you are ready to use Stripes to add more sophisticated functionality to the application. By Part III, you'll move on to some of the more advanced features of Stripes, and will also learn how to integrate third-party libraries such as Hibernate, Spring, Guice, JUnit and jQuery.

Stripes version

This book uses Stripes 1.5, which, at the time of this writing, was not yet released but scheduled to become available in the next couple of months. I decided to use version 1.5 because of its many interesting new features that make developing with Stripes even more enjoyable.

Acknowledgements

Writing this book has been a very fulfilling, challenging, enlightening, and rewarding experience. I have several people to thank. Without them, my lifelong dream of writing a computer book (admittedly, a geek's dream) would not have come true.

Dear Nadia, being married to you has made me happier than I could ever imagine. You never stop believing in me and for that I'll always be grateful. You are a wonderful wife, a fantastic mother, and the most beautiful person I have ever known. I love you.

Lily Nadine, thank you for being such a bright, active, bouncing, laughing, happy baby. Every day, you bring us a tremendous amount of joy.

Merci Papa et Maman, Wasfi et Viva, d'être des parents si merveilleux. Vous faites toujours tout pour moi et j'en suis très reconnaissant. Merci à vous deux d'avoir chacun eu le courage de surmonter de graves problèmes de santé. Je vous admire. Que Dieu vous bénisse.

Thank you Tim Fennell for creating such an excellent framework. I was actually able to read and understand all the source code! You truly did a fantastic job. Thank you for collaborating with me on this book, contributing the Tim Says boxes, reviewing my work, making suggestions for improvement, and answering my questions. Thank you also for welcoming me as a Stripes committer. Finally, thank you for being such a great person. Being brilliant and humble at the same time is a rare and terrific combination.

Thank you Andy Hunt and Dave Thomas, the Pragmatic Programmers, for giving this book a chance in the first place. Special thanks to Dave for being patient with all the back-and-forth for the book cover, and to Andy for offering advice and always answering my questions so promptly and helpfully.

Thank you Jackie Carter for tirelessly reviewing my work, offering advice, always being positive, and helping me make this book better.

Thank you Tony George and Steve Francisco for reviewing my early drafts, back when I had not yet found a publisher. You dedicated your free time to help me and I truly appreciate it.

Thank you Ben Gunter for answering all my questions and for contributing such great features to Stripes.

Thank you Aaron Porter, Chris Herron, Ben Gunter, Brandon Goodin, Jasper Fontaine, Tim Fennell, and Jeppe Cramon for participating in the book's technical review.

Thank you Remi Vankeisbelck, Will Hartung, Jasper Fontaine, and Jeppe Cramon for reviewing my outline and offering your suggestions.

Thank you Aaron Porter for contributing Stripersist and the client-side validation code and agreeing to having them featured in this book. Special thanks for your patience in answering all my questions!

Thank you Oscar Westra van Holthe - Kind for contributing the Stripes security package.

Thank you Martijn Dashorst and Eelco Hillenius for answering my questions and offering advice on undertaking that tremendous challenge of writing a computer book.

Finally, thank you Stripers for forming such a bright, helpful, dynamic, lively and friendly community. That's what Stripes is all about.

Copyright © 2008, The Pragmatic Bookshelf.

Chapter 2 Stripes 101:
Getting Started

It is a mistake to try to look too far ahead. The chain of destiny can only be grasped one link at a time.

Sir Winston Churchill

The best way to get started with a framework is to dive in and get a simple example up and running. So let's do that.

Setting up a Stripes application

First, you need to set up a Stripes web application development environment:

Install the development tools

Install the Stripes framework and dependencies

Configure the web application to use Stripes.

This is a one-time job. You'll be able to reuse this environment for all of the book's examples as well as your own masterpieces.

The development tools

Install the following development tools. Note that every version number is a minimum version---higher versions should work as well. You are probably already familiar with these tools. If not, refer to the installation instructions on the indicated web site.

Java Development Kit (JDK), version 1.5: http://java.sun.com

A Servlet Container that supports Servlet 2.4 and JSP 2.0. There are several; here are just a few examples:

Jetty version 5.0: http://jetty.mortbay.com

Resin version 3.0: http://www.caucho.com

Tomcat version 5.5: http://tomcat.apache.org

(Optional) Apache Ant, version 1.7.0: http://ant.apache.org, if you want to use the build scripts that come with the book's sample code.

A text editor or an IDE to work with the source code. I'm sure you already have some favorites. Mine are VIM (http://www.vim.org), Eclipse (http://www.eclipse.org) and NetBeans (http://www.netbeans.org).

Once all the tools are installed, create a web application. This can involve a wizard in your IDE, or just creating a project directory with sub-directories for the source code and web application files. If you want the easy way out, just use the book's source code.

Stripes framework and dependencies

Next, get the Stripes distribution, version 1.5 or higher from http://www.stripesframework.org. You'll need to copy the required JAR files into the WEB-INF/lib directory of your web application:

stripes.jar: the Stripes framework, of course.

commons-logging.jar: required by Stripes.

You'll also need to copy the StripesResources.properties to a location that's on the web application's class path, such as the WEB-INF/classes directory.

The Java Standard Tag Library (JSTL) is not a Stripes requirement, but very useful when developing Stripes applications with JSPs as you'll see throughout the book's examples. To install the JSTL, copy the following two JARs from the Stripes distribution to your WEB-INF/lib directory:

jstl.jar

standard.jar

Using third-party libraries with Stripes

Stripes has very few dependencies. However, as you build more sophisticated applications, you'll probably want to add other libraries---to manage database transactions, for example. Instead of being a full-stack framework, Stripes is designed to integrate well with third-party libraries so that you are free to choose the best tools for your applications.

The web.xml configuration

Finally, as with any standard Java web application, you'll need the WEB-INF/web.xml file. This is where you configure the web application to use Stripes. The two elements that handle incoming requests are the Stripes Filter and the Dispatcher Servlet. Here is how you set them up in web.xml:

getting_started/web/WEB-INF/web.xml

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

 <web-app 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"

 >

[1]

   <filter>

     <filter-name>StripesFilter</filter-name>

     <filter-class>

       net.sourceforge.stripes.controller.StripesFilter

     </filter-class>

     <init-param>

[2]

       <param-name>ActionResolver.Packages</param-name>

       <param-value>stripesbook.action</param-value>

     </init-param>

   </filter>

[3]

   <servlet>

     <servlet-name>DispatcherServlet</servlet-name>

     <servlet-class>

       net.sourceforge.stripes.controller.DispatcherServlet

     </servlet-class>

     <load-on-startup>1</load-on-startup>

   </servlet>

[4]

   <filter-mapping>

     <filter-name>StripesFilter</filter-name>

     <servlet-name>DispatcherServlet</servlet-name>

     <dispatcher>REQUEST</dispatcher>

     <dispatcher>FORWARD</dispatcher>

   </filter-mapping>

[5]

   <servlet-mapping>

     <servlet-name>DispatcherServlet</servlet-name>

     <url-pattern>*.action</url-pattern>

   </servlet-mapping>

[6]

   <welcome-file-list>

     <welcome-file>index.jsp</welcome-file>

   </welcome-file-list>

 </web-app>

That's a lot of XML, but don't worry---you only have to do this once, and then you can use this configuration as a base for every Stripes application that you write. You'll only need to edit web.xml to enable some of Stripes' more advanced features, and even then it's the “once and for all” type of configuration. You won't have to work with XML files---or any other configuration files---for everyday work.

Here's what is now set up in this web.xml file:

[1]

The Stripes Filter declaration.

[2]

A parameter to the Stripes Filter. More details on this in a minute.

[3]

The Dispatcher Servlet declaration.

[4]

A mapping so that the Stripes Filter intercepts all requests that go through the Dispatcher Servlet.

[5]

A mapping so that the Dispatcher Servlet handles all action requests.

[6]

This says to use index.jsp as a default file when the user accesses the application with the base URL, such as http://localhost:8080/getting_started. We'll see how that works a little later on.

Have a look at an illustration of this configuration in Figure 1. All action requests are intercepted by the Stripes Filter, and then handled by the Dispatcher Servlet which looks for the Action Bean that is bound to the URL. Stripes instantiates the Action Bean and uses it to handle the request. The Action Bean can produce a response directly, or forward to a JSP which in turn produces the response.

Figure 1. A minimal Stripes configuration.

A value for the ActionResolver.Packages initialization parameter is given to the Stripes Filter in [2]. As promised, let's take a closer look at what this parameter does.

The search for Action Beans

Action Beans are the basic building blocks of a Stripes application. Because they are so essential, Stripes automatically loads them at start-up by scanning the class path. But it does need a starting point: at least one package root from which to begin the search. So you must choose the package(s) in which you'll be placing your Action Beans, and indicate the package roots, separated by commas, using the Stripes Filter's ActionResolver.Packages initialization parameter. For each package root, Stripes will examine the classes in that package and all sub-packages. Every Action Bean that it finds will be registered.

All Action Beans in the examples will be in the stripesbook.action package. So this package is indicated at [2] in the web.xml file. Using stripesbook would also work, but being as specific as possible down the package hierarchy reduces the number of classes to be examined and speeds up the start-up process.

I really like this feature of Stripes. You configure the packages for your Action Beans once and for all, and then you're free to add, rename, and remove as many Action Beans as you want. As long as you use one of those packages, you don't have to worry about editing a configuration file. Add an Action Bean, and Stripes will automatically load it. Remove an Action Bean, and you don't have to remember to remove something in a configuration file to keep things “in sync.” Working with Action Beans is the most frequent thing that you're doing in a Stripes application, so freeing you of configuration annoyances saves you a lot of time and effort.

That is all the setup and configuration that you need. You're now ready to write some application code.

Hello, Stripes!

We'll use the page shown in Figure 2 as a “Hello world” example. When you start the application, the page displays the current date and time. The two links at the bottom update the display: the first link refreshes the current date and time, and the second link displays a random date and time instead.

Figure 2. A greeting from Stripes.

Although this example does not do much, it will help you get started with Stripes. By displaying the current date and time, you'll learn how to obtain data from an Action Bean and display it in a JSP. Having two links shows you how to trigger different event handlers on the Action Bean. You'll gain a clear understanding of how the View (JSP) and the Controller (Action Bean) work together. Of course, let's not forget the benefit of getting a Stripes application up and running in the first place!

You've already set up a web application skeleton. All you need to get this example working is one Action Bean (HelloActionBean) and one JSP (hello.jsp). The file structure of the complete example will look like this:

 WEB-INF/lib/stripes.jar

 WEB-INF/lib/commons-logging.jar

 WEB-INF/lib/jstl.jar

 WEB-INF/lib/standard.jar

 WEB-INF/web.xml

 WEB-INF/classes/StripesResources.properties

 WEB-INF/classes/stripesbook/action/HelloActionBean.class

 WEB-INF/jsp/hello.jsp

 index.jsp

Let's write the HelloActionBean class.

Writing the Action Bean

The Action Bean provides the date to be displayed and changes it when the user clicks on one of the links. Action Beans, Action Beans, all this talk about Action Beans, but what exactly is an Action Bean, in terms of code? It's a Java class that implements the ActionBean interface:

 public interface ActionBean {

     public void setContext(ActionBeanContext context);

     public ActionBeanContext getContext();

 }

This is just a getter and a setter method for the ActionBeanContext, which contains the current request and response objects along with other useful information about the current request. Stripes takes care of providing the ActionBeanContext to Action Beans, so you can always count on having easy access to this information in your Action Beans by calling getContext().

Often, within an application, you'll write an abstract base class that implements the ActionBean interface and have your concrete Action Beans extend this base class. This also gives you a single place for adding any code that you want to make available to all of your Action Beans.

There is only one Action Bean in this simple example, so we won't bother creating a separate abstract base class. Let's look at the code for HelloActionBean:

getting_started/src/stripesbook/action/HelloActionBean.java

 package stripesbook.action;

 import java.util.Date;

 import java.util.Random;

 import net.sourceforge.stripes.action.ActionBean;

 import net.sourceforge.stripes.action.ActionBeanContext;

 import net.sourceforge.stripes.action.DefaultHandler;

 import net.sourceforge.stripes.action.ForwardResolution;

 import net.sourceforge.stripes.action.Resolution;

[1]

 public class HelloActionBean implements ActionBean {

     private ActionBeanContext ctx;

     public ActionBeanContext getContext() { return ctx; }

     public void setContext(ActionBeanContext ctx) { this.ctx = ctx; }

[2]

     private Date date;

     public Date getDate() {

         return date;

     }

     @DefaultHandler

[3]

     public Resolution currentDate() {

         date = new Date();

         return new ForwardResolution(VIEW);

     }

     public Resolution randomDate() {

         long max = System.currentTimeMillis();

         long random = new Random().nextLong() % max;

         date = new Date(random);

         return new ForwardResolution(VIEW);

     }

     private static final String VIEW = "/WEB-INF/jsp/hello.jsp";

 }

The class implements the ActionBean interface ([1]) with a standard getter and setter. Next, the date property is defined at [2]. The JSP will access this property using the Expression Language (EL) to display the date. Finally, the currentDate() event handler ([3]) refreshes the current date, while randomDate() produces a random date. Both event handlers set the date property and then forward to /WEB-INF/jsp/hello.jsp, using a ForwardResolution.

The next step is to create the hello.jsp file.

Writing the JSP

Tim says:

JSP Schmay Ess Pee

That's the response that a lot of people have to JSP these days. But the fact that most Stripes applications use JSP (as do the examples in this book) shouldn't put you off. I'll tell you now: JSP isn't nearly as bad as its haters would have you believe. It's true that JSP 1.0 was pretty darn awful and that it only got moderately better with version 1.1. At that point many developers wrote JSP off entirely and stopped paying attention.

Modern JSP development is a different story. With the introduction of the JSP Expression Language (nowadays just “the Expression Language”, or EL), the JSP Standard Tag Library (JSTL), and JSP Tag Files (essentially custom tags written as JSP fragments), JSP has moved past being painful and ugly to being a competent and usable view technology. It is now easy to develop pages without ever resorting to scriptlets!

A singular advantage of JSP over almost every other view technology out there today is by far and away better documentation, examples, and tool support. Every major IDE has a built-in JSP editor and there are hundreds of articles and books about how to do JSP development. Chances are that developers on your team and developers you interview are already familiar with JSP---you won't find such a large pool of developers familiar with other templating systems.

And if you really truly cannot stomach the thought of using JSP---Stripes works equally well with FreeMarker.[1]

http://www.freemarker.org. See http://www.stripesframework.org/display/stripes/FreeMarker+with+Stripes for instructions on using FreeMarker with Stripes.

The hello.jsp file is responsible for displaying the page that you see in Figure 2. Most of it is plain HTML, but there two interesting parts: displaying the date and time, and creating links that trigger event handlers on the Action Bean.

Let's look at the source for hello.jsp:

getting_started/web/WEB-INF/jsp/hello.jsp

 <%@page contentType="text/html;charset=ISO-8859-1" language="java"%>

 <%@taglib prefix="s" uri="http://stripes.sourceforge.net/stripes.tld"%>

 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>

 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"

   "http://www.w3.org/TR/html4/strict.dtd">

 <html>

   <head>

     <title>Hello, Stripes!</title>

   </head>

   <body>

     <h3>Hello, Stripes!</h3>

     <%--

     <p>

       Date and time: ${actionBean.date}

     </p>

     --%>

     <p>

       Date and time:

       <br>

       <b>

[1]

         <fmt:formatDate type="both" dateStyle="full"

           value="${actionBean.date}"/>

       </b>

     </p>

     <p>

[2]

       <s:link beanclass="stripesbook.action.HelloActionBean"

         event="currentDate">

         Show the current date and time

       </s:link> |

       <s:link beanclass="stripesbook.action.HelloActionBean"

         event="randomDate">

         Show a random date and time

       </s:link>

     </p>

   </body>

 </html>

After the standard page directive that declares the page as a Java JSP, the taglib directives import the Stripes tag library and the JSTL's formatting tags. I'll use the prefix “s” to represent the Stripes tag library; most people use either “s” or “stripes”. The “fmt” prefix is standard for the JSTL's formatting tags.

The code at [1] displays the value of the date property from HelloActionBean. The ${actionBean.date} expression calls the getDate() method on the current Action Bean, and the <fmt:formatDate> tag formats the result by displaying both the date and time in full.

Joe asks:

Where does ${actionBean} come from?

This is a feature that Stripes provides---it sets the Action Bean that has handled the current event as the “actionBean” request-scope attribute. This means that in your JSPs, you can always refer to the current Action Bean using ${actionBean}. From there, you can access the Action Bean's properties using standard EL expressions such as ${actionBean.date}. Because Stripes creates new instances of Action Beans for every request, it's quite appropriate to store request-related values in Action Bean properties.

At [2], the <s:link> tag creates a link to currentDate() event handler of HelloActionBean. Notice how clear this is in the tag: the beanclass attribute contains the fully qualified class name of the Action Bean, and event tells you the name of the method. The link to randomDate() is created in the same way. When you read this code, you know exactly which class and method is called by each link.

Just like that, we've made two types of bindings from the JSP to the Action Bean: reading data and triggering an event handler, as illustrated in Figure 3. That was simple, wasn't it? We have links that are bound to event handlers on HelloActionBean, which change the date and redisplay the page by returning a forward resolution back to hello.jsp. Let's talk a little more about these two key concepts: event handlers and resolutions.

Figure 3. Binding a JSP to an Action Bean.

Event handlers

The currentDate() and randomDate() methods in the Action Bean are event handlers. But what makes Stripes recognize these methods? We didn't declare them in a configuration file. The method names don't have a special prefix or suffix. It's all in the method signature. An event handler is a method that:

is declared as public

returns a Resolution

takes no parameters

is defined in an Action Bean

You choose the name of the method, and that becomes the name of the event handler. In HelloActionBean, the two event handlers are named currentDate and randomDate.

When you start the application and the initial request is made to HelloActionBean, how does Stripes know which event handler to execute? Here's where the notion of a default event handler comes in. When no event handler is specified (either because of a plain URL or with an <s:link> tag with no event attribute), the default event handler is triggered. Stripes treats an event handler as the default when:

The event handler is annotated with @DefaultHandler

The event handler is the only one defined in the Action Bean

With more than one event handler and no @DefaultHandler annotation, Stripes won't know which one is the default and will throw an exception. In the example, @DefaultHandler is on currentDate().

There's nothing wrong with using the @DefaultHandler annotation on an event handler that happens to be the only one defined in an Action Bean. In fact, consider it good practice, since it clearly marks the intent and saves you from forgetting to specify it if you decide later on to add other event handlers to the Action Bean.

On the other hand, do not annotate more than one event handler with @DefaultHandler in the same Action Bean---you'll get an exception.

After an event handler has done its work, it returns a resolution. What's a resolution, besides something that people have at New Year's and abandon a few weeks later?

Resolutions

Tim says:

What's with these Resolution classes and hard-coded paths to pages?

You might be wondering why we return instances of the Resolution interface directly instead of returning symbols or codes like "SUCCESS" and "FAILURE". Or if it's a bad idea to have paths to JSPs right there in the ActionBean. The simple answer is that we do things this way because it's simpler, easier, and allows you to do more things without jumping through hoops.

If we were using result codes instead of Resolutions when writing ActionBeans, we would also have to edit a configuration file to set up the result codes and the pages to which they map. That's another file that would have to be kept in sync with our beans; we'd have to be careful that our bean name and result codes always match between two places.

Returning instances of the Resolution interface avoids this and at the same time makes debugging and maintenance much simpler. When you observe a problem with a page, you can find the Action Bean class from the URL in your browser via the URL binding rules that we discuss in Section Binding to Action Beans. When you look at that class, you can see what it's doing and immediately see which page it forwards to without having to look in yet another file and match up a result code to a page name.

That's not all though! The most important reason is that this provides a clean and cohesive interface for sending a response to the client that doesn't require the ActionBean to conform to an interface or put data onto a special stack just to pass it to the Resolution. If you want to add parameters to a forward or stream back a custom data type to the client, it's as easy as:

 // Send a forward with additional arbitrary parameters

 return new ForwardResolution("/foo.jsp").addParameter("foo", bar);

 // Send back a stream of an arbitrary content type

 return new StreamingResolution("image/png", inputStream);

In my experience, most ActionBeans deal with only one or two pages and most pages are owned and forwarded to by a single ActionBean. As a result, even if you hard-code JSP names in your ActionBean, you're usually only hard-coding them in one place each and not scattering the same name in lots of places. If you still would prefer to centralize your JSP names, it's perfectly simple to move them into a page constants class and reference the constants instead---and since it's code, you'll still be able to click right through in your favorite IDE.

A resolution tells Stripes what to do next in response to the current request. An example of a resolution is to forward to a JSP, which is what the event handlers of HelloActionBean do by returning a ForwardResolution to /WEB-INF/jsp/hello.jsp.

In terms of actual code, Resolution is a one-method interface:

 public interface Resolution {

     void execute(HttpServletRequest request,

                  HttpServletResponse response)

         throws Exception;

 }

You usually don't need to implement the Resolution interface yourself; most of the time you'll find a Stripes ready-to-use implementation that does what you need:

ForwardResolution:

forwards to a path, such as a JSP, or to another Action Bean.

RedirectResolution:

same as a ForwardResolution, but uses a client-side redirect instead of a forward.

StreamingResolution:

streams data directly back to the client, for example to produce a binary file.

JavaScriptResolution:

converts a Java object to JavaScript code which is sent back to the client and is suitable for decoding using the JavaScript eval() function. This is particularly useful when using AJAX.

ErrorResolution:

sends an HTTP error message back to the client, using a status code and an optional error message.

That gives you an idea of what types of resolutions are provided by Stripes. We'll discuss them in more detail as we use them in examples.

Running the example

To run the example, package the web application that you've so diligently created and deploy it to your servlet container. Or, if you have just been reading along without typing anything, you can always take the easy way out and use the book's source code. Just go to the getting_started subdirectory of the source code bundle and run ant. The example will be packaged into a WAR file, ready to be deployed. After starting your servlet container, use http://localhost:8080/getting_started to run this chapter's example.[2] You should see the page shown in Figure 2. Try clicking on the links to change the displayed date and time.

When running the example, we used the <welcome-file> parameter in web.xml to set the default path to index.jsp. This file is a one-liner that forwards to /Hello.action:

getting_started/web/index.jsp

 <jsp:forward page="/Hello.action"/>

This path targets HelloActionBean. Remember that we created links to HelloActionBean with the <s:link> tag---if you look at the generated HTML code for those links, you will see that they also point to /Hello.action.

So the question is, how is the path, /Hello.action, connected to the class, stripesbook.action.HelloActionBean?

Binding to Action Beans

Stripes doesn't bother you with URLs and instead lets you work with Action Bean class names. Behind the scenes, Stripes takes care of generating URLs and binding them with Action Beans. That's great, but there's no need to be left in the dark about how URLs and Action Beans are connected. So let's discuss that briefly.

Remember that Stripes searches the class path at start-up, looking for Action Beans. The fully qualified class name of each Action Bean that it finds is associated to a URL. Here are the steps involved to carry out this mapping, with the binding of stripesbook.action.HelloActionBean to /Hello.action as an example:

Start with the fully qualified class name of the Action Bean.

stripesbook.action.HelloActionBean

Remove the package prefix up to and including any of the following package names: action, stripes, web, or www.

HelloActionBean

If present, remove the class name suffix Action, Bean, or ActionBean.

Hello

Convert the package and class name to a path, by prefixing with a forward slash and changing all periods to forward slashes.

/Hello

Append the action suffix.

/Hello.action

This mechanism is called URL binding. When a request arrives, Stripes looks at the URL and searches for the corresponding Action Bean in the mapping that was constructed during the binding process.

Figure 4 shows a few more examples of Action Bean class names and their corresponding URL bindings.

If you're not happy with default URL binding pattern, don't fret. We'll see how it can be changed in [XREF: sec.TappingIntoStripes:UrlBinding].

Action Bean class

Default URL binding

a.web.users.UserActionBean

/users/User.action

a.b.UserAction

/a/b/User.action

www.a.b.UserBean

/a/b/User.action

web.a.actions.User

/a/actions/User.action

theweb.ActionBeanImpl

/theweb/ActionBeanImpl.action

a.b.stripes.ActionBean

/.action

Figure 4. URL binding examples.

Mind the context path!

When you deploy web applications to a servlet container, the context path distinguishes one application from another. With Jetty and Tomcat, for example, an application deployed by placing the myapp.war in the /webapps directory has a context path of /myapp. You can then access the root of the web application with http://localhost:8080/myapp.

Avoid using the same name for the context path of your web application and for the first part of the package name that contains your Action Beans---for example, a context path named /myapp and an Action Bean named myapp.mymodule.ui.MyActionBean. This will cause problems with the URL binding mechanism.

If you must use the same name for the context path and the first package name, place your Action Beans in a package that includes one of the names that are truncated by the URL binding strategy (action, stripes, web or www), such as myapp.mymodule.ui.stripes.MyActionBean.

Using the href attribute

When creating a link with <s:link>, we connected the link to an Action Bean by indicating the fully qualified class name of the Action Bean in the tag's beanclass attribute:

 <s:link beanclass="stripesbook.action.HelloActionBean"

   event="randomDate">

   Show a random date and time

 </s:link>

We can also use URL bindings directly, such as /Hello.action, with the href attribute. In this case, we would have created the link like this:

 <s:link href="/Hello.action" event="randomDate">

   Show a random date and time

 </s:link>

Notice that we did not need to put the context path at the beginning of the URL. The href attribute of the <s:link> tag automatically does this for us.

In most cases, using the beanclass attribute is preferable:

it clearly states which Action Bean is the target

it makes your code independent of URL binding details

if you decide to move or rename the Action Bean, modern IDEs will catch the beanclass references in the refactoring process

Nevertheless, it's useful to understand how URL binding works. For example, you might need to create links to Action Beans within non-Stripes tags or from an application that uses a different framework.

The “pre-action” pattern

A good practice in a Stripes application is to use what is known as the “pre-action” pattern. This consists of always having requests go to Action Beans rather than directly to JSPs. We did this in the example---both links target HelloActionBean using the beanclass attribute of the <s:link> tag. There are no direct links to hello.jsp. In fact, we made sure of that by placing the JSP file in the /WEB-INF/jsp directory. In Java web applications, files anywhere under /WEB-INF cannot be accessed by the browser.

Using the pre-action pattern has the following advantages:

ensures that the current Action Bean will be available in the JSP using ${actionBean}

routes requests through Action Beans, involving the full Stripes request-response lifecycle and giving us more control over what happens between the stages of this lifecycle

restricts the URLs used to access the application, making it easier to control security

targets Action Beans instead of JSPs, making our code refer to class names instead of URLs

Wrapping up

You now have a working development environment and a Stripes application up and running. Hopefully you've gained a better understanding of the basics of Stripes by looking at the Action Bean and JSP code.

A few things to notice after completing this exercise:

Setting up a Stripes application does not stray from the standard procedure for a Java web application, and Stripes has very few dependencies.

Stripes requires very little configuration. You just need to set up the Stripes modules in the standard web.xml file, and indicate the root(s) of the packages that contain your Action Beans.

You can add, remove, and rename Action Beans without having to make changes to the configuration. Stripes will automatically find and load your Action Beans, as long as they are in a package or sub-package of the roots that you've configured.

Day-to-day work involves Action Beans and JSPs, not configuration files.

Your JSPs can link to Action Beans by class name, making the association crystal clear and shielding your code from the details of URL binding.

The ${actionBean} expression allows you to generically refer to the current Action Bean and to its properties.

You can trigger event handlers on Action Beans by writing a method that has the appropriate signature, and referring to the name of the method in the JSP.

In the next chapter, we'll discover more about Action Beans, JSPs, and how they work together. We'll learn how to create HTML forms with Stripes. We'll also start the main sample application that we'll be working on for the remainder of the book.

Footnotes

[1] | http://www.freemarker.org. See http://www.stripesframework.org/display/stripes/FreeMarker+with+Stripes for instructions on using FreeMarker with Stripes.
[2] | Open the index.html file in the root directory of source code bundle to get an index of all the examples.

Copyright © 2008, The Pragmatic Bookshelf.