February 11, 2008
The preview chapters will soon be released but you can get a sneak peak by accessing the code examples here. Feel free to download the examples and try them out! Each example project included in the source bundle is a variant of the Seam Hotel Booking example. The booking project demonstrates the use of natural conversations and navigation-based conversation management while the nestedbooking project demonstrates the use of nested conversations.
You can deploy the examples by first editing the included build.properties file to include the following settings:
- jboss.home – the location of your local JBoss instance (the examples have been tested against JBoss AS 4.2.2.GA)
- seam.home – the location of the latest Seam distribution (the examples have been tested against JBoss Seam 2.0.1.GA)
Once you have made these changes simply execute ant main deploy. This will build the example and deploy it to the configured JBoss instance. If you have any questions or run into any issues with the examples, please let us know!
Enjoyed this post? Share it! |
Posted in JBoss Seam, JBoss Seam 2E News
No Comments »
January 31, 2008
The much anticipated Second Edition of JBoss(R) Seam: Simplicity and Power Beyond Java(TM) EE (Prentice Hall JBoss) is coming soon. Michael Yuan and myself have teamed up to develop the content for the upcoming Second Edition which will cover the ins and outs of Seam 2, and I don’t just mean bijection
The first preview chapters were released around the time of JBoss World along with 2 code examples. The full draft chapters will be available soon from Safari rough cut. The initial electronic release provides a preview of the following chapters:
- Chapter 7: Conversations
- What is a Conversation?
- The Default Conversation Scope
- Display JSF Messages
- Long-running Conversations
- Introducing the Hotel Booking Example
- The Lifecycle of a Long-running Conversation
- Conversation Timeout
- Managing Long-Running Conversations
- Beginning a Long-running Conversation
- Inside the Conversation
- End a Long-running Conversation
- Links and Buttons
- New Frontiers
- Chapter 8: Workspaces
- What is a Workspace?
- Workspace Management
- The Workspace Switcher
- Carry a Conversation Across Workspaces
- Managing the Conversation ID
- Natural Conversations
- Beginning a Natural Conversation through Linking
- Redirecting to a Natural Conversation
- Resuming a Natural Conversation
- Rewriting to User-friendly URLs
- Workspace Timeout
- Desktop Features in a Stateless Web
- Chapter 9: Nested Conversations
- Why are Nested Conversations Needed?
- Continuing the Conversation
- Understanding the Nested Conversation Context
- Nesting Conversations
- The Conversation Stack
- Managing the Conversation Stack
- Displaying Breadcrumbs
- Nested Conversation Timeout
- Fine-grained State Management
The code examples demonstrate how to manage conversations through navigation, the use of natural conversations, a new feature included in the latest release of Seam, and usage of nested conversations. To stay up-to-date you can watch for announcements at both my blog and Michael’s. You can also keep watch at the official Pearson product page. Stay tuned!
Enjoyed this post? Share it! |
Posted in JBoss Seam
No Comments »
January 8, 2008
With Seam you have options for component configuration. One of those options is configuration through use of components.xml. This is especially valuable when you have components that are reused among application instances as it allows the configuration to be specific based on the needs of the application. Seam provides a very simple approach to limit or even eliminate configuration errors through the use of Namespaces and schemas.
It is quite ugly and error-prone to configure components in the following manner:
@Name("myComponent")
public class MyComponent {
private Map<String, String> componentMapping;
private BigDecimal someDecimalValue;
... ...
// component getters and setters
}
In components.xml:
... ...
<component name="myComponent">
<property name="someDecimalValue" value="22.2" />
<property name="componentMapping">
<key>someKey</key> <value>someValue</value>
... ...
</property>
... ...
</component>
... ...
Generating a Namespace and schema for your Seam components is actually quite simple and by taking the time to do this, you gain the benefits of:
- auto-completion within the IDE (or your favorite XML editor)
- validation of your configuration prior to deployment (attributes and even values if restrictions are defined)
- very lean configuration (makes your custom components look good
)
The Seam Reference Guide simply references the schemas shipped with Seam as examples for generating your own, but I thought a brief tutorial for those less familiar with XML schemas might be helpful.
Creating a Namespace
First off, you need to create a Namespace. As the documentation demonstrates, this is actually quite simple with Seam through the use of the @Namespace annotation. Just create a file named package-info.java in the package of your components:
@Namespace(value="http://solutionsfit.com/example/custom")
package com.solutionsfit.example.custom;
import org.jboss.seam.annotations.Namespace;
All of the components for this Namespace must be in this package. You cannot have the same Namespace referenced in multiple package-info.java files. While this makes sense it can be a hinderance in situations where you have sub-packaging.
Now we can reference the Namespace in our components.xml:
<components xmlns="http://jboss.com/products/seam/components"
xmlns:custom="http://solutionsfit.com/example/custom"
... ...
<custom:my-component ... />
As you will note, component names and attribute names are specified in the hyphenated form when using Namespaces. I refer you to the Seam Reference Guide for more details on configuring Namespaced elements.
Manually generating the schema
Now for the schema. So we have a Namespace defined for our custom components, but it would be great to have auto-complete and validation in our components.xml. The following template should help you get there:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
targetNamespace="http://solutionsfit.com/example/custom"
xmlns:custom="http://solutionsfit.com/example/custom"
xmlns:components="http://jboss.com/products/seam/components"
attributeFormDefault="unqualified">
<xs:import namespace="http://jboss.com/products/seam/components"
schemaLocation="http://jboss.com/products/seam/components-2.0.xsd"/>
<xs:element name="my-component">
<xs:complexType>
<xs:sequence>
<xs:element name="component-mapping" minOccurs="1" maxOccurs="1"
type="components:mapProperty" />
</xs:sequence>
<xs:attributeGroup
ref="components:attlist.component"/>
<xs:attributeGroup
ref="custom:attlist.my-component" />
</xs:complexType>
... ...
<xs:attributeGroup id="attlist.my-component">
<xs:attribute name="some-decimal-value"
type="xs:decimal" required="false">
... ...
</xs:attributeGroup>
</xs:element>
... ...
You’ll notice that we import the Seam components-2.0.xsd and reference it as a namespace. This gives us access to the basic component attributes that will be configurable on your component.
Also notice, on my-component we reference an attribute group components:attlist.component. This attribute group is defined in the components Namespace we imported and provides the attributes you’d expect for a Seam component (i.e. name, scope, auto-create, …). In addition, we define an element named component-mapping of type components:mapProperty. Here we have used a type defined in the components Namespace. This is very convenient as we can now specify the following our components.xml:
... ...
<custom:my-component some-decimal-value="22.2">
<custom:component-mapping>
<key>someKey</key> <value>someValue</value>
... ...
</custom:component-mapping>
... ...
Another type multiValuedProperty can be used for Lists configured within your component.
You may also note that I specified restrictions within my component-mapping element. minOccurs=1 and maxOccurs=1 will ensure that the component-mapping element is provided if my-component is specified in the components.xml definition. It is good practice to provide these types of restrictions to avoid configuration errors at run-time which can be difficult to debug. By specifying them in our schema, our XML editor will notify us of validation issues. A good tutorial on schema definitions can be found at w3schools.
Referencing the schema
Once my schema is specified, I can simply reference the schema in components.xml in the xsi:schemaLocation attribute:
<components xmlns="http://jboss.com/products/seam/components"
xmlns:core="http://jboss.com/products/seam/core"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://jboss.com/products/seam/core
http://jboss.com/products/seam/core-2.0.xsd
http://jboss.com/products/seam/components
http://jboss.com/products/seam/components-2.0.xsd
http://solutionsfit.com/example/component
http://solutionsfit.com/example/component-1.0.xsd">
... ...
But, there is one final step to get auto-complete and validation. If you attempt to validate the XML at this point you will notice errors on your custom component configuration. This is simply because Eclipse cannot find the XSD we specified.
Craig Walls posted a blog entry back in August on how to fix errors in Eclipse with Spring Modules in your XML. The same fix applies for your own custom XSDs. Simply reference the XSD on your local drive from the “Add XML Catalog Entry” dialog as Craig describes. Once you’ve referenced your schema, refresh your components.xml and you are in business! You will now have auto-complete and validation for your custom components.
Sidenote: Auto-generation of schemas for custom components would be a great feature addition for seam-gen. While it would not be trivial to implement, if interest in this posting is high enough I would be happy to contribute a patch as soon as my schedule permits
.
Enjoyed this post? Share it! |
Posted in JBoss Seam
2 Comments »
December 20, 2007
Update: Pete Muir recently posted an alternative to the example described here for the UserProfile object. It avoids potential LazyInitializationException if you access a property which was not initialized inside the loading conversation since the UserProfile is SESSION scoped. I prefer Pete’s approach to the implementation but the concept is the same 
______________________________________________________________
One thing I have really come to appreciate in seam is the ask and ye shall receive approach of injection of not only components but also core domain objects (or concepts depending on how you look at it). One issue I’ve always struggled with is the requirement to constantly go and get some domain object that is used very often. This really reminds me of the EJB2 style lookups which was really why we starting using DI frameworks, right? Whether you look up the domain object through a DAO, through the session, or through some holder object, you still have to go and get what you need.
For example, let’s say we have a UserProfile object that is needed by most of our pages and many of the components in our application to retrieve user information. It may not always be needed (we have an Identity of course thanks to Seam which provides our authentication and authorization), but it is needed if we require personal information about our user.
In the general world of Java you could implement this in several ways but lets say we do so through something like the following:
public class UserInformationBean implements UserInformation
...
private UserProfile userProfile;
// injected by your favorite DI framework
// (Seam, EJB3, Spring, even PicoContainer)
private UserProfileDAO userProfileDAO;
...
public boolean isUserLocal()
{
UserProfile userProfile = this.getUserProfile();
if("Texas".equals(userProfile.getState())
&& "Dallas".equals(userProfile.getCity()))
{
return true;
}
log.info("ya'll ain't from around here are ya");
return false;
}
...
public UserProfile getUserProfile()
{
if(userProfile == null)
{
this.userProfile = userProfileDAO.getUserProfile(
SomeContext.getUserPrincipal().getName());
}
return this.userProfile;
}
...
Here is the associated dependency diagram for our UserInformationBean component:

This is all well and good but I would prefer if the call to retrieve the UserProfile was centralized since I use it often. This is quite easy with Seam:
@Name("userProfileManager")
public class UserProfileManager {
...
@In private UserProfileDAO userProfileDAO;
...
@Factory(value="userProfile", scope=ScopeType.SESSION,
autoCreate=true)
public UserProfile initCurrentUserProfile()
{
return userProfileDAO.getUserProfile(
Identity.instance().getUsername());
}
...
Note that I scope my UserProfile to the session which makes sense since the user is not likely changing profiles (or we may be in for some legal issues) and we are using it throughout the application. Note that conversation scope should be considered if the object is only needed in a section of the application to ensure that our state is cleaned up appropriately. The use of other contexts will be discussed further shortly. So now my component looks like:
@Name("userInformation")
public class UserInformationBean implements UserInformation
...
@In UserProfile userProfile;
...
public boolean isUserLocal()
{
if("Texas".equals(userProfile.getState())
&& "Dallas".equals(userProfile.getCity()))
{
return true;
}
log.info("ya'll ain't from around here are ya");
return false;
}
...
Below is the dependency diagram for our UserInformationBean after the change. Note that our UserInformationBean knows nothing about the UserProfileDAO (nor does it care):

So you may ask what does this buy me? I still have to call the DAO to get what I need. Sure, you may have to call your DAO (or the EntityManager if your using EJB3), but the dependency on the DAO is in one place, not scattered. Your component is now only dependent on what it needs to get the job done and we’ve removed unnecessary layering thereby reducing coupling.
In addition, the factory method only executes once during the course of a user session as I’ve scoped my UserProfile to the session. Thus, the UserProfile is instantiated lazily (since the @Factory method only executes on demand) and if it is used elsewhere it is simply provided back from the context rather than invoking the DAO again.
I also find this approach much easier to test. Rather than having to provide a mock DAO (or even worse a mock EntityManager) to my component, I simply set the UserProfile to whatever I need it to be to perform my unit test:
...
public void testIsUserLocal()
{
UserProfile = new UserProfile("Jacob Orshalick", "Dallas", "Texas");
UserInformationBean bean = new UserInformationBean();
bean.setUserProfile(userProfile);
assertTrue("Howdy! Ya'll oughta be returnin' true.",
bean.isUserLocal());
}
...
Additional Considerations
One drawback to this approach is determining where these domain objects are coming from. It may not be immediately obvious as to how these objects are just appearing in the context for developers. One approach to help with this is using symbolic constants. Using our example above we could create a constant for the UserProfile:
...
public final static String USER_PROFILE = "userProfile";
...
We can use this in both the factory and the injection:
...
@Factory(value=DomainConstant.USER_PROFILE, scope=ScopeType.SESSION,
autoCreate=true)
...
@In(value=DomainConstant.USER_PROFILE)
UserProfile userProfile;
...
In this way a user can easily seek out where USER_PROFILE is referenced rather than having to do a text search (which could easily result in a vast number of results especially if used in EL expressions and comments).
Another consideration here is how your domain object will be used. This is necessary to determine which context to outject to. Is my UserProfile being used heavily in all of the application or is it only a section of the application? Conversation context would be a better candidate if the UserProfile is heavily required in a certain section of the application. Also, what are the memory penalties involved? Would it be better to simply request when needed to avoid the additional memory allocation? This may be the case if the object is used infrequently. It may be best to inject a local instance only that is only used for the invocation. Developers should always carefully consider the context.
Bijection and Disinjection
One way to explicitly control the scope of the creation of the UserProfile would be to leave off the ScopeType in your @Factory definition. Because a POJO is by default EVENT scoped, the UserProfile would only be available to your component and you choose whether to outject it to a broader context. This can simply be accomplished through use of the @Out annotation.
If you choose to leave off the ScopeType and inject a local instance in your component, the @Factory method would be invoked once for each request that your component is invoked. Why is that you ask? Essentially, Seam disinjects any attributes in your component annotated with @In after the invocation. Disinject is really just a fancy way of saying set to null.
This is an important concept as you may expect your attribute to remain set in between requests if I scoped my component to the Conversation or the Session. This behavior makes sense though as Seam maintains contextual state. The current context state is always injected into your component for each invocation. Therefore, it makes no sense to maintain the attribute instance as it will be overwritten prior to the next invocation.
This type of domain concept injection is very useful as it helps to reduce coupling and the heavy layering constantly introduced into systems. There are many situations where this type of behavior is quite handy but it is only achievable due to the contextual injection that Seam provides.
Enjoyed this post? Share it! |
Posted in JBoss Seam, JSF
2 Comments »
December 13, 2007
Conversation timeout seems to be a commonly misunderstood Seam concept. I often see postings on the Seam forums claiming that the conversation-timeout doesn’t work! Well, actually it does, you simply have to understand the semantics.
Configuring the conversation-timeout period can be accomplished through the following in your components.xml:
<core:manager conversation-timeout="900000" />
At first glance most developers relate conversation-timeout to session timeout, where any conversation will simply timeout after the configured conversation timeout period. As you will quickly notice during testing, this is not the case. To execute a quick experiment, try the following configuration in the components.xml of the seam-booking example:
<core:manager conversation-timeout="60000" />
Because the conversation-timeout is set in milliseconds, the above configuration sets the conversation-timeout to 1 minute. Now in the web.xml set the session timeout to 5 minutes:
<session-config>
<session-timeout>5</session-timeout>
</session-config>
Now in the destroy method of the HotelBookingAction add the following line:
...
@Destroy @Remove
public void destroy() {
log.info("Destroying HotelBookingAction...");
}
...
This will log our message when the conversation ends and the HotelBookingAction is destroyed. Now deploy the seam-booking example to your local JBoss instance and start up a conversation. This can be accomplished by logging in, navigating to the hotels listing, and selecting a hotel for booking. At this point, wait for the 1 minute period… nothing happens. Now wait for another 4 minutes, the message is displayed. The conversation timed out along with the session.
Foreground vs. Background Conversations
So why didn’t our conversation timeout as configured? This is because the conversation-timeout only affects background conversations. The foreground conversation will only timeout when the session times out. Foreground, background, what? The foreground conversation is the conversation that the user last interacted with. A background conversation is any other conversation in the user’s session. Thus, in our previous scenario the foreground conversation timed out with the session as expected.
Now lets try another approach. Perform the same steps as before to proceed to the booking screen. Now open a new window and perform the same steps. We now have a foreground conversation and a background conversation in progress. Again, wait 1 minute. Nothing happened. If you wait an additional 4 minutes, both conversations will timeout. So what is going on here, I thought we had a background conversation? We did, Seam simply checks the conversation timeout on each request. Thus, if I interact with the foreground conversation after 1 minute, the background conversation times out. Try it, perform the same steps, wait 1 minute and then click on the window of the foreground conversation and you will see the log message.
This is very desirable behavior. Essentially when a user leaves his or her desk for a period of time and comes back, if the session is still active it would be desirable to maintain the state the user was previously in. This is the foreground conversation state. All other background conversation state is left to timeout after the configured conversation-timeout period which reduces overall memory consumption. This enables a developer to think less about memory usage and cleaning up state and more about developing business logic. That’s why we’re here right?
Letting the user choose
So you may be asking at this point why the conversation-timeout doesn’t use polling. As we said, you must interact with the foreground conversation to cause the background conversations to timeout after the conversation-timeout period. Imagine that the user had many windows open and leaves his or her desk. Based on which window the user clicks on when they return, that becomes the foreground conversation timing out any other background conversations. This gives the user a chance to resume whichever conversation he or she chooses, not the one the developer chooses.
Enjoyed this post? Share it! |
Posted in JBoss Seam
25 Comments »
December 4, 2007
Query by example (QBE) is a great feature for easily executing Criteria using Hibernate. By simply filling in an object and submitting it, Hibernate automatically generates the query based on the values set in the object. While this is an attractive option, in my experience it usefulness quickly becomes limited. In many cases, specifying Restrictions is required which quickly leads to ugly code. For example, lets take a Product class:
@Entity
@Table(name="PRODUCTS")
public class Product {
@Id
@Column(name="ID")
private BigDecimal id;
@Column(name="SKU")
private String sku;
@Column(name="CATEGORY")
private Category category;
@Column(name="NAME")
private String name;
@Column(name="DESCRIPTION")
private String description;
@Column(name="STARTED_OFFERING")
private Date startedOffering;
@Column(name="PRICE")
private BigDecimal price;
...
}
This class has a number of attributes we could search on. The easiest of which are probably the category and name. With the id and name we can simply populate and object instance and use QBE:
...
Product product = new Product();
product.setCategory(Category.APPAREL);
product.setName("slacks");
Example productExample =
Example.create(product).ignoreCase().enableLike();
List results = session.createCriteria(Product.class)
.add(productExample)
.list();
...
This works fine, but what if we want to search for products in a price range say gift ideas from $30.00 to $50.00, or products that we started offering between December 1, 2006 and March 31, 2007. Obviously we can’t accomplish this by simply setting values into our example product. We need to use the Criteria API in this case:
...
List products = session.createCriteria(Product.class)
.add(Restrictions.between("price", minPrice, maxPrice))
.add(Restrictions.
between("startedOffering", startDate, endDate))
.list();
...
This seems pretty simple but what if we need to add this to the UI. Well, first we need an object to bind our data to:
...
public class ProductCriteria {
private BigDecimal minPrice;
private BigDecimal maxPrice;
private Date beginStartedOffering;
private Date endStartedOffering;
...
// getters and setters for attributes
...
}
Now we will need to perform checks to determine how to execute the search:
...
if(productCriteria.getMaxPrice() != null)
{
criteria.add(Restrictions.less("price",
productCriteria.getMaxPrice()))
}
if(productCriteria.getMinPrice() != null)
{
criteria.add(Restrictions.greater("price",
productCriteria.getMinPrice()))
}
...
Etc, etc… As you can imagine the problem is exacerbated the more Restrictions that become required to execute the search. So what about a hybrid approach? Lets define a few annotations:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Criteria {
Class entity;
}
...
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Criterion {
String property;
Restriction operator default Restriction.EQUALS;
}
...
Restriction is simply a Java5 enum that will map to a Hibernate Restriction (this can be done through a polymorphic method in your Restriction implementation). Alright, now lets place these annotations on our Criteria object that we bound to the UI:
@Criteria(entity=Product.class)
public class ProductCriteria {
@Criterion(property="price", operator=Restrictions.LESS)
private BigDecimal minPrice;
@Criterion(property="price", operator=Restrictions.GREATER)
private BigDecimal maxPrice;
@Criterion(property="startedOffering",
operator=Restrictions.GREATER)
private Date beginStartedOffering;
@Criterion(property="startedOffering",
operator=Restrictions.LESS)
private Date endStartedOffering;
...
// getters and setters for attributes
...
}
At run-time the annotations can be processed to create and execute the criteria provided the object that we bound to the UI. Assuming we have a ProductCriteria instance populated with data from our UI interaction, the call would look like:
...
List <Product> products =
criteriaManager.execute(productCriteria, entityManager);
...
The CriteriaManager knows the entity type we’re searching for (we placed it in the @Criteria annotation), it knows the restrictions we’re applying and which @Entity property we are applying them to (that is in the @Criterion annotations), and it knows the values that will be used in executing (based on the attribute the @Criterion annotation is placed on). We could also directly inject the EntityManager instance into the CriteriaProcessor.
So you may say this just seems like we’re moving the problem around. Well, not really. There are some benefits to this approach:
- Vendor independence: The use of custom APIs is eliminated. Instead of calling on the Hibernate Criteria API, it becomes very simple to swap out our implementation. Simply alter the code that processes the annotations we defined.
- One-stop shop: The annotations place the meta-data about how a criteria should execute with the actual criteria values. If changes need to be made to your example query, you make the changes in a single location rather than having to alter both your object bound to the UI and some DAO that processes that object. Additionally, the logic associated with executing criteria is right where it belongs, on the criteria object.
- Remove unnecessary DAOs: Removes the need for a custom DAO to process the object bound to the UI with a bunch of if/thens. The EntityManager provided by JPA was a recognition that the constant DAOs implementing CRUD interfaces could be generalized. This approach recognizes that constant implementation of DAOs handling if/then scenarios can be generalized.
- JPA Consistency: The @Criteria and @Criterion annotations look very similar to @Entity and @Column. This is intentional to create consistency between our @Entity mappings and our @Criteria mappings.
- Testability: All logic for creation of criteria is in one place, the annotation processor. This one place can be heavily tested ensuring its functionality. A custom annotation processor could be developed to make testing your criteria classes very simple (development of this annotation processor is actually very simple).
- Code generation: Tools like grails use compile-time annotation processing through an APT to auto-generate things like JSPs, classes, configuration, etc. This same approach can be taken using @Criteria. It would be fairly simple to write an APT that generates search criteria JSPs based on the @Criteria instance and the provided annotations.
Essentially we have a very reusable criteria execution strategy. There are of course many extensions that could be included with this including:
- conjunctions – what about ANDs and ORs?
- associations – what happens if my mappings contain a @OneToOne, @OneToMany, or even a @ManyToMany?
- dynamic operators – what if my operators are not static (i.e. the user can choose an operator)?
These questions will be answered in an upcoming post so stay tuned.
Enjoyed this post? Share it! |
Posted in Hibernate, JPA
6 Comments »
November 16, 2007
Differentiating between an initial login, a session expired, and a logout when displaying messages to the user on the login screen seems like a simple task. The implementation is unfortunately not quite as simple as it sounds and requires a little legwork. The following tutorial will guide you through the requirements.
The first component is a PhaseListener that allows you to determine whether the user’s session expired or whether this is the first time the user accessed the application. You have to make some assumptions here, but you can basically notify the user when the server session has ended by adding the following to a PhaseListener:
...
@Observer("org.jboss.seam.beforePhase")
public void beforePhase(PhaseEvent event)
{
if(event.getPhaseId() == PhaseId.RESTORE_VIEW)
{
HttpServletRequest request =
(HttpServletRequest) FacesContext.getCurrentInstance()
.getExternalContext().getRequest();
if(request.getRequestedSessionId() != null
&& request.getSession().isNew())
Events.instance().raiseEvent("security.sessionExpired");
...
Based on general cookie settings this will raise the event when the user still has the browser window open, the http session expired, and the user tries to access the application. If the user closes and reopens the browser to start the application, the event will not be raised. This of course makes the assumption that cookies expire when the browser session is ended (which is generally the case).
This works well, but unfortunately the FacesMessages component is not available until after the RENDER_RESPONSE phase has executed. This is because the FacesMessages component is conversation scoped and the conversation is not started until after the RENDER_RESPONSE phase. Thus, you have to have a component available to store your message until the FacesMessages component becomes available. This can be accomplished by using an appropriately scoped component. For example:
@Name("customAuthenticator")
@AutoCreate
@Scope(SESSION)
public class CustomAuthenticator implements Authenticator {
@Logger
private Log log;
...
private List<string> messages;
...
@Observer("security.sessionExpired")
public void sessionExpired(String message)
{
log.info("Adding session expired message...");
this.messages.add("User session expired.");
}
public void flushMessages()
{
for(String message : this.messages)
FacesMessages.instance().add(message);
this.messages.clear();
}
}
The flushMessages method should be invoked either by an action on your pages.xml or by flushing after the INVOKE_APPLICATION phase (this is up to your preference). Simply ensure that the flushing occurs only once the conversation has been initialized so that FacesMessages is available in the context.
This takes care of differentiating between a session timeout and a new session. So what about the logout? If you flush the security messages on every request, the user will end up seeing a message saying that the “User session ended” on logout.
To resolve this we can place a page in between and perform a meta redirect. First define a Seam page that does not require a login. Then in this page, add the following meta tags:
<meta http-equiv="Refresh" content="3; URL=/myApp/myPage.seam" />
This page can display a simple message to the user along the lines of: “You have successfully logged out.” The user will then be redirected to myPage after 3 seconds. As long as the messages are flushed on each request, the “User session ended” message will be long gone once the meta redirect executes.
Next add an entry in your pages.xml to redirect to this page when a logout occurs:
<page view-id="*">
<navigation from-action="#{identity.logout}">
<redirect view-id="/logoutConfirmation.xhtml" />
</navigation>
</page>
A feature request has been placed to include the security.sessionExpired event as well as a security.newSession event. If you are interested in Seam providing this behavior out-of-the-box, please vote!
Update: Are you looking for an advanced polling solution for session expiration? Christian Bauer blogged about an approach to polling for session expiration here.
Enjoyed this post? Share it! |
Posted in JBoss Seam, JSF
10 Comments »
November 13, 2007
In an implementation using the JBoss RichFaces rich:dataScroller component, I noticed the first attribute of a UIData component is maintained even if the DataModel it is displaying has changed. It turns out, this is an issue with JSF. The UIData component does not track the DataModel it represents. Thus, when the DataModel is updated it has no effect on the first attribute of the UIData component. In defense of JSF, it would be difficult to know when a DataModel update should trigger an update of the UIData as this would require making some assumptions about the model.
As you can imagine, this can lead to consistency issues with data versus the state of the UI when pagination is used. For example, if I have a DataModel that wraps a List of 100 elements that are the results of a search. In the display, I can show 10 elements per page and allow the user to paginate freely with the rich:dataScroller component. If the user paginates to the fifth listing, the first attribute of the UIData component now points to 50. If the user then narrows the search (by changing some search criteria and re-submitting) the result set is reduced to 10. Now we have an issue. The user sees no results because the UIData is looking for index 50 to start the List. The first attribute does not get updated to reflect the change in the model.
So how can we resolve this? A simple Seam interceptor would do the trick (if you are already using stereotypes this will be a snap). Assuming you have not yet created a stereotype for your Action classes, the following steps can be taken,
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Interceptors(ActionInterceptor.class)
@Inherited
public @interface Action {}
This will ensure that any @Action class will be intercepted by the ActionInterceptor. Now create a method-level annotation similar to the following:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Search {
String dataTableId();
}
The dataTableId is the component ID of the DataTable in your page. Note: This will require that you specify unique IDs for your components which is good practice in JSF anyway. Next, you must provide the interceptor which does the work of reseting the first attribute for the component. When an @Search action is executed that resets the DataModel, we want to reset the UIData:
@Interceptor(stateless=true)
public class ActionInterceptor implements Serializable
{
...
@AroundInvoke
public Object aroundInvoke(InvocationContext invocation)
throws Exception
{
Method method = invocation.getMethod();
if(method.isAnnotationPresent(Search.class))
{
UIComponent component = FacesContext
.getCurrentInstance().getViewRoot()
.findComponent(searchAnnotation.dataTableId());
if(component != null && component instanceof UIData)
{
UIData dataTable = (UIData) component;
dataTable.setFirst(0);
}
}
result = invocation.proceed();
}
...
You would probably want to add your own exception handling to this as well. Finally, we can use it in our application:
@Name("myAction")
@Stateful
@Action
public class MyActionBean implements MyAction {
...
@DataModel
List<myentity> searchResults;
...
@Search(dataTableId="myForm:searchResults")
public void search() throws Exception
{
searchResults = entityManager.createQuery(...)
.getResultList();
}
...
As I mentioned before, if stereotypes are already being used, this becomes a snap. Simply add the @Search annotation and add the code to handle the dataTable reset in your existing ActionInterceptor.
Enjoyed this post? Share it! |
Posted in JBoss Rich Faces, JBoss Seam, JSF
5 Comments »
November 9, 2007
Recently reading the Web Beans Manifesto, I was intrigued by the use of stereotypes through annotation. Stereotypes are not a new concept. In fact the UML used them as extensibility mechanisms for defining new model elements that have specific properties suitable to your problem domain. Sound familiar?
The following diagram demonstrates some typical stereotypes:

Obviously, this indicates certain semantics specific to each class we see in the diagram. Generally the semantics of the stereotype are described in some appended documentation and have to be incorporated into the code through patterns.
In the diagram above, you see an example of an existing Java stereotype Entity. Classes can simply be annotated with @Entity to gain the cross-cutting behavior associated with Entities. In addition, controllers are generally annotated as @Stateful or @Stateless, which also implies cross-cutting behavior (transactional, state maintenance, etc.). The difficulty has been implementing domain-specific stereotypes.
Up to this point, there has been no simple approach to implementing this concept in a domain-specific setting with Java. Sure, you could use inheritance along with the Template method pattern or other patterns to capture commonalties in components, but there was no simple way to inject the cross-cutting behavior that a stereotype implies. Through the Web Beans stereotype approach this behavior can be specified declaratively, just as it is within the model and the properties can be applied through interception.
So building on Gavin’s singleton example, for the <<dao>> shown in the example above, we could specify the following:
@Singleton
@Transactional
@Stereotype(requiredTypes=AbstractDAO.class)
@Target(TYPE)
@Retention(RUNTIME)
public @interface DAO {}
Now our DAO would be implemented as follows:
public @DAO CourseDAO extends AbstractDAO
No additional configuration necessary as the interceptors will take care of our transactions and ensure that the instance is singleton. Implementation of patterns suddenly becomes simple, even for junior developers.
Now lets discuss the requirements associated with the RegistrationAction. There are likely to be a number of methods in the RegistrationAction that are typical to the domain as well. For example, the registerStudent() method is essentially a commit of the changes by the user. What if we would like to audit any commits by the user?
We can first create our domain-specific stereotype, again building on Gavin’s example:
@ConversationScoped
@Named
@Secure
@Auditable
@Transactional
@Component
@Stereotype(requiredTypes=BaseAction.class)
@Target(TYPE)
@Retention(RUNTIME)
public @interface Action {}
Here we’ve specified @Auditable which is a domain-specific requirement. Now we can implement our class:
public @Action class RegistrationAction extends BaseAction {
...
@Audit
public void register(Student, Course)
throws CourseFullException {
// check that course is not full,
// perform registration, and invoke DAO
}
...
Here you notice we annotated the register method with @Audit. Since our @Action is @Auditable, we can specify which methods we want to @Audit and the interceptor will take care of the auditing for us.
So you say, this is great, but I want this behavior today! Well, the AuditInterceptor is actually very simple to implement with Seam. Here is annotation definition:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Interceptors(AuditInterceptor.class)
@Inherited
public @interface Auditable {}
and the interceptor would look something like:
@Interceptor
public class AuditInterceptor implements Serializable {
...
@AroundInvoke
public Object aroundInvoke(InvocationContext invocation)
throws Exception
{
Method method = invocation.getMethod();
if(method.isAnnotationPresent(Audit.class))
{
// handle auditing and proceed with
// invocation and return results
}
}
...
As an improvement we could also add an exception handling interceptor that automatically performs our business exception handling and displays the appropriate messages to the user:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Interceptors(ExceptionMessagingInterceptor.class)
@Inherited
public @interface ExceptionMessaging {}
and the interceptor would look something like:
@Interceptor
public class ExceptionMessagingInterceptor
implements Serializable {
...
@AroundInvoke
public Object aroundInvoke(InvocationContext invocation)
throws Exception
{
Method method = invocation.getMethod();
try
{
invocation.proceed();
}
catch(BusinessException e)
{
FacesMessages.instance()
.addMessage(e.getMessage());
}
}
...
In today’s world with Seam you can simply annotate your base class with the appropriate annotations:
@Scope(ScopeType.CONVERSATION)
@Auditable @ExceptionMessaging
public class BaseAction implements Serializable {
...
Simply ensure that all of your custom annotations are @Inherited and now all domain-specific requirements will be handled by your custom interceptors. In addition, should you migrate to the WebBeans approach once the specification is complete, this makes it simple to swap out the necessary annotations.
So what does all this buy us? Well for one, the implementation speaks to you in the same way the UML diagram does above. If I look at the RegistrationAction class, I know that it is an @Action which indicates certain intrinsic behavior associated with the class. This intrinsic behavior is then associated in a type-safe manner through an interceptor invoked based on the annotation. In addition, I gain the ability to easily test my components as the cross-cutting behavior will be introduced in a container-environment. I can test only my logic and not worry about the cross-cutting aspects knowing they will be introduced at run-time.
Enjoyed this post? Share it! |
Posted in JBoss Seam, Web Beans
2 Comments »
November 8, 2007
Recently an article I wrote was published on the Seam conversation model and how issues with the back-button can be eliminated through a continuation approach. This aids developers in resolving back-button issues with respect to server-side state, but what about the client-side. Ajax development is a breeze with Seam especially when used in conjunction with Ajax4JSF and RichFaces but the use of Ajax can result in issues with caching of client-side state.
Caching is a common issue with Ajax implementations though many of the concerns of caching are alleviated by using the Ajax4JSF/RichFaces libraries (which I highly recommend). The specific problem I would like to address applies to use of Internet Explorer with Ajax (Firefox does not suffer from the problem). Internet Explorer caches pages when the entire page is refreshed. Ajax implementations allow the page to be altered without a refresh, only re-rendering the applicable section of the page. Thus, if a user submits a page or navigates elsewhere, using the back- or forward-button to return to the page will not display any portions of the page that had been updated by Ajax calls. Instead the page will be shown based on what was cached when the page was originally rendered. Firefox, on the other hand, maintains an up-to-date cache that displays the page as it was rendered after any AJAX updates in response to interaction with the user.
If you don’t believe me, try it yourself! Go to maps.google.com and view a map of your favorite location using Internet Explorer. Now type a new URL into your browser and navigate to it. Press the back button and *poof* you’re back at square one. The map of your favorite location is gone. Now perform the same steps using Firefox. Wow, Firefox still shows the map and you can still see your favorite location!
This is a rather annoying issue and of course could lead to issues with our conversation state (not to mention confusion of the users). Not to fear, the issue can be resolved through a fairly simple solution. Internet Explorer invokes the onload function every time a page is displayed (whether through the initial rendering, the back-, or the forward- button). The following code will resolve your issue using Ajax4JSF which ships with JBoss RichFaces:
<body bgcolor="#FFFFFF" text="#000000"
onload="reloadAjaxPanels()">
<h:form id="myAjaxForm">
<a:jsFunction name="reloadAjaxPanels"
reRender="panelToReload" />
...
<a:outputPanel id="panelToReload">
...
</a:outputPanel>
</h:form>
Now each time the user backs up to the page the Ajax panels will be updated according to the state of the current conversation. The downsides to the solution are that the user will notice a flash each time he or she backs up to the page (when the Ajax components reload) and it causes (what I would consider unnecessary) traffic between the client and the server. If this is acceptable, this solution will help you to use Ajax and Seam together to allow applications to behave according to a user’s expectations rather than the developer’s.
Enjoyed this post? Share it! |
Posted in JBoss Ajax4JSF, JBoss Rich Faces, JBoss Seam
18 Comments »
Comments
April 26, 2010
@Tim: I will definitely be posting more on the topic of mashups in the next few...
April 26, 2010
You should give jQuery-JSONP a try, it handles timeouts transparently :)...
April 26, 2010
Very help and concise examples! Thank you for sharing. I was wondering if we’d see...
April 6, 2010
Jacob, I fully agree with you about the 7 good reasons you mentioned above for adopting...
April 6, 2010
Good article. Open source is way to go.