Chapter 1. Seam unifies Java EE

This chapter covers

  • Lightweight Enterprise Java
  • Seam as an application stack
  • Simplified configuration using annotations
  • Tools that enable agile development

Is JSF worth a second look? Is EJB really fixed? Is it worth sticking with Java rather than jumping ship for Ruby on Rails?

With the release of Seam 2.0, you can now confidently answer yes to all of these questions. Seam is a progressive application framework for the Java Platform, Enterprise Edition (Java EE) that makes writing web-based applications simple by finally delivering on the promise of a unified component architecture. Seam builds on the innovative changes in Java EE 5 brought about primarily by the Enterprise JavaBeans (EJB) 3 specification. These changes include favoring annotations over container interfaces and relying on configuration by exception rather than verbose and laborious XML descriptors. Seam tears down Java EE’s remaining heavyweight legacy by spreading EJB 3’s pivotal changes across the platform. Seam also extends the platform as designed by weaving additional functionality into the JavaServer Faces (JSF) life cycle and taps into the unified Expression Language (EL) to allow a wide range of technologies to communicate. With Seam, the pain typically associated with using Java EE has vanished and JSF, in particular, appears completely revamped and worthy of attention.

In this chapter, you discover why Seam is the most exciting technology in Java right now and the reasons why you should make Seam your framework of choice. I demonstrate how Seam solves your current problems with the Java EE platform by blending innovation with existing standards. In a world inundated with frameworks, Seam is the unframework. It does not prescribe a new programming model that you must adopt. Seam simply pulls together the standard Java EE APIs, most notably EJB 3, JSF, Java Persistence API (JPA)/Hibernate, and Java Authentication and Authorization Service (JAAS), and makes them more accessible, functional, and attractive. Seam finishes off these improvements with modern upgrades such as conversations, page flows, business processes, rule-based security, JavaScript (Ajax) remoting, PDF rendering, email composition, charting, file uploads, and Groovy integration. Like a classic car, Seam sports the muscle of Java EE under the hood, but on the surface it appears stunning and elegant.

Putting Seam’s strengths aside, the fact remains that you can choose among many qualified frameworks. In the next section, I provide you with advice that can hopefully put an end to your search and move you toward developing your application. Despite the fact that no one can tell you what framework is right for you, you’re probably going to ask anyway, right? Don’t worry—I came prepared.

1.1. Which framework should I use?

In a world full of framework options, how do you choose one? There are so many frameworks available for the Java platform, some proven, some promising, that the decision is downright agonizing! Does figure 1.1 speak to you?

Figure 1.1. The great framework decision

The choice is so bewildering that the framework inquiry is now the dominant greeting exchanged between developers at conferences. While the question “What do you do?” may have traditionally served in the role of sizing up a person’s abilities, these days you are judged based on the merit of what framework you use for software development (or the advice that you can give pertaining to that choice). Just when you’ve made a decision, a new framework arrives on the scene promising to bury its predecessors.

These choices can be harmful, especially to productivity. Barry Schwartz argues in The Paradox of Choice (Ecco, 2003) that having a bewildering array of options floods our already exhausted brains. The result is that your ability to write a quality application stalls. You keep believing that the best framework is the one you haven’t tried yet. As a consequence, you spend more time researching frameworks than you do designing functional applications. The search consumes you. You develop a false sense of how busy you are.

If any of these choices were truly satisfying, then you probably would not be reading this book. You would already have a set of tools that you know, beyond all doubt, allows you to be highly productive. But you don’t, do you? You’re still searching for a framework that is new, yet familiar. Lightweight, yet powerful. You are in need of a platform that integrates the vast landscape of Java technologies into a unified stack. Seam might be just the framework you are looking for.

1.2. Choosing Seam

You might be tempted to think that Seam is just another web framework, competing in an already flooded market. In truth, to tag Seam as a web framework is quite unfitting. Seam is far broader than a traditional web framework, such as Struts, and is better described as an application stack.

1.2.1. A complete application stack

Let’s consider the distinction between an application stack and a web framework. Web frameworks are analogous to the guests who show up just in time for dinner and then leave immediately after eating. They entertain and soak up the limelight, but they are mostly unhelpful. They go out the same way they arrived: with lots of flair. An application stack, in contrast, is like the people who help to plan the dinner party, shop for the groceries, cook, set up, serve, make the coffee, and then ultimately clean up when it is all over. They are steadfast and resourceful. Sadly, their work goes mostly unrecognized.

In a world where everyone wants to be a rock star (i.e., web framework), Seam is your practical sidekick, your sous-chef. The Seam application stack includes the framework, the libraries, the build script and project generator, the IDE integration, a base test class, the Embedded JBoss container, and integrations with many technologies. Seam is certainly a hard worker. Figure 1.2 gives a sample cross section of the technologies that Seam is capable of pulling together in a typical application.

Figure 1.2. A cross section of the technologies incorporated in the Seam stack

While this stack gives you an idea of the technologies used in a Seam application, it does not give you a clear picture of Seam’s purpose and why it exists. To understand why Seam was created, you have to recognize the challenge that it faced. Although the Java EE 5 release took a gigantic step toward establishing an agile platform for enterprise Java development, it left behind a rather significant gap between the component-based web tier managed by JSF and the component-based business-tier managed by EJB 3. A bridge was needed.

1.2.2. Why Seam was created

The Java EE 5 specification incorporates two key component architectures (specifications for creating reusable objects) for creating web-based business applications: JavaServer Faces (JSF) 1.2 and Enterprise JavaBeans (EJB) 3. JSF is the standard presentation framework for the web tier that provides both a user interface (UI) component model and a server-side event model. EJB 3 is the standard programming model for creating secure and scalable business components that access transactional resources. EJB 3 also encompasses the Java Persistence API (JPA), which defines a standard persistence model for translating data between a relational database and Java entity classes.

Aside from their residence in the Java EE 5 specification, the two architectures just mentioned share little resemblance, their backs facing each other like two sides of a coin. This communication barrier casts a shadow on the tremendous potential of each technology. While it’s true that developers are able to get these two Java EE tiers to work together, it requires a lot of “glue” code. Seam absorbs that responsibility and fits JSF and EJB 3 together, thus ironing out one of the roughest spots in the Java EE 5 specification and completing the missing link in the evolution of the Java EE platform. As such, Seam has positioned itself as the prototype for future Java EE specifications. So far, three Java Specification Requests (JSRs) have been accepted: JSR 299 (Web Beans), JSR 314 (JavaServer Faces 2.0), and JSR 303 (Bean Validation). Seam isn’t married to JSF or EJB 3, as figure 1.2 suggests. You can swap in alternative view technologies such as Wicket, Tapestry, GWT, and Flex in place of JSF, though understandably with less accord. In the business tier, Seam supports the use of JavaBeans as transactional components and also boasts integration with the Spring container, both of which are arguably better choices than EJB 3.

With that said, becoming an important part of Java EE’s future and an integration point for many open source technologies is not what sparked Seam. That’s just what Seam has managed to accomplish. As with most software projects, Seam was started to scratch a single developer’s itch.

The Real Story

As the story (really) goes, Gavin King was fed up with developers using Hibernate improperly by trapping it inside of the stateless design proliferated by the Spring Framework. Recognizing that the missing integration between JSF and EJB 3 would only lead to further abuse of Hibernate as a JPA provider, he decided to step up and build a foundation that would allow the persistence context (Hibernate Session or JPA EntityManager) to transcend layers and would permit stateful session beans to respond directly to JSF UI components. To support this vision, Seam encourages the adoption of a stateful, yet efficient, architecture. As a result, applications built on Seam have effortless continuity from one user interaction (or event) to the next, a feature that is labeled a web conversation. The keen focus on variable scoping is what makes Seam contextual.

The name Seam was chosen for the project because it provides a foundation that brings JSF and EJB 3 together and teaches them to play nicely together in the same sandbox. In the process of solving the mismatch between JSF and EJB 3, the Seam architects broadened the solution to include any Plain Old Java Object (POJO) acting as a business component, not just the EJB 3 variety. Seam’s universal component model brings the implicit and declarative services provided by the EJB 3 programming model, such as transactions, interceptors, threading, and security, to non-EJB components such as JavaBeans and Spring beans. For non-EJB components, Seam takes on the role of processing the Java EE 5 annotations—or synonyms of these annotations from the Seam API—and weaves in the managed services. What this means is that you do not have to rely on an EJB 3 container to leverage the benefits that EJB 3 provides. You may even want to reconsider the use of EJB 3 unless you have a specific need for it, choosing to go with JavaBeans instead. Regardless of your choice, you aren’t required to deploy a Seam application to the JBoss Application Server, despite what you may have heard.

1.2.3. Debunking the “vendor lock-in” myth

I don’t want to be shy about addressing the myth that Seam is a JBoss-focused technology or that by using Seam, you get locked into JBoss. The Seam development team isn’t hesitant about making recommendations against the JBoss party line. The Seam application stack is an aggregation of best-of-breed technologies known to work well together. Seam is no more a JBoss technology than Struts is an Apache technology or Spring is a SpringSource technology. An examination of the most successful complex projects in enterprise Java outside of JBoss, such as Spring, Hibernate, Eclipse, and the Java EE platform itself, reveals that these projects are supported by organizations with paid developers. Seam is open source and can be whatever you, the community,[1] drive it to be. Although the projects may be hosted in the JBoss Labs under the roof of JBoss/Red Hat, the source code is yours to copy, share, and modify. Specifically, JBoss Seam is licensed under the Lesser GNU Public License (LGPL), which is considered one of the more flexible options.

1http://www.seamframework.org is the main community site for Seam.

Seam was designed to be container agnostic and much effort has gone into ensuring that Seam is compatible with all major application servers, including BEA WebLogic, IBM WebSphere, Oracle Containers for Java EE (OC4J), Apache Tomcat, and GlassFish. But the compatibility runs deeper than deployment. The improvements that Seam has introduced into Java EE are being contributed back into the platform as standards using the Java Community Process (JCP) as a vehicle and captured in JSR 299: Web Beans, as mentioned earlier. The goal of this JSR is to unify the JSF managed bean component model with the EJB component model, resulting in a significantly simplified programming model for web-based application development. The effect of this JSR is that it will foster alternative implementations of Seam’s innovations.

With an understanding of why Seam exists, and faith that you are not getting locked into JBoss by choosing this technology, you now need to consider whether Seam is the right framework for you based on technical merit. After all, Seam may have saved Java EE, but can it fit the bill as your development framework of choice?

1.2.4. Making the case for Seam

Is there really a need for another application framework? Wasn’t Spring supposed to be the one framework to rule them all? I’ll let the success of Ruby on Rails, and the wave of Java developers flocking to it, prove that the need for a suitable Java application framework—or, in some developers’ minds, an entire programming environment—remains. So, should you follow the crowd? My advice is to look before you leap.

Promising that a framework will make the job of developing applications simpler is lip service. Just because you are able to create a throwaway blog application with a framework doesn’t make it viable. To earn the right to be called enterprise software, the framework has to stand up to the challenges of the real world, warts and all, and help the developer create well-designed, robust, and readable code. That is Seam’s goal. Seam eliminates complexity and makes proven libraries more accessible. Seam doesn’t turn its back on the pervasive Java EE platform, but rather serves as the glue that makes it truly integrated. Rather than encourage you to forget everything you know, Seam finds a way to allow you to use the Java EE services in a more agile way, while also providing enough new toys, in the form of extensions and third-party integrations, to make using it fun and interesting.

Here is a small sampling of the many improvements that Seam brings to the Java EE platform, all of which succeed in making the platform simpler:

  • Eliminates the shortcomings in JSF that have been the subject of countless rants
  • Mends the communication between JSF and transactional business components
  • Collapses unnecessary layers and cuts out passive middle-man components
  • Offers a solution for contextual state management, discouraging the use of the stateless architecture (i.e., procedural business logic)
  • Manages the persistence context (Hibernate Session or JPA EntityManager) to avoid lazy initialization exceptions in the view and subsequent requests
  • Provides a means for extending the persistence context for the duration of a use case
  • Connects views together with stateful page flows
  • Brings business processes to the web application world
  • Plugs in a POJO-based authentication and authorization mechanism backed by JAAS that is enforced at the JSF view ID level, accessible via the EL, and can be extended using declarative rules and ACLs
  • Provides an embedded container for testing in non-Java EE environments
  • Delivers more than 30 reference examples with the distribution

As you can see, Seam isn’t shy about addressing problems in the platform, particularly those with JSF. For existing JSF developers, the first bullet point is enough to justify the need for this framework. They can attest to that fact that JSF can be quite painful at times. That is no longer true with Seam’s aid. The second point justifies Seam’s usefulness in standards-based environments, where Seam fits in quite naturally. But Seam doesn’t stop there. It encourages developers to collapse unnecessary layers to achieve simpler architectures and promotes the use of long-running contexts to relieve the burden of state management. Aside from improving the programming model, Seam provides a tool that prepares the scaffolding of a Seam-based project; generates a create, read, update, delete (CRUD) application from an existing database schema; makes integration testing easy; and serves up Ajax in a variety of ways.

1.3. Seam’s approach to unification

Seam revitalizes the standard Java EE platform by putting an end to its divergence and unifying its components, filling in the voids for which it is often criticized, making it more accessible, extending its reach to third-party frameworks and libraries, and form-fitting them all together as a well-integrated and consistent stack. While the features of Seam are vast, Seam’s core mission is getting JSF, JPA, and POJO components to work together so that the developer’s focus can be placed on building the application, not on integrating unallied technologies.

1.3.1. Seam integrates JSF, JPA, and POJO components

Getting technologies to work with one another is more than just having them pass messages back and forth. It’s about creating an interaction that blurs the boundary between them, making them act as a single, unified technology. Seam achieves this integration by fitting EJB 3 up against the web tier, finding a place for JPA, and scrapping the ineffectual JSF managed bean container. After reviewing how Seam tackles these challenges, you get a chance to determine which Seam stack is right for you.

Helping Out a Web-Challenged EJB 3

By design, EJB components cannot be bound directly to a JSF view. It’s great that EJB components are scalable, transactional, thread-safe, and secure, but it doesn’t do much good if they are completely isolated from the web tier, accessible only through a JSF backing bean acting as an intermediary. This isolation makes them of limited use in web applications because of the complexity involved to integrate them. They are not able to access data stored in any of the web-tier scopes (request, session, and application) or the JSF component tree, thus impairing their insight into essential parts of the application. (The goal here is really just to give EJB 3 components access to Seam’s stateful scopes.) Also, it’s easy to get into trouble with concurrency when using EJB components from the web tier. For instance, the Java EE container is not required to serialize access to the same stateful session bean, leaving it up to the developer to take care of this task or catch the exception that can result. Also, complexities arise when dealing with non-thread-safe resources such as the JPA EntityManager. The only way the developer can safely use EJB components in the web tier is by interfacing with an adapter layer.

Seam gives EJB 3 components access to web-tier scopes, offers a way to manage the state of EJB 3 components so that they can be used safely in the web tier, and even serializes access to stateful components to make concurrency issues a responsibility of the infrastructure and not the developer. Also, there is never a question about accessing non-thread-safe resources since Seam handles the scoping properly.

Turning the tables, JSF faces equivalent challenges accessing business-tier components.

Hooking JSF to a Better back End

JSF has its own “managed” bean container that is configured using a verbose XML descriptor, as opposed to the annotation-based configuration in EJB 3, and has a limited dependency injection facility. While JSF managed beans can be stored in the web-tier contexts, they are barren objects, lacking scalability, transaction atomicity, and security (probably why they are termed beans and not components). They must reach out to an EJB 3 component to attain these business services. What you find is that you’re stuck creating this façade layer to bridge EJB 3 components to the UI that acts on them.

To correct this mismatch, Seam enables JSF UI components to tap right into the EJB layer by allowing EJB 3 components to stand in as JSF “backing” beans and action listeners. There’s no longer a need for the managed bean façade layer and its verbose XML descriptor. By eliminating the complexity caused by the mismatch, it encourages developers to relax stringent mandates on overarchitected designs.

Which Seam are You?

Seam is not just a collection of classes and artifacts that get dropped on your desk with the disclaimer “Some assembly required.” The key to Seam’s success is that it offers a handful of well-tested bundles that operate fluently. These bundles include compatible versions of many third-party libraries. You can liken the offering to the simplicity of buying a Mac when compared to buying a Dell. When you buy a Dell, you can customize the assembly down to the last stick of RAM. You get a product customized exactly to your needs, but getting there requires a lot of thought and effort on your part. Buying a Mac is much simpler in comparison. You choose between a laptop and a notebook, and then you select a screen size. Everything else is just details that Apple works out for you. Seam has a comparable set of options. You choose a state provider and a persistence provider (and, down the road, a web framework). Everything else is just details that the Seam developers work out for you. By removing the burden of too many choices, Seam can make life for the developer simpler.

The two main technology choices in a Seam application, summarized in figure 1.3, are the state provider and the persistence provider. The state provider is the technology that handles the application logic and responds to events in the UI. The persistence provider transports data to and from persistence storage. Seam manages the persistence provider to allow for the persistence context to be extended across a series of pages and shared among multiple components.

Figure 1.3. Seam’s stack matrix, with options for a state and persistence provider

As mentioned earlier, Seam does not require you to use EJB 3. You have the option of using basic JavaBeans along with Hibernate without fear that you are losing out on functionality. The term JavaBean broadly encompasses all non-EJB components, so Spring beans apply here as well. Another popular choice is to partially adopt EJB 3 by combining JPA with JavaBeans, which is the bundle used by the example application in this book.

Prior to Seam, getting these technologies to work together meant integrating the containers that manage them. EJB 3 has its container. JSF has one too. Spring is yet another. Once again, the task of writing this glue code fell on the shoulders of the developer. The need for a central integration point gave rise to Seam’s contextual component model.

1.3.2. The contextual component model

At the heart of Seam is the contextual component model. Before your eyes gloss over, give me three short sentences to make this term meaningful to you. (1) Seam is a factory that constructs objects according to component definitions. (2) After creation, each object is stored in the container under one of several contexts (i.e., variable scopes) with varying lifetimes, making the objects contextual and capable of holding state (i.e., stateful). (3) Seam promotes the interaction of these stateful objects across contexts, assembling them together according to metadata associated with their respective classes. Chapter 4 explores components and contexts in depth and gives you an opportunity to learn how they are used in an application.

In this section, you learn how this model provides the basis for the unification of the technologies previously discussed. The unification is facilitated by a combination of the component registry, annotations, configuration by exception, method interceptors, and the unified Expression Language (EL).

A Central Component Registry

Seam rakes in all of the Java EE components into a central registry, whether they are EJB session beans, JavaBeans, Spring beans, or JPA entities. Any technology incorporated into the Seam stack can look to the Seam container to retrieve instances of the components by name and collaborate with the container to exchange state. Technologies that have access to the container include Seam components, JSF view templates, Java Business Process Management (jBPM) process definitions, Java Process Definition Language (jPDL) page flow definitions, Drools rules, Spring beans, JavaScript, and more. Seam’s container also unifies the variable scopes of the Servlet API while introducing two of its own stateful scopes, conversation and business process, that are better suited to support user interactions.

Of course, components aren’t just going to fall into this registry; they have to be recruited. Seam scours the classpath and enlists any class that contains a marker annotation, discussed next, that identifies it as a Seam component.

Annotations Over Xml

One way that Seam cuts down on the configuration overhead of Java EE is by eliminating needless XML. Although once thought to be desirable because of is flexibility, XML is external configuration and quickly becomes out of sync (and out of touch) with the application logic. Seam brings configuration back in line with the code where it is easier to locate and can be refactored.

When the temptation arises to define JSF managed beans in XML, Seam just says “No!,” a tenet that is captured in figure 1.4. Seam reduces the declaration of a component to a single annotation, @Name, placed above the class definition. Seam components can take the place of JSF managed beans.

Figure 1.4. Seam cuts down on superfluous XML configuration that’s difficult to keep in sync with the source code.

With enough dedication, you can avoid the use of XML in Seam altogether, which is quite surprising given the number of places it could be warranted. Seam only resorts to XML when annotations do not suffice or to isolate deployment overrides. If you are not a fan of annotations, don’t go running for the door just yet. Seam still allows you to define components using XML, which is the main topic of chapter 5. Annotations are just more concise and easier to maintain, in my opinion.

Moving to annotations is more than just improving the efficiency of keystrokes. Annotations are the central piece of Seam’s configuration by exception strategy, conserving keystrokes until they are really necessary.

Configuration by Exception

A good way to describe configuration by exception is by saying that the software is “opinionated.” The general idea is that the framework happily prefers to operate as designed. The more you embrace the defaults, the less work you have to do. You are only required to step in and play a part when the software needs to do something different than the typical behavior.

In Seam, configuration by exception goes hand in hand with annotations. The annotations give Seam a hint to apply behavior and Seam tries to assume as much as possible about the declaration by relying on sensible defaults and standard naming conventions to keep your load light. In this way, Seam offers a nice balance between explicit declarations and assumed functionality.

While annotations cut down on keystrokes, there’s more to annotations than just the elimination of XML. Annotations supply extra metadata to the class definition, where it is easier to find and refactor than metadata stored in external descriptors.

Decorating Components with Services

Since components are requested through the Seam container, Seam has an opportunity to manage the instances throughout their life cycle. Seam wires the object with interceptors, wrapping it in a shell known as an object proxy, before handing down the newly created instance. This allows Seam to act as the object’s puppeteer, pulling on its strings during each method call to add behavior, as depicted in figure 1.5. Interceptors account for much of the implicit logic in Seam that makes it “just work.” Examples include beginning and committing transactions, enforcing security, and getting objects to socialize with one another. Annotations on the class definition give the interceptors a hint of how to apply the extra functionality, if for some reason it can’t be implied or needs to be different than the default behavior.

Figure 1.5. Interceptors trap method calls and perform cross-cutting logic around a method invocation.

The final piece to the unification puzzle is to give the application a way to access components in the container using a universal syntax. That’s the role of the unified EL.

Extending the Reach of the Unified EL

The unified EL is an expressive syntax used to resolve variables and bind components to properties and methods on JavaBeans. It was first introduced to better integrate JSF with JavaServer Pages (JSP), to look up managed beans and other objects stored in web-tier scopes, and to serve as the basis for the JSF binding mechanism. Its impact, however, is far more widespread, thanks to its pluggable design.

The EL is an open API that allows custom resolvers to be registered, thus turning the EL into a variable hub. Consequently, any layer of the code that wants to tap into the EL unified variable context can do so using the public API. Thus, the EL frees you from having to develop a custom bridge between the variable contexts used by the different technologies in your application. Although you’re used to seeing the EL only in the view, there isn’t anything web specific about it.

Seam takes advantage of the EL in two ways. First, it registers a custom EL resolver that is aware of the Seam container. This allows Seam components to be accessed using EL notation from anywhere in the application where the EL is available (which is pretty much everywhere). Second, Seam makes heavy use of the EL under the covers, allowing EL notation to be used in annotations, configuration descriptors, log and message strings, Java Persistence Query Language (JPQL) queries, page flow definitions, and even business processes. With Seam, the EL truly is unified.

Despite all that has been said about Seam, nothing speaks to a programmer like lines of code. To help demonstrate why Seam is a sound choice and how it saves you valuable development time, I am going to whet your appetite with a brief example. In chapter 2, you’ll get a chance to sink your teeth into Seam by building an entire application with just a couple of commands.

1.4. Your first swings with Seam

To demonstrate some of the core principles of Seam, I’m going to step you through a basic application that manages a collection of golf tips. Don’t worry about trying to understand everything that you see here. Instead, focus on how Seam relies on annotations to define components, how the layers of the application are pulled together through the unified component model, and the high signal-to-noise ratio in the business logic thanks to configuration by exception. I demonstrate a densely packed set of features in this example, so don’t think that you have to use all of these techniques in order to use Seam.

We all want to be better golfers (at least, those of us who torture ourselves with the sport). Focusing on a simple golf tip can help shave off a couple of strokes from your round. To keep track of the tips that you collect from the pros, buddies, and articles, you’re going to slap together a Seam application that reads and writes these tips to a database. Aside from the deployment artifacts, which aren’t considered in this example, there are only a handful of files that you need to produce a functional application.

1.4.1. Entity classes serving as backing beans

I’ll start by discussing the GolfTip JPA entity class, shown in listing 1.1. In a Seam application, entity classes serve two purposes. Their primary role is to carry data to and from the database. The object-relational mapping (ORM) mechanism, as this is called, is not part of Seam per se. That work is handled either by JPA (the standard Java persistence framework) or Hibernate, though you discover in chapter 8 how Seam can bootstrap the ORM runtime and regulate the lifetime of the ORM’s persistence manager.

The second role of entity classes in a Seam application is to serve as form “backing” beans (akin to a Struts ActionForm) to capture input from the user, thus replacing the need for a shallow “backing” bean class. An entity class becomes a candidate for use in a JSF view if it has a @Name annotation on its class definition, a condition that is satisfied by the GolfTip class in listing 1.1. You then bind the form inputs directly to properties on the entity class and JSF handles the necessary conversions and validations.

Listing 1.1. The JPA entity class that represents a golf tip
  @Entity     
  @Name("tip")      
  public class GolfTip implements Serializable {
     @Id @GeneratedValue     
     protected Long id;

     protected String author;

     protected String category;

     protected String content;

     // getters/setters for author, category and content not shown
  }

The keywords prefixed with the @ symbol are Java 5 annotations. The @Name annotation , shown in bold, is a Seam annotation that registers the GolfTip class as a Seam component named tip. Whenever the context variable tip is requested from the Seam container, Seam creates a new instance of the GolfTip class, binds the instance to the tip context variable in the conversation context (the default scope for entity classes), and returns the instance to the requester.

The remaining annotations in this class pertain to JPA. The @Entity annotation associates the GolfTip class with a database table by the same name. The @Id annotation indicates to JPA which property is to be used as the primary key. The @GeneratedValue annotation enables automatic surrogate key generation in the database. All of the other properties on the class (author, category, and content) are automatically mapped to columns with the same name as the respective property in the GolfTip table, following configuration by exception semantics.

As you can see, using the @Name annotation gives you one less file to worry about (that of the JSF managed bean facility and its verbose XML dialect). Staying away from the managed bean configuration is one of the early benefits of moving to Seam components. Another compelling advantage of adopting Seam is being able to bind the action of the UI command component to a method on a transactional business object.

1.4.2. An all-in-one component

As with entity classes, there’s no need to create a dedicated managed bean to act as a mediator between the JSF page and the service object in Seam. Instead, the service object can respond directly to an action invoked in the UI. At first, that might sound like a bad idea because it appears to cause tight coupling between the UI and the application logic. Seam prevents this coupling by acting as the mediator. As a result, the action component does not have to contain a single reference to a JSF resource. In fact, in chapter 3 you discover that the return value of the method need not serve as a logical outcome for a navigation rule—a typical requirement of JSF managed beans—since Seam can evaluate an arbitrary EL value expression for this purpose. This example relaxes the separation from JSF to keep the number of classes to a minimum.

In the golf tips application, the TipAction class, shown in listing 1.2, is declared as a Seam component using the @Name annotation and is thus capable of having its methods bound to UI controls. It handles the add and delete operations in the golf tips interface.

Listing 1.2. The action listener for the JSF view

Like the GolfTip entity class, the @Name annotation marks the TipAction class as a Seam component, this time scoped to the event context (the default scope for JavaBean components). What sets this component apart from the GolfTip entity class is that it is capable of having other components “wired” into it because the @In annotation is placed above certain fields of the class , a mechanism known as bijection. In this example, the two dependent components are the JPA EntityManager and Seam’s built-in JSF messages manager. This component also prepares a collection of GolfTip objects for use in the JSF view ; captures the GolfTip that the user selects from that collection, making it available to both the method handling the event and the subsequent view ; and interpolates the active GolfTip in the JSF status messages .

The TipAction component packs a lot of functionality in a limited amount of space. What I want you to recognize is that, aside from the annotations, there’s practically no evidence of infrastructure code in this class. Apart from creating the status messages, the only code that you’re required to write is code that reads, persists, and removes tips from the database using the JPA EntityManager instance. It’s probably best to push this code into a data access object (DAO), which may also be a Seam component, but Seam doesn’t impose this architectural requirement on you. Seam’s focus is on frugality, as demonstrated in this example. Absent are any Servlet API calls that read request parameter values or set request or session attributes. Instead, the component consists solely of business logic.

1.4.3. Binding components to the view

Seam bridges the layers in the golf tips application by binding both the properties of the entity class and the methods of the action component to elements in the JSF view. Figure 1.6 shows the golf tips user interface. Behind this rendered page is a Facelets template, golftips.xhtml, which associates value- and method-binding expressions to elements on this page to output data, capture form input, and respond to user actions. Use this figure to follow along with the discussion of how the JSF view interacts with the Seam components in the server.

Figure 1.6. The golf tips page, which renders the collection of tips at the top and a form for contributing a new tip at the bottom

 

Note

The file extension .xhtml indicates that this file is a Facelets template. Facelets is an alternative view handler for JSF that was created to escape the mismatch between the JSF and JSP life cycles. Facelets is the preferred view technology for Seam applications and is used throughout the book.

 

Start by focusing your attention on the form that is used to submit a new tip at the bottom of the page. Each input element is bound to properties on the GolfTip entity class using EL notation (e.g., #{tip.author}). When used in the value attribute of an input element, the EL notation acts as a value-binding expression. It captures the form value and transfers it to an instance of the GolfTip entity class as part of the JSF life cycle. Here’s the (slightly trimmed-down) fragment of the JSF template that renders the form:

  <h:form>
    <h3>Do you have golf wisdom to add?</h3>
    <div class="field">
      <h:outputLabel for="author">Author:</h:outputLabel>
      <h:inputText value="#{tip.author}"/>
    </div>
    <div class="field">
      <h:outputLabel for="category">Category:</h:outputLabel>
      <h:selectOneMenu value="#{tip.category}">
        <f:selectItem itemValue="The Swing"/>
        <f:selectItem itemValue="Putting"/>
        <f:selectItem itemValue="Attitude"/>
      </h:selectOneMenu>
    </div>
    <div class="field">
      <h:outputLabel for="content">Advice:</h:outputLabel>
      <h:inputTextarea value="#{tip.content}"/>
    </div>
    <div class="actions">
      <h:commandButton action="#{tipAction.add(tip)}"
        value="Submit Tip"/>
    </div>
  </h:form>

Seam makes the association between the value-binding expressions used by the input fields and the GolfTip entity class through the context variable tip. The @Name annotation on the GolfTip class binds the class to the tip context variable. When the tip context variable is referenced by a value expression in the JSF template (#{tip.*}), Seam instantiates the GolfTip class and stores the instance in the Seam container under the variable name tip. All the value expressions that reference the tip context variable are bound to that same instance of the GolfTip class. When the form is submitted, the input values are transferred to the properties of the unsaved entity instance.

Let’s consider what happens when the form is submitted. With Seam working in conjunction with JSF, any interaction with the Servlet API is abstracted away. Instead, you work through declarative bindings. The method-binding expression specified in the action attribute of the submit button, #{tipAction.add(tip)}, indicates that the TipAction component serves as the action component for this form and that when the button is activated, the add() method is invoked. Notice that this method expression actually passes the GolfTip instance associated with the tip context variable directly into the action method as its sole argument, which effectively makes the form data available to the method. Seam provides parameterized method-binding expressions as an enhancement to JSF. When the method completes, the list of tips is refreshed and the page is once again rendered.

1.4.4. Retrieving data on demand

What makes Seam so powerful is that it includes a mechanism for initializing a variable on demand. The top half of the screen in figure 1.6 renders the collection of tips in the database using the following markup:

  <rich:dataGrid var="_tip" value="#{tips}" columns="1">
    <rich:panel>
      <f:facet name="header">
        <h:outputText value="#{_tip.author} on #{_tip.category}"/>
      </f:facet>
      <h:outputText value="#{_tip.content}"/>
      <h:commandLink action="#{tipAction.delete}">
        <h:graphicImage value="/images/delete.png" style="border: 0;"/>
      </h:commandLink>
    </rich:panel>
  </rich:dataGrid>

The focal point of this markup is the #{tips} value expression. Notice that tips is not the name of one of the Seam components in the golf tips application. However, it is referenced in the value attribute of the @Factory annotation above the retrieveAllTips() method of the TipAction class from listing 1.2. The purpose of this method is to initialize the value of the tips context variable when it’s requested. Subsequent requests for the same variable return the previously retrieved value rather than triggering the method to execute again.

But hold on a minute! The retrieveAllTips() method doesn’t return a value. How is the value passed back to the view renderer? That’s where things get a little tricky. After executing this method, Seam exports properties of the component that are annotated with either @Out or @DataModel to the view. Seam notices that the @DataModel annotation is assigned to the tips property on the TipAction component. That tells Seam not only to export its value to the tips context variable, but also to wrap the value in a JSF DataModel instance. The view iterates over this wrapped collection to render the data grid. The reason the collection is wrapped in a DataModel is to enable clickable lists to support the delete functionality.

1.4.5. Clickable lists

The scope specified on the annotation is ScopeType.PAGE, which instructs Seam to store the collection of tips in the JSF component tree. Since the data model is being stored in the JSF component tree, it is made available to any JSF action that is invoked from that page (resulting in a “postback”).

The #{tipAction.delete} method expression, bound to the delete link adjacent to each golf tip, benefits from the propagation of the tips data model through the JSF component tree. When the user clicks one of the delete buttons, the data model is restored along with the JSF component tree. When JSF processes the event, the internal pointer of the data model is positioned to the index of the activated row. This is where the complement to the @DataModel annotation, the @DataModelSelection annotation, is used. This annotation reads the current row data (the instance of GolfTip) from the data model and injects it into the property over which the annotation resides. All the action method has to do is pass the instance of the selected GolfTip to the JPA EntityManager to have it removed from the underlying database. Once again, the action component remains void of infrastructure code. Compare that to the JSF blueprints.[2]

2https://bpcatalog.dev.java.net/nonav/webtier/index.html

All that’s left is to write a quick end-to-end test to ensure that we can save a new tip and that it can be subsequently retrieved.

1.4.6. Integration tests designed for JSF

The area of development that has routinely slowed down Java EE developers most often is testing. Even if you’ve never written a test, you’re still testing. You test your code every time you redeploy your application or restart the application server to view the result of your latest modifications. It’s just slow and boring to do it that way. These days, testing is an integral part of any application development, and no framework is complete without an environment that allows you to test “outside of the container.” Seam once again demonstrates its simplicity by exposing a single test class that can handle all of the integration testing needs in a Seam-powered application.

To make integration testing of JSF actions a breeze, Seam provides a base test class that sets up a stand-alone Java EE environment and executes the JSF life cycle within the test cases. The test infrastructure is driven by TestNG,[3] a modern unit-testing framework that can be configured using annotations. Although TestNG doesn’t require you to inherit from a base test class, Seam’s testing framework uses this approach to set up the fixture needed to bootstrap the embedded Java EE environment and the JSF context.

3http://www.testng.org

The test class GolfTipsTest in listing 1.3 simulates the initial request for the golf tips page and the subsequent form submission to add a new tip. The code in the test is invoked nearly identical to when it’s used in the deployed application.

Listing 1.3. An end-to-end test of the golf tips application using the Seam test framework

Listing 1.3 tests both the initial rendering of the JSF view and the subsequent JSF action triggered from the rendered page. The first request is an HTTP GET request, which simulates the user requesting the golf tips page in the browser. This part of the test verifies that when the tips are retrieved in the Render Response phase, Seam properly resolves a DataModel, but the collection underlying that model is empty. The second part of the test simulates the user submitting the form to create a new tip. The Update Model Values phase performs the work JSF does to bind the input values to the value expressions. The method expression that is bound to the submit button is then explicitly invoked. Because Seam automatically wraps the Invoke Application phase in a transaction, there is no need to worry about beginning and committing the transaction. Finally, in the Render Response phase, the test verifies that when the tips are retrieved this time, exactly one tip is found and that the author’s name has been interpolated properly in the message displayed to the user. This test is intentionally terse. There are, of course, many other scenarios that could be verified. Focus instead on how easy it is to exercise a Seam application using this simple test framework and how you can leverage EL notation to perform assertions.

Hopefully the golf tips application has given you a general understanding of how Seam simplifies your application and saves you time by relying on a centralized container, annotations, configuration by exception, and the unified EL. That’s the essence of Seam. I now want to give you an idea of what else Seam offers before you begin your journey down the road to becoming a Seam master.

1.5. Seam’s core competencies

Throughout this chapter, there has been a lot of discussion about how Seam resolves issues in Java EE. I want to leave you with an understanding of how Seam is going to help your development process. Given how much Seam has to offer, this was a challenging exercise, but I’ve been able to summarize its benefits into three core competencies. Seam offers a better JSF, allows you to get rich quick, and fosters an agile environment.

1.5.1. Turns JSF into a pro

Although JSF isn’t without flaws, it was selected as the main presentation framework in Seam because of its extensible request life cycle and strong UI component model. Realizing its potential, Seam taps into this design to strengthen JSF, making it a compelling and modern technology for creating web-based interfaces. While it’s true that Seam supports alternative view technologies, this book primarily focuses on using Seam with JSF. Much of this coverage comes in chapter 3, which covers Seam’s extension to the JSF life cycle.

Enhancing JSF

Seam’s most recognizable improvement to JSF is eliminating the requirement to declare managed beans in the JSF descriptor. In addition, Seam adds a rich set of page-oriented functionality, covered in chapter 3, that makes the navigation rules in the JSF descriptor obsolete as well. These features include

  • Prerender page actions
  • Managed request parameters (for a given page)
  • Intelligent stateless and stateful navigation
  • Transparent JSF data model and data model selection handling
  • Fine-grained exception handling
  • Page-level security (per view ID)
  • Annotation-based form validation
  • Bookmarkable command links (solving the “everything is a POST” problem)
  • Entity converter for pick lists
  • Conversation controls
  • Support for preventing lazy initialization exceptions and nontransactional data access in the view

Part of the cleaning-out process of JSF involves purging passive connector beans that do nothing more than adapt UI events to back-end business components.

Eliminating Connector Beans

Any Seam component can be connected to a JSF view using EL bindings. Figure 1.7 shows the design of an interaction between a UI form and an EJB 3.0 session bean (or regular JavaBean) that completely eliminates the need for the legacy connector bean. The form inputs are bound directly to the entity class and the session bean is bound to the Save button to handle the action of persisting the data.

Figure 1.7. Seam cuts out the middleman by eliminating the need for a JSF backing bean. Instead, the entity class and the EJB 3.0 session bean work together to capture data from the UI and handle the event to persist the data.

By cutting out the middleman, not only does Seam allow you to eliminate a class that you have to write and maintain, but it allows you to cut back on the number of layers, thus allowing your applications to become more lightweight.

Aside from providing universal access to components, the Seam container augments the coarsely grained scopes in the Java servlet specification—request, session, and application—to include scopes that make more sense from the perspective of the application user. Seam offers two “stateful” contexts that are used to support single and multiuser pages flows in an application.

Introducing Stateful Variable Scopes

One of the main challenges with developing applications that are delivered over the web is learning how to efficiently propagate data from one page to the next—so-called state management. The two go-to options are hidden form fields or the HTTP session. The first is cumbersome for the developer, and the second eventually eats through precious server resources and hurts an application’s ability to scale.

Seam addresses need for stateful variable scopes whose lifetime aligns with user interactions by adding the conversation context and business process context to the standard web scopes. The conversation scope, covered in chapter 7, maintains data for a single user across a well-defined series of pages while the business process scope, covered in chapter 14 (online), is used to manage data that supports multiuser flows complete with wait states. The relationship between the lifetime of the scopes managed by the Seam container is illustrated in figure 1.8.

Figure 1.8. The lifetimes of the six scopes in a Seam application. The standard scopes are represented by dashed lines. The scopes that Seam contributes appear as solid lines. The business process scope is persisted to a database and can thus outlive the application scope across server restarts.

The conversation context is tremendously important in Seam not only because it is so unique and gives the user a better experience, but because it makes working with an ORM tool easy on the developer.

Extending the Persistence Context

When you talk to the database using ORM, you use a persistence manager (i.e., JPA EntityManager or Hibernate Session). Each instance of a persistence manager maintains an internal persistence context, which is an in-memory cache of entity instances that have been unmarshaled from the database. Given that databases are among the most expensive and heavily used resources in your server room, you want to leverage this in-memory cache as much as possible to avoid redundant queries. Extending the persistence context across the entire request is a step in the right direction (the socalled Open Session in View Pattern), but having it extend across multiple page requests is even better. Prior to Seam, there was just no good place to stick it, and as a result, each request reset the persistence context to a blank slate.

Seam takes control of the persistence manager and stores it in the conversation context. As a result, Seam is able to carry it, along with its persistence context, across the duration of an entire use case, potentially spanning more than one request, as shown in figure 1.9. Extending the persistence context across the three operations in this feature allows the entity instance to remain managed by the persistence context and monitored for changes that need to be written to the database. This ensures object identity and can guarantee atomicity of the operation.

Figure 1.9. Using the extended persistence context to keep an object in scope for an entire use case, even across multiple page views. The extended persistence context avoids the need to merge detached entity instances.

With Seam in control of the persistence manager, lazy initialization exceptions (LIEs) are also a thing of the past since the persistence manager remains open throughout the use case and can thus load additional records as needed. The conversation and persistence context fit together so naturally that the conversation has been dubbed Seam’s unit of work. You learn all about the interaction between the two in part 3.

1.5.2. Gets you rich quick

Seam gives you tools to build rich, Web 2.0 applications or to gently weave this richness into an existing page-oriented application. Lately, the term “rich” has become synonymous with a desktop-like experience in the web browser driven by Ajax. There are two approaches you can take to incorporate Ajax into a Seam application. You can use Ajax-enabled JSF components, such as RichFaces or ICEfaces, or you can invoke server-side components directly from the browser using JavaScript remoting. Seam extends the meaning of rich to incorporate media such as PDFs, charts, and graphics.

Tapping into the JSF Ecosystem

Web user interfaces are getting more and more sophisticated, and it is unreasonable to think that you can code the XHTML and JavaScript from scratch and get the job done cheaply. You need to build on what others have done. That is one of the primary goals of JSF and why Seam went with JSF as the primary UI framework.

JSF is all about putting widgets on the screen. It decouples the design of a UI component from its use. Similar to widgets in Swing, JSF components are general solutions to common controls. This time, the vendors really did come through. There are loads of component libraries for JSF that range from basic data tables, to tree structures, to drag-and-drop targets.

Historically one of the most entangled parts of an enterprise application is the UI (let’s share hideous JSP files). By moving to JSF, the UI becomes a much simpler place. You don’t even need a WYSIWYG IDE because visualizing what these components render is quite reasonable. They are human-friendly, rather than tool-friendly. With JSF, the UI finally has an API too.

While JSF has its place, if you are looking for a lighter way to communicate with the server, Seam’s JavaScript remoting library is a great alternative.

Javascript Remoting

Invoking server-side components from JavaScript in Seam couldn’t be easier, as chapter 12 proves. You simply add the @WebRemote annotation to the Seam component method that you want to call from JavaScript, import the JavaScript remoting library into the web page, and then invoke the component method using a JavaScript client stub of the component. Seam handles the rest. The punchline of this feature is that it opens the door to creating single-page applications with Seam.

Although Ajax gets most of the attention these days when web applications are discussed, there are other ways to make your application rich. These fall under the heading of rich media.

Creating Rich Media

Seam is adept at generating a variety of rich media, which you learn to incorporate into your application in chapter 13. Seam uses the Facelets view library to support alternate output based on XHTML templates, including PDF documents, RTF documents, charts, and multipart emails with attachments that include the previous items. With the addition of two JSF component tags, Seam can accept file uploads without any custom, low-level coding and can render dynamic graphics. All of these tasks are typically passed off by web frameworks to third-party libraries. While it’s true that Seam leverages functionality provided by libraries such as iText and JFreeChart, the delegation is abstracted away. You are provided with a consistent approach, based on Facelets composition templates, that allows these features to be a native part of your Seam application.

1.5.3. Fosters an agile environment

In addition to being a framework, Seam provides a collection of tools that help you set up a project, generate code, and develop in an incremental manner.

Project Generator

One of the main highlights of Seam is its project generator, seam-gen. This tool serves two main functions. It sets up the structure of a Seam-based project, complete with a build script, environment profiles, a compatible set of libraries, and the configurations required to start developing your application. It’s the best way to get started with Seam if you are new to the framework. The seam-gen tool can also create an application prototype by reverse-engineering a database schema and generating all of the necessary artifacts to create, read, update, and delete (CRUD) data in that database. In Chapter 2, you learn all about seam-gen and use it to create a complete golf course directory web application.

Hot Deployment

Seam makes preparations to enable “instant change” in the development cycle, which you learn to take advantage of in Chapter 2. Seam’s strategy is to initialize a hot deploy classloader capable of detecting and dynamically reloading changed Java class files, just as if they were JSP pages.[4] The project build script compiles any source files that have changed and ships them off to a special path in the server’s hot deployment directory, where Seam picks them up and incorporates them into its runtime. Because the modified files remain isolated, they do not cause the application server to restart nor do they cause the application to reload. That means you can make a change to a Java file and have it take effect in the application immediately. This feature applies to Seam page descriptors and uncompiled Groovy scripts as well. You can finally match the change-view-change-view cycle that was previously only available with scripting languages such as PHP and Ruby!

4 Java EE containers support dynamic reloading of JSP pages when they’re moved into the deployment directory for the application or web module.

Seam Debug Page

While developing your application, bad stuff happens. As a result, you get exceptions. Rather than always having to race to the log file to find the cause, Seam gives you a head start. When you run Seam in debug mode, any exception that occurs will be caught and summarized on a special debug page, accessible at the servlet path /debug.seam. In addition to the exception, this page gives you a snapshot of the JSF component tree and any Seam component instances that are present at the time of the exception.

You don’t have to wait for an exception to occur to use this page. When the debug page is accessed directly, it renders a list of all conversations and sessions that are currently active. From there, you can drill down on any of the active contexts to inspect the component instances that are stored in them.

Testing Without Deploying

The primary reason developers grew wary of the standard Java EE platform was because of its inability to operate in isolation. Testing an application meant packaging it up and shipping it off to a Java EE–compliant application server, a costly process.

To work around this problem, developers adopted the POJO programming model, which encourages you to design code in such a way that it can be tested in isolation from the container and its services. While POJOs are definitely a good thing and encourage proper unit testing, there is no replacement for integrating your components in a real environment to ensure that they work together. Previously, that meant deploying to the application server once again. Seam has a better solution.

To support integration test environments (and also deployment to non-Java EE containers, such as Tomcat), Seam ships with the Embedded JBoss container. This portable container bootstraps a Java EE environment to support services such as JNDI, JTA, JCA, and JMS in a stand-alone environment. With these services up and running, you can test your application in place without having to deploy to a container. Seam supports this testing scenario by bootstrapping the Embedded JBoss container as part of its single class integration test framework, demonstrated back in section 1.4.6. This test infrastructure should prevent you from having to deploy over and over again to verify that your action components talk properly to your persistence layer and so on.

Between the incremental hot deployment support and the in-place testing infrastructure, your valuable time should rarely be wasted when working on a Seam application. If it’s your business logic that is hanging you up, unfortunately there is not much Seam can do to help you there. That’s all you.

1.6. Summary

The enthusiasm for Ruby on Rails was a real wake-up call for the Java EE platform. It enlightened developers to the fact that sacrifice is not a prerequisite for creating a successful application. Developers no longer wanted to tolerate the burden of “XML situps”[5] and overengineered flexibility. In response, the Seam developers assembled an agile platform, comprised of best-of-breed Java EE technologies, that takes a bold stance against the formalities of the Java EE specifications, cutting back the XML descriptor overgrowth, accentuating the platform’s recent adoption of annotations and configuration by exception, and embracing the expressive syntax embodied by the EL, Facelets, and Groovy. With Seam, creating applications in Java becomes exciting again, whether you are a front-end designer, back-end developer, or jack-of-all-trades. Best of all, you can be confident that applications built with Seam are scalable because the Java EE platform has proven itself in this regard, giving you productivity without sacrificing performance.

5 A term coined by the Ruby on Rails camp that equates XML authoring to strenuous exercise

First and foremost, Seam makes the task of defining and accessing stateful business-logic components simple, regardless of whether they are EJB or non-EJB components. A basic @Name annotation atop a class gains it admission into Seam’s contextual container. The container wraps these components in method interceptors, enabling enterprise services, such as transactions, security, and component assembly, to be declared with equivalent ease by applying an annotation at the class, method, or field level. Seam grants the technologies that it integrates access to the components in this container, primarily through the use of the unified EL. This arrangement facilitates the use of JPA entity classes as “backing” beans in a JSF form, EJB session beans or transactional JavaBeans as action listeners on a JSF UI component, and variables to be resolved on demand using Seam’s factory or manager mechanism.

An important aspect of Seam’s container is its state management capabilities. It consolidates the variable scopes in JSF with two of its own business-oriented scopes. Seam understands variable scoping and helps components from different scopes to work with one another without violating thread safety. Of particular note, Seam can extend the lifetime of the persistence manager across multiple page requests to reduce load on the database and eliminate complexities of using ORM in web applications.

If you picked up this book because you believe that there is a better framework choice out there for you (and you are not yet using Seam), my promise to you is that Seam is worth checking out and that the time you spend reading this book will be worthwhile. But merely knowing what framework someone recommends is not enough to decide to use it. You have to know why a person prefers a particular framework.[6] In this book, I share with you my extensive knowledge of Seam and explain to you why I find it to be a compelling technology choice. As you read along, I encourage you to develop your own reason for choosing Seam.

6 Scott Davis’ talk, given during the No Fluff, Just Stuff 2007 tour, entitled “No, I Won’t Tell You Which Framework to Use: or The Truth (With Jokes)” inspired this perspective.

The key to agile development with Seam begins with the project generator, seam-gen. In the next chapter, I show you how to use this tool to develop an entire application from scratch, how to get the application set up in your IDE, and how to take advantage of incremental hot deployment. While you must turn over some control when you opt to go with seam-gen, you’ll quickly find that you don’t miss the work.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.136.186