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
8 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
1 Comment »
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
10 Comments »
November 8, 2007
I have been meaning to put together a blog for quite a while, but simply never got around to it. Now seemed like the right time given the publication of my first article and my involvement in the upcoming second edition of JBoss(R) Seam: Simplicity and Power Beyond Java(TM) EE.
I look forward to providing information that is useful to other developers in their daily work!
Enjoyed this post? Share it! |
Posted in JBoss Seam
No Comments »
Comments
December 13, 2007
Thanks, I’m glad you enjoyed it! If you want even more, our book goes...
December 13, 2007
This is a fantastic article. It’s a shame that Dan Allen spends 50 pages...
June 17, 2008
I manage it by letting you do it. :)
June 6, 2008
A link to the examples has now been provided in the original posting. Please let us...
June 6, 2008
Thanks for the comment, I hadn’t seen the issue! I will contact the publisher...