CDI conversation scope is a nice feature when developing JSF applications. Imagine you have large data tables which take a long time to be loaded. You normally don't want to place the loaded data in session scoped beans by reason of high memory consumption. And you can't place the loaded data in view scoped beans because you wouldn't like always to reload data again if user leave and enter the same view. It would be nice only to keep data if user enters the same page within a certain time interval and reload them again if the bean was not accessed within this time interval. This can be achieved by conversation scoped bean with timeout. We will deal with
MyFaces CODI (CDI Extensions) and see how to set a custom timeout for beans annotated with
@ConversationScoped. The default timeout is 30 min. what is too long for our example. We will configure it for 1 min. The first step is to extend CODI's
ConversationConfig and overwrite the method
getConversationTimeoutInMinutes(). Let's write a class
AlternativeConversationConfig.
package controller.cdi;
import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.inject.Alternative;
import javax.enterprise.inject.Specializes;
import org.apache.myfaces.extensions.cdi.core.api.config.ConfigEntry;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.config.ConversationConfig;
@ApplicationScoped
@Alternative
@Specializes
public class AlternativeConversationConfig extends ConversationConfig {
@ConfigEntry
public int getConversationTimeoutInMinutes() {
return 1;
}
}
The important thing is the annotation
@Specializes which allows to inject
AlternativeConversationConfig instead of
ConversationConfig at every existing places. The second step is a proper entry in
beans.xml to use (activate) our class on all injection points for
ConversationConfig.
<alternatives>
<class>controller.cdi.AlternativeConversationConfig</class>
</alternatives>
Server's log output during startup contains these lines now
config implementation:
controller.cdi.AlternativeConversationConfig$Proxy$_$$_WeldClientProxy
config implementation: controller.cdi.AlternativeConversationConfig
method: getConversationTimeoutInMinutes
value: 1
To check if everything is ok, we can write a conversation scoped bean and use it in facelets.
import java.io.Serializable;
import javax.faces.event.ActionEvent;
import javax.inject.Named;
import org.apache.myfaces.extensions.cdi.core.api.scope.conversation.ConversationScoped;
@Named
@ConversationScoped
public class CdiBeanConversationScoped implements Serializable {
private int counter;
public int getCounter() {
return counter;
}
public void increment(ActionEvent e) {
counter++;
}
}
<h:outputText id="counter" value="Conversation scoped counter: #{cdiBeanConversationScoped.counter}"/>
<p:commandButton value="Increment counter" process="@this" update="counter"
actionListener="#{cdiBeanConversationScoped.increment}"/>
The counter will expire after 1 min. if no access to the bean happens within this time interval. Simple push the button to increment the counter, wait longer than 1 min. and increment it again. You will see that counter was reseted.