diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationStore.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationStore.java new file mode 100644 index 000000000000..e49d8d37b490 --- /dev/null +++ b/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationStore.java @@ -0,0 +1,155 @@ +/* + * 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.ArrayList; +import java.util.List; +import java.util.Map; + +import org.springframework.conversation.Conversation; + +/** + * An abstract base implementation for the {@link ConversationStore} interface + * used by the {@link ConversationManager} to register conversation objects + * within. This implementation supports the basic mechanism and exposes two + * methods to be implemented by concrete stores to provide the conversation map + * and optionally a fallback map used, if the default one is not reachable. This + * could be the case, if the default one is session scoped and the conversation + * management is used from within a non web thread so the fallback map could be + * a thread attached map using a {@link ThreadLocal} for instance. + * + * @author Micha Kiener + * @since 3.1 + */ +public abstract class AbstractConversationStore implements ConversationStore { + /** + * Flag indicating whether to use the fallback conversation map, if the + * default one is not reachable, see {@link #getConversationMapSafe()} for + * more information. Default is true. + */ + private boolean useFallbackMap; + + /** + * Default constructor, turning the fallback map on by default. + */ + public AbstractConversationStore() { + useFallbackMap = true; + } + + /** + * @see org.springframework.conversation.manager.ConversationStore#getConversation(java.lang.String) + */ + public Conversation getConversation(String id) { + Map map = getConversationMapSafe(); + return map.get(id); + } + + /** + * @see org.springframework.conversation.manager.ConversationStore#getConversations() + */ + public List getConversations() { + Map map = getConversationMapSafe(); + return new ArrayList(map.values()); + } + + /** + * @see org.springframework.conversation.manager.ConversationStore#registerConversation(org.springframework.conversation.Conversation) + */ + public void registerConversation(Conversation conversation) { + Map map = getConversationMapSafe(); + map.put(conversation.getId(), conversation); + } + + /** + * @see org.springframework.conversation.manager.ConversationStore#removeConversation(java.lang.String) + */ + public Conversation removeConversation(String id) { + Map map = getConversationMapSafe(); + return map.remove(id); + } + + /** + * @see org.springframework.conversation.manager.ConversationStore#size() + */ + public int size() { + return getConversationMapSafe().size(); + } + + /** + * Internal method returning the conversation map in a safe way as the + * method {@link #getConversationMap()} could actually raise an exception, + * if the method is injected and the map is currently not available (for + * instance if the map is in session scope and this method is invoked from a + * non web thread). If the fallback mechanism is turned on (as done by + * default), in this case the fallback map as being returned by + * {@link #getConversationMapFallback()} is returned in order to use the + * conversation management in a non web thread as well (for instance for + * asynchronous tasks or batch stuff). + * + * @return the conversation map to be used currently + */ + protected Map getConversationMapSafe() { + try { + return getConversationMap(); + } catch (Exception e) { + // if the map is not reachable and fallback is on, return the + // fallback map + if (isUseFallbackMap()) { + return getConversationMapFallback(); + } + } + + throw new IllegalAccessError("The conversation map to store conversations in is currently not available."); + } + + /** + * Returns the map used to store the conversations in using their id as the + * key. This method can either be injected by providing a map implementation + * in session or window scope or might be implemented. + * + * @return the map for storing the conversations + */ + public abstract Map getConversationMap(); + + /** + * Returns the conversation map used if the default one returned by + * {@link #getConversationMap()} is not available. This could be the case, + * if the default one is session based and the conversation management is + * used from within a non web thread. This method must always be able to + * provide a map, if the conversation management should be available in any + * situation. + * + * @return the fallback conversation map + */ + public abstract Map getConversationMapFallback(); + + /** + * @param useFallbackMap true, if the fallback map should be + * used in the case the default one is not reachable, false to + * raise an exception in that case + */ + public void setUseFallbackMap(boolean useFallbackMap) { + this.useFallbackMap = useFallbackMap; + } + + /** + * @return the true, if the fallback map should be used in the + * case the default one is not reachable + */ + public boolean isUseFallbackMap() { + return useFallbackMap; + } +} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationStore.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationStore.java index acfc78666662..56eb24761635 100644 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationStore.java +++ b/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationStore.java @@ -76,7 +76,8 @@ public interface ConversationStore { /** * Returns a list of available conversations in the current store which have * been registered using the {@link #registerConversation(Conversation)} - * method. + * method. The list being returned is not backed by the store so it can be + * modified safely from outside. * * @return the list of available conversations or an empty list, never * null