17.1. The Java EE 5.0 programming model

Java EE 5.0 is significantly easier to use and much more powerful than its predecessors. Two specifications of the Java EE 5.0 platform that are most relevant for web application developers are JSF and EJB 3.0.

What's so great about JSF and EJB 3.0? We first highlight major concepts and features in each specification. You'll then write a small example with JSF and EJB 3.0 and compare it to the old way of writing web applications in Java (think Struts and EJB 2.x). After that, we'll focus on the issues that are still present and how Seam can make JSF and EJB 3.0 an even more powerful and convenient combination.

Note that it's impossible to cover all of JSF and EJB 3.0 in this chapter. We recommend that you read this chapter together with the Sun Java EE 5.0 tutorial (http://java.sun.com/javaee/5/docs/tutorial/doc/) and browse through the tutorial if you want to know more about a particular subject. On the other hand, if you've already had some contact with JSF or EJB 3.0 (or even Hibernate), you'll likely find learning Seam easy.

17.1.1. Considering JavaServer Faces

JSF simplifies building web user interfaces in Java. As a presentation framework, JSF provides the following high-level features:

  • JSF defines an extensible component model for visual components, often called widgets.

  • JSF defines a component programming model for backing beans, or managed beans, which contain the application logic.

  • JSF defines the interaction between the user interface and the application logic and allows you to bind both together in a flexible fashion.

  • JSF allows you to define navigation rules declaratively in XML—that is, which page is displayed for a particular outcome in your application logic.

Let's spend a little more time on each of these features and what makes them useful.

JSF defines a set of built-in visual components that every JSF implementation has to support (such as buttons and input text fields). These visual components are rendered on pages as HTML (and Javascript). At the time of writing, several high-quality open source and commercial JSF widget libraries are available. Ready-made visual components are great for you as a developer; you don't have to code them by hand, and, most important, you don't have to maintain them or make them work on different browsers (which is especially painful if you need more sophisticated visual components that use Javascript).

Pages are created with any HTML templating engine that understands JSF widgets. Although JSP seems like an obvious choice, in our experience it isn't the best. We found that JavaServer Facelets (https://facelets.dev.java.net/) is a perfect fit for building JSF views and creating HTML templates that contain JSF widgets. (Another nice bonus of using Facelets is that you get the new unified expression language for free, even without a JSP 2.1-capable servlet container.) We'll use Facelets in all JSF examples in this chapter.

JSF-managed application components, called backing beans, make your web application interface work; they contain the application code. These are regular POJOs, and they're defined and wired together in JSF XML configuration files. This wiring supports basic dependency injection, as well as lifecycle management of backing bean instances. The available scopes for a backing bean (where it lives) are the current HTTP request context, the current HTTP session context, and the global application context. You write application logic by creating beans and letting JSF manage their lifecycle in one of these contexts.

You can bind model values from a backing bean to a visual component with an expression language. For example, you create a page with a text input field and bind it to a named backing bean field or getter/setter method pair. This backing bean name is then mapped in JSF configuration to an actual backing bean class, along with a declaration of how an instance of that class should be handled by JSF (in the request, in the HTTP session, or in the application context). The JSF engine automatically keeps the backing bean field (or property) synchronized with the state of the widget as seen (or manipulated) by the user.

JSF is an event-driven presentation framework. If you click a button, a JSF ActionEvent is fired and passed to registered listeners. A listener for an action event is again a backing bean you name in your JSF configuration. The backing bean can then react to this event—for example, by saving the current value of a backing bean field (which is bound to a text input widget) into the database. This is a simplified explanation of what JSF does. Internally, each request from the web browser passes through several phases of processing.

A typical request-processing sequence on the server, when you click a button on a JSF page, is as follows (this process is illustrated in figure 17.7):

  1. Restore View of all widgets (JSF can store the widget state on the server or on the client).

  2. Apply Request Parameters to update the state of widgets.

  3. Process Validations that are necessary to validate user input.

  4. Update Model Values that back the widget by calling the bound fields and setter methods of a backing bean.

  5. Invoke Application, and pass the action event to listeners.

  6. Render Response page the user sees.

Obviously a request can take different routes; for example, Render Response may occur after Process Validations, if a validation fails.

A nice illustration of the JSF lifecycle and the processing phases can be found in the already mentioned Sun Java EE 5 tutorial in chapter 9, "The Life Cycle of a JavaServer Faces Page." We'll also get back to the JSF processing model later in this chapter.

Which response is rendered and what page is shown to the user depends on the defined navigation rules and what the outcome of an action event is. Outcomes in JSF are simple strings, like "success" or "failure." These strings are produced by your backing beans and then mapped in a JSF XML configuration file to pages. This is also called free navigation flow; for example, you can click the Back button in your browser or jump directly to a page by entering its URL.

JSF, combined with Facelets, is a great solution if you're looking for a web framework. On the other hand, the backing beans of your web application—the components that implement the application logic—usually need to access transactional resources (databases, most of the time). This is where EJB 3.0 comes into the picture.

17.1.2. Considering EJB 3.0

EJB 3.0 is a Java EE 5.0 standard that defines a programming model for transactional components. For you, as a web application developer, the following features of EJB 3.0 are most interesting:

  • EJB 3.0 defines a component programming model that is primarily based on annotations on plain Java classes.

  • EJB 3.0 defines stateless, stateful, and message-driven components, and how the runtime environment manages the lifecycle of component instances.

  • EJB 3.0 defines how components are wired together, how you can obtain references to components, and how components can call each other.

  • EJB 3.0 defines how crosscutting concerns are handled, such as transactions and security. You can also write custom interceptors and wrap them around your components.

  • EJB 3.0 standardizes Java Persistence and how you can access an SQL database with automatic and transparent object/relational mapping.

If you want to access an SQL database, you create your domain model entity classes (such as Item, User, Category) and map them with annotations from the Java Persistence specification to a database schema. The EJB 3.0 persistence manager API, the EntityManager, is now your gateway for database operations.

You execute database operations in EJB 3.0 components—for example, stateful or stateless session beans. These beans are plain Java classes, which you enable as EJBs with a few annotations. You then get the container's services, such as automatic dependency injection (you get the EntityManager when you need it) and declarative transaction demarcation on component methods. Stateful session beans help you to keep state for a particular client, for example, if a user has to go through several pages in a conversation with the application.

Can you use EJB 3.0 components and entities as backing beans for JSF actions and widgets? Can you bind a JSF text field widget to a field in your Item entity class? Can a JSF button-click be directly routed to a session bean method?

Let's try this with an example.

17.1.3. Writing a web application with JSF and EJB 3.0

The web application you'll create is simple; it has a search screen where users can enter an identifier for a particular item, and a detail screen that appears when the item is found in the database. On this detail screen, users can edit the item's data and save the changes to the database.

(We don't think you should necessarily code this application while reading the examples; later, we make significant improvements by introducing Seam. That's the time to start coding.)

Start with the data model for the entity: an Item.

Creating the entity class and mapping

The Item entity class comes from CaveatEmptor. It's also already annotated and mapped to the SQL database (listing 17.1).

Listing 17-1. An annotated and mapped entity class
package auction.model;
import ...;

@Entity
@Table(name = "ITEM")
public class Item implements Serializable {

    @Id @GeneratedValue
    @Column(name = "ITEM_ID")
    private Long id = null;

    @Column(name = "ITEM_NAME", length = 255,
            nullable = false, updatable = false)
    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="SELLER_ID",
                nullable = false, updatable = false)
    private User seller;

    @Column(name = "DESCRIPTION", length = 4000, nullable = false)
    private String description;

    @Column( name="INITIAL_PRICE", nullable = false)

    private BigDecimal initialPrice;
    Item() {}

    // Getter and setter methods...
}

This is a simplified version of the CaveatEmptor Item entity, without any collections. Next is the search page that allows users to search for item objects.

Writing the search page with Facelets and JSF

The search page of the application is a page written with Facelets as the templating engine, and it's valid XML. JSF widgets are embedded in that page to create the search form with its input fields and buttons (listing 17.2).

Listing 17-2. The search.xhtml page in XHTML with Facelets
<!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"> <head> <title>CaveatEmptor - Search items</title> <link href="screen.css" rel="stylesheet" type="text/css"/>
</head> <body> <ui:include src="header.xhtml"/>
<h:form>
<span class="errors"><h:message for="itemSearchField"/></span>
<div class="entry">
<div class="label">Enter item identifier:</div> <div class="input"> <h:inputText id="itemSearchField"
size="3" required="true" value="#{itemEditor.itemId}"> <f:validateLongRange minimum="0"/>
</h:inputText> </div> </div> <div class="entry"> <div class="label">&#160;</div> <div class="input"> <h:commandButton value="Search" styleClass="button"
action="#{itemEditor.doSearch}"/> </div> </div> </h:form> </body> </html>

❶ Every valid XHTML file needs the right document type declaration.

❷ In addition to the regular XHTML namespace, you import the Facelets and two JSF namespaces for visual HTML components and core JSF components (for example, for input validation).

❸ The page layout is handled with cascading stylesheets (CSS) externalized to a separate file.

❹ A common page header template is imported with <ui:import> from Facelets.

❺ A JSF form (note the h namespace) is an HTML form that, if submitted, is processed by the JSF servlet.

❻ JSF can output messages, such as validation errors.

❼ Each <div> is a label or a form field, styled with the CSS class label or input.

❽ The JSF input text component that renders an HTML input field. The identifier is useful to bind it to error-message output, the size defines the visual size of the input field, and user input is required when this form is submitted. The most interesting part is the value binding of the input field to a backing bean (named itemEditor) and a getter/setter method pair (named getItemId()/setItemId()) on that backing bean. This is the data model this input field is bound to, and JSF synchronizes changes automatically.

❾ JSF also supports input validation and comes with a range of built-in validators. Here you declare that user input can't be negative (item identifiers are positive integers).

❿ The submit button of the form has an action binding to the method doSearch() of the backing bean named itemEditor. What happens after the action executes depends on the outcome of that method.

This is how the page looks rendered in the browser (figure 17.1).

Figure 17-1. The search page with JSF widgets

If you look at the URL, you see that the page has been called with the suffix .jsf; you probably expected to see search.xhtml. The .jsf suffix is a servlet mapping; the JSF servlet runs whenever you call a URL that ends in .jsf, and after installation of Facelets, you configured it in web.xml to use .xhtml internally. In other words, the search.xhtml page is rendered by the JSF servlet.

If you click the Search button without entering a search value, an error message is shown on the page. This also happens if you try to enter a noninteger or nonpositive integer value, and it's all handled by JSF automatically.

If you enter a valid item identifier value, and the backing bean finds the item in the database, you're forwarded to the item-editing screen. (Let's finish the user interface before focusing on the application logic in the backing bean.)

Writing the edit page

The edit page shows the details of the item that has been found in the search and allows the user to edit these details. When the user decides to save his changes, and after all validation is successful, the application shows the search page again.

The source code for the edit page is shown in listing 17.3.

Listing 17-3. The edit.xhtml page with a detail form
<!DOCTYPE html PUBLIC
...
<html xmlns=
...
<head>
...
<body>
...

<h2>Editing item: #{itemEditor.itemId}</h2> 
<h:form> <span class="errors"><h:messages/></span> <div class="entry"> <div class="label">Name:</div> <div class="input"> <h:inputText required="true" size="25"
value="#{itemEditor.itemName}"> <f:validateLength minimum="5" maximum="255"/> </h:inputText> </div> </div> <div class="entry"> <div class="label">Description:</div> <div class="input"> <h:inputTextarea cols="40" rows="4" required="true" value="#{itemEditor.itemDescription}"> <f:validateLength minimum="10" maximum="4000"/> </h:inputTextarea> </div> </div> <div class="entry"> <div class="label">Initial price (USD):</div> <div class="input"> <h:inputText size="6" required="true" value="#{itemEditor.itemInitialPrice}" > <f:converter converterId="javax.faces.BigDecimal"/> </h:inputText> </div> </div> <div class="entry"> <div class="label">&#160;</div> <div class="input"> <h:commandButton value="Save" styleClass="button" action="#{itemEditor.doSave}"/>
</div> </div> </h:form> </body> </html>

❶ You can place a value-binding expression outside of any component. In this case, the getItemId() method on the itemEditor backing bean is called, and the return value ends up in the HTML page.

❷ Again, a value binding is used to bind the input text field to a getter/setter method pair (or field) in the backing bean.

❸ This action binding references the doSave() method in the itemEditor backing bean. Depending on the outcome of that method, either the page is displayed again (with error messages) or the user is forwarded to the search page.

Figure 17.2 shows the rendered page.

Figure 17-2. The edit page with loaded item details

Why is the URL showing search.jsf? Shouldn't it be edit.jsf? Consider the request processing of the JSF servlet. If the user clicks the Search button on the search.jsf page, the backing bean's doSearch() method runs after input validation. If the outcome of that method triggers a forward to the edit.xhtml page, this document is rendered by the JSF servlet, and the HTML is sent to the browser. The URL doesn't change! Users can't bookmark the edit page, which in this simple application is desirable.

Now that you've completed the top layer of the application, the view, consider the layer that accesses the database (you might call this the business layer). Because accessing an SQL database is a transactional operation, you write an EJB.

Accessing the database in an EJB

If you've worked with EJB 2.x (and Struts) before, the code that accesses the database is most likely procedural code in a stateless session bean. Let's do that in EJB 3.0 (listing 17.4).

Listing 17-4. A stateless session bean with a data access facade
package auction.beans;

import ...;

@Stateless 
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public class EditItemBean implements EditItem {
@PersistenceContext
EntityManager em; public Item findById(Long itemId) {
return em.find(Item.class, itemId); } public Item save(Item item) {
return em.merge(item); } }

❶ A @Stateless annotation turns this plain Java class into a stateless session bean. At runtime, a pool of instances is prepared, and each client that requests a session bean gets an instance from the pool to execute a method.

❷ All methods that are called on this session bean are wrapped in a system transaction, which enlists all transactional resources that may be used during that procedure. This is also the default if you don't annotate the bean.

❸ A session bean needs an interface. Usually you implement this interface directly. The EditItem interface has two methods.

❹ When the runtime container hands out a session bean instance from the pool, it injects an EntityManager with a (fresh) persistence context scoped to the transaction.

❺ If a client calls findById(), a system transaction starts. The EntityManager operation executes an SQL query in that transaction; the persistence context is flushed and closed when the transaction commits (when the method returns). The returned Item entity instance is in detached state.

❻ If a client calls save(), a system transaction starts. The given detached instance is merged into a (new) persistence context. Any changes made on the detached Item instance are flushed and committed to the database. A new handle to the now up-to-date Item instance is returned. This new Item instance is again in detached state when the method returns, and the persistence context is closed.

You can call the session bean shown in listing 17.4 a data access object (DAO). It can also be a session facade. The application isn't complex enough to make a clear distinction; if more nondata access methods were added to its interface, the session bean would represent part of the business layer interface with a traditional (mostly procedural) session facade.

A piece is still missing from the puzzle: The JSF input widgets and buttons have value and action bindings to a backing bean. Is the backing bean the same as the session bean, or do you have to write another class?

Connecting the layers with a backing bean

Without Seam, you have to write a backing bean that connects your JSF widget state and actions to the transactional stateless session bean. This backing bean has the getter and setter methods that are referenced with expressions in the pages. It can also talk to the session bean and execute transactional operations. The code for the backing bean is shown in listing 17.5.

Listing 17-5. A JSF backing bean component connects the layers.
package auction.backingbeans;

import ...
public class ItemEditor { 
private Long itemId;
private Item item;
public Long getItemId() { return itemId; } public void setItemId(Long itemId) {
this.itemId = itemId; } public String getItemName() { return item.getName(); } public void setItemName(String itemName) { this.item.setName( itemName ); } public String getItemDescription() { return item.getDescription(); } public void setItemDescription(String itemDescription) { this.item.setDescription( itemDescription ); } public BigDecimal getItemInitialPrice() {
return item.getInitialPrice(); } public void setItemInitialPrice(BigDecimal itemInitialPrice) { this.item.setInitialPrice( itemInitialPrice ); } public String doSearch() { item = getEditItemEJB().findById(itemId);
return item != null ? "found" : null; } public String doSave() { item = getEditItemEJB().save(item);
return "success"; } private EditItem getEditItemEJB() { try {
return (EditItem) new InitialContext() .lookup("caveatemptor/EditItemBean/local"); } catch (NamingException ex) { throw new RuntimeException(ex); } } }

❶ You don't implement any interfaces; this is a plain Java class.

❷ The backing bean maintains an item identifier internally with a field.

❸ The backing bean also holds the Item instance that is being edited by a user.

❹ Getter and setter methods for all value bindings in search.xhtml and edit.xhtml. These are the methods used by JSF to synchronize the backing beans internal model state with the state of UI widgets.

❺ The doSearch() method is bound to the action of a JSF button. It uses the EJB session bean component to find the Item instance for the current itemId in the backing bean. Its outcome is either the string found or null.

❻ The doSave() method is bound to the action of a JSF button. It uses the EJB session bean component to save the state of the item field. (Because this is a merge, you have to update the item field with the returned value, the state after merging.) Its outcome is either the string success or an exception.

❼ The helper method getEditItemEJB() obtains a handle on the EJB session bean. This lookup in JNDI can be replaced with automatic dependency injection if the runtime environment supports the Java Servlet 2.5 specification. (At the time of writing, Tomcat 5.5 implements only Java Servlets 2.4, and Tomcat 6 is in alpha stage.)

The backing bean is a component that is managed by the JSF runtime. The expressions you use in the pages refer to a backing bean by name, itemEditor. In the JSF XML configuration file (WEB-INF/faces-config.xml usually), you map this name to the backing bean class (listing 17.6).

Listing 17-6. A JSF configuration describes the backing bean and navigation flow.
<?xml version="1.0"?>
<!DOCTYPE faces-config PUBLIC
  "-//Sun Microsystems, Inc.//DTD JavaServer Faces Config 1.0//EN"
  "http://java.sun.com/dtd/web-facesconfig_1_1.dtd" >

<faces-config>

    <managed-bean>
        <managed-bean-name>itemEditor</managed-bean-name>
        <managed-bean-class>
            auction.backingbeans.ItemEditor
        </managed-bean-class>
        <managed-bean-scope>session</managed-bean-scope>
    </managed-bean>

    <navigation-rule>
        <from-view-id>/search.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>found</from-outcome>
            <to-view-id>/edit.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>

    <navigation-rule>
        <from-view-id>/edit.xhtml</from-view-id>
        <navigation-case>
            <from-outcome>success</from-outcome>
            <to-view-id>/search.xhtml</to-view-id>
        </navigation-case>
    </navigation-rule>

</faces-config>

This application has one backing bean and two navigation rules. The backing bean is declared with the name itemEditor and implemented by auction.backingBeans.ItemEditor. Expressions in JSF pages can now reference methods and fields of that backing bean in a loosely coupled fashion, by name. The JSF servlet manages instances of the backing bean, one instance for each HTTP session.

Let's take this one step further: An expression in a JSF page is a string, such as #{itemEditor.itemId}. This expression basically results in a search for a variable named itemEditor. Searched, in that order, are the current request, the current HTTP session, and the current application context. If a JSF page renders and this expression has to be evaluated, then either a variable with that name is found in the HTTP session context, or the JSF servlet creates a new backing bean instance and binds it into the HTTP session context.

The navigation rules declare which page is rendered after an action outcome. This is a mapping from strings, returned by actions, to pages.

Your application is now complete; it's time to analyze it in more detail.

17.1.4. Analyzing the application

Possibly you look at the code in the previous sections and think, "This was a lot of code to write to put four form fields onto web pages and connect them to four columns in the database." Or, if you've spent a lot of time with EJB 2.x and Struts, you'll probably say, "This is great: I don't have to manage the HTTP session myself anymore, and all the EJB boilerplate code is gone."

You're right either way. Java EE 5.0 and especially JSF and EJB 3.0 are a significant step forward for Java web applications, but not everything is perfect. We'll now look at the advantages of Java EE 5.0 and compare it to J2EE 1.4 and web frameworks before JSF. But we'll also try to find things that can be improved, code that can be avoided, and strategies that can be simplified. This is where Seam comes in later.

Comparing the code to J2EE

If you have a J2EE 1.4/Struts background, this JSF and EJB 3.0 application already looks much more appealing. There are fewer artifacts than in a traditional Java web application—for example, you can detach an Item instance from the session bean facade and transfer it into the JSF backing bean. With EJB 2.x entity beans, you needed a data transfer object (DTO) to do this.

The code is much more compact. With EJB 2.x, the session bean must implement the SessionBean interface with all its maintenance methods. In EJB 3.0, this is resolved with a simple @Stateless annotation. There is also no Struts ActionForm code that manually binds the state of an HTML form field to an instance variable in the action listener.

Overall, the application is transparent, with no obscure calls that maintain values in the HTTP session or in the HTTP request. JSF transparently puts and looks up values in these contexts.

If you consider the object/relational mapping of the Item class, you'll probably agree that a few annotations on a POJO are simpler than a deployment descriptor for an EJB 2.x entity bean. Furthermore, object/relational mapping as defined by Java Persistence is not only much more powerful and feature-rich than EJB 2.x. entity beans, but also a lot easier to use (even compared to native Hibernate).

What we couldn't show in a simple application is the power behind JSF and EJB 3.0. JSF is amazingly flexible and extensible; you can write your own HTML widgets, you can hook into the processing phases of a JSF request, and you can even create your own view layer (if Facelets isn't what you want) without much effort. EJB 3.0 is much easier to tame than EJB 2.x, and it also has features (such as interceptors and dependency injection) that have never before been available in a standardized Java programming model.

The application can easily be tested with a testing framework like JUnit or TestNG. All classes are plain Java classes; you can instantiate them, set (mock) dependencies manually, and run a test procedure.

However, there is room for improvement.

Improving the application

The first thing that stands out in this JSF/EJB 3.0 application is the JSF backing bean. What's the purpose of this class? It's required by JSF, because you need to bind values and actions to its fields and methods. But the code doesn't do anything useful: It passes any action to an EJB, one to one. Worse, it's the artifact with the most lines of code.

You might argue that it decouples the view from the business layer. That seems reasonable, if you use your EJB with a different view layer (say, a rich client). Still, if the application is a simple web application, the backing bean results in tighter coupling between the layers. Any change you make to either the view or the business layer requires changes to the component with the most lines of code. If you want to improve the code, get rid of the artificial layering and remove the backing bean. There is no reason why an EJB shouldn't be the backing bean. A programming model shouldn't force you to layer your application (it shouldn't restrict you, either). To improve the application, you need to collapse artificial layers.

The application doesn't work in several browser windows. Imagine that you open the search page in two browser windows. In the first, you search for item 1; in the second, you search for item 2. Both browser windows show you an edit screen with the details of item 1 and item 2. What happens if you make changes to item 1 and click Save? The changes are made on item 2! If you click Save in the first browser window, you work on the state that is present in the HTTP session, where the backing bean lives. However, the backing bean no longer holds item 1—the current state is now the state of the second browser window, editing item 2. In other words, you started two conversations with the application, but the conversations weren't isolated from each other. The HTTP session isn't the right context for concurrent conversation state; it's shared between browser windows. You can't fix this easily. Making this (trivial) application work in several browser windows requires major architectural changes. Today, users expect web applications to work in several browser windows.

The application leaks memory. When a JSF page first tries to resolve the itemEditor variable, a new instance of ItemEditor is bound to the variable in the HTTP session context. This value is never cleaned up. Even if the user clicks Save on the edit screen, the backing bean instance stays in the HTTP session until the user logs out or the HTTP session times out. Imagine that a much more sophisticated application has many forms and many backing beans. The HTTP session grows as the user clicks through the application, and replicating the HTTP session to other nodes in a cluster gets more expensive with every click. If a user comes back to the item search screen, after working with another module of the application, old data is shown in the forms. One solution for this problem would be manual cleanup of the HTTP session at the end of a conversation, but there is no easy way to do this. With JSF and EJB 3.0, you must code this manually. In our experience, handling variables and values in the HTTP session manually is a common source of issues that are incredibly difficult to track down.

The flow of the application is difficult to visualize and control. How do you know where clicking the Search button will take you? At a minimum, you have to look into two files: the backing bean, which returns string outcomes, and the JSF XML configuration file, which defines the page shown for a particular outcome. There is also the ever-present problem of the Back button in the browser, a nasty problem in any conversation that has more than two screens.

Think also about the business process. How can you define that your flow of pages is part of a larger business process? Imagine that searching and editing an item is only one task in a business process that involves many more steps—for example, as part of a review process. No tools or strategies help you integrate business process management in your application. Today, you can no longer afford to ignore the business processes of which your applications is a part; you need a programming model that supports business-process management.

Finally, this application includes too much XML. There is no way around metadata in the application, but not all of it has to be in an XML file. Metadata in XML files is great if it changes independently from code. This may be true for navigation rules, but it probably isn't true for the declaration of backing beans and the context they live in. This kind of metadata grows linearly with the size of your application—every backing bean must be declared in XML. Instead, you should put an annotation on your class that says, "I'm a backing bean for JSF, and I live inside the HTTP session (or any other) context." It's unlikely that your class will suddenly change its role without any changes to the class code.

If you agree with this analysis, you'll like Seam.

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

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