In this tutorial we will compare the available options for storing Object data into a Web application, showing at first the core JSF 2 scopes and the extension provided by CDI.

Core JSF scopes

JSF 2.0 specification defines the following scope scopes for storing data:

@RequestScoped
@ViewScoped
@SessionScoped
@ApplicationScoped
@CustomScope

Using the Request scope is quite straightforward: all you need in including the @RequestScoped annotation into your Bean. The most typical use of a @RequestScoped bean is as a JSF backing bean for a single page handling one HTTP request/response cycle. The vast majority of CDI beans you will use with JSF will likely belong to the request scope.

import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;

@ManagedBean
@RequestScoped

public class RequestManager {

}

jsf 2 cdi requestscope conversationscope sessionscope
On the other hand, @SessionScoped beans are used for objects that are used throughout the HTTP session. For example user details are typical information which are used all across the session so they are a typical canidate to be @SessionScoped:

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;

@ManagedBean
@SessionScoped
public class SessionManager {

}

jsf 2 cdi requestscope conversationscope sessionscope
One important addition introduced in JSF 2.0 API is the ViewScoped which is particularly useful when you are editing some objects while staying in the same page. In other words it's something broader then request but smaller then session, since this scope terminates if you navigate to other pages.

import javax.faces.bean.ManagedBean;
import javax.faces.bean.ViewScoped;

@ManagedBean
@ViewScoped
public class SessionManager {


}


As you can see, from the following picture, as long as we stay in the same JSF page, the data is preserved between requests. If we navigate to another page, the data is evicted from memory:

jsf 2 cdi requestscope conversationscope sessionscope

A detailed example of a JSF 2.0 CRUD application which uses @ViewScoped can be found here.


CDI JSF scopes

Besides JSF standard scopes, CDI provides a set of scopes for storing Object data into a Web application. Most of them work just the same as JSF scopes.

javax.enterprise.context.DependentScoped
javax.enterprise.context.RequestScoped
javax.enterprise.context.SessionScoped
javax.enterprise.context.ConversationScoped
javax.enterprise.context.ApplicationScoped

Starting CDI

Remember, in order to kickstart CDI dependencies in your application, you have to include a beans.xml file in your WEB-INF folder:
jsf cdi requestscope sessionscope viewscope conversationscope

So this is our equivalent RequestManager which now uses the javax.enterprise.context.RequestScoped annotation:

import javax.inject.Named;
import javax.enterprise.context.RequestScoped;    
@Named
@RequestScoped
public class RequestManager  {

}

Also notice that when using CDI, we need adding the @Named annotation, so that the RequestManager class becomes a managed bean, as defined by CDI. Moving on, this is the equivalent javax.enterprise.context.SessionScoped annotation

import javax.inject.Named;
import javax.enterprise.context.SessionScoped;    
@Named
@SessionScoped
public class SessionManager  {

}

However, what is really new in CDI is the Conversation scope which can be used to control the lifecycle of conversations in a JSF application. Think of conversation scope as a developer-controlled session scope across multiple invocations of the JSF lifecycle. At first you need to inject the Conversation object:

@Inject Conversation conversation;

Then, in order to start the conversation associated with the current request to a long-running conversation, call the begin() method from application code. To schedule the current long-running conversation context for destruction at the end of the current request, call end().

@Named
@ConversationScoped
public class ConversationManager {
    private @Inject Conversation conversation;

   private ArrayList<Property>   cacheList = new ArrayList ();
   private String key;
   private String value;

   // Getters/Setters omitted for brevity

    public void startConv(){
        conversation.begin();
    }
    public void stopConv(){
        conversation.end();
    }

    public void save() {
        Property p = new Property();
        p.setKey(key);
        p.setValue(value);
        cacheList.add(p);
    }

    public void clear() {
        cacheList.clear();

    }
    public List getCacheList() {
        return cacheList;
    }
    
}

As you can see from the following picture, the Conversation scope is able to propagate the life of objects stored  across JSF navigations.

jsf 2 conversational scope

Important: by default the state is propagated only when using Faces navigation: for example, we have included a button which allows navigation to another page leveraging JSF 2.0 implicit navigation:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:ui="http://java.sun.com/jsf/facelets"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:c="http://java.sun.com/jsp/jstl/core">

<h:body>

            <h2>Conversational Scope</h2>
            <h:form id="jsfexample">
                <h:panelGrid columns="2" styleClass="default">

                    <h:outputText value="Enter key:" />
                    <h:inputText value="#{conversationManager.key}" />

                    <h:outputText value="Enter value:" />
                    <h:inputText value="#{conversationManager.value}" />

                    <h:commandButton actionListener="#{conversationManager.save}"
                        styleClass="buttons" value="Save key/value" />
                    <h:commandButton actionListener="#{conversationManager.clear}"
                        styleClass="buttons" value="Clear cache" />

                    <h:commandButton value="Start Conversation"
                        actionListener="#{conversationManager.startConv}"
                        action="conversation" />

                    <h:commandButton value="Stop Conversation"
                        actionListener="#{conversationManager.stopConv}"
                        action="conversation" />
                        
                    <h:commandButton value="Navigate"
                        action="request" />
                    <h:messages />


                </h:panelGrid>

                <h:dataTable value="#{conversationManager.cacheList}" var="item"
                    styleClass="table" headerClass="table-header"
                    rowClasses="table-odd-row,table-even-row">
                    <h:column>
                        <f:facet name="header">Key</f:facet>
                        <h:outputText value="#{item.key}" />
                    </h:column>
                    <h:column>
                        <f:facet name="header">Value</f:facet>
                        <h:outputText value="#{item.value}" />
                    </h:column>
                </h:dataTable>
            </h:form>

</h:body>
</html>

We can however force the conversation to propagate with a non-faces request by including the unique identifier of the conversation as a request parameter. The CDI specification reserves the request parameter named cid for this use. The unique identifier of the conversation may be obtained from the Conversation object, which has the EL bean name conversation.

Therefore, the following link propagates the conversation:

<a href="/example.xhtml?cid=#{conversation.id}">Move to another Page</a>

Choosing between ViewScoped and ConversationScoped

At this point you might wonder which of this two JSF scopes fits better in your application schema.
From one point of view, using @ViewScoped has the advantage of being a standard JSF scope so it will run on any JSF 2 compliant container. Using this scope can be particularly useful when your application is dataTable-centric, that is you happen to create/read/update/delete data while staying in the same page. This is also the case of applications which use Ajax to pursue most of its tasks.

On the other hand, the @ConversationScope is the ideal if your application requires wizard-like functionalities where data is preserved between the JSF navigation. Also, you might find confortable to work with this scope, if you application requires to perform CRUD operations using a separate Web page (think of a pop-up page which allows data modification).

0
0
0
s2smodern