Class DesignerConversationBean
- java.lang.Object
-
- de.xima.fc.gui.bean.designer.conversation.DesignerConversationBean
-
- All Implemented Interfaces:
Serializable
@Named @SessionScoped public class DesignerConversationBean extends Object implements Serializable
Bean for handling the designer conversation context. A designer session consists of multiple pages within iframes that need to communicate with each other. They do so by by sharing a conversation ID that identifies the designer session. The ID is created when the designer is first opened and propagated to all child iframes and pages. All individual beans in the pages are scoped to the view. When the view who initiated the designer session is destroyed, the entire designer session is destroyed. This bean itself is scoped to the session and keeps a map of all active designer sessions.This is similar to the CDI
ConversationScoped
annotation via thecid
parameter, but does not require a lock on the entire request, which can quickly result in aBusyConversationException
. Instead, locking is performed via a reentrantsynchronized
on the designer session state (seewithDesignerConversationModel
) only when it is needed. This allows for more parallelity between requests of different designer pages and preventsBusyConversationException
. Make sure you only access the conversation model directly within the handler passed towithDesignerConversationModel
!This bean also lets you send events to other designer views via
post
. When you need to access data from a different view, you can userequest
.- Since:
- 7.0.0
- Author:
- XIMA MEDIA GmbH
- See Also:
- Serialized Form
-
-
Constructor Summary
Constructors Constructor Description DesignerConversationBean()
-
Method Summary
All Methods Instance Methods Concrete Methods Modifier and Type Method Description String
getConversationId()
void
handleConversationRequest()
Remote command callback forCmnConst.Designer.RemoteCommand.HANDLE_CONVERSATION_REQUEST
.void
handleConversationResponse()
Remote command callback forCmnConst.Designer.RemoteCommand.HANDLE_CONVERSATION_RESPONSE
.void
post(ISessionConversationEvent event)
Posts the given designer conversation event and informs all event handlers that have subscribed to that event.void
registerEventHandler(ISessionConversationEventHandler eventHandler)
Registers the given conversation event handler for the active designer conversation.<T extends Serializable,R extends ICrossViewScopeRequest<T>>
voidregisterRequestHandler(Class<R> requestType, ICrossViewScopeRequestHandler<T,R> requestHandler)
Registers the given conversation request handler for the active designer conversation.<T extends Serializable,R extends ICrossViewScopeRequest<T>>
booleanrequest(R request, Duration timeout, ICrossViewScopeResponseConsumer<? super T> consumer, BackendViewPushContext viewPushContext)
Allows to retrieve a piece of data from another view scope that participates in the same conversation.IRequestHandlerBuilder
requestBuilder(BackendViewPushContext viewPushContext)
void
unregisterEventHandler(ISessionConversationEventHandler eventHandler, String conversationId)
Unregisters the given conversation event handler from the active designer conversation.<T extends Serializable,R extends ICrossViewScopeRequest<T>>
voidunregisterRequestHandler(Class<R> requestType, ICrossViewScopeRequestHandler<T,R> requestHandler, String conversationId)
Unregisters the given conversation request handler for the active designer conversation.<R> R
withDesignerConversationModel(Function<DesignerConversationModel,R> fn)
The designer conversation model is shared between different views and may thus be accessed in simultaneously by different threads handling different requests.
-
-
-
Method Detail
-
getConversationId
public String getConversationId()
- Returns:
- The current conversation ID, if it exists.
-
handleConversationRequest
public void handleConversationRequest()
Remote command callback forCmnConst.Designer.RemoteCommand.HANDLE_CONVERSATION_REQUEST
. This remote command is invoked by the client in the view scope of the request target. We can now invoke the supplier that can provide the requested data.
-
handleConversationResponse
public void handleConversationResponse()
Remote command callback forCmnConst.Designer.RemoteCommand.HANDLE_CONVERSATION_RESPONSE
. This remote command is invoked by the client in the view scope of the original request source. We can now invoke the consumer that originally requested the data.
-
post
public void post(ISessionConversationEvent event)
Posts the given designer conversation event and informs all event handlers that have subscribed to that event. When no designer conversation is active, this is a no-op.- Parameters:
event
- Event to post.
-
registerEventHandler
public void registerEventHandler(ISessionConversationEventHandler eventHandler)
Registers the given conversation event handler for the active designer conversation. When no designer conversation is active, this is a no-op.- Parameters:
eventHandler
- Designer conversation event handler to register. All subscriber methods of the event handler will be noticed when the corresponding designer conversation event occurs.
-
registerRequestHandler
public <T extends Serializable,R extends ICrossViewScopeRequest<T>> void registerRequestHandler(Class<R> requestType, ICrossViewScopeRequestHandler<T,R> requestHandler)
Registers the given conversation request handler for the active designer conversation. When no designer conversation is active, this is a no-op.- Type Parameters:
T
- Type of the requested data.R
- Type of the request.- Parameters:
requestType
- Request type to listen to.requestHandler
- Designer conversation request handler to register. The handler is called when arequest
is made.
-
request
public <T extends Serializable,R extends ICrossViewScopeRequest<T>> boolean request(R request, Duration timeout, ICrossViewScopeResponseConsumer<? super T> consumer, BackendViewPushContext viewPushContext)
Allows to retrieve a piece of data from another view scope that participates in the same conversation.Assume there are two view scopes A and B. A method running in the scope of A wishes to obtain some data form B. It needs to send a message (such as via an event bus) to B. However, when the message handler of B is invoked synchronously, it will still be within the scope of A and will not have access to the state of B.
To solve this, A can first store the request data within the shared conversation state. A can send a push message via a web socket to the client (web browser) of B, which can then initiate an AJAX call to the view scope of B. Now B can access the request data from the shared conversation state, create the requested data and store the requested data in the conversation state. Afterwards, B sends a push message to the client (browser) of A, which initiates another AJAX call to the view scope of A. Finally, A can access the response from the conversation state and proceed to process that response.
- Type Parameters:
T
- Type of the requested data.R
- Type of the request.- Parameters:
request
- Request to send.timeout
- Timeout to set on the request. When no response is received within this time frame, the handler is invoked with an error.consumer
- Handler to invoke when the request completes either successfully or erroneously.viewPushContext
- The current view push context of the caller.- Returns:
true
if there are any pending responses,false
if all requests have been processed, such as when no handlers did respond to the request.
-
requestBuilder
public IRequestHandlerBuilder requestBuilder(BackendViewPushContext viewPushContext)
- Parameters:
viewPushContext
- The current view push context of the caller.- Returns:
- A new builder for sending multiple
requests
and performing some logic when all have finished.
-
unregisterEventHandler
public void unregisterEventHandler(ISessionConversationEventHandler eventHandler, String conversationId)
Unregisters the given conversation event handler from the active designer conversation. When no designer conversation is active, this is a no-op.- Parameters:
eventHandler
- Designer conversation event handler to remove.conversationId
- ID of the conversation from which to unregister the handlers. This is required because a bean may be destroyed e.g. during a different view scope (when the number of allowed views per session has been exceeded). In that case, it is impossible to determined the correct conversation ID.
-
unregisterRequestHandler
public <T extends Serializable,R extends ICrossViewScopeRequest<T>> void unregisterRequestHandler(Class<R> requestType, ICrossViewScopeRequestHandler<T,R> requestHandler, String conversationId)
Unregisters the given conversation request handler for the active designer conversation. When no designer conversation is active, this is a no-op.- Type Parameters:
T
- Type of the requested data.R
- Type of the request.- Parameters:
requestType
- Request type to listen to.requestHandler
- Designer conversation request handler to unregister.conversationId
- ID of the conversation from which to unregister the handlers. This is required because a bean may be destroyed e.g. during a different view scope (when the number of allowed views per session has been exceeded). In that case, it is impossible to determined the correct conversation ID.
-
withDesignerConversationModel
public <R> R withDesignerConversationModel(Function<DesignerConversationModel,R> fn)
The designer conversation model is shared between different views and may thus be accessed in simultaneously by different threads handling different requests. This method acquires a lock to ensure only on thread processed a conversation model at a given time. The lock is held for as long as the given handlerfn
is invoked. Make sure you do not use the model outside the handlerfn
.- Parameters:
fn
- It is given the model for the designer session. This is used to share data between the different views in each iframe. This model is scoped to the designerConversation
.- Returns:
- The value return by the given handler
fn
-
-