/* * Copyright 2002-2008 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); you may not * use this file except in compliance with the License. You may obtain a copy of * the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.springframework.conversation.manager; import java.util.List; import org.springframework.conversation.Conversation; import org.springframework.conversation.ConversationEndingType; import org.springframework.conversation.ConversationListener; import org.springframework.conversation.ConversationType; import org.springframework.conversation.JoinMode; import org.springframework.conversation.annotation.BeginConversation; import org.springframework.conversation.annotation.Conversational; import org.springframework.conversation.annotation.EndConversation; import org.springframework.conversation.scope.ConversationResolver; import org.springframework.conversation.scope.ConversationScope; /** *
* The interface to be implemented by any conversation manager. It is used by
* the advice behind the conversational annotations like
* {@link BeginConversation}, {@link EndConversation} and {@link Conversational}
* but might be used for even fine grained access to the underlying conversation
* management, if a initializer callback is needed for instance or if
* conversation switching should be used. If used directly, the conversation
* manager can be injected into any bean to be used as it is a singleton and
* thread safe.
*
* Conversations are a good way to scope beans and attributes depending on
* business logic boundary rather than a technical boundary of a scope like
* session, request etc. Usually a conversation boundary is defined by the
* starting point of a use case and ended accordingly or in other words a
* conversation defines the boundary for a unit of work.
*
*
* Here is a short description on how to use the conversation management:
*
* Starting a conversation
* A conversation can be started in two different ways, either by placing the
* {@link BeginConversation} annotation on a method defining the starting point
* of the conversation (use case) or by invoking
* {@link ConversationManager#beginConversation(boolean, JoinMode)} manually
* through the conversation manager. The {@link JoinMode} declares on how a new
* conversation is created (see its javadoc for more details on the different
* join modes).
*
*
* Ending a conversation
* A current conversation is ended by either placing the {@link EndConversation}
* annotation on the ending method or by manually invoke the
* {@link ConversationManager#endCurrentConversation(ConversationEndingType)}
* method. A current conversation might also be ended, if a new conversation is
* started having {@link JoinMode#NEW} being declared where the current
* conversation is ended silently and a new one is created. This might be the
* obvious way to end a conversation, if the end of a use case is not always
* forced to be invoked by a user.
*
*
* Temporary conversations
* A temporary conversation is automatically created, if the container is about
* to create a bean having conversation scope but there is no current
* conversation in progress, hence a new, temporary conversation is created. A
* temporary conversation might be turned into a long running one by joining it
* or manually invoke {@link Conversation#begin()}.
*
*
* Initializing the conversation
* If there is any need to initialize beans or entities while starting a new
* conversation, the {@link ConversationInitializationCallback} might be used to
* be invoked if the new conversation was started in order to initialize it.
* This is done by providing such a callback to the
* {@link ConversationManager#beginConversation(JoinMode, ConversationType, ConversationInitializationCallback...)}
* method. The callback feature is not available through the annotation support
* and hence is only available through the conversation manager API. Here is an
* example on such an initializing feature; if a conversation is used in
* conjunction of a JPA entity manager or Hibernate session, there might be
* entity beans already loaded, cached or referenced within backing beans which
* have to be merged into the entity manager or session in order to be used
* within the conversation's work. So it would be possible to implement the
* callback, merging the necessary entities used within the conversation into
* the entity manager.
*
*
* Listening to conversation events
* If there is a need to listening to events of a conversation, add yourself as
* a {@link ConversationListener} to a new {@link Conversation} as being
* returned by this {@link ConversationManager}. The same goal can be achieved
* by implementing the {@link ConversationListener} interface on a conversation
* scoped bean which will be registered automatically to receive events.
*
*
* Nesting conversations
* Conversations might be nested either by inheriting the state of the parent (
* {@link JoinMode#NESTED}) or by isolating its state from the parent (
* {@link JoinMode#ISOLATED}). Ending a nested conversation automatically
* switches back to its parent making it the current conversation.
*
*
* Where are conversations stored?
* Conversations are created by the {@link ConversationManager} and registered
* within the {@link ConversationScope}. The scope handler is injected into the
* manager by Spring (statically as both beans are singletons) and registered as
* a custom scope. As the scope handler is a singleton, it needs a store where
* conversations are stored within which is usually bound to the current session
* or window of a user and represented by the {@link ConversationStore}
* interface. The store is usually being injected into the scope handler using
* method injection as the store has a narrower scope than the scope handler. In
* a web environment, the store would typically live in session scope to
* separate the conversations from each of the sessions. There is always one
* current conversation either stored within the session or as a request
* parameter passed along every request to set the current conversation and is
* accessed by the manager using a {@link ConversationResolver}.
*
false
)
* @param joinMode the mode declaring on how to use an already existing
* conversation, if any
* @return the newly created conversation which may be a nested one
*/
Conversation beginConversation(boolean temporary, JoinMode joinMode);
/**
* In addition to {@link #beginConversation(boolean, JoinMode)} this method
* provides the possibility of callbacks to be invoked after the
* conversation was created to be initialized. See
* {@link ConversationInitializationCallback} for more details about
* conversation initialization callbacks.
*
* @param joinMode the mode declaring on how to use an already existing
* conversation, if any
* @param conversationType the optional type of conversation to be started,
* used to pass along to the callback(s)
* @param callbacks the optional callback(s) to be invoked after the new
* conversation has been created in exactly the same order they are passed
* in
* @return the newly created conversation which may be a nested one
*
* @param null
* otherwise. Does not start a new temporary transaction, if none available.
* This method delegates to the {@link ConversationResolver} and the
* {@link ConversationStore} to finally get the currently used conversation.
*
* @return the current conversation if any, null
otherwise
*/
Conversation getCurrentConversation();
/**
* Ends the current conversation, if any is in progress. This is the same as
* ending the conversation returned by {@link #getCurrentConversation()}
* using {@link #endConversation(Conversation, ConversationEndingType)}.
*
* @param endingType the type qualifying on how this conversation is to be
* ended (only passed on to any listeners, does not have an impact on the
* conversation manager)
* @return the current conversation which has been ended
*/
Conversation endCurrentConversation(ConversationEndingType endingType);
/**
* Returns a list of available conversations within the current store.
* Depending on the setup of the {@link ConversationStore}, this will return
* all conversations available for the current session if the store is
* stored within the session for instance.
*
* @return the list of available conversations or an empty list, never
* null
*/
List0
means no timeout and any positive value represents
* the timeout in milliseconds.
*
* @return the default timeout in milliseconds for a new conversation
*/
long getDefaultConversationTimeout();
/**
* Set the default timeout to be set on newly created conversations, if not
* overwritten by the conversation itself. A value of 0
means
* no timeout at all.
*
* @param timeout the timeout in milliseconds or 0
if no
* timeout should be set by default
*/
void setDefaultConversationTimeout(long timeout);
}