DeltaSpike conversations are based on the window-scope. Therefore, do not
forget to add the ds:windowId
(xmlns:ds="http://deltaspike.apache.org/jsf"
) component in case of
ClientWindowConfig#CLIENTWINDOW
to your page(/template) and ensure
that the window-handling works properly (otherwise conversations will not
work correctly). The base principle is similar to CODI-Conversations.
CODI users just have to ensure that they have to add ds:windowId
and
the names are slightly different.
First of all, it is important to mention that DeltaSpike starts (grouped)
conversations automatically as soon as you access conversation scoped
beans. Furthermore, the invocation of GroupedConversation#close
leads
to an immediate termination of the conversation.
@GroupedConversationScoped
public class DemoBean1 implements Serializable
{
}
-
leads to a conversation which contains just one bean with the group
DemoBean1.
|
If you would like to use the bean within your JSF pages, you have
to add @Named (javax.inject.Named ).
|
(In case of CDI standard conversations there is just one big conversation
which contains all conversation scoped beans.) The grouped conversations
provided by DeltaSpike are completely different. By default every
conversation scoped bean exists in an "isolated" conversation. That
means there are several parallel conversations within the same window.
Separated DeltaSpike Conversations
@GroupedConversationScoped
public class DemoBean2 implements Serializable
{
}
@GroupedConversationScoped
public class DemoBean3 implements Serializable
{
}
The above example leads to two independent conversations in the same window (context).
If you close the conversation of DemoBean2, the conversation of
DemoBean3 is still active. If you have an use-case (e.g. a wizard) which
uses multiple beans which are linked together very tightly, you can
create a type-safe conversation group.
Grouped Conversation Scoped Beans
interface Wizard1 {}
@GroupedConversationScoped
@ConversationGroup(Wizard1.class)
public class DemoBean4 implements Serializable
{
}
@GroupedConversationScoped
@ConversationGroup(Wizard1.class)
public class DemoBean5 implements Serializable
{
}
You can use @ConversationGroup
to tell DeltaSpike that there is a
logical group of beans. Technically @ConversationGroup
is just a CDI
qualifier. Internally DeltaSpike uses this information to identify a
conversation. In the previous example both beans exist in the same
conversation (group). If you terminate the conversation group, both
beans will be destroyed. If you do not use @ConversationGroup
explicitly, DeltaSpike uses the class of the bean as conversation group.
Injecting a Conversation Scoped Bean with an Explicit Group
public class CustomBean1
{
@Inject
@ConversationGroup(Group1.class)
private CustomBean2 demoBean;
@Inject
@ConversationGroup(Group2.class)
private CustomBean2 demoBean;
}
Since @ConversationGroup
is a standard CDI qualifier you have to use it at
the injection point. You have to do that especially because it is possible to
create beans of the same type which exist in different groups (e.g. via
producer methods).
Producer Methods which Produce Conversation Scoped Beans with
Different Groups
interface Group1 {}
interface Group2 {}
public class CustomBean2
{
@Produces
@GroupedConversationScoped
@ConversationGroup(Group1.class)
public CustomBean2 createInstanceForGroup1()
{
return new CustomBean2();
}
@Produces
@GroupedConversationScoped
@ConversationGroup(Group2.class)
public CustomBean2 createInstanceForGroup2()
{
return new CustomBean2();
}
}
Terminating Conversations
You can inject the conversation via @Inject
and use it to terminate
the conversation immediately or you inject the
GroupedConversationManager
which can be used to terminate a given
conversation (group). All conversations within a window are closed
automatically, once WindowContext#closeWindow
gets called for the window.
Injecting and Using the Current Conversation
@GroupedConversationScoped
public class DemoBean6 implements Serializable
{
@Inject
private GroupedConversation conversation;
public void finish()
{
this.conversation.close();
}
}
@GroupedConversationScoped
public class DemoBean7 implements Serializable
{
@Inject
private GroupedConversation conversation;
public void finish()
{
this.conversation.close();
}
}
Injecting and Using the Explicitly Grouped Conversation
interface Wizard2 {}
@GroupedConversationScoped
@ConversationGroup(Wizard2.class)
public class DemoBean8 implements Serializable
{
@Inject
private GroupedConversation conversation;
public void finish()
{
this.conversation.close();
}
}
@GroupedConversationScoped
@ConversationGroup(Wizard2.class)
public class DemoBean9 implements Serializable
{
@Inject
private GroupedConversation conversation;
public void finish()
{
this.conversation.close();
}
}
Terminating a Grouped Conversation Outside of the Conversation
public class DemoBean10 implements Serializable
{
@Inject
private GroupedConversationManager conversationManager;
public void finish()
{
this.conversationManager.closeConversationGroup(Wizard2.class);
}
}
Terminate All Conversations
public class DemoBean11 implements Serializable
{
@Inject
private GroupedConversationManager conversationManager;
public void finish()
{
this.conversationManager.closeConversations();
}
}
|
DeltaSpike conversations get closed/restarted immediately instead
of keeping them until the end of the request like standard conversations do,
because the behaviour of standard conversations breaks a lot of use-cases.
However, if you really need to keep them until the end of the request,
you can close them in a @PostRenderView callback.
|
Sub-Conversation-Groups
Due to the parallel conversation concept of DeltaSpike there is no need
of something like nested conversations. Just use them in parallel and
terminate them in a fine-granular way as soon as you do not need them any
longer. As described above, you can terminate a whole
conversation-group. However, sometimes it is essential to have subgroups
if you need to end just a part of an use-case instead of all beans
related to an use-case. A sub-group is just a class or an interface used
to identify a bunch of beans within a group. To terminate such a
sub-group, it is just needed to pass the class/interface to the
corresponding API for terminating a conversation. The sub-group gets
detected automatically and instead of terminating a whole conversation-group,
the beans of the sub-group get un-scoped.
Explicitly Listing Beans of a Sub-group
public class MyGroup{}
@GroupedConversationScoped
@ConversationGroup(MyGroup.class)
public class BeanA {}
@GroupedConversationScoped
@ConversationGroup(MyGroup.class)
public class BeanB {}
@GroupedConversationScoped
@ConversationGroup(MyGroup.class)
public class BeanC {}
@ConversationSubGroup(subGroup = {BeanA.class, BeanB.class})
public class MySubGroup extends MyGroup {}
@ConversationSubGroup(of = MyGroup.class, subGroup = {BeanA.class, BeanB.class})
public class MySubGroup {}
Terminating a Sub-group
@Inject
private GroupedConversationManager conversationManager;
this.conversationManager.closeConversationGroup(MySubGroup.class);
As you see the class/interface of the sub-group has to extend/implement
the group or you specify it via the @ConversationSubGroup#of
. With
@ConversationSubGroup#subGroup
you can list all beans which belong to
the sub-group. If you have a lot of such beans or you would like to form
(sub-)use-case oriented groups, you can use implicit groups:
Implicit Sub-group
public interface Wizard {}
@ConversationSubGroup(of = MyGroup.class, subGroup = Wizard.class)
public class ImplicitSubGroup
{
}
@Named("myWizard")
@GroupedConversationScoped
@ConversationGroup(MyGroup.class)
public class WizardController implements Serializable, Wizard
{
}
this.conversationManager.closeConversationGroup(ImplicitSubGroup.class);
In the listing above all beans which implement the Wizard interface will
be closed as soon as you close the ImplicitSubGroup.