Red Hat

In Relation To Seam

In Relation To Seam

Seam 1.0.1 released

Posted by    |       |    Tagged as Seam

Last week thousands of people downloaded Seam 1.0 and tried it out. Inevitably, they picked up on a couple of bugs of the minorish variety. At the same time, I was getting some useful feedback from users who are already developing and/or deploying Seam applications at JBoss World. Finally, Roger Kitain from Sun reported a problem running Seam on GlassFish. So, I needed to do a 1.0.1 release:

http://labs.jboss.com/portal/jbossseam/download/index.html

This release has been properly tested on GlassFish.

Note that if you are using JBoss AS, Seam requires JBoss EJB 3.0 RC8. The best way to get the right versions of everything is to use the JEMS installer here:

http://sourceforge.net/project/showfiles.php?group_id=22866&package_id=193295&release_id=424215

(I know that this caused some hiccups for some people.)

Of late, the pressure on us has been to stop throwing in new features, and focus on stabilising the platform, so that people can feel confident using Seam in production. I think we are finally there now. I'm really happy with some of the applications I'm seeing built in Seam: you can really see the difference in user experience between a traditional web application and a Seam application with conversations, AJAX, business process management, etc. I was especially impressed with the workflow application built by JBoss Innovation Award winners Lexicon Genetics in just a couple of months. Doing something like that without jBPM and Seam would be a seriously much bigger undertaking. And they are pushing the limits of the environment, and helping feed me new ideas for Seam.

Seam on InfoQ

Posted by    |       |    Tagged as Seam

Floyd provides an excellent summary of some of the key ideas on Seam based on an interview we did yesterday:

http://www.infoq.com/news/JBoss-SEAM-1.0-Gavin-interview

Seam 1.0 GA released!

Posted by    |       |    Tagged as Seam

The Seam project is proud to announce the release of JBoss Seam 1.0 GA, an application framework for Java EE 5. Seam aims to be the most productive platform for development of enterprise and rich internet applications in any programming language.

Seam integrates Java EE 5 technologies like EJB 3.0, JSF and JMS into a unified programming model and then narrows the semantic gap between the business domain and the Java programming language by deeply integrating technologies like jBPM for business process and user interaction modelling and Drools for management of business rules. Seam Remoting provides an AJAX-based remoting layer for EJB 3.0, allowing client-side JavaScript to call EJB session beans directly. Seam's unique contextual state management architecture makes it easy to build applications with complex, stateful user interactions and helps eliminate a whole class of bugs endemic to browser-based applications. Seam also eliminates the XML hell that plagues Java frameworks designed for use with J2EE by leveraging Java 5 annotations for declarative programming.

Seam 1.0 introduces the following new features:

  • Seam Remoting - an AJAX-based remoting layer for EJB 3.0 components and JMS (created by Shane Bryzak)
  • Support for JSR-168 compliant portal engines such as JBoss Portal
  • Elegant handling of internationalization and JSF messages via EL-based interpolation
  • Helper components for JMS senders/publishers
  • JSF tag library
  • Redesigned XML-based configuration facility
  • Support for integrating databinding architectures
  • Eventing architecture for loosely-coupled components
  • Seam Logging
  • JBoss Cache integration for cluster-wide state replication
  • Experimental Drools integration
  • Compatibility with the Java EE 5 reference implementation
  • Much more...

As usual, the best way to learn about Seam is to check out the example applications. Start with the registration, numberguess, booking, blog, dvdstore and chatroom examples.

Get it here:

http://jboss.com/products/seam

Seam on the Java EE 5 RI

Posted by    |       |    Tagged as Seam

I've seen a couple of comments online to the effect that Seam is some kind of JBoss-only thing. This is not the case, Seam doesn't have any hard dependencies to anything other than the standard Java EE 5 APIs.

Roger Kitain from Sun has done the hard work to get Seam up and running on the Java EE 5 reference implementation. He had to make a couple of patches to the Seam sourecode, mainly reflecting the fact that I'm developing Seam on JBoss, which is currently slightly behind the final draft of the Java EE specs. This situation should be fixed sometime in the next two weeks. My plan is that Seam 1.0 final - coming /real/ soon now - will run on both JBoss and the Java EE RI (and presumably, any other Java EE 5 implementation). Thanks to Roger I now know what I need to do ;-) Of course, Seam already runs on standalone Tomcat, if you use the JBoss Embeddable EJB3 container, or if you are happy using JavaBeans and Hibernate instead of EJB3.

So, thanks Roger!

Comparing web frameworks: Seam

Posted by    |       |    Tagged as Seam

Recently, Simon Brown put together a set of requirements for a very simple blogger application that could be used to compare Java web frameworks. I have my reservations about the actual requirememts he put together (in particular, there is no form submission!) but since some other framework authors have bitten, I've gone ahead and ported the example to Seam. I want to put a massive caveat around this post: Seam is absolutely not designed for applications like blogs or web forums; these kind of problems are very easy to solve using something like PHP or Ruby on Rails and there is no really good reason to use Java for a problem like this (unless Java is all you know). We have a set of requirements here with /no conversations/ and /no business processes/, so all the sophisticated state management machinery of Seam is redundant. Nevertheless, frameworks need to make simple things easy, and you'll see how little Java code we need to write to solve this simple problem using Seam.

To begin, I copied the standard Seam web.xml, faces-config.xml, application.xml and build.xml files from the Seam booking demo, changing names in a couple of places, and removing all the JSF navigation rules from faces-config.xml. None of this stuff is interesting, and it is always almost identical in every Seam application. I also copied Simon's screen.css stylesheet.

Simon started out with a domain model with Blog and BlogEntry classes that in a real application would be mapped to the database via Hibernate or EJB3, along with a BlogService class, which implements a static singleton containing some test data. The static variable and static initializer is an incredibly ugly way to implement a singleton in Seam, so I took the liberty of rewriting this class as an application-scope Seam component.

@Name("blog")
@Startup
@Scope(APPLICATION)
public class BlogService 
{

   private Blog blog;

   @Create
   public void initBlog()
   {
      blog = new Blog();
      blog.setName("Webapp framework blog");
      blog.setDescription("Comparison of J2EE web application frameworks");
      blog.setLocale(new Locale("en", "AU"));
      blog.setTimeZone(TimeZone.getTimeZone("PST"));
      blog.addBlogEntry(new BlogEntry(...);
      blog.addBlogEntry(new BlogEntry(...);
      blog.addBlogEntry(new BlogEntry(...);
   }
  
  @Unwrap
  public Blog getBlog()
  {
     return blog;
  }

}

I left Blog and BlogEntry the way I found them and just copied them across.

That's all we need to start work on the first page of the web application.

There is some common header information on all pages of the application, so we'll use a facelets template, template.xhtml, to define the common stuff.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                      "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<html xmlns="[=>http://www.w3.org/1999/xhtml]"
      [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
      [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
      [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
      [=>xml:lang=]"en"  
      lang="en">
      
<f:view>
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
      <title>#{blog.name}</title>
      <link href="screen.css" rel="stylesheet" type="text/css" />
   </head>
   
   <body>
      <div id="container">
         <h1>#{blog.name}</h1>
         <h2>#{blog.description}</h2>
         <[=>ui:insert] name="content"/>
      </div>
   </body>
</f:view>

</html>

Note that this is all plain XML with namespaces, no wierd tags.

The index page, index.xhtml, in the example application displays a list of the three latest blog entries.

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
    [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
    [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
    [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
    template="template.xhtml">

<[=>ui:define] name="content">
   <h:dataTable value="#{blog.recentBlogEntries}" var="blogEntry" rows="3">
      <h:column>
         <div class="blogEntry">
            <h3>#{blogEntry.title}</h3>
            <div>
               #{blogEntry.excerpt==null ? blogEntry.body : blogEntry.excerpt}
            </div>
            <p>
               <h:outputLink value="entry.seam" rendered="#{blogEntry.excerpt!=null}">
                  <f:param name="blogEntryId" value="#{blogEntry.id}"/>
                  Read more
               </h:outputLink>
            </p>
            <p>
               Posted on 
               <h:outputText value="#{blogEntry.date}">
                  <f:convertDateTime timeZone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
               </h:outputText>
            </p>
         </div>
      </h:column>
   </h:dataTable>
</[=>ui:define]>

</[=>ui:composition]>

This is of course also plain XML.

(Usually I would not need to explicitly define locales in my templates. JSF and Seam use the request locale by default. But Simon's requirements say that I have to use the locale of the Blog.)

Now, if we hit http://localhost:8080/seam-blog/index.seam, this is the result:

http://hibernate.org/~gavin/blog_index.png

Now for the blog entry page (which we get to by clicking Read more). Assuming I've understood them correctly, Simon's requirements say that if a nonexistent entry is requested, we are supposed to send a 404 error and forward to an error page. Now, this is not the most natural thing to do in JSF or Seam. Usually, JSF applications use pull-style MVC when handling GET requests. Normally I would write the entry page to be able to handle the case of a nonexistent entry (this is easy). But Simon is the boss here, and his requirements call for a push-style design. We'll use a Seam /page action/.

@Name("entryAction")
public class EntryAction
{
   @In private Blog blog;
   @In private FacesContext facesContext;
 
   @RequestParameter
   private String blogEntryId;
   
   @Out(scope=EVENT, required=false)
   private BlogEntry blogEntry;

   public void getBlogEntry() throws IOException
   {
      blogEntry = blog.getBlogEntry(blogEntryId);
      if (blogEntry==null)
      {
         HttpServletResponse response = (HttpServletResponse) facesContext.getExternalContext().getResponse();
         response.sendError(HttpServletResponse.SC_NOT_FOUND);
         facesContext.responseComplete();
      }
   }

}

This action is meant to run before the entry page is rendered. It retrieves the requested BlogEntry from the singleton instance of Blog and outjects it to the event context. If no BlogEntry matches the request parameter, it sends a 404 error.

We need to list the page action in WEB-INF/pages.xml.

<pages>
   <page view-id="/entry.xhtml" action="#{entryAction.getBlogEntry}"/>
</pages>

Now we can write the entry page, entry.xhtml:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
                [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
                [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
                [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
                template="template.xhtml">

<[=>ui:define] name="content">
   <div class="blogEntry">
      <h3>#{blogEntry.title}</h3>
      <div>#{blogEntry.body}</div>
      <p>
         Posted on 
         <h:outputText value="#{blogEntry.date}">
            <f:convertDateTime timezone="#{blog.timeZone}" locale="#{blog.locale}" type="both"/>
         </h:outputText>
      </p>
   </div>
</[=>ui:define]>

</[=>ui:composition]>

Along with the 404 error page, 404.xhtml:

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" 
                             "[=>http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd]">
<[=>ui:composition] xmlns="=>http://www.w3.org/1999/xhtml"
                [=>xmlns:ui=]"=>http://java.sun.com/jsf/facelets"
                [=>xmlns:h=]"=>http://java.sun.com/jsf/html"
                [=>xmlns:f=]"=>http://java.sun.com/jsf/core"
                template="template.xhtml">

<[=>ui:define] name="content">
   <h3>Page not found</h3>
</[=>ui:define]>

</[=>ui:composition]>

This page needs to be listed in web.xml:

<error-page>
   <error-code>404</error-code>
   <location>/404.seam</location>
</error-page>

Now if I click the Read more link, I get to the URL http://localhost:8080/seam-blog/entry.seam?blogEntryId=3 and see the following:

http://hibernate.org/~gavin/blog_entry.png

If I edit the URL and change the id to 6, I'll get a 404:

http://hibernate.org/~gavin/blog_404.png

And so we're done :-)

Reverse engineering a Seam application from a database

Posted by    |       |    Tagged as Seam

Thomas has posted a movie demonstrating the use of Hibernate Tools (part of JBoss IDE) to reverse engineer an entire runnable Seam application from an existing database.

http://www.jboss.com/products/seam/SeamHBTools.html

The generated application includes

  • search screens with sorting and pagination
  • create/update/delete screens with association editing and navigation
  • full internationalization

I'm especially proud of the association handling, which is something that these kinds of application generation tools usually miss.

Of course, there is nothing very new about tools like this. There have always been tools in Java that let you reverse engineer databases. Unfortunately, the code that was generated tended not to be so easily customized or extended to handle complex cases. But this tool is generating JSF/Seam/EJB3 code. These are technologies designed to make it easy to handle the complex cases. So, you'll use the tool to get started quickly, and yet know that you aren't going to run into a wall when you get to the features that go beyond the trivial CRUD-type stuff.

Seam 1.0 beta 2

Posted by    |       |    Tagged as Seam

Seam 1.0 beta 2 has been released:

http://sourceforge.net/project/showfiles.php?group_id=22866&package_id=163777

There are too many changes and new features for me to list them all here, but I'll talk briefly about the three most interesting things.

The first is the idea of workspace management. You can see this feature in action by trying out the Seam Issue Tracker demo application that is included in the Seam distribution. Workspace management is like a Windows taskbar for web applications: the user can view a list of active workspaces (Seam conversations), switch between them and manage them, all within a single browser window. The list of workspaces may be represented as a drop down menu or clickable list. If you use Seam's powerful new nested conversation model, you can even have Seam automatically manage a meaningful trail of breadcrumbs.

You don't have to write any Java code to take advantage of workspace management in Seam, just include some standard JSF fragments in your JSP or Facelets pages.

For more information about this stuff, refer to the Seam documentation:

http://docs.jboss.com/seam/reference/en/html/conversations.html#d0e2374

The second new feature is tight integration with jBPM. In Seam, jBPM can fill two distinctly different roles.

The first role is traditional business process management (workflow). In this case, jBPM and Seam provide management of task lists, task assignment, business process execution, and business process state without any need to write any Java code. You can call Seam components from your jPDL file in exactly the same way that you call Seam components from a JSF page: by writing a JSF EL expression.

For example, the following trivial Seam/jPDL workflow definition might be used to describe a TODO list.

<process-definition name="todo">
  
  <start-state name="start">
     <transition to="todo"/>
  </start-state>
  
  <task-node name="todo">
     <task name="todo" description="#{todoList.description}">
        <assignment actor-id="#{actor.id}"/>
     </task>
     <transition to="done">
        <action expression="#{todoList.sendEmail}"/>
     </transition>
  </task-node>
  
  <end-state name="done"/>
  
</process-definition>

Check out the Seam DVD Store or Todo List examples to see exactly how this stuff fits together, or refer to the Seam documentation:

http://docs.jboss.com/seam/reference/en/html/jbpm.html#d0e2696 The second application of jBPM in Seam is pageflow definition. A Seam jPDL pageflow defines the navigation for a particular conversation. Just like a business process definition, we use JSF EL to define the interaction between the pageflow and the Seam components. This lets us centralize all information about the flow of the user interaction, and how the different components and pages fit together to implement the user interaction in one place.

Here is an example pageflow for a number guessing game:

<pageflow-definition name="numberGuess">
  
  <start-state name="start">
     <transition to="displayGuess"/>
  </start-state>
  
  <page name="displayGuess" view-id="/numberGuess.jsp" redirect="true">
     <transition name="guess" to="evaluateGuess">
     	<action expression="#{numberGuess.guess}" />
     </transition>
  </page>
  
  <decision name="evaluateGuess" expression="#{numberGuess.correctGuess}">
     <transition name="true" to="win"/>
     <transition name="false" to="evaluateRemainingGuesses"/>
  </decision>
  
  <decision name="evaluateRemainingGuesses" expression="#{numberGuess.lastGuess}">
     <transition name="true" to="lose"/>
     <transition name="false" to="displayGuess"/>
  </decision>
  
  <page name="win" view-id="/win.jsp" redirect="true">
     <end-conversation />
  </page>
  
  <page name="lose" view-id="/lose.jsp" redirect="true">
     <end-conversation />
  </page>
  
</pageflow-definition>

Notice how easy it is to get an understanding how the pages and Seam components fit together to solve the business problem.

For more information, refer to the Seam DVD Store or Number Guess examples in the Seam distribution, or to the Seam documentation:

http://docs.jboss.com/seam/reference/en/html/jbpm.html#d0e2530

The final interesting new feature is the application reverse engineering functionality provided by the latest release of Hibernate Tools. It takes just minutes to create a pretty full-featured application with CRUD, Search screens and full association navigation. This is a great way to get started with Seam.

More information (including screenshots) here:

http://docs.jboss.com/seam/reference/en/html/tools.html

Over the past few months, Seam has developed a vibrant community and so I've enjoyed working on this project more than anything since the early days of Hibernate. Thanks to everyone who has been involved!

Seam Webinar

Posted by    |       |    Tagged as Seam

Don't miss the Seam webinar on December 7 at 1PM EST. Enrol here .

For people based in Melbourne or Atlanta, I'll be speaking at EJV on December 15, and at AJUG on January 16.

The Seam Component Model

Posted by    |       |    Tagged as Seam

One of the distinctive features of Seam is that a lot more things are treated as components than what you might be used to from other architectures. In fact, pretty much every object you write will be treated as a Seam component.

For example, it is not normal in other frameworks to think of entity objects as components. But in Seam, we would typically treat User as a session-scope component (to model the currently logged in user) and entities like Order and Document as conversation-scope components (most conversations are centric to some entity instance).

Objects that listen for events are also components. Just like JSF, Seam does not have any notion of an Action class. Rather, it lets events be bound to methods of any Seam component. This means, in particular, that one Seam component can model a whole conversation, with the attributes of the component holding conversational state, and the methods of the component defining the functionality that occurs for each step in the conversation. (Note that this would be possible in plain JSF, except for the fact that JSF does not define a conversation context.)

The vision for Seam is that the notion of event will also be a unifying one. An event might be a UI event, it might be Web Services request, a transition event for the long-running business process, a JMS message, or something else we havn't thought of yet.

Again like JSF, an event listener method never takes any argument. This is quite in contrast to GUI frameworks like Swing, or Action based web frameworks like Struts where there is some Event object passed as a paremeter to the action method (a Servlet HttpRequest is an example of this pattern). Alternatively, some other frameworks will expose some thread-bound context object to the action listener. Both JSF and Seam offer thread-bound contexts as a secondary mechanism, but in the case of Seam, this mechanism is for exceptional cases only.

JSF has the right idea here. Ideally, the whole state of the system can be represented by components, that are assembled together automatically by the container. This eliminates the event object or context object from the view of the application, resulting in tidier and more naturally object-oriented code. Under the covers, the JSF implementation locates dependent beans of a managed bean using named context variables, and automagically instantiates a new instance of the needed managed bean if the context variable is empty.

Unfortunately, JSF is limited in three ways.

First, initilizing or modifying the value of a context variable requires direct access to the context object, FacesContext, breaking the abstraction. Seam fixes this problem by introducing outjection.

@In @Out Document document;

public void updateDocument() {
    document = entityManager.merge(document);
}

@Out User user;

public void login() {
    user = entityManager.createQuery("from User user ....")
           .setParameter("username", username)
           .setParameter("password", password)
           .getSingleResult();
}

Second, assembly (dependency injection) is performed when a managed bean is instantiated, which means that, (a) a component in a wide scope (the session, say) cannot have a reference to a component in a narrow scope (the request, for example) and (b) if we modify the value of a context variable, components which were already assembled will not see the new value, and will keep working with the obsolete object. Seam fixes this problem by making assembly (injection/outjection) a process that occurs at component invocation time.

@Entity @Scope(REQUEST)
public class OrderLine { ... }

@Stateful @Scope(CONVERSATION)
public class CreateOrderConversation {
   @In OrderLine orderLine;

   public addOrderLine()
   {
       order.addOrderLine(orderLine);
   }
}

At this time, most other IoC frameworks have the same two limitations, and this is perfectly defensible in the case of something like Spring where the components being injected are understood to be stateless, and hence any two instances of a component are interchangeable. It's not so good if components are stateful, as they are in JSF.

Third, JSF has just three contexts (request, session, application). So, if I want to hold state relating to a particular user across several requests, I have to put it in a session scoped component. This makes it effectively impossible to use JSF managed beans to create an application where the user can be doing two different things, concurrently, working in two windows at once! It also leaves it up to you to clean up state when you're finished with it, by manually removing session context variables via the context object (FacesContext).

Seam is the first attempt to create a truly uniform and unifying model of contexts which are meaningful to the /application/. The five basic contexts are event, conversation, session, business process and application. There is also the stateless psuedo-context.

The conversation context is a logical (application demarcated) context scoped to a particular view (browser window). For example, in an insurance claims application, where user input is collected over several screens, the Claim object might be a conversation scoped component.

The business process context holds state associated with the long running business process being orchestrated by jBPM. If review and approval of the insurance claim involves interaction with several different users, the Claim could be a business process scoped component, and would be available for injection during each user interaction.

You might object that an object might have one scope some of the time, and another scope at other times. Actually, I think this happens /much/ less frequently than you might expect, and if it does occur, Seam will support the idea of the same class having multiple roles in the system.

For applications with /extremely/ complex workflows, nested conversations and nested business processes are almost certainly needed, which opens the possibility for an /arbitrary/ set of scopes. Seam does not currently implement this, but the context model of Seam is designed for eventual extension to cover this kind of thing.

We've even discussed introducing more exotic contexts. Do transaction scoped components make sense? Probably not for application components, but possibly for infrastructural components. (Yes, the Seam component model has uses beyond application component management.) For now I'd prefer not to add things like this until we see a very clear need.

So, by this stage you're probably asking what this idea of contextual components actually /buys/ you? Well, for me there are three key things.

First, it allows us to bind stateful components, expecially entity beans, directly to the webpage. (Note that if you are going to bind your entities directly to JSF forms, you will also need some nice way to do validation, which is where Seam's integration with Hibernate Validator comes into the picture.) So, you can build a whole application from just pages, session-beans bound to events produced by the page, and entity beans bound to the page. It is this possibility for an unlayered architecture which makes Seam such a potentially productive environment. (Of course, if you want to introduce extra layers yourself, you can certainly do that, but it is not forced upon you.)

Second, it means that the container (Seam) can guarantee cleanup of state from ended or abandoned conversations. In the case of abandoned conversations, Seam gives you a choice: for server-side conversations, there is a conversation timeout that is independent of the session timeout. Alternatively, you can use client-side conversations.

Finally, the model allows stateful components to interact in a relatively loosly coupled way. Clients of a component need not to be aware of its lifecycle, or of its relationships to other components. All they need to know is what /kind/ of thing it is, and what are its operations.

Seam

Posted by    |       |    Tagged as Seam

We released Seam today.

http://jboss.com/products/seam

I feel like this is something I'm obligated to blog about. Unfortunately, I've just spent the past two weeks writing docs and webpages and blurbs and I feel if I sit down now and try to describe what Seam is all about, then I'll just be saying the same stuff, yet again, in another slightly different way. (And I'm afraid I get more grandiose each time.)

So let me just link to this page instead:

http://docs.jboss.com/seam/reference/en/html/pr01.html

Hopefully, I'll find the time to get a bit deeper into specific bits of Seam in future posts.

Thanks to everyone who made this release possible.

back to top