Index: Seam_Reference_Guide.xml =================================================================== --- Seam_Reference_Guide.xml (revision 39393) +++ Seam_Reference_Guide.xml (working copy) @@ -11,7 +11,7 @@ - + @@ -47,3 +47,4 @@ + Index: Dependencies.xml =================================================================== --- Dependencies.xml (revision 39393) +++ Dependencies.xml (working copy) @@ -563,7 +563,7 @@ - Required for incoming mail support. + Required for incoming mail support. Index: Migration.xml =================================================================== --- Migration.xml (revision 39393) +++ Migration.xml (working copy) @@ -16,13 +16,16 @@
Migrating from Seam 1.2.x to Seam 2.0 - In this section, we show you how to migrate from Seam 1.2.x to Seam 2.0. We also list the changes to Seam components between versions. + In this section, we show you how to migrate from Seam 1.2.x to Seam 2.0. We also list the changes to Seam + components between versions.
Migrating to JavaServer Faces 1.2 - Seam 2.0 requires JSF 1.2 to work correctly. We recommend Sun's JSF Reference Implementation (RI), which ships with most Java EE 5 application servers, including JBoss 4.2. To switch to the JSF RI, you will need to make the following changes to your web.xml: + Seam 2.0 requires JSF 1.2 to work correctly. We recommend Sun's JSF Reference Implementation (RI), which ships + with most Java EE 5 application servers, including JBoss 4.2. To switch to the JSF RI, you will need to make the + following changes to your web.xml: @@ -124,28 +127,36 @@ - BPM-related annotations are now included in the org.jboss.seam.annotations.bpm package. + BPM-related annotations are now included in the org.jboss.seam.annotations.bpm + package. - JSF-related annotations are now included in the org.jboss.seam.annotations.faces package. + JSF-related annotations are now included in the org.jboss.seam.annotations.faces + package. - Interceptor annotations are now included in the org.jboss.seam.annotations.intercept package. + Interceptor annotations are now included in the org.jboss.seam.annotations.intercept + package. - Annotations related to asynchronicity are now included in the org.jboss.seam.annotations.async package. + Annotations related to asynchronicity are now included in the + org.jboss.seam.annotations.async package. - @RequestParameter is now included inthe org.jboss.seam.annotations.web package. + @RequestParameter is now included in the + org.jboss.seam.annotations.web package. - @WebRemote is now included in the org.jboss.seam.annotations.remoting package. + @WebRemote is now included in the + org.jboss.seam.annotations.remoting package. - @Restrict is now included in the org.jboss.seam.annotations.security package. + @Restrict is now included in the + org.jboss.seam.annotations.security package. - Exception handling annotations are now included in the org.jboss.seam.annotations.exception package. + Exception handling annotations are now included in the + org.jboss.seam.annotations.exception package. Use @BypassInterceptors instead of @Intercept(NEVER). @@ -154,7 +165,8 @@
Migrating <filename>components.xml</filename> - The new packaging system outlined in the previous section means that you must update components.xml with the new schemas and namespaces. + The new packaging system outlined in the previous section means that you must update + components.xml with the new schemas and namespaces. Namespaces originally took the form org.jboss.seam.foobar. The new namespace format is http://jboss.com/products/seam/foobar, and the schema is of the form http://jboss.com/products/seam/foobar-2.0.xsd. You will need to update the format of the namespaces and schemas in your components.xml file so that the URLs correspond to the version of Seam that you wish to migrate to (2.0 or 2.1). @@ -163,13 +175,16 @@ - Replace ]]> with ]]>. + Replace ]]> with + ]]>. - Replace ]]> with ]]>. + Replace ]]> with + ]]>. - Remove conversation-is-long-running parameter from ]]> element. + Remove conversation-is-long-running parameter from + ]]> element. Remove ]]>. @@ -178,10 +193,12 @@ Remove ]]>. - Replace ]]> with ]]>. + Replace ]]> with + ]]>. - Replace ]]> with ]]>. + Replace ]]> with + ]]>. @@ -210,14 +227,16 @@ - Instead of the org.jboss.seam.postAuthenticate event, use the org.jboss.seam.security.loginSuccessful event to return to the captured view. + Instead of the org.jboss.seam.postAuthenticate event, use the + org.jboss.seam.security.loginSuccessful event to return to the captured view.
Migrating to Embedded JBoss - Embedded JBoss no longer supports the use of JBoss Embeddable EJB3 or JBoss Microcontainer. Instead, the new Embedded JBoss distribution provides a complete set of Java EE-compatible APIs with simplified deployment. + Embedded JBoss no longer supports the use of JBoss Embeddable EJB3 or JBoss Microcontainer. Instead, the new + Embedded JBoss distribution provides a complete set of Java EE-compatible APIs with simplified deployment. For testing, you will need to include the following in your classpath: @@ -231,24 +250,28 @@ - Remove any references or artifacts relating to JBoss Embeddable EJB3, such as the embeddded-ejb directory and jboss-beans.xml. (You can use the Seam examples as reference.) + Remove any references or artifacts relating to JBoss Embeddable EJB3, such as the + embeddded-ejb directory and jboss-beans.xml. (You can use the Seam + examples as reference.) - There are no longer any special configuration or packaging requirements for Tomcat deployment. To deploy with Tomcat, follow the instructions in the User Guide. + There are no longer any special configuration or packaging requirements for Tomcat deployment. To deploy with + Tomcat, follow the instructions in the User Guide. - Embedded JBoss can bootstrap a datasource from a -ds.xml file, so the jboss-beans.xml file is no longer required. + Embedded JBoss can bootstrap a datasource from a -ds.xml file, so the + jboss-beans.xml file is no longer required.
Migrating to jBPM 3.2 - If you use jBPM for business processes as well as pageflows, you must add the tx service to jbpm.cfg.xml: + If you use jBPM for business processes as well as pageflows, you must add the tx service to + jbpm.cfg.xml: - ]]> - + ]]>
Migrating to RichFaces 3.1 @@ -256,7 +279,10 @@ There has been a major reorganization of the codebase for both RichFaces and AJAX4JSF. The ajax4jsf.jar and richfaces.jar jars have been replaced with the richfaces-api.jar (to be placed in the EAR lib/ directory) and the richfaces-impl.jar and richfaces-ui.jar (to be placed in WEB-INF/lib). - ]]> has been deprecated in favour of ]]>. There will be no further development of ]]>. The styles associated with the data picker should be removed from your style sheet to reduce bandwidth use. + ]]> has been deprecated in favour of + ]]>. There will be no further development of + ]]>. The styles associated with the data picker should be removed from + your style sheet to reduce bandwidth use. Check the RichFaces documentation for more information about changes to namespace and parameter names. @@ -267,13 +293,18 @@ Packaging Changes - All dependencies that were previously declared as modules in application.xml should now be placed in the lib/ directory of your EAR, except jboss-seam.jar, which should be declared as an EJB module in application.xml. + All dependencies that were previously declared as modules in application.xml should now + be placed in the lib/ directory of your EAR, except + jboss-seam.jar, which should be declared as an EJB module in + application.xml. Changes to the Seam User Interface - ]]> has become a naming container. Client IDs have therefore changed from fooForm:fooInput to fooForm:foo:fooInput, assuming that the following has been declared: + ]]> has become a naming container. Client IDs have therefore changed + from fooForm:fooInput to fooForm:foo:fooInput, assuming that the + following has been declared: @@ -282,12 +313,14 @@ ]]> - If you do not provide an ID for ]]>, JSF will generate an ID automatically. + If you do not provide an ID for ]]>, JSF will generate an ID + automatically. Changes to <application>seam-gen</application> - Since Seam 2.0.0.CR2, there have been changes to the organization of generated classes in seam-gen when generate-entities is executed. + Since Seam 2.0.0.CR2, there have been changes to the organization of generated classes in + seam-gen when generate-entities is executed. @@ -332,7 +365,9 @@
Migrating from Seam 2.0 to Seam 2.1 or 2.2 - This section describes the changes between Seam 2.0 and Seam 2.1 or 2.2. If you are trying to migrate from Seam 1.2.x, you will need to read the previous section, , before following any steps outlined in this section. + This section describes the changes between Seam 2.0 and Seam 2.1 or 2.2. If you are trying to migrate from Seam + 1.2.x, you will need to read the previous section, , before following any steps + outlined in this section.
Index: Tutorial.xml =================================================================== --- Tutorial.xml (revision 39393) +++ Tutorial.xml (working copy) @@ -7,7 +7,10 @@
Using the Seam examples - Seam provides a number of example applications which demonstrate how to use a variety of Seam's features. This tutorial will guide you through a few of those examples to help you get started learning Seam. The Seam examples are located in the examples subdirectory of the Seam distribution. The first example, on registration, is in the examples/registration directory. + Seam provides a number of example applications which demonstrate how to use a variety of Seam's features. This + tutorial will guide you through a few of those examples to help you get started learning Seam. The Seam examples + are located in the examples subdirectory of the Seam distribution. The first example, on + registration, is in the examples/registration directory. Each example has the same directory structure: @@ -15,7 +18,8 @@ - The view directory contains view-related files such as web page templates, images and stylesheets. + The view directory contains view-related files such as web page templates, images and + stylesheets. @@ -30,18 +34,31 @@ - Note that all examples are built and run from the Ant build.xml, so you will need a recent version of Ant installed before you get started. + Note that all examples are built and run from the Ant build.xml, so you will need a recent + version of Ant installed before you get started.
Running the examples on JBoss AS - The examples are configured for use on JBoss Enterprise Web Platform. You will need to set jboss.home, in the shared build.properties file (in the root folder of your Seam installation) to the location of your JBoss AS installation. + The examples are configured for use on JBoss Enterprise Web Platform. You will need to set + jboss.home, in the shared build.properties file (in the root folder of + your Seam installation) to the location of your JBoss AS installation. - Once you have set the location of JBoss AS and started the application server, you can build and deploy any example by typing ant explode in that example's directory. Any example that is packaged as an EAR (Enterprise Archive) deploys to a URL like /seam-example, where example is the name of the example folder, with one exception: if the example folder begins with "seam", the prefix "seam" is ommitted. For instance, if JBoss AS is running on port 8080, the URL for the Registration example is http://localhost:8080/seam-registration/, whereas the URL for the SeamSpace example is http://localhost:8080/seam-space/. + Once you have set the location of JBoss AS and started the application server, you can build and deploy any + example by typing ant explode in that example's directory. Any example that is packaged + as an EAR (Enterprise Archive) deploys to a URL like + /seam-example, where example is the + name of the example folder, with one exception: if the example folder begins with "seam", the prefix "seam" is + ommitted. For instance, if JBoss AS is running on port 8080, the URL for the Registration example is + http://localhost:8080/seam-registration/, whereas the URL for the SeamSpace example + is http://localhost:8080/seam-space/. - If, on the other hand, the example is packaged as a WAR, then it deploys to a URL like /jboss-seam-example. + If, on the other hand, the example is packaged as a WAR, then it deploys to a URL like + /jboss-seam-example. @@ -53,10 +70,13 @@
Running the example tests - Most of the examples come with a suite of TestNG integration tests. The easiest way to run the tests is to run ant test. + Most of the examples come with a suite of TestNG integration tests. The easiest way to run the tests is to run + ant test. - It is also possible to run the tests inside your IDE using the TestNG plugin. This required you to run ant test before running or debugging Seam test cases in Eclipse IDE. Consult the readme.txt in the examples directory of the Seam distribution for more information. + It is also possible to run the tests inside your IDE using the TestNG plugin. This required you to run ant test + before running or debugging Seam test cases in Eclipse IDE. Consult the readme.txt in the examples directory of + the Seam distribution for more information.
@@ -64,10 +84,13 @@
Your first Seam application: the registration example - The registration example is a simple application that lets a new user store their username, real name, and password in the database. This example uses only basic functions to demonstrate the use of an EJB3 session bean as a JSF action listener, and the basic configuration of Seam. + The registration example is a simple application that lets a new user store their username, real name, and + password in the database. This example uses only basic functions to demonstrate the use of an EJB3 session bean as + a JSF action listener, and the basic configuration of Seam. - The start page displays a basic form with three input fields. Filling them in and submitting the form will save a user object in the database. + The start page displays a basic form with three input fields. Filling them in and submitting the form will save a + user object in the database. @@ -80,12 +103,15 @@
Understanding the code - The example is implemented with two Facelets templates: one entity bean, and one stateless session bean. This section will take you through the code in detail, starting from the base level. + The example is implemented with two Facelets templates: one entity bean, and one stateless session bean. This + section will take you through the code in detail, starting from the base level.
The entity bean: <literal>User.java</literal> - We need an EJB entity bean for user data. This class defines persistence and validation declaratively, via annotations. It also requires some extra annotations to define the class as a Seam component. + We need an EJB entity bean for user data. This class defines persistence and + validation declaratively, via annotations. It also requires some extra annotations to + define the class as a Seam component. @@ -109,47 +135,42 @@ A Seam component needs a component name specified by the - @Name - annotation. This name must be unique within the Seam application. When JSF - asks Seam to resolve a context variable with a name that is the same as a Seam - component name, and the context variable is currently undefined (null), Seam will - instantiate that component, and bind the new instance to the context variable. In - this case, Seam will instantiate a User the first time JSF - encounters a variable named user. + @Name annotation. This name must be unique within the Seam application. When JSF asks + Seam to resolve a context variable with a name that is the same as a Seam component name, and the + context variable is currently undefined (null), Seam will instantiate that component, and bind the new + instance to the context variable. In this case, Seam will instantiate a User the + first time JSF encounters a variable named user. - Whenever Seam instantiates a component, it binds the new instance to a context - variable in the component's default context. The default - context is specified using the - @Scope - annotation. The User bean is a session scoped component. + Whenever Seam instantiates a component, it binds the new instance to a context variable in the + component's default context. The default context is specified using the + @Scope annotation. The User bean is a session scoped component. - The EJB standard @Table annotation indicates that the - User class is mapped to the users table. + The EJB standard @Table annotation indicates that the User + class is mapped to the users table. - name, password and username - are the persistent attributes of the entity bean. All of our persistent attributes - define accessor methods. These are needed when this component is used by JSF in the - render response and update model values phases. + name, password and username are the + persistent attributes of the entity bean. All of our persistent attributes define accessor + methods. These are needed when this component is used by JSF in the render response and update model + values phases. An empty constructor is required by both the EJB specification and Seam. - The @NotNull and @Length annotations are - part of the Hibernate Validator framework. Seam integrates Hibernate Validator and - lets you use it for data validation (even if you are not using Hibernate for - persistence). + The @NotNull and @Length annotations are part of the + Hibernate Validator framework. Seam integrates Hibernate Validator and lets you use it for data + validation (even if you are not using Hibernate for persistence). - The EJB standard @Id annotation indicates the primary key - attribute of the entity bean. + The EJB standard @Id annotation indicates the primary key attribute of the + entity bean. @@ -157,13 +178,17 @@ - The most important things to notice in this example are the @Name and @Scope annotations. These annotations establish that this class is a Seam component. + The most important things to notice in this example are the @Name and + @Scope annotations. These annotations establish that this class is a Seam component. - In the next section, you will see that the properties of the User class are bound directly to JSF components and populated by JSF during the update model values phase. There is no glue code to copy data back and forth between the JSP pages and the entity bean domain model. + In the next section, you will see that the properties of the User class are bound directly + to JSF components and populated by JSF during the update model values phase. There is no glue code to copy + data back and forth between the JSP pages and the entity bean domain model. - However, entity beans should not perform transaction management or database access, so this component should not be used as a JSF action listener. In this situation, a session bean is a better choice. + However, entity beans should not perform transaction management or database access, so this component should + not be used as a JSF action listener. In this situation, a session bean is a better choice.
@@ -173,7 +198,9 @@ Most Seam applications use session beans as JSF action listeners, though you may also use JavaBeans. - We have exactly one JSF action in this application, and one session bean method attached to it. In this case, we will use a stateless session bean, since all the state associated with our action is held by the User bean. + We have exactly one JSF action in this application, and one session bean method attached to it. In this case, + we will use a stateless session bean, since all the state associated with our action is held by the + User bean. The relevant code is shown below: @@ -192,61 +219,56 @@ - + - The EJB @Stateless annotation marks this class as - a stateless session bean. + The EJB @Stateless annotation marks this class as a stateless session + bean. - The @In - annotation marks an attribute of the bean as injected by Seam. In this case, - the attribute is injected from a context variable named user (the - instance variable name). + The @In annotation marks an attribute of the bean as injected by Seam. In this + case, the attribute is injected from a context variable named user (the instance + variable name). - The EJB standard @PersistenceContext annotation is used to - inject the EJB3 entity manager. + The EJB standard @PersistenceContext annotation is used to inject the EJB3 + entity manager. The Seam @Logger annotation is used to inject the component's Log instance. - The action listener method uses the standard EJB3 - EntityManager API to interact with the database, and returns the - JSF outcome. Note that, since this is a session bean, a transaction is automatically - begun when the register() method is called, and committed when it - completes. + The action listener method uses the standard EJB3 EntityManager API to + interact with the database, and returns the JSF outcome. Note that, since this is a session bean, a + transaction is automatically begun when the register() method is called, and + committed when it completes. - Notice that Seam lets you use a JSF EL expression inside EJB-QL. Under the - covers, this results in an ordinary JPA setParameter() call on - the standard JPA Query object. Nice, huh? + Notice that Seam lets you use a JSF EL expression inside EJB-QL. Under the covers, this results + in an ordinary JPA setParameter() call on the standard JPA Query + object. Nice, huh? - The Log API lets us easily display templated log messages which - can also make use of JSF EL expressions. + The Log API lets us easily display templated log messages which can also make + use of JSF EL expressions. - JSF action listener methods return a string-valued outcome that determines what - page will be displayed next. A null outcome (or a void action listener method) - redisplays the previous page. In plain JSF, it is normal to always use a JSF - navigation rule to determine the JSF view id from the - outcome. For complex applications this indirection is useful and a good practice. - However, for very simple examples like this one, Seam lets you use the JSF view id - as the outcome, eliminating the requirement for a navigation rule. Note - that when you use a view id as an outcome, Seam always performs a browser - redirect. + JSF action listener methods return a string-valued outcome that determines what page will be + displayed next. A null outcome (or a void action listener method) redisplays the previous page. In plain + JSF, it is normal to always use a JSF navigation rule to determine the JSF view id + from the outcome. For complex applications this indirection is useful and a good practice. However, for + very simple examples like this one, Seam lets you use the JSF view id as the outcome, eliminating the + requirement for a navigation rule. Note that when you use a view id as an outcome, Seam always + performs a browser redirect. - Seam provides a number of built-in components to help solve - common problems. The FacesMessages component makes it easy to - display templated error or success messages. (As of Seam 2.1, you can use - StatusMessages instead to remove the semantic dependency on JSF). - Built-in Seam components may be obtained by injection, or by calling the + Seam provides a number of built-in components to help solve common + problems. The FacesMessages component makes it easy to display templated error or + success messages. (As of Seam 2.1, you can use StatusMessages instead to remove the + semantic dependency on JSF). Built-in Seam components may be obtained by injection, or by calling the instance() method on the class of the built-in component. @@ -256,14 +278,19 @@ - Note that we did not explicitly specify a @Scope this time. Each Seam component type has a default scope, which will be used if scope is not explicitly specified. For stateless session beans, the default scope is the stateless context. + Note that we did not explicitly specify a @Scope this time. Each Seam component type has a + default scope, which will be used if scope is not explicitly specified. For stateless session beans, the + default scope is the stateless context. - The session bean action listener performs the business and persistence logic for our mini-application. In a more complex application, a separate service layer might be necessary, but Seam allows you to implement your own strategies for application layering. You can make any application as simple, or as complex, as you want. + The session bean action listener performs the business and persistence logic for our mini-application. In a + more complex application, a separate service layer might be necessary, but Seam allows you to implement your + own strategies for application layering. You can make any application as simple, or as complex, as you want. - This application is more complex than necessary for the sake of clear example code. All of the application code could have been eliminated by using Seam's application framework controllers. + This application is more complex than necessary for the sake of clear example code. All of the application + code could have been eliminated by using Seam's application framework controllers.
@@ -285,7 +312,8 @@
The view: <literal>register.xhtml</literal> and <literal>registered.xhtml</literal> - The view pages for a Seam application can be implemented using any technology that supports JSF. This example was written with Facelets. + The view pages for a Seam application can be implemented using any technology that supports JSF. This example + was written with Facelets. @@ -294,7 +322,9 @@ - The only Seam-specific tag here is ]]>. This JSF component tells JSF to validate all the contained input fields against the Hibernate Validator annotations specified on the entity bean. + The only Seam-specific tag here is ]]>. This JSF component tells + JSF to validate all the contained input fields against the Hibernate Validator annotations specified on the + entity bean. registered.xhtml @@ -309,13 +339,23 @@
The Seam component deployment descriptor: <literal>components.xml</literal> - Before looking at deployment descriptors, it is worth noting that Seam strongly values minimal configuration. These configuration files will be created for you when you create a Seam application, and there will rarely be any need to alter them. They are presented here solely to assist you in understanding the purpose and function of all of the example code. + Before looking at deployment descriptors, it is worth noting that Seam strongly values minimal + configuration. These configuration files will be created for you when you create a Seam application, and there + will rarely be any need to alter them. They are presented here solely to assist you in understanding the + purpose and function of all of the example code. - If you have used Java frameworks previously, you will be used to declaring your component classes in an XML file. You have probably also noticed that as a project matures, these XML files tend to become unmanageable. Fortunately, Seam does not require application components to be accompanied by XML. Most Seam applications require only a small amount of XML, which does not tend to increase in size as projects expand. + If you have used Java frameworks previously, you will be used to declaring your component classes in an XML + file. You have probably also noticed that as a project matures, these XML files tend to become + unmanageable. Fortunately, Seam does not require application components to be accompanied by XML. Most Seam + applications require only a small amount of XML, which does not tend to increase in size as projects expand. - However, it is often useful to be able to provide for some external configuration of some components, particularly the components that are built into Seam. The most flexible option, here, is to provide this configuration in a file called components.xml, located in the WEB-INF directory. The components.xml file can be used to tell Seam how to find our EJB components in JNDI: + However, it is often useful to be able to provide for some external configuration of some components, + particularly the components that are built into Seam. The most flexible option, here, is to provide this + configuration in a file called components.xml, located in the WEB-INF + directory. The components.xml file can be used to tell Seam how to find our EJB components + in JNDI: @@ -324,14 +364,18 @@ - The above code configures a property named jndiPattern, which belongs to a built-in Seam component named org.jboss.seam.core.init. The @ symbols are used to direct the Ant build script to insert the correct JNDI pattern from the components.properties file when the application is deployed. You will learn more about this process in . + The above code configures a property named jndiPattern, which belongs to a built-in Seam + component named org.jboss.seam.core.init. The @ symbols are used to + direct the Ant build script to insert the correct JNDI pattern from the components.properties file when the + application is deployed. You will learn more about this process in .
The web deployment description: <literal>web.xml</literal> - The presentation layer for our mini-application will be deployed in a WAR, so a web deployment descriptor is required: + The presentation layer for our mini-application will be deployed in a WAR, so a web deployment descriptor is + required: web.xml @@ -339,24 +383,32 @@ - The above web.xml file configures both Seam and JSF. The configuration you see here changes very little between Seam applications. + The above web.xml file configures both Seam and JSF. The configuration you see here changes + very little between Seam applications.
The JSF configration: <literal>faces-config.xml</literal> - Most Seam applications use JSF views as the presentation layer, so faces-config.xml is usually a requirement. In this case, Facelets is used to define our views, so we need to tell JSF to use Facelets as its templating engine. + Most Seam applications use JSF views as the presentation layer, so faces-config.xml is + usually a requirement. In this case, Facelets is used to define our views, so we need to tell JSF to use + Facelets as its templating engine. faces-config.xml - Note that JSF managed bean declarations are unnecessary because the managed beans are annotated Seam components. In Seam applications, faces-config.xml is used much less often than in plain JSF. Here, we use it simply to enable Facelets (and not JSP) as the view handler. + Note that JSF managed bean declarations are unnecessary because the managed beans are annotated Seam + components. In Seam applications, faces-config.xml is used much less often than in plain + JSF. Here, we use it simply to enable Facelets (and not JSP) as the view handler. - Once you have set up all the basic descriptors, the only XML you need write to add functionality to a Seam application will be for orchestration: navigation rules or jBPM process definitions. Seam operates on the principle that process flow and configuration data are all that truly belongs in XML. + Once you have set up all the basic descriptors, the only XML you need write to add functionality to a Seam + application will be for orchestration: navigation rules or jBPM process definitions. Seam operates on the + principle that process flow and configuration data are all that + truly belongs in XML. The above example does not require a navigation rule, since the view ID was embedded in our action code. @@ -366,7 +418,8 @@
The EJB deployment descriptor: <literal>ejb-jar.xml</literal> - The ejb-jar.xml file integrates Seam with EJB3 by attaching the SeamInterceptor to all session beans in the archive. + The ejb-jar.xml file integrates Seam with EJB3 by attaching the + SeamInterceptor to all session beans in the archive. @@ -378,7 +431,9 @@
The EJB persistence deployment descriptor: <literal>persistence.xml</literal> - The persistence.xml file directs the EJB persistence provider to the appropriate datasource, and contains some vendor-specific settings. In this case, it enables automatic schema export at startup time. + The persistence.xml file directs the EJB persistence provider to the appropriate + datasource, and contains some vendor-specific settings. In this case, it enables automatic schema export at + startup time. persistence.xml @@ -397,7 +452,8 @@ - This deployment descriptor links modules in the enterprise archive and binds the web application to the context root /seam-registration. + This deployment descriptor links modules in the enterprise archive and binds the web application to the + context root /seam-registration. You have now seen all of the files in the application. @@ -409,22 +465,36 @@
How it works - When the form is submitted, JSF asks Seam to resolve the variable named user. Since no value is yet bound to that name (in any Seam context), Seam instantiates the user component, and returns the resulting User entity bean instance to JSF after storing it in the Seam session context. + When the form is submitted, JSF asks Seam to resolve the variable named user. Since no value + is yet bound to that name (in any Seam context), Seam instantiates the user component, and + returns the resulting User entity bean instance to JSF after storing it in the Seam session + context. - The form input values are now validated against the Hibernate Validator constraints specified on the User entity. If the constraints are violated, JSF redisplays the page. Otherwise, JSF binds the form input values to properties of the User entity bean. + The form input values are now validated against the Hibernate Validator constraints specified on the + User entity. If the constraints are violated, JSF redisplays the page. Otherwise, JSF binds + the form input values to properties of the User entity bean. - Next, JSF asks Seam to resolve the variable named register. Seam uses the JNDI pattern mentioned earlier to locate the stateless session bean, wraps it as a Seam component, and returns it. Seam then presents this component to JSF and JSF invokes the register() action listener method. + Next, JSF asks Seam to resolve the variable named register. Seam uses the JNDI pattern + mentioned earlier to locate the stateless session bean, wraps it as a Seam component, and returns it. Seam then + presents this component to JSF and JSF invokes the register() action listener method. - Seam then intercepts the method call and injects the User entity from the Seam session context, before allowing the invocation to continue. + Seam then intercepts the method call and injects the User entity from the Seam session + context, before allowing the invocation to continue. - The register() method checks if a user with the entered username already exists. If so, an error message is queued with the FacesMessages component, and a null outcome is returned, causing a page redisplay. The FacesMessages component interpolates the JSF expression embedded in the message string and adds a JSF FacesMessage to the view. + The register() method checks if a user with the entered username already exists. If so, an + error message is queued with the FacesMessages component, and a null outcome is returned, + causing a page redisplay. The FacesMessages component interpolates the JSF expression + embedded in the message string and adds a JSF FacesMessage to the view. - If no user with that username exists, the "/registered.xhtml" outcome triggers a browser redirect to the registered.xhtml page. When JSF comes to render the page, it asks Seam to resolve the variable named user and uses property values of the returned User entity from Seam's session scope. + If no user with that username exists, the "/registered.xhtml" outcome triggers a browser + redirect to the registered.xhtml page. When JSF comes to render the page, it asks Seam to + resolve the variable named user and uses property values of the returned + User entity from Seam's session scope.
@@ -433,7 +503,10 @@
Clickable lists in Seam: the messages example - Clickable lists of database search results are a vital part of any online application. Seam provides special functionality on top of JSF to make it easier to query data with EJB-QL or HQL, and display it as a clickable list using a JSF ]]>. The messages example demonstrates this functionality. + Clickable lists of database search results are a vital part of any online application. Seam provides special + functionality on top of JSF to make it easier to query data with EJB-QL or HQL, and display it as a clickable + list using a JSF ]]>. The messages example demonstrates this + functionality. @@ -446,12 +519,14 @@
Understanding the code - The message list example has one entity bean (Message), one session bean (MessageListBean), and one JSP. + The message list example has one entity bean (Message), one session bean + (MessageListBean), and one JSP.
The entity bean: <literal>Message.java</literal> - The Message entity defines the title, text, date and time of a message, and a flag indicating whether the message has been read: + The Message entity defines the title, text, date and time of a message, and a flag + indicating whether the message has been read: Message.java @@ -463,13 +538,21 @@
The stateful session bean: <literal>MessageManagerBean.java</literal> - As in the previous example, this example contains a session bean (MessageManagerBean) which defines the action listener methods for both of the buttons on our form. As in the previous example, one of the buttons selects a message from the list and displays that message; the other button deletes a message. + As in the previous example, this example contains a session bean (MessageManagerBean) + which defines the action listener methods for both of the buttons on our form. As in the previous example, + one of the buttons selects a message from the list and displays that message; the other button deletes a + message. - However, MessageManagerBean is also responsible for fetching the list of messages the first time we navigate to the message list page. There are various ways for users to navigate to the page, not all of which are preceded by a JSF action. (Navigating to the page from your favourites will not necessarily call the JSF action, for example.) Therefore, fetching the message list must take place in a Seam factory method, instead of in an action listener method. + However, MessageManagerBean is also responsible for fetching the list of messages the + first time we navigate to the message list page. There are various ways for users to navigate to the page, + not all of which are preceded by a JSF action. (Navigating to the page from your favourites will not + necessarily call the JSF action, for example.) Therefore, fetching the message list must take place in a Seam + factory method, instead of in an action listener method. - We want to cache the list of messages in memory between server requests, so we will make this a stateful session bean. + We want to cache the list of messages in memory between server requests, so we will make this a stateful + session bean. MessageManagerBean.java @@ -484,15 +567,15 @@ - + The @DataModel annotation exposes an attibute of type java.util.List to the JSF page as an instance of - javax.faces.model.DataModel. This allows us to use the list - in a JSF <h:dataTable> with clickable links for - each row. In this case, the DataModel is made available in a - session context variable named messageList. + javax.faces.model.DataModel. This allows us to use the list in a JSF + <h:dataTable> with clickable links for each row. In this case, the + DataModel is made available in a session context variable named + messageList. The @DataModelSelection annotation tells Seam to inject the @@ -580,13 +663,31 @@
How it works - The first time we navigate to messages.jsp, the page will try to resolve the messageList context variable. Since this variable is not yet initialized, Seam calls the factory method findMessages, which queries the database and retrieves a DataModel. This provides the row data required to render the ]]>. + The first time we navigate to messages.jsp, the page will try to resolve the + messageList context variable. Since this variable is not yet initialized, Seam calls the + factory method findMessages, which queries the database and retrieves a + DataModel. This provides the row data required to render the + ]]>. - When the user clicks the ]]>, JSF calls the select() action listener. Seam intercepts this call and injects the selected row data into the message attribute of the messageManager component. The action listener fires, marking the selected Message as read. At the end of the call, Seam outjects the selected Message to the message context variable. Next, the EJB container commits the transaction, and the change to the Message is flushed to the database. Finally, the page is re-rendered, redisplaying the message list, and displaying the selected message below it. + When the user clicks the ]]>, JSF calls the + select() action listener. Seam intercepts this call and injects the selected row data into + the message attribute of the messageManager component. The action + listener fires, marking the selected Message as read. At the end of the call, Seam outjects + the selected Message to the message context variable. Next, the EJB + container commits the transaction, and the change to the Message is flushed to the + database. Finally, the page is re-rendered, redisplaying the message list, and displaying the selected message + below it. - When the user clicks the ]]>, JSF calls the delete() action listener. Seam intercepts this call and injects the selected row data into the message attribute of the messageList component. The action listener fires, which removes the selected Message from the list, and also calls remove() on the EntityManager. At the end of the call, Seam refreshes the messageList context variable and clears the message context variable. The EJB container commits the transaction, and deletes the Message from the database. Finally, the page is re-rendered, redisplaying the message list. + When the user clicks the ]]>, JSF calls the + delete() action listener. Seam intercepts this call and injects the selected row data into + the message attribute of the messageList component. The action listener + fires, which removes the selected Message from the list, and also calls + remove() on the EntityManager. At the end of the call, Seam refreshes the + messageList context variable and clears the message context variable. The + EJB container commits the transaction, and deletes the Message from the database. Finally, + the page is re-rendered, redisplaying the message list.
@@ -594,7 +695,9 @@
Seam and jBPM: the todo list example - jBPM provides sophisticated functionality for workflow and task management. As an example of jBPM's integration with Seam, what follows is a simple "todo list" application. Managing task lists is a core function of jBPM, so little Java is required in this example. + jBPM provides sophisticated functionality for workflow and task management. As an example of jBPM's + integration with Seam, what follows is a simple "todo list" application. Managing task lists is a core function + of jBPM, so little Java is required in this example. @@ -607,7 +710,9 @@
Understanding the code - This example revolves around the jBPM process definition. It also uses two JSPs and two basic JavaBeans. (Session beans are not required here since they would not access the database or have any transactional behavior.) We will start with the process definition: + This example revolves around the jBPM process definition. It also uses two JSPs and two basic + JavaBeans. (Session beans are not required here since they would not access the database or have any + transactional behavior.) We will start with the process definition: @@ -623,30 +728,27 @@ - The <start-state> node represents the logical start - of the process. When the process starts, it immediately transitions to the - todo node. + The <start-state> node represents the logical start of the process. When + the process starts, it immediately transitions to the todo node. - The <task-node> node represents a wait - state, where business process execution pauses, waiting for one or more - tasks to be performed. + The <task-node> node represents a wait state, where + business process execution pauses, waiting for one or more tasks to be performed. - The <task> element defines a task to be performed by - a user. Since there is only one task defined on this node, when it is complete, - execution resumes, and we transition to the end state. The task gets its description - from a Seam component named todoList (one of the JavaBeans). + The <task> element defines a task to be performed by a user. Since there + is only one task defined on this node, when it is complete, execution resumes, and we transition to the + end state. The task gets its description from a Seam component named todoList (one of + the JavaBeans). - Tasks need to be assigned to a user or group of users when they are created. In this - case, the task is assigned to the current user, which we get from a built-in Seam - component named actor. Any Seam component may be used to perform task - assignment. + Tasks need to be assigned to a user or group of users when they are created. In this case, the + task is assigned to the current user, which we get from a built-in Seam component named + actor. Any Seam component may be used to perform task assignment. - The <end-state> node defines the logical end of the - business process. When execution reaches this node, the process instance is destroyed. + The <end-state> node defines the logical end of the business + process. When execution reaches this node, the process instance is destroyed. @@ -665,10 +767,14 @@ - This document defines our business process as a graph of nodes. This is the simplest possible business process: there is one task to be performed, and when that task is complete, the business process ends. + This document defines our business process as a graph of nodes. This is the simplest + possible business process: there is one task to be performed, and when that task is + complete, the business process ends. - The first JavaBean handles the login screen, login.jsp. Here, it simply initializes the jBPM actor ID with the actor component. In a real application, it would also need to authenticate the user. + The first JavaBean handles the login screen, login.jsp. Here, it simply initializes the jBPM + actor ID with the actor component. In a real application, it would also need to authenticate + the user. Login.java @@ -697,25 +803,24 @@ - + - The description property accepts user input from the JSP page, and exposes it to the - process definition, allowing the task description to be set. + The description property accepts user input from the JSP page, and exposes it to the process + definition, allowing the task description to be set. - The Seam @CreateProcess annotation creates a new jBPM process - instance for the named process definition. + The Seam @CreateProcess annotation creates a new jBPM process instance for the named + process definition. The Seam @StartTask annotation starts work on a task. The - @EndTask ends the task, and allows the business process execution - to resume. + @EndTask ends the task, and allows the business process execution to resume. @@ -723,8 +828,8 @@ - In a more realistic example, @StartTask and @EndTask would not appear on the - same method, because some work would need to be done with the application in order to complete the task. + In a more realistic example, @StartTask and @EndTask would not appear on + the same method, because some work would need to be done with the application in order to complete the task. @@ -738,14 +843,17 @@ For simplicity's sake, we will look at this once section at a time. - The page renders a list of tasks, which it retrieves from a built-in Seam component named taskInstanceList. The list is defined inside a JSF form. + The page renders a list of tasks, which it retrieves from a built-in Seam component named + taskInstanceList. The list is defined inside a JSF form. todo.jsp (taskInstanceList) - Each element of the list is an instance of the jBPM class TaskInstance. The following code displays certain properties for every task in the list. Input controls are used for description, priority, and due date to allow users to update these values. + Each element of the list is an instance of the jBPM class TaskInstance. The following code + displays certain properties for every task in the list. Input controls are used for description, priority, and + due date to allow users to update these values. TaskInstance List Properties @@ -753,17 +861,22 @@ - Seam provides a default JSF date converter for converting a string into a date, so no converter is necessary for the field bound to #{task.dueDate}. + Seam provides a default JSF date converter for converting a string into a date, so no converter is necessary + for the field bound to #{task.dueDate}. - This button ends the task by calling the action method annotated @StartTask @EndTask. It passes the task ID to Seam as a request parameter: + This button ends the task by calling the action method annotated @StartTask @EndTask. It + passes the task ID to Seam as a request parameter: - Note that this uses a Seam ]]> JSF control from the seam-ui.jar package. This button updates the properties of the tasks. When the form is submitted, Seam and jBPM will make any changes to the tasks persistent. There is no need for any action listener method: + Note that this uses a Seam ]]> JSF control from the + seam-ui.jar package. This button updates the properties of the tasks. When the form is + submitted, Seam and jBPM will make any changes to the tasks persistent. There is no need for any action + listener method: @@ -778,19 +891,37 @@
How it works - After logging in, todo.jsp uses the taskInstanceList component to display a table of outstanding todo items for the current user. (Initially there are none.) The page also displays a form to enter a new task item. When the user types the todo item and clicks the Create New Item button, #{todoList.createTodo} is called. This starts the todo process, as defined in todo.jpdl.xml. + After logging in, todo.jsp uses the taskInstanceList component to + display a table of outstanding todo items for the current user. (Initially there are none.) The page also + displays a form to enter a new task item. When the user types the todo item and clicks the Create + New Item button, #{todoList.createTodo} is called. This starts the todo process, + as defined in todo.jpdl.xml. - When the process instance is created, it transitions immediately to the todo state, where a new task is created. The task description is set based on the user input saved to #{todoList.description}. The task is then assigned to the current user, stored in the seam actor component. In this example, the process has no extra process state — all the state is stored in the task definition. The process and task information is stored in the database at the end of the request. + When the process instance is created, it transitions immediately to the todo state, where a + new task is created. The task description is set based on the user input saved to + #{todoList.description}. The task is then assigned to the current user, stored in the seam + actor component. In this example, the process has no extra process state — all the state is stored in the task + definition. The process and task information is stored in the database at the end of the request. - When todo.jsp is redisplayed, taskInstanceList finds the newly-created task and displays it in an h:dataTable. The internal state of the task is displayed in each column: #{task.description}, #{task.priority}, #{task.dueDate}, etc. These fields can all be edited and saved to the database. + When todo.jsp is redisplayed, taskInstanceList finds the newly-created + task and displays it in an h:dataTable. The internal state of the task is displayed in each + column: #{task.description}, #{task.priority}, + #{task.dueDate}, etc. These fields can all be edited and saved to the database. - Each todo item also has a Done button, which calls #{todoList.done}. Each button specifies taskInstance="#{task}" (the task for that particular row of the table) so that the todoList component is able to distinctly identify which task is complete. The @StartTask and @EndTask annotations activate and immediately complete the task. The original process then transitions into the done state (according to the process definition) and ends. The state of the task and process are both updated in the database. + Each todo item also has a Done button, which calls + #{todoList.done}. Each button specifies taskInstance="#{task}" (the task + for that particular row of the table) so that the todoList component is able to distinctly + identify which task is complete. The @StartTask and @EndTask annotations + activate and immediately complete the task. The original process then transitions into the + done state (according to the process definition) and ends. The state of the task and process + are both updated in the database. - When todo.jsp is displayed again, the completed task is no longer shown in the taskInstanceList, since this component displays only incomplete tasks. + When todo.jsp is displayed again, the completed task is no longer shown in the + taskInstanceList, since this component displays only incomplete tasks.
@@ -799,10 +930,14 @@
Seam pageflow: the numberguess example - For Seam applications with freeform (ad hoc) navigation, JSF/Seam navigation rules are a good way to define page flow. However, in applications with more constrained navigation styles, especially user interfaces that are more stateful, navigation rules make understanding system flow difficult. Combining information from view pages, actions, and navigation rules makes this flow easier to understand. + For Seam applications with freeform (ad hoc) navigation, JSF/Seam navigation rules are a good way to define page + flow. However, in applications with more constrained navigation styles, especially user interfaces that are more + stateful, navigation rules make understanding system flow difficult. Combining information from view pages, + actions, and navigation rules makes this flow easier to understand. - With Seam, jPDL process definition can be used to define pageflow, as seen in the number guessing example that follows. + With Seam, jPDL process definition can be used to define pageflow, as seen in the number guessing example that + follows. @@ -815,7 +950,8 @@
Understanding the code - The example uses one JavaBean, three JSP pages and a jPDL pageflow definition. We will start by looking at the pageflow: + The example uses one JavaBean, three JSP pages and a jPDL pageflow definition. We will start by looking at the + pageflow: @@ -830,26 +966,23 @@ - The <page> element defines a wait state where the - system displays a particular JSF view and waits for user input. The - view-id is the same JSF view id used in plain JSF navigation rules. - The redirect attribute tells Seam to use post-then-redirect when - navigating to the page. (This results in friendly browser URLs.) + The <page> element defines a wait state where the system displays a + particular JSF view and waits for user input. The view-id is the same JSF view id used + in plain JSF navigation rules. The redirect attribute tells Seam to use + post-then-redirect when navigating to the page. (This results in friendly browser URLs.) - The <transition> element names a JSF outcome. The - transition is triggered when a JSF action results in that outcome. Execution will then - proceed to the next node of the pageflow graph, after invocation of any jBPM transition - actions. + The <transition> element names a JSF outcome. The transition is triggered + when a JSF action results in that outcome. Execution will then proceed to the next node of the pageflow + graph, after invocation of any jBPM transition actions. - A transition <action> is just like a JSF action, - except that it occurs when a jBPM transition occurs. The transition action can invoke - any Seam component. + A transition <action> is just like a JSF action, except that it occurs + when a jBPM transition occurs. The transition action can invoke any Seam component. - A <decision> node branches the pageflow, and - determines the next node to execute by evaluating a JSF EL expression. + A <decision> node branches the pageflow, and determines the next node to + execute by evaluating a JSF EL expression. @@ -876,7 +1009,8 @@ - Note that the command button names the guess transition instead of calling an action directly. + Note that the command button names the guess transition instead of calling an action + directly. The win.jspx page is predictable: @@ -901,17 +1035,17 @@ - The first time a JSP page asks for a numberGuess component, Seam - will create a new one for it, and the @Create method will be invoked, - allowing the component to initialize itself. + The first time a JSP page asks for a numberGuess component, Seam will create a + new one for it, and the @Create method will be invoked, allowing the component to + initialize itself. - The pages.xml file starts a Seam conversation, and specifies the pageflow - definition to use for the conversation's page flow. Refer to for more + The pages.xml file starts a Seam conversation, and specifies the + pageflow definition to use for the conversation's page flow. Refer to for more information. @@ -922,7 +1056,8 @@ - This component is pure business logic. Since it requires no information about the user interaction flow, it is potentially more reuseable. + This component is pure business logic. Since it requires no information about the user interaction flow, it is + potentially more reuseable.
@@ -941,33 +1076,34 @@ #{numberGuess.currentGuess}. - The "Guess" button triggers the guess action. Seam refers to the pageflow to handle the action, - and the pageflow invokes #{numberGuess.guess} (which updates the guess count and highest/lowest - suggestions in the numberGuess component), and transitions to the + The "Guess" button triggers the guess action. Seam refers to the pageflow to handle the + action, and the pageflow invokes #{numberGuess.guess} (which updates the guess count and + highest/lowest suggestions in the numberGuess component), and transitions to the evaluateGuess state. - The evaluateGuess state checks the value of #{numberGuess.correctGuess} and - transitions to either the win or evaluatingRemainingGuesses state. Assuming - the number was incorrect, the pageflow transitions to evaluatingRemainingGuesses. This is also - a decision state, which tests the #{numberGuess.lastGuess} state to determine whether or not - the user is allowed further guesses. If further guesses are allowed (lastGuess is - false), we transition back to the original displayGuess state. Since this is - a page state, the associated page /numberGuess.jspx is displayed. This page also contains a - redirect element, so Seam sends a redirect to the user's browser, which begins the process again. + The evaluateGuess state checks the value of #{numberGuess.correctGuess} + and transitions to either the win or evaluatingRemainingGuesses + state. Assuming the number was incorrect, the pageflow transitions to + evaluatingRemainingGuesses. This is also a decision state, which tests the + #{numberGuess.lastGuess} state to determine whether or not the user is allowed further + guesses. If further guesses are allowed (lastGuess is false), we + transition back to the original displayGuess state. Since this is a page state, the + associated page /numberGuess.jspx is displayed. This page also contains a redirect + element, so Seam sends a redirect to the user's browser, which begins the process again. - If on a future request either the win or the lose transition were invoked, - the user would be taken to /win.jspx or /lose.jspx respectively. Both - states specify that Seam should end the conversation, stop holding game and pageflow state, and redirect the user - to the final page. + If on a future request either the win or the lose transition were + invoked, the user would be taken to /win.jspx or /lose.jspx + respectively. Both states specify that Seam should end the conversation, stop holding game and pageflow state, + and redirect the user to the final page. - The numberguess example also contains Give up and Cheat buttons. The - pageflow state for both actions is relatively easy to trace, so we do not describe it here. Pay particular - attention to the cheat transition, which loads a sub-process to handle that particular - flow. Although in this application this process is superfluous, this demonstrates how complex pageflows can be - broken down into smaller, simpler structures to make them easier to understand. + The numberguess example also contains Give up and Cheat + buttons. The pageflow state for both actions is relatively easy to trace, so we do not describe it here. Pay + particular attention to the cheat transition, which loads a sub-process to handle that + particular flow. Although in this application this process is superfluous, this demonstrates how complex + pageflows can be broken down into smaller, simpler structures to make them easier to understand.
@@ -1039,20 +1175,30 @@ - The booking application uses JSF, EJB 3.0 and Seam, together with Facelets for the view. There is also a port of this application to JSF, Facelets, Seam, JavaBeans and Hibernate3. + The booking application uses JSF, EJB 3.0 and Seam, together with Facelets for the view. There is also a port + of this application to JSF, Facelets, Seam, JavaBeans and Hibernate3. - One of the things you will notice about this application is that it is extremely robust. You can open multiple windows, use the back and browser refresh buttons, and enter nonsensical data, but the application is difficult to crash. Seam was designed to make building robust web applications straightforward, so robustness that would previously be hand-coded comes naturally and automatically with Seam. + One of the things you will notice about this application is that it is extremely + robust. You can open multiple windows, use the back and browser refresh buttons, and enter + nonsensical data, but the application is difficult to crash. Seam was designed to make building robust web + applications straightforward, so robustness that would previously be hand-coded comes naturally and + automatically with Seam. - As you browse the source code of the example application and learn how the application works, pay particular attention to the way the declarative state management and integrated validation has been used to achieve this robustness. + As you browse the source code of the example application and learn how the application works, pay particular + attention to the way the declarative state management and integrated validation has been used to achieve this + robustness.
Overview of the booking example - The project structure here is identical to that of the previous project. To install and deploy this application, refer to . Once you have successfully started the application, you can access it by pointing your browser to http://localhost:8080/seam-booking/ + The project structure here is identical to that of the previous project. To install and deploy this + application, refer to . Once you have successfully started the application, you + can access it by pointing your browser to + http://localhost:8080/seam-booking/ The application uses six session beans to implement the business logic for the following features: @@ -1075,7 +1221,9 @@ - HotelBookingAction implements booking and confirmation functionality. This is implemented as a conversation, so this is one of the more important classes in the application. + HotelBookingAction implements booking and confirmation functionality. This is + implemented as a conversation, so this is one of the more important classes in the + application. @@ -1114,31 +1262,63 @@
Understanding Seam conversations - This tutorial concentrates upon one particular piece of functionality: placing a hotel reservation. From the user's perspective, hotel search, selection, booking, and confirmation are one continuous unit of work — a conversation. However, from our perspective, it is important that searching remains separate so that users can select multiple hotels from the same search results page, and open distinct conversations in separate browswer tabs. + This tutorial concentrates upon one particular piece of functionality: placing a hotel reservation. From the + user's perspective, hotel search, selection, booking, and confirmation are one continuous unit of work — a + conversation. However, from our perspective, it is important that searching remains + separate so that users can select multiple hotels from the same search results page, and open distinct + conversations in separate browswer tabs. - Most web application architectures do not have first class constructs to represent conversations, which makes managing conversational state problematic. Java web applications generally use a combination of several techniques. Some state is transferred in the URL, but what cannot be transferred here is either added to the HttpSession or recorded to the database at the beginning and end of each request. + Most web application architectures do not have first class constructs to represent conversations, which makes + managing conversational state problematic. Java web applications generally use a combination of several + techniques. Some state is transferred in the URL, but what cannot be transferred here is either added to the + HttpSession or recorded to the database at the beginning and end of each request. - Since the database is the least-scalable tier, this drastically reduces scalability. The extra traffic to and from the database also increases latency. In order to reduce redundant traffic, Java applications often introduce a data cache to store commonly-accessed data between requests. However, since invalidation is based upon an LRU policy, rather than whether the user has finished using the data, this cache is inefficient. It is also shared between concurrent transactions, which introduces further issues associated with keeping the cached state consistent with that of the database. + Since the database is the least-scalable tier, this drastically reduces scalability. The extra traffic to and + from the database also increases latency. In order to reduce redundant traffic, Java applications often + introduce a data cache to store commonly-accessed data between requests. However, since invalidation is based + upon an LRU policy, rather than whether the user has finished using the data, this cache is inefficient. It is + also shared between concurrent transactions, which introduces further issues associated with keeping the cached + state consistent with that of the database. - State held in the HttpSession suffers similar issues. The HttpSession is fine for storing true session data — data common to all requests between user and application — but for data related to individual request series, it does not work so well. Conversations stored here quickly break down when dealing with multiple windows or the back button. Without careful programming, data in the HttpSession can also grow quite large, which makes the session difficult to cluster. Developing mechanisms to deal with the problems these methods present (by isolating session state associated with distinct concurrent conversations, and incorporating failsafes to ensure conversation state is destroyed when a conversation is aborted) can be complicated. + State held in the HttpSession suffers similar issues. The HttpSession is + fine for storing true session data — data common to all requests between user and application — but for data + related to individual request series, it does not work so well. Conversations stored here quickly break down + when dealing with multiple windows or the back button. Without careful programming, data in the + HttpSession can also grow quite large, which makes the session difficult to + cluster. Developing mechanisms to deal with the problems these methods present (by isolating session state + associated with distinct concurrent conversations, and incorporating failsafes to ensure conversation state is + destroyed when a conversation is aborted) can be complicated. - Seam greatly improves conditions by introducing conversation context as a first class construct. Conversation state is stored safely in this context, with a well-defined lifecycle. Even better, there is no need to push data continually between the application server and the database; the conversation context is a natural cache for currently-used data. + Seam greatly improves conditions by introducing conversation context as a first class + construct. Conversation state is stored safely in this context, with a well-defined lifecycle. Even better, + there is no need to push data continually between the application server and the database; the conversation + context is a natural cache for currently-used data. - In the following application, the conversation context is used to store stateful session beans. These are sometimes regarded as detrimental to scalability, and in the past, they may have been. However, modern application servers have sophisticated mechanisms for stateful session bean replication. JBoss AS performs fine-grained replication, replicating only altered bean attribute values. Used correctly, stateful session beans pose no scalability problems, but for those uncomfortable or unfamiliar with the use of stateful session beans, Seam also allows the use of POJOs. + In the following application, the conversation context is used to store stateful session beans. These are + sometimes regarded as detrimental to scalability, and in the past, they may have been. However, modern + application servers have sophisticated mechanisms for stateful session bean replication. JBoss AS performs + fine-grained replication, replicating only altered bean attribute values. Used correctly, stateful session + beans pose no scalability problems, but for those uncomfortable or unfamiliar with the use of stateful session + beans, Seam also allows the use of POJOs. - The booking example shows one way that stateful components with different scopes can collaborate to achieve complex behaviors. The main page of the booking application allows the user to search for hotels. Search results are stored in the Seam session scope. When the user navigate to a hotel, a conversation begins, and a conversation scoped component retrieves the selected hotel from the session scoped component. + The booking example shows one way that stateful components with different scopes can collaborate to achieve + complex behaviors. The main page of the booking application allows the user to search for hotels. Search + results are stored in the Seam session scope. When the user navigate to a hotel, a conversation begins, and a + conversation scoped component retrieves the selected hotel from the session scoped component. - The booking example also demonstrates the use of RichFaces Ajax to implement rich client behavior without handwritten JavaScript. + The booking example also demonstrates the use of RichFaces Ajax to implement rich client behavior without + handwritten JavaScript. - The search function is implemented with a session-scoped stateful session bean, similar to the one used in the message list example. + The search function is implemented with a session-scoped stateful session bean, similar to the one used in the + message list example. @@ -1161,17 +1341,17 @@ - The @Restrict annotation applies a security restriction to the component. It restricts - access to the component allowing only logged-in users. The security chapter explains more about security - in Seam. + The @Restrict annotation applies a security restriction to the component. It + restricts access to the component allowing only logged-in users. The security chapter explains more + about security in Seam. The @DataModel annotation exposes a List as a JSF - ListDataModel. This makes it easy to implement clickable lists for search screens. In - this case, the list of hotels is exposed to the page as a ListDataModel in the - conversation variable named hotels. + ListDataModel. This makes it easy to implement clickable lists for search + screens. In this case, the list of hotels is exposed to the page as a ListDataModel + in the conversation variable named hotels. @@ -1206,20 +1386,21 @@ The RichFaces Ajax <a:support> tag allows a JSF action event listener to be called by asynchronous XMLHttpRequest when a JavaScript event like - onkeyup occurs. Even better, the reRender attribute lets us render a - fragment of the JSF page and perform a partial page update when the asynchronous response is received. + onkeyup occurs. Even better, the reRender attribute lets us + render a fragment of the JSF page and perform a partial page update when the asynchronous response is + received. - The RichFaces Ajax <a:status> tag lets us display an animated image while we wait - for asynchronous requests to return. + The RichFaces Ajax <a:status> tag lets us display an animated image while we + wait for asynchronous requests to return. - The RichFaces Ajax <a:outputPanel> tag defines a region of the page which can be - re-rendered by an asynchronous request. + The RichFaces Ajax <a:outputPanel> tag defines a region of the page which can + be re-rendered by an asynchronous request. @@ -1228,12 +1409,13 @@ (non-JavaScript) HTML link. The advantage of this over the standard JSF <h:commandLink> is that it preserves the operation of "open in new window" and "open in new tab". Also notice that we use a method binding with a parameter: - #{hotelBooking.selectHotel(hot)}. This is not possible in the standard Unified EL, but - Seam provides an extension to the EL that lets you use parameters on any method binding expression. + #{hotelBooking.selectHotel(hot)}. This is not possible in the standard Unified EL, + but Seam provides an extension to the EL that lets you use parameters on any method binding expression. If you're wondering how navigation occurs, you can find all the rules in - WEB-INF/pages.xml; this is discussed in . + WEB-INF/pages.xml; this is discussed in . @@ -1245,9 +1427,9 @@ selectHotel() method of HotelBookingAction, where the real work occurs. - The following code shows how the booking example application uses a conversation-scoped stateful session bean to - achieve a natural cache of persistent data related to the conversation. Think of the code as a list of scripted - actions that implement the various steps of the conversation. + The following code shows how the booking example application uses a conversation-scoped stateful session bean + to achieve a natural cache of persistent data related to the conversation. Think of the code as a list of + scripted actions that implement the various steps of the conversation. @@ -1271,31 +1453,32 @@ - The @Out annotation declares that an attribute value is outjected - to a context variable after method invocations. In this case, the context variable named - hotel will be set to the value of the hotel instance variable after - every action listener invocation completes. + The @Out annotation declares that an attribute value is + outjected to a context variable after method invocations. In this case, the + context variable named hotel will be set to the value of the + hotel instance variable after every action listener invocation completes. The @Begin annotation specifies that the annotated method begins a - long-running conversation, so the current conversation context will not be destroyed - at the end of the request. Instead, it will be reassociated with every request from the current window, - and destroyed either by timeout due to conversation inactivity or invocation of a matching - @End method. + long-running conversation, so the current conversation context will not be + destroyed at the end of the request. Instead, it will be reassociated with every request from the + current window, and destroyed either by timeout due to conversation inactivity or invocation of a + matching @End method. - The @End annotation specifies that the annotated method ends the current long-running - conversation, so the current conversation context will be destroyed at the end of the request. + The @End annotation specifies that the annotated method ends the current + long-running conversation, so the current conversation context will be destroyed at the end of the + request. - This EJB remove method will be called when Seam destroys the conversation context. Don't forget to define - this method! + This EJB remove method will be called when Seam destroys the conversation context. Don't forget to + define this method! @@ -1304,32 +1487,29 @@ - HotelBookingAction contains all the action listener methods that implement selection, booking - and booking confirmation, and holds state related to this work in its instance variables. This code is much - cleaner and simpler than getting and setting HttpSession attributes. + HotelBookingAction contains all the action listener methods that implement selection, + booking and booking confirmation, and holds state related to this work in its instance variables. This code is + much cleaner and simpler than getting and setting HttpSession attributes. - Even better, a user can have multiple isolated conversations per login session. Log in, run a search, and navigate - to different hotel pages in multiple browser tabs. You'll be able to work on creating two different hotel - reservations at the same time. If you leave any one conversation inactive for long enough, Seam will eventually - time out that conversation and destroy its state. If, after ending a conversation, you backbutton to a page of - that conversation and try to perform an action, Seam will detect that the conversation was already ended, and - redirect you to the search page. + Even better, a user can have multiple isolated conversations per login session. Log in, run a search, and + navigate to different hotel pages in multiple browser tabs. You'll be able to work on creating two + different hotel reservations at the same time. If you leave any one conversation inactive for long enough, Seam + will eventually time out that conversation and destroy its state. If, after ending a conversation, you + backbutton to a page of that conversation and try to perform an action, Seam will detect that the conversation + was already ended, and redirect you to the search page.
The Seam Debug Page - The WAR also includes seam-debug.jar. To make the Seam debug page available, deploy this jar - in WEB-INF/lib alongside Facelets, and set the debug property of the init - component as shown here: + The WAR also includes seam-debug.jar. To make the Seam debug page available, deploy this + jar in WEB-INF/lib alongside Facelets, and set the debug property of the + init component as shown here: - - ]]> - + The debug page lets you browse and inspect the Seam components in any of the Seam contexts associated with your current login session. Just point your browser at @@ -1353,14 +1533,14 @@ Introduction Long-running conversations let you easily maintain state consistency in an application, even in the face of - multi-window operation and back-buttoning. Unfortunately, simply beginning and ending a long-running conversation - is not always enough. Depending on the requirements of the application, inconsistencies between user expectations - and application state can still result. + multi-window operation and back-buttoning. Unfortunately, simply beginning and ending a long-running + conversation is not always enough. Depending on the requirements of the application, inconsistencies between + user expectations and application state can still result. The nested booking application extends the features of the hotel booking application to incorporate room - selection. Each hotel has a list of available rooms from which the user can select. This requires the addition of - a room selection page in the hotel reservation flow. + selection. Each hotel has a list of available rooms from which the user can select. This requires the addition + of a room selection page in the hotel reservation flow. @@ -1371,21 +1551,21 @@ - The user can now select any available room to be included in the booking. If room selection were left in the same - conversation context, this could lead to issues with state consistency — if a conversation variable changes, it - affects all windows operating within the same conversation context. + The user can now select any available room to be included in the booking. If room selection were left in the + same conversation context, this could lead to issues with state consistency — if a conversation variable + changes, it affects all windows operating within the same conversation context. For example, suppose the user clones the room selection screen in a new window. The user then selects the - Wonderful Room and proceeds to the confirmation screen. To check the cost of a more expensive - room, the user returns to the original window, selects the Fantastic Suite for booking, and - again proceeds to confirmation. After reviewing the total cost, the user returns to the window showing - Wonderful Room to confirm. + Wonderful Room and proceeds to the confirmation screen. To check the cost of a more + expensive room, the user returns to the original window, selects the Fantastic Suite for + booking, and again proceeds to confirmation. After reviewing the total cost, the user returns to the window + showing Wonderful Room to confirm. - In this scenario, if all state were stored in the conversation, flexibility for multi-window operation within the - same conversation would be limited. Nested conversations allow us to achieve correct behavior even when context - can vary within the same conversation. + In this scenario, if all state were stored in the conversation, flexibility for multi-window operation within + the same conversation would be limited. Nested conversations allow us to achieve correct behavior even when + context can vary within the same conversation.
@@ -1409,32 +1589,30 @@ - The hotel instance is injected from the conversation context. The hotel - is loaded through an extended persistence context so that the entity - remains managed throughout the conversation. This allows us to lazily load the - availableRooms through an @Factory method by - simply walking the association. + The hotel instance is injected from the conversation context. The hotel is + loaded through an extended persistence context so that the entity remains managed + throughout the conversation. This allows us to lazily load the availableRooms through + an @Factory method by simply walking the association. - When @Begin(nested=true) - is encountered, a nested conversation is pushed onto the conversation stack. When - executing within a nested conversation, components still have access to all outer conversation - state, but setting any values in the nested conversation’s state container does not affect - the outer conversation. In addition, nested conversations can exist concurrently stacked on the + When @Begin(nested=true) is encountered, a nested conversation is pushed onto + the conversation stack. When executing within a nested conversation, components still have access to all + outer conversation state, but setting any values in the nested conversation’s state container does not + affect the outer conversation. In addition, nested conversations can exist concurrently stacked on the same outer conversation, allowing independent state for each. - The roomSelection is outjected to the conversation based on the - @DataModelSelection. Note that because the nested conversation has an - independent context, the roomSelection is only set into the new nested - conversation. Should the user select a different preference in another window or tab a new - nested conversation would be started. + The roomSelection is outjected to the conversation based on the + @DataModelSelection. Note that because the nested conversation has an independent + context, the roomSelection is only set into the new nested conversation. Should the + user select a different preference in another window or tab a new nested conversation would be + started. - The @End - annotation pops the conversation stack and resumes the outer conversation. The - roomSelection is destroyed along with the conversation context. + The @End annotation pops the conversation stack and resumes the outer + conversation. The roomSelection is destroyed along with the conversation + context. @@ -1456,21 +1634,24 @@ - + - When requested from EL, the #{availableRooms} are loaded by the @Factory - method defined in RoomPreferenceAction. The @Factory method will only be executed once to load the values - into the current context as a @DataModel instance. + When requested from EL, the #{availableRooms} are loaded by the + @Factory method defined in RoomPreferenceAction. The + @Factory method will only be executed once to load the values into the current context + as a @DataModel instance. - Invoking the #{roomPreference.selectPreference} action results in the row being selected - and set into the @DataModelSelection. This value is then outjected to the nested conversation context. + Invoking the #{roomPreference.selectPreference} action results in the row being + selected and set into the @DataModelSelection. This value is then outjected to the + nested conversation context. - Revising the dates simply returns to the /book.xhtml. Note that we have not yet nested - a conversation (no room preference has been selected), so the current conversation can simply be resumed. The <s:button> - component simply propagates the current conversation when displaying the /book.xhtml view. + Revising the dates simply returns to the /book.xhtml. Note that we have not yet + nested a conversation (no room preference has been selected), so the current conversation can simply be + resumed. The <s:button> component simply propagates the current conversation when + displaying the /book.xhtml view. @@ -1478,7 +1659,8 @@ - Now that you have seen how to nest a conversation, the following code shows how we can confirm the booking of a selected room by extending the behavior of the HotelBookingAction. + Now that you have seen how to nest a conversation, the following code shows how we can confirm the booking of a + selected room by extending the behavior of the HotelBookingAction. HotelBookingAction.java @@ -1492,24 +1674,22 @@ - Annotating an action with @End(root=true) - ends the root conversation which effectively destroys the entire conversation stack. - When any conversation is ended, its nested conversations are ended as well. As the root is - the conversation that started it all, this is a simple way to destroy and release all state - associated with a workspace once the booking is confirmed. + Annotating an action with @End(root=true) ends the root conversation which + effectively destroys the entire conversation stack. When any conversation is ended, its nested + conversations are ended as well. As the root is the conversation that started it all, this is a simple + way to destroy and release all state associated with a workspace once the booking is confirmed. - The roomSelection is only associated with the booking - on user confirmation. While outjecting values to the nested conversation context will not - impact the outer conversation, any objects injected from the outer conversation are injected - by reference. This means that any changing to these objects will be reflected in the parent - conversation as well as other concurrent nested conversations. + The roomSelection is only associated with the booking on user + confirmation. While outjecting values to the nested conversation context will not impact the outer + conversation, any objects injected from the outer conversation are injected by reference. This means + that any changing to these objects will be reflected in the parent conversation as well as other + concurrent nested conversations. - By simply annotating the cancellation action with - @End(root=true, beforeRedirect=true) - we can easily destroy and release all state associated with the - workspace prior to redirecting the user back to the hotel selection view. + By simply annotating the cancellation action with @End(root=true, + beforeRedirect=true) we can easily destroy and release all state associated with the workspace + prior to redirecting the user back to the hotel selection view. @@ -1517,7 +1697,9 @@ - Feel free to deploy the application and test it yourself. Open many windows or tabs, and attempt combinations of various hotel and room preferences. Confirming a booking will always result in the correct hotel and room preference with the nested conversation model. + Feel free to deploy the application and test it yourself. Open many windows or tabs, and attempt combinations + of various hotel and room preferences. Confirming a booking will always result in the correct hotel and room + preference with the nested conversation model.
@@ -1543,7 +1725,8 @@
- The administration screens use jBPM to manage the approval and shipping cycle for orders. The business process can even be changed dynamically by selecting a different process definition. + The administration screens use jBPM to manage the approval and shipping cycle for orders. The business process + can even be changed dynamically by selecting a different process definition. @@ -1557,14 +1740,20 @@ - The Seam DVD Store demo can be run from the dvdstore directory, as with previous applications. + The Seam DVD Store demo can be run from the dvdstore directory, as with previous + applications.
Bookmarkable URLs with the Blog example - Seam makes it easy to implement applications which keep state on the server side. However, server-side state is not always appropriate, particularly for functionality that serves up content. For this, application state is often stored as part of the URL, so that any page can be accessed through a bookmark at any time. The blog example shows how to implement an application that supports bookmarking throughout, even on the search results page. This example demonstrates Seam's management of application state in the URL. + Seam makes it easy to implement applications which keep state on the server side. However, server-side state is + not always appropriate, particularly for functionality that serves up content. For this, application state is + often stored as part of the URL, so that any page can be accessed through a bookmark at any time. The blog + example shows how to implement an application that supports bookmarking throughout, even on the search results + page. This example demonstrates Seam's management of application state in the URL. @@ -1578,7 +1767,9 @@ - The blog example demonstrates the use of "pull"-style model view control (MVC), where the view pulls data from components as it is being rendered rather than using action listener methods to retrieve and prepare data for the view. + The blog example demonstrates the use of "pull"-style model view control (MVC), where the view pulls data from + components as it is being rendered rather than using action listener methods to retrieve and prepare data for the + view.
Using "pull"-style MVC @@ -1587,7 +1778,10 @@ - If we navigate to this page from a bookmark, the #{blog.recentBlogEntries} data used by the ]]> is retrieved lazily — "pulled" — when required, by a Seam component named blog. This flow of control is the reverse of that used in traditional action-based web frameworks like Struts. + If we navigate to this page from a bookmark, the #{blog.recentBlogEntries} data used by the + ]]> is retrieved lazily — "pulled" — when required, by a Seam + component named blog. This flow of control is the reverse of that used in traditional + action-based web frameworks like Struts. @@ -1601,17 +1795,16 @@ - This component uses a seam-managed persistence context. Unlike - the other examples we've seen, this persistence context is managed by Seam, instead of - by the EJB3 container. The persistence context spans the entire web request, allowing us - to avoid any exceptions that occur when accessing unfetched associations in the view. + This component uses a seam-managed persistence context. Unlike the other + examples we've seen, this persistence context is managed by Seam, instead of by the EJB3 container. The + persistence context spans the entire web request, allowing us to avoid any exceptions that occur when + accessing unfetched associations in the view. - The @Unwrap annotation tells Seam to provide the return value of - the method — the Blog — instead of the actual - BlogService component to clients. This is the Seam - manager component pattern. + The @Unwrap annotation tells Seam to provide the return value of the method + — the Blog — instead of the actual BlogService + component to clients. This is the Seam manager component pattern. @@ -1619,20 +1812,25 @@ - This will store basic view content, but to bookmark form submission results like a search results page, there are several other required definitions. + This will store basic view content, but to bookmark form submission results like a search results page, there + are several other required definitions.
Bookmarkable search results page - The blog example has a small form at the top right of each page that allows the user to search for blog entries. This is defined in menu.xhtml, which is included by the Facelets template template.xhtml: + The blog example has a small form at the top right of each page that allows the user to search for blog + entries. This is defined in menu.xhtml, which is included by the Facelets template + template.xhtml: - To implement a bookmarkable search results page, after the search form submission is processed, we must perform a browser redirect. Because the JSF view ID is used as the action outcome, Seam automatically redirects to the view ID when the form is submitted. We could also have defined a navigation rule as follows: + To implement a bookmarkable search results page, after the search form submission is processed, we must perform + a browser redirect. Because the JSF view ID is used as the action outcome, Seam automatically redirects to the + view ID when the form is submitted. We could also have defined a navigation rule as follows: @@ -1642,20 +1840,35 @@ - However, to get a bookmarkable URL like http://localhost:8080/seam-blog/search/, the values submitted with the form must be included in the URL. There is no easy way to do this with JSF, but with Seam, only two features are required: page parameters and URL rewriting. Both are defined here in WEB-INF/pages.xml: + However, to get a bookmarkable URL like http://localhost:8080/seam-blog/search/, the values + submitted with the form must be included in the URL. There is no easy way to do this with JSF, but with Seam, + only two features are required: page parameters and URL + rewriting. Both are defined here in WEB-INF/pages.xml: - The page parameter instructs Seam to link the searchPattern request parameter to the value held by #{searchService.searchPattern}, whenever the search page is requested, and whenever a link to the search page is generated. Seam takes responsibility for maintaining the link between URL state and application state. + The page parameter instructs Seam to link the searchPattern request parameter to the value + held by #{searchService.searchPattern}, whenever the search page is requested, and whenever + a link to the search page is generated. Seam takes responsibility for maintaining the link between URL state + and application state. - The URL for a search on the term book would ordinarily be http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern=book. Seam can simplify this URL by using a rewrite rule. The first rewrite rule, for the pattern /search/{searchPattern}, states that whenever a URL for search.xhtml contains a searchPattern request parameter, that URL can be compressed into a simplified URL. So, the earlier URL (http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern= book) can instead be written as http://localhost:8080/seam-blog/search/book. + The URL for a search on the term book would ordinarily be + http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern=book. Seam can simplify this + URL by using a rewrite rule. The first rewrite rule, for the pattern + /search/{searchPattern}, states that whenever a URL for search.xhtml contains a + searchPattern request parameter, that URL can be compressed into a simplified URL. So, the earlier URL + (http://localhost:8080/seam-blog/seam/search.xhtml?searchPattern= book) can instead be + written as http://localhost:8080/seam-blog/search/book. - As with page parameters, rewriting URLs is bidirectional. This means that Seam forwards requests for the simplified URL to the correct view, and it automatically generates the simplified view — users need not construct URLs. The entire process is handled transparently. The only requirement for rewriting URLs is to enable the rewrite filter in components.xml: + As with page parameters, rewriting URLs is bidirectional. This means that Seam forwards requests for the + simplified URL to the correct view, and it automatically generates the simplified view — users need not + construct URLs. The entire process is handled transparently. The only requirement for rewriting URLs is to + enable the rewrite filter in components.xml: ]]> @@ -1674,15 +1887,19 @@
Using "push"-style MVC in a RESTful application - Push-style MVC is sometimes used to process RESTful pages, so Seam provides the notion of a page action. The blog example uses a page action for the blog entry page, entry.xhtml. + Push-style MVC is sometimes used to process RESTful pages, so Seam provides the notion of a page + action. The blog example uses a page action for the blog entry page, + entry.xhtml. - We use push-style for the sake of an example, but this particular function would be simpler to implement with pull-style MVC. + We use push-style for the sake of an example, but this particular function would be simpler to implement with + pull-style MVC. - The entryAction component works much like an action class in a traditional push-MVC action-oriented framework like Struts. + The entryAction component works much like an action class in a traditional push-MVC + action-oriented framework like Struts. @@ -1693,16 +1910,23 @@ - Note that the example uses page actions for post validation and the pageview counter. Also note the use of a parameter in the page action method binding. This is not a standard JSF EL feature, but Seam allows it both here and in JSF method bindings. + Note that the example uses page actions for post validation and the pageview counter. Also note the use of a + parameter in the page action method binding. This is not a standard JSF EL feature, but Seam allows it both + here and in JSF method bindings. - When the entry.xhtml page is requested, Seam first binds the blogEntryId page parameter to the model. Remember that, because of URL rewriting, the blogEntryId parameter name won't appear in the URL. Seam then runs the page action, which retrieves the required data — the blogEntry — and places it in the Seam event context. Finally, it renders the following: + When the entry.xhtml page is requested, Seam first binds the + blogEntryId page parameter to the model. Remember that, because of URL rewriting, the + blogEntryId parameter name won't appear in the URL. Seam then runs the page action, which retrieves the + required data — the blogEntry — and places it in the Seam event context. Finally, it renders + the following: - If the blog entry is not found in the database, the EntryNotFoundException exception is thrown. We want this exception to result in a 404 error, not a 505, so we annotate the exception class: + If the blog entry is not found in the database, the EntryNotFoundException exception is + thrown. We want this exception to result in a 404 error, not a 505, so we annotate the exception class: @@ -1717,7 +1941,8 @@ The implementation used depends entirely upon personal preference. - The blog example also demonstrates very simple password authentication, posting to the blog, page fragment caching and atom feed generation. + The blog example also demonstrates very simple password authentication, posting to the blog, page fragment + caching and atom feed generation.
Index: Webservices.xml =================================================================== --- Webservices.xml (revision 39393) +++ Webservices.xml (working copy) @@ -271,13 +271,14 @@ ]]> - + Here, the path of a resource is now mapped with @Path("/seam/resource/rest/customer"). Disabling this feature binds your resource class mappings to a particular deployment scenario. This is not recommended. - + + Seam scans your classpath for any deployed @javax.ws.rs.Path resources or @javax.ws.rs.ext.Provider classes. You can disable scanning and configure these classes manually like so: - + ]]> - + This definition would map the URI suffix of .txt.deutsch to the additional Accept and Accept-Language header values, text/plain and de-DE.
- -
+ +
Resources and providers as Seam components - + Resource and provider instances are, by default, managed by RESTEasy. A resource class will be instantiated by RESTEasy and serve a single request, after which it will be destroyed. This is the default JAX-RS lifecycle. Providers are instantiated once for the entire application. These are stateless singletons. - + Resources and providers can also be written as Seam components to take advantage of Seam's richer lifecycle management, and bijection and security abilities. Make your resource class into a Seam component like so: - + @Name("customerResource") @Path("/customer") public class MyCustomerResource { @@ -470,13 +471,14 @@
- -
+ +
Mapping exceptions to HTTP responses - + + Section 3.3.4 of the JAX-RS specification defines how JAX RS handles checked and unchecked exceptions. Integrating RESTEasy with Seam allows you to map exceptions to HTTP response codes within Seam's pages.xml. If you use pages.xml already, this is easier to maintain than many JAX RS exception mapper classes. - + For exceptions to be handled within Seam, the Seam filter must be executed for your HTTP request. You must filter all requests in your web.xml, not as a request URI pattern that does not cover your REST requests. The following example intercepts all HTTP requests and enables Seam exception handling: @@ -490,20 +492,20 @@ /* ]]> - + To convert the unchecked UnsupportedOperationException thrown by your resource methods to a 501 Not Implemented HTTP status response, add the following to your pages.xml descriptor: - + The requested operation is not supported ]]> - + Custom or checked exceptions are handled in the same way: - + Service not available: #{org.jboss.seam.handledException.message} @@ -513,7 +515,7 @@ You do not have to send a HTTP error to the client if an exception occurs. Seam lets you map the exception as a redirect to a view of your Seam application. Since this feature is typically used for human clients (web browsers) and not for REST API remote clients, you should pay attention to conflicting exception mappings in pages.xml. - + The HTTP response does pass through the servlet container, so an additional mapping may apply if you have <error-page> mappings in your web.xml configuration. The HTTP status code would then be mapped to a rendered HTML error page with status 200 OK. Index: Book_Info.xml =================================================================== --- Book_Info.xml (revision 39393) +++ Book_Info.xml (working copy) @@ -4,7 +4,7 @@ Seam Reference Guide - for Use with JBoss Enterprise Web Platform 5 + for use with JBoss Enterprise Web Platform 5 5.1.0 11 JBoss Enterprise Web Platform