Conversations (Draft)

Basic Idea

Std. CDI conversations are very limited. So CODI will provide conversations which are similar to the conversations of Orchestra.Basically each window has its own context (see WindowContext - it's similar to the ConversationContext of Orchestra).Within this context it's possible to define multiple conversations (grouped by a typesafe conversation-group instead of a string based name).

The following part explains the available annotations. (All scopes are stored in the session - so the max. lifetime is restricted by the session of the user.)

@ConversationScoped

Beans which are marked with this annotations will be scoped as a grouped conversation. That means the bean exists as one of n (parallel) conversations in the WindowContext. The group is identified via the class of the bean and the qualifiers of the bean.

If the bean isn't used any more it will be un-scoped automatically after a configurable timeout (default: 30 min).

@ConversationGroup

Furthermore it's possible to create conversation groups (it's a std. CDI qualifier annotation which is handled in a special way). That means 1-n beans will exist in the same conversation. As soon as the conversation gets destroyed all beans will be un-scoped.

TODO: test if the current approach works also with dependency injection in other beans.

Both beans of example 2 will be scoped in a conversation with the group-key: Group1.class

Some important use-case for groups are e.g. wizards, master/detail views,... (e.g. it's possible to use one page-bean for each wizard step. All page-beans used for the wizard are scoped in the same conversation group. At the end of the wizard we can destroy the conversation group of the wizard and every bean gets un-scoped. Furthermore, conversation groups allow an easier API for the WindowContext.

@WindowScoped

The window scope is like a session per window. (It's just a special conversation without timeout). All beans exist as long as the WindowContext is active (or the session of the user).

We will see an API for destroying the WindowContext as a whole or just all window scoped beans. However, usually you don't need to use it.

We can use the window scope e.g. for the current user. So it's possible to support e.g. multiple tabs with different logins.

Example:

@WindowScoped
public class WindowDemoBean implements Serializable
{
}

@ViewAccessScoped

This scope is similar to the access scope of Orchestra. That means: a bean will be available in the next request if it is used in the current request.

We have to support AJAX so the name as well as the rule is a bit different: All beans which are used in a view will be available in the current view (e.g. multiple AJAX requests) as well as in the next view. (Redirects are supported as well.)

APIs

Core-Module

Annotations

Interfaces

Conversation

The central interface for a conversation which is a container for 1-n beans which share the same time for destruction.

public interface Conversation extends Serializable
{
/**
* Deactivates the conversation and un-scopes all bean instances immediately.<br/>
* At the next cleanup the whole conversation will be destroyed.
* (If an inactive {@link org.apache.myfaces.extensions.cdi.core.api.scope.conversation.Conversation}
* gets resolved before the cleanup, the
* {@link org.apache.myfaces.extensions.cdi.core.api.scope.conversation.WindowContext} has to destroy it.
* -> A new conversation will be created immediately.
*/
void end();
/**
* Un-scopes all bean instances immediately.
* Instead of destroying the whole conversation the conversation stays active.
* (The conversation will be marked as used.)<br/>
* As soon as an instance of a bean is requested,
* the instance will be created based on the original bean descriptor.
* This approach allows a better performance, if the conversation is needed immediately.
*/
void restart();
}

WindowContext

It's like a session per window.

If you need the id of the current WindowContext you can use: #{currentWindowContext.id}

WindowContext - Advanced Topics

By default we have to add a window-id to the url automatically. Furthermore, (currently) the first request has to force a redirect to force a window id also for the first page. If you don't like a window-id in your url/s, you have to switch to a server-side solution. MyFaces CODI provides the ServerSideWindowHandler which uses the flash-scope of JSF2. That means the JSF version you are using needs a working flash-scope! (os890 provides a 2nd alternative.) However, if you store the window-id via a server-side mechanism you lose the support for window refreshes.

We need a window-id for all pages (similar to MyFaces Orchestra). Reason: if you would have a lazy window-id which is just active on pages which use conversation scoped beans, you might get strange problems. E.g. if Page A doesn't use conversations and Page B starts using conversations and you navigate back to Page A - also Page A needs the window-id. If Page A doesn't supports the window-id (e.g. a menu which uses GET-Requests), the navigation would lead to a broken application. In this case it's just broken in special constellations. Such issues are very hard to find. So we have to force the window-id for all pages. By default you don't have to adjust your pages - just if you have e.g. a GET-Request based menu). That means we are using a fail fast approach (as fast as possible) and you have to refactor such a page - e.g. add ?windowId=#{currentWindowContext.id} to the entries of a menu which uses GET-Requests. (There might be a ViewDefinition based solution for pages which are just available for external applications and not part of the nav.-flow within the application.)

Currently the initial redirect is activated by default - you can deactivate it via: org.apache.myfaces.extensions.cdi.DISABLE_INITIAL_REDIRECT(that might change - see EXTCDI-44)

If you have an external application which isn't able to handle redirects, you can use: windowId=automatedEntryPoint as url parameter.

If you have a 2nd application which has to propagate it's own window-id to your application, you have to deactivate trusted window-ids via: org.apache.myfaces.extensions.cdi.ALLOW_UNKNOWN_WINDOW_IDS

If your component lib is aware of windows, you can impl. a cusotm WindowHandler which delegates the work to the component lib.