Authors: Deepak Alur, Dan Malks, John Crupi
Publisher: Prentice Hall / Sun Microsystems Press
ISBN: 0131422464 (Click to buy from Amazon)
With the advent of lightweight frameworks promoting dependency injection, and now JEE 5, with both dependency injection and pojo based EJBs, one might question the current practical applicability of a four year old book that describes patterns targeted at the JEE 1.4 platform. Indeed, some of the patterns in this book are outdated. However, the majority of the patterns are still applicable. This book review will go through each of the patterns, showing which of them are still relevant. If you decide that one or more of the still relevant patterns applies to the problems you are facing, then you would be well advised to purchase this book. The book divides its patterns into presentation tier, business tier, and integration tier, and I will use that same format.
Intercepting Filter: This pattern is certainly still highly relevant. Indeed, this pattern is often how current frameworks add functionality. For example, in the Spring Framework, Acegi is used as the security manager. Acegi works as an intercepting filter, checking the incoming request to ensure that the user has permissions to access the target of the request.
Front Controller: The most well know front controller may be the one built into Struts. The struts controller takes protocol specific information, such as request parameters, and puts them into a more protocol independent object, such as a Form, and then delegates the rest of the processing to specific other classes. Such behavior is classic for a Front Controller, and can been seen in more modern frameworks as well. For example, in JSF, the request specific parameters are processed and directly applied in the Apply Request Values phase before the rest of the JSF lifecycle continues. If you are bypassing your framework for some set of requests, or not using a framework at all, then you should still write a Front Controller of your own.
Context Object: This is simply the protocol independent object created by the front controller holding the information received by the application, and meant to be passed to the rest of the application. It’s mostly hidden in current frameworks, which directly apply request values to your objects for you.
Application Controller: The most well known example here may be the Struts action subclasses that are written by programmers, but other frameworks also use application controllers. The idea here is to take the Context object, and then act on the information received. In more modern frameworks, this basic idea is still present, but without the context objects. For example, in JSF, a value change event may be used to act on information received from the user.
View Helper: This pattern is still used anytime a jsp or jsf tag is placed on a page, which is to say that is it highly relevant to today’s programmer. The view helper kicks in after the view is already in the process of being rendered, and helps to format or otherwise process the information in the business tier. The business tier may place objects in the session or request object, which are then processed and rendered by the view helper.
Composite View: This pattern is even more used today than when the book was first written, and consequently, frameworks have made this pattern easier and easier to use. In this pattern, a view is composed of multiple smaller views. For example, you may want to include a navigation bar on each page, but you don’t want to have to code that navigation bar in each page. Earlier composite views were assembled with jsp:include, and later with Struts Tiles. Using Tiles in Struts requires the use of a tiles config file, mapping tile name to jsp. Modern templating libraries such as facelets, which can be used with JSF, have tiling and composite views built in, and no external configuration is required.
Service to worker: This pattern describes how to combine some of the other presentation patterns, so that you can specify business logic to be performed before a view is rendered. Basically, the Front Controller delegates to the Application Controller, which communicates with the business layer (via a Command Object (GOF) or a Business Helper), and then the Application Controller determines which view to show. This model is still how even modern frameworks work.
Dispatcher view: This is simply an alternate to the service to worker, where the dispatcher simply delegates to the view, and the view can use view helpers to construct the view. As such, it is also used today.
Business Delegate: This pattern is one that is less likely to be used in modern frameworks. The purpose of this pattern is to present a non ejb view of an underlying Session EJB facade, capturing and rethrowing EJB specific exceptions. The Business delegate can also handle lookups. However, with the dependency injection in today’s frameworks and in JEE5, lookups are not really needed, and a Session EJB is more likely to be local. When scaling is needed, the SessionEJB can be clustered, but one instance will still be local to the presentation layer, so again the remote access to a Session EJB is less likely.
Service Locator: This pattern is obsolete with dependency injection, present in most frameworks and JEE5.
Session Facade: Originally, to quote the book, the pattern was to “control client access to business objects” and “limit network traffic between remote clients and fine grained business components and services”. The key change is from when the book was originally written is that the remote clients today are often web services request, and so that generally limits any session facade servicing web services to being a Stateless session bean, as those are those are the only ones (in Jee5) which can expose a web service via a simple annotation. However, the other benefits that derive from controlling client access to business objects remain…in the rich domain model, access to modifications of the model are generally done via a session facade.
Application Service: The purpose of an application service is to hold logic that coordinates multiple business objects, removing such logic from teh session facade. However, with the advent of pojo bases EJBs that can easily communicate among themselves, leading to a rich domain model, the need for an Application Service pattern is diminished.
Business Object: While the importance of the Application Service has diminished, the importance of the business object pattern has increased. This is where the rich domain model, where the object model is patterned after the problem space, is actually implemented.
Composite Entity: This pattern, of tying the lifecycle of related business objects together, is quite useful, and has been standardized in EJB3 through the use of Value Type classes, which explicitly tie a Value Type lifecycle to that of an Entity.
Transfer Object: This pattern is now obsolete, since EJB3 entity beans can be detached from the persistence context and sent over the wire, if need be. Typically, though, these classes are not sent over the wire at all, but merely passed to the presentation layer as is.
Transfer Object Assembler: This pattern is mostly obsolete, for the same reasons as for the Transfer object, but it may still have a role in the use of web services, where you may want to send just a few objects, and not an entire object graph.
Value List Handler: This pattern is also obsolete since the built in query mechanisms of EJB3 does not use the same sort of mechanism as the finders of ejb2, and so is much more lightweight.
Integration Tier Patterns
Data Access Object: While technically, the persistence of objects can be handled through the EJB3 entity manger, it may still be nice to provide type safe DAOs. However, with generics in java 5, there is no need to write more than one such DAO with actual functionality it it–just write that one DAO, and then subclass it for each object type. The subclasses can be very simple and do not have to have any functionality in them–they are just for the strong typing. See this piece of hibernate documentation for examples.
Service Activator: The original reasons for this pattern (which is basically JMS) were for asynchronous methods, publish and subscribe, and splitting a business task into several parts. While publish and subscribe are still valid reasons for using messaging, there are now other options for the asynchronous part. For example, in the Seam framework, annotating a method with @Asychronous turns the method call into an asynchronous one. Behind the scenes, Seam uses the EJB Timer service (default) or Quartz to schedule a job that will run and actually perform the method. The main reason for choosing @Asynchronous would be ease of use. However, if your framework of choice does not support similar functionality, then JMS is still a useful option.
Domain Store: This pattern describes a way to persist and object model without changing the object model, and has thus been supplanted by EJB3.
As you can see from the above listing, many of the patterns described in the book are still in use today, and an understanding of the patterns will help you to understand and get the most use out of whatever modern framework you happen to choose.