The
conversation scope allows developers to
demarcate the lifespan of the session scope.
The conversation scope is committed to the user's interaction with JSF
applications and represents a unit of work from the point of view of the user;
a bean in this scope is able to follow a conversation with a user. We may
charge the conversation scope as a developer-controlled session scope across
multiple invocations of the JSF life cycle; while session scoped lives across
unlimited requests, the conversation scopes lives only across a limited number
of requests.
The developer can explicitly set the conversation scope boundaries and can start, stop, or propagate the conversation scope based on the business logic flow. All long-running conversations are scoped to a particular HTTP servlet session and may not cross session boundaries. In addition, conversation scope keeps the state associated with a particular Web browser window/tab in a JSF application.
Conversation Scope Annotations
CDI: The conversation scope
annotation is @ConversationScoped
and is defined in the javax.enterprise.context
package for CDI.
Implements Serializable
The conversation scope bean might get passivated by the container and
should be capable of passivity by implementing the java.io.Serializable interface
Simple Example
Dealing with the conversation scope is slightly different from the rest
of the scopes. First, you mark the bean with @ConversationScope, represented by the javax.enterprise.context.ConversationScoped
class. Second, CDI provides a built-in bean (javax.enterprise.context.Conversation) for
controlling the life cycle of conversations in a JSF application—its main
responsibility is to manage the conversation context. This bean may be obtained
by injection, as shown in the following code:
private @Inject
Conversation conversation;
By default, the Conversation
object is in transient state and it should be transformed into a long-running
conversation by calling the begin()
method. You also need to prepare for the destruction of the conversation by
calling the end()
method. If we try to call the begin()
method when the conversation is active, or the end() method when the conversation is
inactive, IllegalStateException
will be thrown. We can avoid this by testing the transitivity state of the Conversation objects
using the method named isTransient(),
which returns a boolean
value.
Now, add the begin(),
end(), and isTransient() methods
together to the following conversations:
• For start conversation, the code is as follows:
if
(conversation.isTransient()) {
conversation.begin();
}
• For stop conversation, the code is as follows:
if
(!conversation.isTransient()) {
conversation.end();
}
For example, you can add the conversation scope in PlayersBean as
follows:
@Named
@ConversationScoped
public class
PlayersBean implements Serializable {
private @Inject
Conversation conversation;
final String[] players_list = {"Nadal,
Rafael (ESP)","Djokovic,
Novak
(SRB)", "Ferrer, David (ESP)", "Murray, Andy (GBR)",
"Del
Potro, Juan Martin (ARG)"};
private ArrayList players = new ArrayList();
private String player;
public PlayersBean() {
}
//getters and setters
public void newPlayer() {
int nr = new Random().nextInt(4);
player = players_list[nr];
players.add(player);
}
public void startPlayerRnd() {
if (conversation.isTransient()) {
conversation.begin();
}
}
public void stopPlayerRnd() {
if (!conversation.isTransient()) {
conversation.end();
}
}
}
Besides injecting the built-in CDI bean, notice that you have defined a
method (startPlayerRnd())
for demarcating the conversation start point and another method (stopPlayerRnd()) for
demarcating the conversation stop point. In this example, both the methods are
exposed to the user through two buttons, but you can control the conversation
programmatically by calling them conditionally.
In order to test the above bean we can have a simple JSF page, as
below:
<h:body>
Just generated:
<h:outputText
value="#{playersBean.player}"/><br/>
List of generated numbers:
<h:dataTable var="t"
value="#{playersBean.players}">
<h:column>
<h:outputText value="#{t}"/>
</h:column>
</h:dataTable>
<h:form>
<h:commandButton value="Start Conversation"
style="background-color: #00cc00;"
actionListener="#{playersBean.startPlayerRnd()}" action="index"/>
actionListener="#{playersBean.startPlayerRnd()}" action="index"/>
<h:commandButton value="Get Players
In Same View" actionListener="#{playersBean.newPlayer()}"/>
<h:commandButton value="Get Players
With Page Forward" actionListener="#{playersBean.newPlayer()}"
action="index"/>
action="index"/>
<h:commandButton value="Get Players
With Page Redirect" actionListener="#{playersBean.newPlayer()}"
action="index?faces-redirect=true;"/>
action="index?faces-redirect=true;"/>
<h:commandButton value="Stop Conversation"
style="background-color: #00cc00;"
actionListener="#{playersBean.stopPlayerRnd()}"
action="index"/>
</h:form>
</h:body>
The complete application is available here.
The list of randomly extracted players will be empty or will contain
only the current extracted player until the button labeled Start Conversation is
clicked. At that moment the list will be stored in session, until the button
labeled Stop Conversation
is clicked.
During the conversation, the user may execute AJAX/non-AJAX requests
against the bean or perform navigations to other pages that still reference
this same managed bean. The bean will keep its state across user interactions using a conversation identifier generated by the
container, and this is why the conversation scope can be the right choice when
you need to implement wizards. But it might be a good idea to take into account the new JSF 2.2 flow scope as well, which
solves several gaps of the conversation scope.
In this example, the conversation context automatically propagates with
any JSF faces request or redirection (this facilitates the implementation of
the common POST-then-redirect pattern), but it does not automatically propagate
with non-faces requests, such as links. In this case, you need to include the
unique identifier of the conversation as a request parameter. The CDI
specification reserves the request parameter cid for this use. The following code will propagate the conversation
context over a link:
<h:link
outcome="/link.xhtml" value="Conversation Propagation">
<f:param name="cid"
value="#{conversation.id}"/>
</h:link>
A method annotated with @PostConstruct
will be called for each request as long as the bean is not involved in a
conversation. When the conversation begins, the method is called for that
instance and subsequent requests will use this instance until the conversation ends.
Therefore, be careful how you manage this method content.
See you in the next post about CDI flow scope.
See you in the next post about CDI flow scope.
Niciun comentariu :
Trimiteți un comentariu