Table of Contents
This article compares application development using either Seam or Spring Web Flow . We’ll compare the two by developing a common project and examining different aspects of development. In this first part, we’ll look at the histories and the differences between Seam and Spring and start looking at the example application we want to develop, and issues that we might face. These articles are not meant to be a how-to, but are meant to describe the higher level functional differences between the two frameworks as far as they attempt to solve the same problems.
In many examples that demonstrate the use of web frameworks, the authors typically take a simple example such as Hello World, or displaying a list of items created in an array or perhaps read from a database and write a form for creating a new item in the database. The strange reality is that most of these are simple enough that we don't need any complex framework to make the example verbose. We turn to frameworks to solve the complex, the monotonous and the things we do daily and yet the only demonstrations we get are mostly for things we might never even do in simple code. Hopefully, these examples might demonstrate how these frameworks can solve the practical problems you meet on a daily basis or have to code around such as contextual navigation and state management.
Let's try an outline some of the complexities we face as application developers when writing complete CRUD type applications.
Web development is stateless by nature and the process of making it appear it has state is difficult and often done so using different techniques and often with flawed results. One could use either the session or the database to hold the state, but there are a number of problems with that approach both at an application and server level:
If the user forgets to push data back into the session after changing it there is a danger that changes to mutable objects will be lost from one request to another. There is also no dirty checking for determining which objects need to be replicated.
Objects in the session are stored by name, which could cause problems when the same page is opened in two browser windows or tabs. There is no way to isolate data to a page, all user data is session scoped.
Reading objects back and forth between the database per request soon makes the database a performance bottleneck. You also lose your optimistic locking since you are always working on the most recent version of the object, not the version when the user started editing it.
In an AJAX world where a page may be submitted every few seconds our problems have multiplied because now we are communicating with the server several times instead of once per interaction.
One answer to all these problems lies in using a conversation which is a unit of work done by the user where the server manages the state of the objects involved in the conversation. Data held in the conversation is isolated from the data in other conversations. How the conversation data is stored is really up to the implementation.
As part of the conversation solution, we can also
solve problems relating to persistence managers such
as the management of entities, the prevention of
lazy initialization exceptions and dealing with
detached entities. This eliminates the need for the
OpenSessionInView
type solutions to solve these problems.
We also seek to solve the problems of contextual navigation. Typically, navigation from one page to another is done via a static link, usually involving passing parameters. However, this mechanism doesn't let us easily provide contextual navigation. If we have a page that lets you search for an object, we might want to re-use that page to let users select objects for use elsewhere in the application. One example might be searching for and selecting a customer to be sent an order. We can re-use the page to allow the user to search for customers, or in other places where we want to select a customer. This kind of functionality has been used and re-used in thick client apps for years. The goal is for the search form to know as little as possible about where it needs to return to in order to have a loosely coupled and easily re-usable form.
In order to do this we can make the customer search page navigation contextual so the page we are taken to depends on the process that we are currently executing. These processes are defined as work flows and are used to determine which page we navigate to based on the outcome from the page we are on. As part of contextual navigation, we may also need to pass data from one page to another which also involves knowing what process you are active in and where the data needs to go.
There are a number of other issues with web development that both of these frameworks solve, whether it is the propagation of messages from one page to another or providing Ajax functions to JSF. It also includes less visual elements such as gracefully handling exceptions in business objects. We will also consider these additional benefits to the core functions that these frameworks provide.
These articles are designed for someone who is considering Seam or Spring for web application development using JSF. The reader should be familiar with JSF since it is the presentation framework used in both examples. For the Spring example, it is assumed the user has some familiarity with Spring, and is able to configure beans for use in Spring. I have gone into a little more detail in the Seam example because most readers will have less familiarity with Seam.
These two frameworks are considered from the view of building a web application which requires both complex state management and navigation, even though our example is still fairly trivial. There are a number of frameworks which can be used to build data driven web sites, but many frameworks do not tend to provide functionality to solve these problems easily. You can solve these problems with other frameworks, especially if you use add-ons, but the goal here is to consider the two cohesive single stacks as out-of-the box solutions.
Seam refers to a conversation as a series of stateful interactions between the user and the server. Within that conversation, you can have a nested conversation which is a child-conversation that starts within the context of the parent conversation. Objects in the nested conversation can see the objects in the parent conversation, but not vice versa.
Spring uses the concepts of flows and conversations. A flow is a set of stateful interactions between the user and server and can invoke nested sub-flows. A conversation in Spring is a term which encapsulates the top level flow from start to finish, and may or may not involve one or more subflows. Each flow can define variables that are scoped to the flow or conversation scoped and therefore available in all flows in that conversation.
Where possible, this document has tried to use the correct terms for the framework being discussed.
Seam is a project developed by Gavin King under JBoss that sought to unify numerous standard technologies (EL, JPA, JSF, EJB) as well as non-standard ones (Facelets, iText, Jbpm, Richfaces) and to solve the problem of stateful development. As part of the Seam Framework, Gavin really introduced the concept of conversations into the web framework discussion. Not only did it provide the ‘seams’ between these technologies but it also covered a number of shortcomings (perceived or factual) of those technologies such as the Lazy Initialization Exceptions from Hibernate and the difficulty of using parameters in JSF.
Another goal for Seam was to try and create a single stack of libraries and tools for building applications and interweave them with Dependency Injection (and also bijection) and EL expressions. With Seam, the whole is far greater than the sum of the parts as it works towards a deeper and consistent integration of the individual pieces.
While most users may gravitate towards using Seam on a JBoss Application Server with Hibernate as the JPA solution, users are not tied to these implementations. You can use Tomcat with the JBoss Embedded EJB container or any other EJB container. However, straying from the most common configuration can mean you are in a minority and fewer people have experience with your configuration and any problems you run into. The inverse of this is also true. Since there is a very common configuration that most people use, there are plenty of people who have experience with that configuration, and any problems you might run into. This is just one of the benefits of using the default stack.
Seam is open source and also has commercial backing as it is part of JBoss Enterprise Application Platform (EAP). The libraries are identical to the open source versions except that the pieces of the EAP (which includes Seam) has been tested and certified to work well together by JBoss. The same applies to the IDE plug-ins. The JBoss Tools plugins work the same as the commercial JBoss Developer Studio, except the commercial version includes the EAP and has a slightly more complete setup intially. However, there is nothing that you can't configure yourself in minutes.
I’m sure most will need no introduction to Spring which was created by Rod Johnson in response to the difficulties and complexities people faced with J2EE prior to EJB 3.0. Spring stayed outside of the standards to create their own framework for developing J2EE applications. Spring lets developers use XML or annotations to specify beans available to the application and automatically inject other beans to provide functionality
The environment that is usually rigid in EJB containers can be specified dynamically in the Spring environment. For example, you can specify a standard transaction manager or subclass it and use that instead or even write your own from scratch (good luck). This concept is really nice and used throughout the Spring platform from data access to transaction management to managing web page controllers in Spring MVC and Web Flow. This makes the Spring approach more transparent and less like a black box that the EJB containers represent and only forces developers to include and setup the pieces that will be used.
While EJB may be a standard, there are differences between implementations which is not an issue for Spring even when using different containers since you are using the same Spring container in each actual container.
The downside (if you can call it that) is that Spring is in essence proprietary. While it is open source and freely available, there is only one implementation of it, there is only one controller of it (SpringSource) and the direction Spring will take will depend on what side of the bed Rod Johnson gets up on in the morning.
For years, Spring has advocated a stateless approach to software development and has had no real thrust in the area of stateful web development other than to use the session and rely on re-fetching data from the database on each request, as well as providing an interface for using stateful EJBs.
Spring Web Flow is the part of Spring that brings stateful development and workflow management to Spring. It is designed as another add-on to the Spring platform, this time integrating with Spring MVC. The particular aspect of Spring Web Flow we will be looking at is the Java Server Faces focused piece called SpringFaces.
While Spring offers the flexibility of swapping out one technology for another (except for Spring itself), Seam commits wholeheartedly to the technology set that it has chosen which are mostly standards. Some people may not consider the issue of standards to be a valuable one, but it is an issue that could get Seam a foot in the door of some of the bigger shops. However, there is rigidity in there that prevents you from adjusting parts of the framework like Spring can.
Spring requires you to define beans to provide the environment in which your application will run. For the most part, these beans are stateless singletons. State is held completely in the web flow by defining any stateful objects (i.e. Entities) there, and then passing them to and from the stateless beans (i.e. a Dao).
Seam on the other hand can use this method, but it also tends to worry less about the layering of applications. It’s not that it ignores good design, or promotes bad design, it’s simply that it isn’t really needed. Typically, an entity might be held by a Dao type object, which can also contain methods for JSF event handlers. Seam makes great use of EL (Expression Language) expressions and uses those to decouple the view and logic from the implementation. You wouldn’t want your view methods integrated with business methods.
Seam is geared towards using the JSF framework for presentation which again, is the standard component framework. Spring Web Flow has really made efforts to support JSF as well as their own Spring MVC framework. Seam is also diversifying since version 2.1.0 has Wicket support and there is also information out there on using it with Google Web Toolkit (GWT). Exadel also have produced tools for using Seam with Adobe Flex called Flamingo. JSF however is still the strongest view technology out there behind the original struts and still the main focus of Seam. The level of integration these different view technologies will have with Seam or Spring Web Flow may vary however.
Seam takes a global approach to the application in terms of defining stateful data, where it comes from, and what parameters it is derived from. Spring on the other hand takes a localized approach where data is only declared in the flows themselves and passed to and from subflows. The two frameworks differ greatly in the choice of mechanism and both have the pros and cons.
This could create problems in the Seam application since one name change can cause changes across the whole application. It could also create a duplication of data definitions which is why naming is important. Spring localized data could run into problems if a new variable is given the name of existing data introduced in a parent flow but is shared among the nested subflows which are unaware of the variable name in a parent flow.
Note that when we talk about globally declared data, we are NOT talking about global instances of data (i.e. it is not a global variable), merely that the declaration of binding a name to a class is global in much the same way that Spring declares beans globally within the context of the Spring container.
In terms of IDE support, Seam has JBoss Developer Studio (JBDS) which it has released as a commercial open source product and also has made the plugins available free as open source. This is really a very good development tool for the Seam stack, with a visual page editor and bean code completion nearly everywhere. While the visual IDE may not be everyone’s cup of tea, the code completion when coding by hand in the editor is priceless. Spring has the Spring IDE plugins which help when writing bean definitions and even web flow definitions including a visual flow editor, both of which are excellent. JBDS also provides code assist for JSF tags, and attributes using Seam component definitions.
Our test application will consists of a simple issue tracker. We have a set of projects, each of which has a set of related technical support issues. Each issue has a title, a description and a status represented by a status entity. We have one page which lists the projects, and one page which lets us edit the project, and another which lets us view the project. The project viewer lists the issues with links to edit or add a new issue and we can edit or view the issues. The issue editor will contain a drop down for the issue status value and also, we will eventually have a link on the project field so we can go to our project list and select a project for this issue. This project selection should re-use the project list and demonstrate making a page part of a workflow.
The goal is to make the pages as accessible as possible
so that we can get to any page without having to go
through another page first. So for example, we can go
straight to
/projectView?projectId=3
without having to go to the projects list and selecting
project 3. This is somewhat essential in the spirit of
loose coupling since we never know where we might want
to display those project details from. Both frameworks
offer the option of just passing data objects around,
but we want to demonstrate loose coupling, especially
with page parameters in JSF.
The goal is to mostly use features out of the box which means as little changes to the actual supplied framework as possible. This includes writing additional classes to help out the core framework. Our coding should be limited to solving the use case. Again, this is not so much a how-to, but a description of the frameworks and to demonstrate the differences. By default I’ve made the entity models use lazy loading everywhere, mainly so I can demonstrate some solutions to Lazy Initialization Exceptions and because I can use eager fetching in the queries if needed.
| http://www.andygibson.net/ | Copyright © 2008 Andy Gibson |