Chapter 4. Summary

Table of Contents

4.1. Comparing Solutions
4.1.1. Configuration
4.1.2. Flow Variable Declarations
4.1.3. Conversational URLS
4.1.4. Page flows
4.1.5. Documentation and Examples
4.1.6. A Complete Solution?
4.1.7. Layering and Decoupling
4.1.8. Taking the future into account
4.1.9. Usability
4.2. Summing it up

First off, these are two excellent solutions to have to choose between. Most of the problems with basic CRUD web development can be solved with either of these frameworks, and it's fairly safe to say that there are no real reasons not to use either of these.

4.1. Comparing Solutions

Let's start by recapping some of the differences between the two and noting their respective strengths and weaknesses in different areas

4.1.1. Configuration

Seam comes with Seam-Gen which is a command line tool to get you started writing Seam applications. Alternatively, you can use the JBoss Tools / JBoss Developer Studio tools to create applications. Seam requires you to list any page flows in the components.xml file. Annotations are usually used to name components in source, but that too can be done in components.xml . Pageflows are invoked by name when a conversation is started.

Spring essentially leaves application creation up to the developer which isn't surprising given that Spring gives you unlimited options on the libraries you can use with it. Web Flow configuration involves a number of different classes and beans. It also requires you to be running Spring MVC underneath it all. It wouldn't be a Spring solution if you couldn't interchange nearly each and every part of the solution. For that reason, I'm sure there are no limits on how you could set up the mappings between URLs and flows. The default is to map URLs to flows with the option of using wildcards. Spring beans are defined either by annotation or using xml configuration files. These can be imported into the spring config files so there is no rigid structure in terms of content or location.

4.1.2. Flow Variable Declarations

In addition to the stateless, session and application scopes, both frameworks offer additional scopes. Spring offers a flash, view, flow or conversation scope, with the conversation spanning one or more flows. Seam lets you define a conversation scope which is equivalent to SWF's flow scope, or a page scope which holds the object in the page and appears similar to Spring's view scope. As a modifier to the Seam conversation scope, you can indicate that an object is created per nested conversation giving it a scope limited to that conversation, similar to Spring's flow scope.

Spring lets you wrap values in a JSF DataModel which can be specified in the flow. Seam also enables you to easily do so using an annotation which requires that you have an actual class to annotate. If you define a query in components.xml then there is no way to wrap the results in a DataModel .

Regarding instance declaration, Spring uses a 'push' convention over 'pull' while Seam can use both although it tends towards the pull convention. With Spring, you need to declare a data instance in the flow before you use it, while with Seam, you typically declare how that data is created with a factory annotation before you can use it. When it is requested (usually from a reference on a JSF page), the data instance is created and put into one of the Seam variable contexts (depending on the assigned scope). Alternatively, you can just outject object instances from classes to emulate a push technique, although this technique requires you to call a method call on the bean to trigger the outjection process.

Seam uses a global approach to defining it's named beans which gives you the benefit of being able to define beans once and use them anywhere in the application. Seam also allows you to create multiple instances of the same class with different names and possibly different scopes. Defining a component with perNestedConversation gives you most of the power of Spring's declaration within the flow. However, this cannot easily be applied to the persistence context which by default, only allows one instance per conversation stack.

Since Spring defines the data in the flow itself, it gives you slightly more control on a per flow basis, but it could lead to repetition and the possibility of variable names stepping in each others toes as one flow invokes another flow. However, this could be managed by scope control of the variables created and mostly using the more restrictive flow scope, and only using conversational scope when needed. Flow inheritance could solve the repetition issue, but it might be overkill to create a flow with common code in just to be inherited by two flows (i.e. edit and view CRUD pages).

4.1.3. Conversational URLS

Seam offers natural conversation urls where the conversation is identified by a an identifier that is contextual. By default, a Seam url with a conversation is partEdit.seam?partId=1234?cid=5 where the conversation is identified by the cid parameter. You can define a naturial conversation for that page that makes the conversation Id defined by the part number parameter instead so rather than have a synthetic conversation id of 5 passed in a parameter called cid , you will have a contextual conversation id defined by the part number in the partId parameter. This leaves you with a URL of /partEdit.seam?partId=1234 , or, if you use the UrlRewriter a RESTful URL of /parts/edit/1234 . Spring appends something like ?execution=e3s1 on to your URLs which can be quite ugly. The ' s ' part of the URL indicates the state and increments for each page in the flow. It is this that identifies each state point in the flow allowing us to use the back button to get to any point in the flow and essentially, travel back in time to that point, and resume the flow from that point. Seam just has one conversation that spans all pages that participate in it and only one set of state which is the current state.

4.1.4. Page flows

Both solutions provided an easy way to write navigation rules and flows, and took very different approaches to it.

Spring navigation is more decoupled from the view than Seam. Spring favors returning action strings like save , cancel , or select from the view and executing code within the flow based on those actions. It is probably the more technically correct way to do it from the sense of decoupling the view from the navigation and business logic. While the existing navigation language is simple, but fairly adequate, the Web Flow team has talked about adding new features based upon user feedback. On important feature I found was the ability to put as many commands as you wanted in the transition segments.

Seam gives developers a choice of navigation methods. While you can use the JSF based navigation, it is much easier to use one of the two alternatives. If you use pages.xml for navigation, you navigate based on string actions, on logical statements, and it also depends on what method the string action was returned from. However, you cannot call methods in response to those string actions as part of the navigation. Typically this means your view has to call a method to perform an action and you navigate based on the outcome of that action. In order to use string actions in your view and call methods on the back end, you must use page flows like Spring Web Flow does. Having multiple navigation methodologies might seem overkill and complex, but it does offer solutions of different degrees. The page flow language does feel rigid, and unforgiving in many ways. There's no way to make multiple method calls, there's no way to outject values to the parent conversation. It often feels like you are digging for ways to do things which should be intuitive.

Another issue is that if you navigate through the flow, and click the back button and try to take another path, you get Illegal Navigation error messages. This is because the flow isn't synchronized with the view. If you navigate from page A to page B, and click the back button and try to navigate off page A using action string "XYZ", the pageflow handler is still on page B, and since page B doesn't know about action string "ABC", it throws an illegal navigation error. Spring has a finer granularity in storing its state. When it appends the execution info in the url, it is of the form execution=e3s4 . When you navigate through the flow the number after the 's' increments, so Spring stores not only the state for the flow, but also for each state of the flow on a page by page basis. This is handy for avoiding problems like the one shown above, but can come with it's own set of headaches. Spring however lets us discard or invalidate history on a transition by transition basis.

One thing that should be noted is that it appears that Spring Web Flow cannot be used for pages not included in a web flow. If you have a page that is not in a page flow and you want to display some data, then you still need to provide some way to generate that data and bind it to the EL expression for JSF to display. For this reason, any time you want to use Web Flow for passing data to JSF, it must be done within a flow. While there is a JSF variable resolver for Spring, it means you have to learn and use a whole different technique for implementing JSF pages with Spring. On the other hand, you could also use this as an opportunity to delve in to some Spring MVC for those pages since you already have most if not all Spring MVC elements installed in your application.

Seam on the other hand is designed to be used with varying degrees of intrusion into your pages. You don't have to start a conversation and a pageflow in order to use the Seam defined variables. The expression #{projects} works in any page and even outside of pages because the declaration is application wide. This can even make your java code conversational since it always executes within a conversation. EL expression values can be used for error messages, navigation rules, in any email or PDFs you generate and even logging. Overall, Seam delivers a more unified and integrated approach to fetching and generating data than Spring.

One point where Spring shines is the ability to localize the data in a flow resulting in cleaner nested flows. With Seam, data is declared globally, there is the @PerNestedConversation annotation that can let you define new instances of variables in a nested conversation which is a half measure to achieving the same functionality. However, passing data to a nested or parent conversation is not easily done. Part of this probably stems from Seam's perception of nested conversations. To Seam, a nested conversation is meant to be a part of the parent conversation, not a separate action. I.e. choosing a hotel room type in the nested flow for a hotel booking that is in the parent flow. Spring on the other hand can let you use subflows as totally separate and encapsulated processes such as editing an issue, going to select a project for the issue, and then choosing to add a new project). This behavior is very thick-client-ish since it gives the users a lot of flexibility. However, in Seam, as soon as you go to create a new project, it would look up the project variable and find the instance from the parent conversation, thus preventing you from adding a new one. You would then have to add the PerNestedConversation annotation to the projects bean which could introduce problems of its own. While this is very potential problem, it isn't a big one. Interfaces that let users go round in endless circles usually end up with the user getting lost and to some degree should be somewhat constrained. However, it was impressive going round in circles in the Spring implementation and having Spring keep track of my flows and data instances and shuffling up and down the conversation stack with ease.

4.1.5. Documentation and Examples

Seam has excellent documentation, and a large number of Samples, with a 650+ page PDF manual starting with simple examples and documenting most of the features with a mini example of the syntax for each. The documentation for core Spring is excellent, however the documentation for Web Flow is lagging behind with most functions having little coverage. This is understandable to a degree, and Seam documentation was lacking (although a little better than SWF's current state) for the first few releases until Gavin took the time to document and it grew from 250 pages in 1.2 to 350 pages in version 2.0.1 to 650+ in 2.1.0. However, poor documentation can be annoying, especially after I wasted a couple of hours trying to get the expression currentEvent.entity to work when changes in the web flow API made in May 2008 required it to be currentEvent.attributes.entity . The documentation, as of January 2009 still reflects the old version. It wasn't until I read the release notes that I found out about the change. Spring has only a few examples, mainly a duplication of the Seam booking application, with one version for each of the different web flow technologies. Since many people use the examples as a basis for finding solutions to their own problems, fewer examples means less chance that people will find answers within them.

4.1.6. A Complete Solution?

It might be unfair to compare how far these two products go to provide a complete solution since Spring isn't aiming to do that. Spring offers page flow control and stateful data management on top of its IoC container and other core functions. It doesn't strive to be a complete solution, and it expects you to add in any additional nuts and bolts (i.e. security, Ajax Frameworks, iText or email generation) yourself, and either implement your own Spring integration with third party libraries or hope the libraries already have it built in. Either way adding the pieces to the Spring stack would take time and the integration probably won't be as seamless.

Seam on the other hand aims to be a complete software stack. Cynics might disagree with the idea of someone else choosing which libraries they use for development since in this day and age it almost feels like Framework and library selection should be a full time job for Java developers. However, the Seam team has strived to create a stack that really does deliver almost everything a developer could need. Most components could be replaced if needed, but out of the box, everything works together nicely. If you want to get going and start writing an application with Seam and the JBoss Tools IDE, you can find yourself very productive in less than a minute, complete with IDE integration and hot deploy.

4.1.7. Layering and Decoupling

Both frameworks let you design layered applications in order to separate concerns. They both let you create Dao or Service beans which provide generic services to more function specific beans. Seam has come under some fire due to the lack of apparent layering in the demo applications. However, the lack of layering is by design in the demos (they don't really need it), and not because Seam is incapable of layering. You can add as much layering as your sanity will allow under Seam without a problem.

One advantage of JSF is the ability to decouple the view from the back end objects via the use of EL to loosely couple beans to view elements. Seam expands on this with contextually named data that results in less coupling between the view and the data in the conversation. If we use the expression #{customers} in several pages, our view is only bound to this expression. Seam then binds this expression to a method or object using a factory. At a later date, we can change the factory for the customers expression to another method, or another bean, or even another layer in our applications and all bindings in our view will get the data from our new source.

With Spring, because all of our variable declarations are in the flows themselves, if we want to fetch our customers from a different location, we need to change the declaration in each flow that uses it. This is because each flow couples that variable name to a method. Spring can eliminate the problem by layering the application and having a customerDao with a getCustomers method which is then coupled to the expression customers in the flow. To change the source of the data, you need change the implementation in the Dao. This would require a little pre-thought before implementation. However, it does demonstrate one reason why Seam doesn't require as much layering as it has an extra layer (Seam itself) between the view and the backing beans.

Another aspect of this is code portability. Spring maintains the same Model/Dao layering where the Dao returns model data, and model data is put into the flow under a variable name which makes it accessible to the view. Spring makes it fairly easy to take that Model/Dao code and use it in another application or test environment, as well as keeping things lightweight. Seam on other hand promotes thicker classes in the conversation. For example, the EntityHome beans contains the reference to the model entity instance, as well as all the Dao functionality including a reference to the EntityManager . While this is still somewhat portable, there is a higher degree of integration of the code with Seam than with Spring's 'Roll Your Own' data access approach. You can of course roll your own data access layer with Seam, but then you lose the ease of using the EntityHome/Query beans.

4.1.8. Taking the future into account

Of course, one factor in all of this is how well the frameworks will weather the future. Nobody wants to adopt a framework that will be extinct in a couple of years. Spring has somewhat of an advantage here in that there are plenty of Spring users already in existence, although few of those are Web Flow users. One might compare that to the number of EJB users versus the number of Seam users since there are plenty of people use EJB but without Seam.

Gavin King is working on creating the Web Beans JSR (JSR-299) which will seek to make a standard out of the component declaration model used in Seam and Google Guice. This is not a case of making Seam a standard since I believe there are a number of differences between Seam and Web Beans. However, once Web Beans is out, Seam will probably move towards being a Web Beans implementation and is probably due to become the reference implementation for the JSR. Depite building the framework around standards, there is support for Wicket, Adobe Flex and GWT. A web beans standard can likely help those integrations by standardizing the use of contextual named components. Web beans will also become a more pojo oriented framework which could attract those that run screaming at the sight of EJBs. However, since Web Beans is a standard, like all standards, it will not be as complete as either Seam or Spring as a solution. One concern for Seam could be that once Web Beans comes out, will we start seeing Web Beans based stateful frameworks without all the additional features that Seam has (pageflows, security, deep EL integration etc) that might be more attractive as Seam-Lite.

Spring have been moving ahead with their own efforts to create a single full stack with the Spring Application Platform focused around an OSGI based application server. They are passing up on the standards and sticking with their own solutions. Interestingly enough Spring are pushing their own application servers for use with their own Spring stack, while the Seam team are making efforts to promote cross server usage of Seam.

While many have aversions to standards (rational and otherwise), there is a varying degree of benefit to adopting standard technologies. Seam is all about standards, and will probably continue to be a framework built on standards. Spring on the other hand caters to the standards when they think it is prudent (i.e. plenty of JSF integration with Spring Web Flow), and ignore them when they think it is not. Support for Spring Web Flow with other frameworks is more likely to come from the other frameworks trying to integrate with Spring rather than the Spring Team reaching out to other frameworks. The Seam team has made a number of efforts to include other frameworks (i.e. Wicket, GWT and even spring), as well as other app services (WebSphere OC4j, Glassfish).

4.1.9. Usability

Sometimes, SWF feels like a more professional and polished product with professional developers building real world products in mind. As such it seems not to suffer from some of the pains that Seam has, many of which can be overcome, but some that require a little work. Even when things go wrong in Spring, you get a fairly clear error message most of the time (but not always!), sometimes even a suggestion on how to fix it. With Seam, you often have to first decode the exception to determine where things went wrong, and then fix the application. For example, if you have an error in your pageflow, it will often loop endlessly complaining that the workflow hasn't started. Somewhere in there (or at the top of the log) is a helpful error message, but only if you are lucky and only if you dig for it. Usually the error messages are cryptic and I find myself struggling to remember what kind of problem is represented by the symptoms I am seeing rather than having a message telling me what happened. However, these are relatively small problems and somewhat superficial even if they are frustrating. Support on the groups is often very helpful since everyone is using the same product stack (in most cases, the same versions too), and not mixing and matching libraries and library versions which can be a problem with Spring.

4.2. Summing it up

These are two very good frameworks, with only small issues between the two which makes any kind of summary or conclusion difficult to determine.

To get the obvious out of the way, Seam is jam packed full of features which many people might not appreciate and consider Seam to be bloated or heavyweight which seems nonsensical given that Seam is designed to be a complete solution in a box. That said, here we are looking at how well the frameworks tackle most of the work we do which is CRUD with logical flows between pages.

While Spring Web Flow might offer a more lightweight solution as an optional plugin to your web framework stack, it lacks the same deep integration that Seam has. Like many Spring libraries which can be bolted on to your projects it takes a little work and sometimes even some code to get the different pieces working together.

If you are using JSF and have no problems using EJB3.0 (but not requiring it) with a default stack of JBoss AS and Hibernate then Seam is well worth taking a look. I think Seam as a back end to JSF can be easier to use with the EL integration and the narrower focus of the framework makes it more powerful out of the box. There are still some points which need polishing up on, but for the most part they can be worked around.

If you favor Spring libraries then you can feel right at home with Spring Web Flow as it will meet most of your needs and integrates the same way most of the other Spring plugins do. The weakest points are exception handling, passing messages outside the flow and the issue of choosing between using a flow for each page or using another technique to create non-flow JSF pages. Any weak or missing points can probably be resolved through custom code.

The Spring solution isn't as well integrated as the Seam solution which is good and bad for both. When Seam makes a mistake it is hammered all the way through the framework while Spring requires you to do more work but gives you a little more control on a few features. However, in some areas, Spring provides no support for some features and expects the user to handle those pieces. JBoss has some potential to add features to Seam that can bring some aspects up to par with that of Spring Web Flow. For example, defining variables in a pageflow or even in pages.xml making it local to that flow or page, giving the persistence context more flexible scopes, and allowing multiple action calls during navigation transitions. These are probably not without backwards compatibility issues, but it would allow Seam to take on some of SWF's strengths.

IDE support for Seam really shines since they partnered with Exadel and the code suggestion for Seam components (even EL expression within Java code) is wonderful. Spring also has IDE plugins but again suffers from the lack of deep integration in the Spring framework. This idea of a full stack offering deep integration while the lighter stack offers less integration is a common theme between these two solutions.

Regardless, both projects have been well received, and appropriately so as these are two excellent and freely available tools. While they both have strengths and weaknesses, they are both great frameworks.


http://www.andygibson.net/