The Hidden Gem of Web Frameworks

Tutorial - Stripes: a lean, mean Java web framework

Stripes is a real hidden gem of a web framework. It is relatively low-key but those who use it, swear by it. And for good reason–it is simple, effective, and tightly focused on doing a few things and doing them really, really well. This gives you a framework that does a lot more for you than you have to do for it, while staying out of your way and letting you do things the way you want to do them. It also lets you pick your favorite tools for the other layers involved in developing a complete web application, such as persistence, security, and a jazzy user interface.

If you've never heard of Stripes, you might wonder if it is being used in real-world applications. It certainly is. Just one example is Modernizing Medicine where my colleagues and I use Stripes to develop a powerful Electronic Medical Assistant for Dermatologists. Daniel Cane, President and CEO of Modernizing Medicine, states: "HOW I heard about Stripes, I have no idea. But, once I did, I was immediately hooked: the ease of binding and validation, and elegance of manipulation of forms, the power of localization, and a solid community of people willing to help. When looking at the Stripes book, the tag line "...and Java Web Development is Fun Again" sold me on the platform. I have been so happy with this framework, and each week I learn something new."

Show me some code

Intrigued yet? Let's look at some code. Say you are showing a list of products from your inventory and you want to create a link that goes to the detail page for each product. The code in your page might look something like this:  

 

 <%-- sample01.jsp --%>
  <ul>
    <c:forEach var="${products}" item="product">
      <li>
       <stripes:link beanclass="com.example.ProductActionBean" event="showDetail">
          <stripes:param name="productId" value="${product.id}"/>
          ${product.name}
       </stripes:link>
      </li>
    </c:forEach>
  </ul>

 

Things to take away from this example:

  •  Stripes uses JSP for templating. It is easy to use, has great support in your IDE, has an enormous user base, copious amounts of third-party libraries and support, and is documented by a ton of reference pages, articles, books, and blog posts.
  • Stripes does not reinvent anything that is already available in standard JSP, such as the forEach tag.
  • Stripes tags are straightforward. The link clearly shows that it targets the com.jaxenter.stripes.action.ProductActionBean class and the showDetail event. You know exactly where to look next. Also, if you rename ProductActionBean or change its package, it's a plain search to find where it is referenced in JSPs. Finally, adding a productId parameter to the link is easily (and cleanly) done as well.

Let's take a peek at the Java side of things:

 

  /* ProductActionBean.java */
  package com.jaxenter.stripes.action;
  
  import net.sourceforge.stripes.action.ForwardResolution;
  import net.sourceforge.stripes.action.Resolution;
  import com.jaxenter.stripes.model.Product;
  
  public class ProductActionBean extends BaseActionBean {
    private Integer productId;
    private Product product;
  
    public Resolution showDetail() {
      product = loadProduct(productId);
      return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
    }
  
    public Product getProduct() {
      return product;
    }
  
    public Integer getProductId() {
      return productId;
    }
    public void setProductId(Integer productId) {
      this.productId = productId;
    }
  }

 

Now we have a few more takeaways:

  • The class includes a method named showDetail, which matches the value of the event="showDetail" attribute in the JSP. This method will automatically be called when the user clicks on the link.
  • The class also includes a productId property. Its value will be set to the product ID associated with the link, because we have <stripes:param name="productId"> tag in the body of the link.
  • Although all parameter values arriving over HTTP are Strings, we can use Integer for our productId property. Stripes will automatically do the type conversion, and also supports Date, BigDecimal, BigInteger, and all primitive and wrapper types, out-of-the-box. It's easy to write type conversions for your own types, as well.
  • The result returned by the showDetail method is a Resolution, which defines what happens next. Here, we are using ForwardResolution which clearly shows that we are forwarding to productDetail.jsp. The information is all there, no need to search in a separate file to figure out what the "success" string means!
  • Stripes uses Action Beans, which are so named because they combine actions with JavaBean properties. Here, the action is showDetail, and the bean is the inclusion of the productId and product properties.

In productDetail.jsp, we can easily show the details of the selected product by taking advantage of the automatic presence of the action bean within the JSP, under actionBean, courtesy of Stripes: 

 <%-- productDetails.jsp --%>
  <h1>Product details</h1>
  <ul>
    <li>Name: ${actionBean.product.name}</li>
    <li>Description: ${actionBean.product.description}</li>
    <li>Price: ${actionBean.product.price}</li>
  </ul>
 

Knowing that the current action bean is always available in the JSP under {actionBean} makes it easy to transfer data to the view: just add a getter method in the action bean class for the information that you want to access.

More about action beans

Action beans are the workhorses of a Stripes application. These classes are where you receive input and handle events triggered by the user clicking on links or submitting forms. One feature that makes things easy for you, the developer, is, that action beans are thread-safe. A fresh instance is created to handle each request, so you are free to use instance variables without worry. The next thing to know about action beans is that you handle events with methods of the following signature:

 

 public Resolution eventName()

 

The method name determines the name of the event that it handles. We already saw how to indicate the action bean class and event name in a link:  

 

 <stripes:link beanclass="..." event="...">

 

We can do the same for a form just as easily:  

 

 <stripes:form beanclass="...">
    <stripes:submit name="save" value="Save Data"/>
    <stripes:submit name="cancel" value="Cancel everything"/>
  </stripes:form>

 

The name in each <stripes:submit> tag indicates which event handler method to call in the action bean (the value is the button label to show in the browser). This makes it really easy to handle multiple submit buttons in a form! Just write an event handler method for each button:  

 

 public Resolution save() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

 

 

You can have a default event handler in an action bean in two ways: first, if it is the only event handler method in the action bean, it is automatically the default. Second, you can designate an event handler method as the default by annotating it:  

 

@DefaultHandler
  public Resolution view() {
    // ... 
  }
  public Resolution cancel() {
    // ... 
  }

 

 

After you have handled an event, you need to tell Stripes where to go next. You do this with a Resolution. Let's talk about those now.

Where to next? Resolutions

In Stripes, Resolution is a simple interface to tell Stripes how to respond to the browser after handling a request. The interface has just one method:  

 

void execute(HttpServletRequest request, HttpServletResponse response);

 

As you can see, it is simple and lets you do just about anything in order to send a response to the browser. Of course, Stripes has some built-in implementations for common responses:

  • ForwardResolution forwards to a template, typically a JSP
  • RedirectResolution sends a redirect to the browser, typically to another action bean
  • StreamingResolution makes it easy to send a binary file as a response, such as a PDF
  • JavaScriptResolution sends a Java object in JavaScript, which is very useful when using Ajax
  • ErrorResolution sends an HTTP error, with error code and descriptive message

One of these will suit your needs most of the time, but you can extend them or write your own from scratch to get any customized behavior that you require. The two most commonly used resolutions are ForwardResolution and RedirectResolution:

 

  // Forwards to a JSP
  return new ForwardResolution("/WEB-INF/jsp/productDetails.jsp");
  
  // Redirects to another action bean and its default event handler
  return new RedirectResolution(AnotherActionBean.class);
  
  // Redirects to another action bean and a specific event handler
  return new RedirectResolution(AnotherActionBean.class, "showDetails");
  
  // Redirects to another action bean and a specific event handler, 
  // with request parameters
  return new RedirectResolution(AnotherActionBean.class, "showDetails")
    .addParameter("productId", 42).addParameter("showDescription", true);

 

Resolutions are expressive and let you know right then and there, exactly what the next step is in responding to the browser.

 

Pages

Fred Daoud
Fred Daoud

What do you think?

JAX Magazine - 2014 - 03 Exclucively for iPad users JAX Magazine on Android

Comments

Latest opinions