Pretty image
Fred shows how to customize Stripes, a Web application framework that you can learn in a day or two.

Stripes is a Java web application framework that minimizes configuration, keeps things simple, and helps you get your work done without getting in your way. But by tapping a powerful feature of Stripes, you can adapt the framework in just about any way that you need.

You can get started with Stripes in a day or two, and keep learning new features as you need them. And you can definitely get great web applications up and running with what comes out of the box. But Stripes makes it easy to just tweak a few minor things or completely remold certain modules and effectively build yourself a customized web framework. That’s what I’m going to show you.

Modularized design and effective use of the strategy pattern makes this possible, and the Resolver makes it surprisingly easy. One configuration parameter, and you can customize just about anything that you want!

Stripes extensions are classes that you write to add and change the framework’s behavior. A single parameter in the web.xml file tells Stripes where to automatically discover your classes:

 <param-name>Extension.Packages</param-name>
 <param-value>com.example, org.library</param-value>

Here we’ve told Stripes to look for extension classes in the com.example and org.library packages, and all subpackages of those packages. So you can add, modify, or remove extension classes in those packages without needing to keep any configuration in sync; Stripes automatically discovers your classes at startup.

Note that org.library could very well be the parent package of a plugin that a third party has provided. To enable the features of that plugin, you’d only need to add the org.library package to your Extension.Packages parameter, and the library’s JAR file(s) to your application’s class path.

Here are some examples of functionalities that you can add and modify by writing extension classes:

  • How to convert a String request parameter to any type, and how to format any type back to a String

  • What to do at different stages of a request (interceptors)

  • How to decide the locale for the current request

  • Which resource bundle(s) to use

  • How to handle exceptions

  • How to map request URLs to Action Beans and event handler methods

  • How to bind request parameters to Action Bean properties

  • How to resolve validation metadata

  • ...and more.

As you can see, you can customize just about anything about how Stripes works.

Effective Use of the Strategy Pattern

Modular design and effective use of the strategy pattern are what makes Stripes so easily extensible. For every significant chunk of functionality, there is an interface that defines what needs to be done and a default implementation that says how it is done. In the default implementation, each step of the algorithm is broken into a protected method. This makes it very easy to tweak behavior by overriding the method that corresponds to the step that you want to customize. Finally, by virtue of your placing your class in one of the packages that you defined in the Extension.Packages parameter, your class will automatically be discovered by Stripes and used instead of the default implementation. In this way, Stripes is effectively using the strategy pattern by selecting algorithms at runtime.

Taking Advantage of Stripes Extensions in Your Own Plugins

Not only does Stripes allow you to customize the framework using extensions, but you can easily take advantage of the extensions mechanism to let other developers customize the use of plugins that you write to enhance the Stripes framework. This is where the extension mechanism really shines!

Let’s say that you are writing a nifty plugin that adds integration with a third-party framework. Obviously, this functionality does not belong in the Stripes core, because you wouldn’t want to bloat the framework. On the other hand, users of that third-party framework will certainly appreciate the integration. So you provide a plugin.

Now, as you are writing your plugin, you realize that you are making some arbitrary decisions about how things will be done. You have some sensible defaults, but you’d like to let users tailor your plugin to their own needs, and with minimal effort.

To this end, you can create an interface and a default implementation for each module of your plugin that you want to make easily customizable. Your users can adjust the behavior of a module either by implementing the interface from scratch, or by extending your default implementation and overriding the appropriate methods.

The beauty of this comes when it’s desirable to decide at runtime which implementation to use for each module. You’d like your users to be able to add their extensions to your plugin in the same way that they add extensions to Stripes itself: just by placing their custom implementations in one of the packages that they defined in their web.xml file. Here’s how you do exactly that:

 public static T resolve(Class type, String initParam, Class defaultImpl)
  throws Exception
 {
  Configuration config = StripesFilter.getConfiguration();
 
  T resolved = null;
 
  Class resolvedClass =
  config.getBootstrapPropertyResolver().getClassProperty(initParam, type);
 
  resolved = config.getObjectFactory().newInstance(
  resolvedClass != null ? resolvedClass : defaultImpl);
 
  if (resolved instanceof ConfigurableComponent) {
  ((ConfigurableComponent) resolved).init(config);
  }
 
  return resolved;
 }

This method takes as parameters the interface of the module that you want to resolve, the name of the initialization parameter, and the class of the default implementation. The body of the method uses the Stripes bootstrap property resolver to look for an implementation of the interface in the extension packages. The initialization parameter gives the user the option of defining the implementation in the web.xml file instead of taking advantage of the autodiscovery mechanism. Finally, the default implementation is used if no other implementation is found.

Voilà! By using this resolve method for each interface of your plugin, you’ll take advantage of any extensions that your users provide, and fall back as necessary to your own default implementations. Your users can use your plugin’s out-of-the-box features, and, with minimal configuration, provide their own customizations.

The Stripes framework is not only an excellent web application framework, it is a great example of putting the strategy pattern to good use by modularizing the key parts of the framework into interfaces that have default implementations and that can be customized easily by users, with minimal configuration. Some resources to help you learn more about Stripes are the Stripes Framework, Stripes ...and Java Web Development is Fun Again, the Stripes book blog, and the Strategy Pattern Wikipedia entry.

Frederic Daoud is the author of Stripes ...And Java Web Development Is Fun Again. He is a software developer who has been using Java since 1997 and developing web applications since the “pre-JSP” days of just Servlets. A web framework junkie, he learned a dozen of them before Stripes became his favorite. Currently a Stripes committer, he is active on the Stripes mailing list, answering questions and helping new users. Freddy lives in Montreal, Canada, where he shares the roasting hot summers and freezing cold winters with his beautiful wife Nadia and their two cuties, Lily and Ruby.