Recently, we attended Adam Bien’s presentation concerning Java EE 6 technology. Inspired by Adam Bien we decided to describe one of the CDI features: conversational context lifecycle. With an example we will show you the advantages.

A short introduction to show the context

Conversation context allows maintaining the state of objects between HTTP requests; however it has a smaller scope than session context. That’s because the lifecycle of conversation consists of a specified number of requests, while a session has unlimited requests, which makes it a lot more heavy.

For a web wizard conversation context is all you need

Conversation context is the ideal solution for creating web wizards in association with JSF; this is actually what is going to be shown in this post. First let’s start organizing the project.

 

An example paints more than 1000 words

Our example is created with Eclipse and Maven. The structure of the project, as shown in the above image, is rather common for this tool and it doesn’t require more explanation, so let’s move on to the content of the pom.xml file.

As you can see for this project we need only two dependencies which are CDI and JSF APIs (implementations will be provided by the container which is Glassfish server 3.1). In order to activate CDI in our application a beans.xml configuration file is required. It needs to be placed under /WEB-INF directory (see project tree). For the purpose of our application this file can be empty, so in fact, only a single line of code is required:

The next step is to create a bean which will be the engine of our web wizard application. This is very easy, take a look at the code below:

A few things need to be done while creating the conversational bean:

  • Bean has to be serializable
  • Bean class must be annotated with @ConversationScoped annotation which tells the container that the state of this particular bean will be maintained while conversation is running
  • Bean class must have a reference to Conversation object (injected via @Inject annotation) which takes the responsibility of managing the conversation context (beginning and ending conversation with begin and end methods respectively)
  • Additionally @Named annotation makes the bean accessible from Expression Language (in JSF page).

By default the Conversation object is in transient state. Invocation of the begin method marks it as long-running (when a real conversation starts). Ending conversation (by invoking end method) marks Conversation object as transient. If we try to invoke begin method when Conversation object is in long-running state an IllegalStateException will be thrown. Similarly, we can’t invoke end method while Conversation object is in transient state, otherwise we will get the same exception. That’s why I’m using isTransient method in order to check the state of Conversation object.

Some logic is still needed

As you might guess our example code is not sufficient to make web wizard working. We need to add some logic which will control the workflow of application as well as some views (JSF pages) and model. The conversation bean itself is almost done, however we decided to go one step further and write a generic wizard which will be reusable. This requires more code, which looks as follows:

The core functionality of this class is closed in two private methods: beginConversation and endConversation which are parts of template methods such as start, finish and cancel. The main assumption of this approach is to keep basic code in one place and delegate specific responsibilities (via prepareViews, complete and clean abstract methods) to concrete wizard classes. In our example specific responsibilities mean:

  • Preparing a list of views which are part of a concrete web wizard (prepareViews method)
  • Storing model object(s) which state will be maintained during the conversation
  • Completing conversation by invoking some business logic (which processes the model) and navigating to specific view (that’s why the complete method returns a String which is the name of the view’s outcome)
  • Canceling conversation (clean method) which is similar to completion as described before.

There are also next, previous and getViewAt methods which control the flow of conversation (don’t pay attention to ViewManager and View classes, we will describe them later).

The concrete wizard class

Let’s have a look at the concrete wizard class:

The responsibility of UserWizard class conforms to the four points described earlier. The main advantage of this approach is the flexibility of adding or removing views without affecting the basic code, what makes it reusable (we can have many different concrete wizards which will extend the abstract one).

ViewManager class

Now let’s have a look at the ViewManager class, which is just a simple iterator for a list of views:

This class contains some useful methods allowing to manage a list of view objects, which represents JSF pages in our example. It also controls the display of particular components on JSF pages. ViewManager uses a View class which represents a particular JSF page (we could use also JSP or even pure HTML).

View object holds information about the view’s name, outcome (page URL) and flag which determines whether or not the name of a particular view should be available for a user. For better understanding you will find the code of model objects (notice that they are serializable) below:

Time to move on to JSF pages

Ok, let’s move on to JSF pages now. In order to activate JSF in our application we need to configure the web.xml file. We have to register a Facelet servlet which will handle all JSF requests within the application.

Firstly, we show the main template which will be used by all pages in application.

Below you will find the code of the JSF pages which use template: index.xhtml

wizardFinish.xhtml

wizardCancel.xhtml

wizardTemplate.xhtml

The last one is an example of nesting templates using Facelets. Generally wizardTemplate.xhtml contains elements (control buttons and a list of available steps) which will be used by all step pages included in the particular web wizard. Below we present the code of the step pages: firstStep.xhtml

secondStep.xhtml

thirdStep.xhtml

summary.xhtml

Time to look forward to the end result

We are done now. After building the project and launching it by using an application server you should get the following result: We can freely move between particular steps and the state of conversation will be maintained. We can also cancel the conversation any moment. Clicking the finish button will end the conversation as well. Be aware we completely omitted validation as well as internationalization, because this is out of the scope for this article. As you can see using conversation context lifecycle is quite easy to implement, designing a generic wizard which could be reusable takes a lot more time. Below you can find the source code files described as well as a war file, which can be deployed on an application server. Thanks for reading this post. I’m looking forward to read about your experiences or to answer your questions. Please share them below. com.wizard-1.0.0-SNAPSHOT wizard