diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/Conversation.java b/org.springframework.context/src/main/java/org/springframework/conversation/Conversation.java deleted file mode 100644 index c464e5d81e..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/Conversation.java +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright 2002-2011 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; - -import java.util.List; - -/** - * The interface for a conversation object being managed by the {@link ConversationManager} and created, stored and - * removed by the {@link org.springframework.conversation.manager.ConversationRepository}.
- * The conversation object is most likely never used directly but rather indirectly through the - * {@link org.springframework.conversation.scope.ConversationScope}. It supports fine grained access to the conversation - * container for storing and retrieving attributes, access the conversation hierarchy or manage the timeout behavior - * of the conversation. - * - * @author Micha Kiener - * @since 3.1 - */ -public interface Conversation { - - /** - * Returns the id of this conversation which must be unique within the scope it is used to identify the conversation - * object. The id is set by the {@link org.springframework.conversation.manager.ConversationRepository} and most - * likely be used by the {@link org.springframework.conversation.manager.ConversationResolver} in order to manage - * the current conversation. - * - * @return the id of this conversation - */ - String getId(); - - /** - * Stores the given value in this conversation using the specified name. If this state already contains a value - * attached to the given name, it is returned, null otherwise.
This method stores the attribute - * within this conversation so it will be available through this and all nested conversations. - * - * @param name the name of the value to be stored in this conversation - * @param value the value to be stored - * @return the old value attached to the same name, if any, null otherwise - */ - Object setAttribute(String name, Object value); - - /** - * Returns the value attached to the given name, if any previously registered, null otherwise.
- * Returns the attribute stored with the given name within this conversation or any within the path through its parent - * to the top level root conversation. If this is a nested, isolated conversation, attributes are only being resolved - * within this conversation, not from its parent. - * - * @param name the name of the value to be retrieved - * @return the value, if available in the current state, null otherwise - */ - Object getAttribute(String name); - - /** - * Removes the value in the current conversation having the given name and returns it, if found and removed, - * null otherwise.
Removes the attribute from this specific conversation, does not remove it, if - * found within its parent. - * - * @param name the name of the value to be removed from this conversation - * @return the removed value, if found, null otherwise - */ - Object removeAttribute(String name); - - /** - * Returns the top level root conversation, if this is a nested conversation or this conversation, if it is the top - * level root conversation. This method never returns null. - * - * @return the root conversation (top level conversation) - */ - Conversation getRoot(); - - /** - * Returns the parent conversation, if this is a nested conversation, null otherwise. - * - * @return the parent conversation, if any, null otherwise - */ - Conversation getParent(); - - /** - * Returns a list of child conversations, if any, an empty list otherwise, must never return null. - * - * @return a list of child conversations (may be empty, never null) - */ - List getChildren(); - - /** - * Returns true, if this is a nested conversation and hence {@link #getParent()} will returns a non-null - * value. - * - * @return true, if this is a nested conversation, false otherwise - */ - boolean isNested(); - - /** - * Returns true, if this is a nested, isolated conversation so that it does not inherit the state from its - * parent but rather has its own state. See {@link ConversationType#ISOLATED} for more details. - * - * @return true, if this is a nested, isolated conversation - */ - boolean isIsolated(); - - /** - * Returns the timestamp in milliseconds this conversation has been created. - * - * @return the creation timestamp in millis - */ - long getCreationTime(); - - /** - * Returns the timestamp in milliseconds this conversation was last accessed (usually through a {@link - * #getAttribute(String)}, {@link #setAttribute(String, Object)} or {@link #removeAttribute(String)} access). - * - * @return the system time in milliseconds for the last access of this conversation - */ - long getLastAccessedTime(); - - /** - * Returns the timeout of this conversation object in seconds. A value of 0 stands for no timeout. - * The timeout is usually managed on the root conversation object and will be returned regardless of the hierarchy - * of this conversation. - * - * @return the timeout in seconds if any, 0 otherwise - */ - int getTimeout(); - - /** - * Set the timeout of this conversation hierarchy in seconds. A value of 0 stands for no timeout. - * Regardless of the hierarchy of this conversation, a timeout is always set on the top root conversation and is - * valid for all conversations within the same hierarchy. - * - * @param timeout the timeout in seconds to set, 0 for no timeout - */ - void setTimeout(int timeout); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/ConversationManager.java b/org.springframework.context/src/main/java/org/springframework/conversation/ConversationManager.java deleted file mode 100644 index 983876da3c..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/ConversationManager.java +++ /dev/null @@ -1,109 +0,0 @@ - -/* - * Copyright 2002-2011 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; - -/** - *

- * A conversation manager is used to manage conversations, most of all, the current conversation. It is used by - * the advice behind the conversation annotations {@link org.springframework.conversation.annotation.BeginConversation} - * and {@link org.springframework.conversation.annotation.EndConversation} in order to start and end conversations. - *

- *

- * A conversation manager uses a {@link org.springframework.conversation.manager.ConversationRepository} to create, - * store and remove conversation objects and a {@link org.springframework.conversation.manager.ConversationResolver} - * to set and remove the current conversation id. - *

- *

- * A conversation manager might be used manually in order to start and end conversations manually. - *

- *

- * 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.

- * - * A conversation is either implicitly started upon the first request of a conversation scoped bean or it is - * explicitly started by using the conversation manager manually or by placing the begin conversation on a method.
- * The same applies for ending conversations as they are either implicitly ended by starting a new one or if the - * timeout of a conversation is reached or they are ended explicitly by placing the end conversation annotation or - * using the conversation manager manually. - *

- *

- * Conversations might have child conversations which are either nested and hence will inherit the state of their - * parent or they are isolated by having its own state and hence being independent from its parent. - *

- *

- * Extending the conversation management
- * The conversation management ships with different out-of-the box implementations but is easy to extend. - * To extend the storage mechanism of conversations, the {@link org.springframework.conversation.manager.ConversationRepository} - * and maybe the {@link org.springframework.conversation.manager.DefaultConversation} have to be extended or - * overwritten to support the desired behavior.
- * To change the behavior where the current conversation is stored, either overwrite the - * {@link org.springframework.conversation.manager.ConversationResolver} or make sure the current conversation id - * is being resolved, stored and removed within the default {@link org.springframework.conversation.manager.ThreadLocalConversationResolver}. - *

- * - * @author Micha Kiener - * @since 3.1 - */ -public interface ConversationManager { - - /** - * Returns the current conversation and creates a new one, if there is currently no active conversation yet. - * Internally, the manager will use the {@link org.springframework.conversation.manager.ConversationResolver} - * to resolve the current conversation id and the {@link org.springframework.conversation.manager.ConversationRepository} - * to load the conversation object being returned. - * - * @return the current conversation, never null, will create a new conversation, if no one existing - */ - Conversation getCurrentConversation(); - - /** - * Returns the current conversation, if existing or creates a new one, if currently no active conversation available - * and createIfNotExisting is specified as true. - * - * @param createNewIfNotExisting true, if a new conversation should be created, if there is currently - * no active conversation in place, false to return null, if no current conversation active - * @return the current conversation or null, if no current conversation available and - * createIfNotExisting is set as false - */ - Conversation getCurrentConversation(boolean createNewIfNotExisting); - - /** - * Creates a new conversation according the given conversationType and makes it the current active - * conversation. See {@link ConversationType} for more detailed information about the different conversation - * creation types available.
- * If {@link ConversationType#NEW} is specified, the current conversation will automatically be ended - * - * @param conversationType the type used to start a new conversation - * @return the newly created conversation - */ - Conversation beginConversation(ConversationType conversationType); - - /** - * Ends the current conversation, if any. If root is true, the whole conversation - * hierarchy is ended and there will no current conversation be active afterwards. If root is - * false, the current conversation is ended and if it is a nested one, its parent is made the - * current conversation. - * - * @param root true to end the whole current conversation hierarchy or false to just - * end the current conversation - */ - void endCurrentConversation(boolean root); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/ConversationType.java b/org.springframework.context/src/main/java/org/springframework/conversation/ConversationType.java deleted file mode 100644 index c08e166ba9..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/ConversationType.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2011 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; - -/** - * The conversation type is used while starting a new conversation and declares how the conversation manager - * should create and start it as well how to end the current conversation, if any. - * - * @author Micha Kiener - * @since 3.1 - */ -public enum ConversationType { - /** - * The type NEW creates a new root conversation and will end a current one, if any. - */ - NEW, - - /** - * The type NESTED will create a new conversation and add it as a child conversation to the current one, - * if available. If there is no current conversation, this type is the same as NEW. - * A nested conversation will inherit the state from its parent. - */ - NESTED, - - /** - * The type ISOLATED is basically the same as NESTED but will isolate the state from its parent. While a - * nested conversation will inherit the state from its parent, an isolated one does not but rather has its - * own state. - */ - ISOLATED -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/AnnotationConversationAttributeSource.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/AnnotationConversationAttributeSource.java deleted file mode 100644 index 1efcd176f0..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/AnnotationConversationAttributeSource.java +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.reflect.Method; -import java.util.Collections; -import java.util.LinkedHashSet; -import java.util.Set; - -import org.springframework.aop.support.AopUtils; -import org.springframework.conversation.interceptor.ConversationAttribute; -import org.springframework.conversation.interceptor.ConversationAttributeSource; -import org.springframework.util.Assert; - -/** - * ConversationAttributeSource implementation that uses annotation meta-data to provide a ConversationAttribute instance - * for a particular method. - * - * @author Agim Emruli - */ -public class AnnotationConversationAttributeSource implements ConversationAttributeSource { - - private final Set conversationAnnotationParsers; - - /** - * Default constructor that uses the Spring standard ConversationAnnotationParser instances to parse the annotation - * meta-data. - * - * @see org.springframework.conversation.annotation.BeginConversationAnnotationParser - * @see org.springframework.conversation.annotation.EndConversationAnnotationParser - * @see org.springframework.conversation.annotation.ConversationAnnotationParser - */ - public AnnotationConversationAttributeSource() { - Set defaultParsers = new LinkedHashSet(); - Collections - .addAll(defaultParsers, new BeginConversationAnnotationParser(), new EndConversationAnnotationParser()); - conversationAnnotationParsers = defaultParsers; - } - - /** - * Constructor that uses the custom ConversationAnnotationParser to parse the annotation meta-data. - * - * @param conversationAnnotationParsers The ConversationAnnotationParser instance that will be used to parse annotation - * meta-data - */ - public AnnotationConversationAttributeSource(ConversationAnnotationParser conversationAnnotationParsers) { - this(Collections.singleton(conversationAnnotationParsers)); - } - - /** - * Constructor that uses a pre-built set with annotation parsers to retrieve the conversation meta-data. It is up to - * the caller to provide a sorted set of annotation parsers if the order of them is important. - * - * @param parsers The Set of annotation parsers used to retrieve conversation meta-data. - */ - public AnnotationConversationAttributeSource(Set parsers) { - Assert.notNull(parsers, "ConversationAnnotationParsers must not be null"); - conversationAnnotationParsers = parsers; - } - - /** - * Resolves the conversation meta-data by delegating to the ConversationAnnotationParser instances. This implementation - * returns the first ConversationAttribute instance that will be returned by a ConversationAnnotationParser. This - * method returns null if no ConversationAnnotationParser returns a non-null result. - * - * The implementation searches for the most specific method (e.g. if there is a interface method this methods searches - * for the implementation method) before calling the underlying ConversationAnnotationParser instances. If there is no - * Annotation available on the implementation method, this methods falls back to the interface method. - * - * @param method The method for which the ConversationAttribute should be returned. - * @param targetClass The target class where the implementation should look for. - */ - public ConversationAttribute getConversationAttribute(Method method, Class targetClass) { - Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass); - - for (ConversationAnnotationParser parser : conversationAnnotationParsers) { - ConversationAttribute attribute = parser.parseConversationAnnotation(specificMethod); - if (attribute != null) { - return attribute; - } - - if(method != specificMethod){ - attribute = parser.parseConversationAnnotation(method); - if(attribute != null){ - return attribute; - } - } - } - return null; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversation.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversation.java deleted file mode 100644 index d277b65cc1..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversation.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import org.springframework.conversation.Conversation; -import org.springframework.conversation.ConversationManager; -import org.springframework.conversation.ConversationType; -import org.springframework.conversation.interceptor.ConversationAttribute; - -/** - * This annotation can be placed on any method to start a new conversation. This has the same effect as invoking {@link - * org.springframework.conversation.ConversationManager#beginConversation(boolean, JoinMode)} using false - * for the temporary mode and the join mode as being specified within the annotation or {@link JoinMode#NEW} as the - * default.
The new conversation is always long running (not a temporary one) and is ended by either manually - * invoke {@link ConversationManager#endCurrentConversation(ConversationEndingType)}, invoking the {@link - * Conversation#end(ConversationEndingType)} method on the conversation itself or by placing the {@link EndConversation} - * annotation on a method.
The new conversation is created BEFORE the method itself is invoked as a before-advice. - * - * @author Micha Kiener - * @author Agim Emruli - * @since 3.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface BeginConversation { - /** - * The conversation type declares how to start a new conversation and how to handle an existing current one. - * See {@link ConversationType} for more information. - */ - ConversationType value() default ConversationType.NEW; - - /** The timeout for this conversation in seconds. */ - int timeout() default ConversationAttribute.DEFAULT_TIMEOUT; -} - diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversationAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversationAnnotationParser.java deleted file mode 100644 index a5c04b545c..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversationAnnotationParser.java +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.reflect.AnnotatedElement; - -import org.springframework.conversation.interceptor.ConversationAttribute; -import org.springframework.conversation.interceptor.DefaultConversationAttribute; - -/** - * ConversationAnnotationParser for the BeginConversation annotation - * - * @author Agim Emruli - * @see BeginConversation - */ -class BeginConversationAnnotationParser implements ConversationAnnotationParser { - - public ConversationAttribute parseConversationAnnotation(AnnotatedElement annotatedElement) { - BeginConversation beginConversation = annotatedElement.getAnnotation(BeginConversation.class); - if (beginConversation != null) { - return new DefaultConversationAttribute(beginConversation.value(), beginConversation.timeout()); - } - - return null; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/ConversationAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/ConversationAnnotationParser.java deleted file mode 100644 index 7e7d674963..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/ConversationAnnotationParser.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.reflect.AnnotatedElement; - -import org.springframework.conversation.interceptor.ConversationAttribute; - -/** - * Parser interface that resolver the concrete conversation annotation from an AnnotatedElement. - * - * @author Agim Emruli - */ -interface ConversationAnnotationParser { - - /** - * This method returns the ConversationAttribute for a particular AnnotatedElement which can be a method or class at - * all. - */ - ConversationAttribute parseConversationAnnotation(AnnotatedElement annotatedElement); - -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversation.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversation.java deleted file mode 100644 index 0e067a348a..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversation.java +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation can be placed on a method to end the current conversation. It - * has the same effect as a manual invocation of - * {@link org.springframework.conversation.ConversationManager#endCurrentConversation(ConversationEndingType)}.
- * The conversation is ended AFTER the method was invoked as an after-advice. - * - * @author Micha Kiener - * @since 3.1 - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -public @interface EndConversation { - - /** - * If root is true which is the default, using this annotation will end a current conversation - * completely including its path up to the top root conversation. If declared as false, it will - * only end the current conversation, making its parent as the new current conversation. - * If the current conversation is not a nested or isolated conversation, the root parameter has - * no impact. - */ - boolean root() default true; -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversationAnnotationParser.java b/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversationAnnotationParser.java deleted file mode 100644 index fb496ee89f..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/annotation/EndConversationAnnotationParser.java +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2002-2011 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.annotation; - -import java.lang.reflect.AnnotatedElement; - -import org.springframework.conversation.interceptor.ConversationAttribute; -import org.springframework.conversation.interceptor.DefaultConversationAttribute; - -/** - * ConversationAnnotationParser for the EndConversation annotation - * - * @author Agim Emruli - * @see EndConversation - */ -class EndConversationAnnotationParser implements ConversationAnnotationParser { - - public ConversationAttribute parseConversationAnnotation(AnnotatedElement annotatedElement) { - EndConversation endConversation = annotatedElement.getAnnotation(EndConversation.class); - if (endConversation != null) { - return new DefaultConversationAttribute(endConversation.root()); - } - return null; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/BeanFactoryConversationAttributeSourceAdvisor.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/BeanFactoryConversationAttributeSourceAdvisor.java deleted file mode 100644 index d702183ebe..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/BeanFactoryConversationAttributeSourceAdvisor.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import org.springframework.aop.Pointcut; -import org.springframework.aop.support.AbstractBeanFactoryPointcutAdvisor; - -/** - * Advisor implementation that advises beans if they contain conversation meta-data. Uses a - * ConversationAttributeSourcePointcut to specify if the bean should be advised or not. - * - * @author Agim Emruli - */ -public class BeanFactoryConversationAttributeSourceAdvisor extends AbstractBeanFactoryPointcutAdvisor { - - private ConversationAttributeSource conversationAttributeSource; - - private Pointcut pointcut = new ConversationAttributeSourcePointcut() { - @Override - protected ConversationAttributeSource getConversationAttributeSource() { - return conversationAttributeSource; - } - }; - - /** - * Sets the ConversationAttributeSource instance that will be used to retrieve the ConversationDefinition meta-data. - * This instance will be used by the point-cut do specify if the target bean should be advised or not. - */ - public void setConversationAttributeSource(ConversationAttributeSource conversationAttributeSource) { - this.conversationAttributeSource = conversationAttributeSource; - } - - /** - * Returns the pointcut that will be used at runtime to test if the bean should be advised or not. - * - * @see org.springframework.conversation.interceptor.ConversationAttributeSourcePointcut - */ - public Pointcut getPointcut() { - return pointcut; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttribute.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttribute.java deleted file mode 100644 index a96d9bddc9..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttribute.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import org.springframework.conversation.ConversationType; - -/** - * ConversationDefinition Attributes that will be used by the AOP interceptor to start and end conversation before and - * after methods. This attributes are not in the conversation definition itself because these attributes are only - * relevant for a interceptor based approach to handle conversations. - * - * @author Agim Emruli - */ -public interface ConversationAttribute { - - /** - * The default timeout for a conversation, means there is no timeout defined for the conversation. It is up to the - * concrete conversation manager implementation to handle conversation without a timeout, like a indefinite - * conversation or some other system specific timeout - */ - int DEFAULT_TIMEOUT = -1; - - /** - * Defines if the a conversation should be started before the interceptor delegates to the target (like a method - * invocation). This can be a short-running conversation where the method is the whole life-cycle of a conversation or - * a long-running conversation where the conversation will be started but not stopped while calling the target. - * - * @return if the conversation should be started - */ - boolean shouldStartConversation(); - - /** - * Defines if the a conversation should be ended after the interceptor delegates to the target (like a method - * invocation). The stopped that should be stopped after the call to the target can be a short-running conversation - * that has been start before the method call or a long-running conversation that has been started on some other method - * call before in the life-cycle of the application. - * - * @return if the conversation should be ended - */ - boolean shouldEndConversation(); - - boolean shouldEndRoot(); - - /** - * Returns the type used to start a new conversation. See {@link org.springframework.conversation.ConversationType} - * for a more detailed description of the different types available.
- * Default type is {@link org.springframework.conversation.ConversationType#NEW} which will create a new root - * conversation and will automatically end the current one, if not ended before. - * - * @return the conversation type to use for creating a new conversation - */ - ConversationType getConversationType(); - - /** - * Returns the timeout to be set within the newly created conversation, default is -1 which means to use - * the default timeout as being configured on the {@link org.springframework.conversation.ConversationManager}. - * A value of 0 means there is no timeout any other positive value is interpreted as a timeout in - * milliseconds. - * - * @return the timeout in milliseconds to be set on the new conversation - */ - int getTimeout(); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSource.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSource.java deleted file mode 100644 index 6aff2c774a..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSource.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import java.lang.reflect.Method; - -/** - * Interface used by the ConversationInterceptor to retrieve the meta-data for the particular conversation. The - * meta-data can be provided by any implementation which is capable to return a ConversationAttribute instance based on - * a method and class. The implementation could be a annotation-based one or a XML-based implementation that retrieves - * the meta-data through a XML-configuration. - * - * @author Agim Emruli - */ -public interface ConversationAttributeSource { - - /** - * Resolves the ConversatioNAttribute for a particular method if available. This method must return null if there are - * no ConversationAttribute meta-data available for one particular method. It is up to the implementation to look for - * alternative sources like class-level annotations that applies to all methods inside a particular class. - * - * @param method The method for which the ConversationAttribute should be returned. - * @param targetClass The target class where the implementation should look for. - * @return the conversation attributes if available for the method, otherwise null. - */ - ConversationAttribute getConversationAttribute(Method method, Class targetClass); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSourcePointcut.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSourcePointcut.java deleted file mode 100644 index e2f45a615c..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationAttributeSourcePointcut.java +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.springframework.aop.support.StaticMethodMatcherPointcut; - -/** - * Pointcut implementation that matches for methods where conversation meta-data is available for. This class is a base - * class for concrete Pointcut implementations that will provide the particular ConversationAttributeSource instance. - * - * @author Agim Emruli - */ -abstract class ConversationAttributeSourcePointcut extends StaticMethodMatcherPointcut implements Serializable { - - public boolean matches(Method method, Class targetClass) { - ConversationAttributeSource attributeSource = getConversationAttributeSource(); - return (attributeSource != null && attributeSource.getConversationAttribute(method, targetClass) != null); - } - - /** - * @return - the ConversationAttributeSource instance that will be used to retrieve the conversation meta-data - */ - protected abstract ConversationAttributeSource getConversationAttributeSource(); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationInterceptor.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationInterceptor.java deleted file mode 100644 index 4dedcb75f3..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/ConversationInterceptor.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import org.aopalliance.intercept.MethodInterceptor; -import org.aopalliance.intercept.MethodInvocation; - -import org.springframework.conversation.Conversation; -import org.springframework.conversation.ConversationManager; - -/** - * MethodInterceptor that manages conversations based on ConversationAttribute meta-data. - * - * @author Agim Emruli - */ -public class ConversationInterceptor implements MethodInterceptor { - - private ConversationManager conversationManager; - - private ConversationAttributeSource conversationAttributeSource; - - /** - * Sets the ConversationManager implementation that will be used to actually handle the conversations. - * - * @see org.springframework.conversation.manager.DefaultConversationManager - */ - public void setConversationManager(ConversationManager conversationManager) { - this.conversationManager = conversationManager; - } - - /** - * Sets the ConversationAttributeSource that will be used to retrieve the meta-data for one particular method at - * runtime. - * - * @see org.springframework.conversation.annotation.AnnotationConversationAttributeSource - */ - public void setConversationAttributeSource(ConversationAttributeSource conversationAttributeSource) { - this.conversationAttributeSource = conversationAttributeSource; - } - - /** - * Advice implementations that actually handles the conversations. This method retrieves and consults the - * ConversationAttribute at runtime and performs the particular actions before and after the target method call. - * - * @param invocation The MethodInvocation that represents the context object for this interceptor. - */ - public Object invoke(MethodInvocation invocation) throws Throwable { - - Class targetClass = (invocation.getThis() != null ? invocation.getThis().getClass() : null); - - ConversationAttribute conversationAttribute = - conversationAttributeSource.getConversationAttribute(invocation.getMethod(), targetClass); - - Object returnValue; - try { - - if (conversationAttribute != null && conversationAttribute.shouldStartConversation()) { - Conversation conversation = - conversationManager.beginConversation(conversationAttribute.getConversationType()); - if (conversationAttribute.getTimeout() != ConversationAttribute.DEFAULT_TIMEOUT) { - conversation.setTimeout(conversationAttribute.getTimeout()); - } - } - - returnValue = invocation.proceed(); - - if (conversationAttribute != null && conversationAttribute.shouldEndConversation()) { - conversationManager.endCurrentConversation(conversationAttribute.shouldEndRoot()); - } - - } - catch (Throwable th) { - if (conversationAttribute != null) { - conversationManager.endCurrentConversation(conversationAttribute.shouldEndRoot()); - } - throw th; - } - - return returnValue; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/DefaultConversationAttribute.java b/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/DefaultConversationAttribute.java deleted file mode 100644 index 6fd0291063..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/interceptor/DefaultConversationAttribute.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright 2002-2011 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.interceptor; - -import org.springframework.conversation.ConversationType; - -/** - * Default implementation of the ConversationAttribute used by the conversation system. - * - * @author Agim Emruli - */ -public class DefaultConversationAttribute implements ConversationAttribute { - - private final boolean shouldStartConversation; - - private final boolean shouldEndConversation; - - private final ConversationType conversationType; - - private final boolean shouldEndRoot; - - private int timeout = DEFAULT_TIMEOUT; - - private DefaultConversationAttribute(boolean startConversation, - boolean endConversation, - ConversationType conversationType, - int timeout, boolean shouldEndRootConversation) { - shouldStartConversation = startConversation; - shouldEndConversation = endConversation; - this.conversationType = conversationType; - this.timeout = timeout; - this.shouldEndRoot = shouldEndRootConversation; - } - - public DefaultConversationAttribute(ConversationType conversationType, int timeout) { - this(true,false,conversationType,timeout, false); - } - - public DefaultConversationAttribute(boolean shouldEndRoot) { - this(false, true, null, DEFAULT_TIMEOUT, shouldEndRoot); - } - - public boolean shouldStartConversation() { - return shouldStartConversation; - } - - public boolean shouldEndConversation() { - return shouldEndConversation; - } - - public boolean shouldEndRoot() { - return shouldEndRoot; - } - - public ConversationType getConversationType() { - return conversationType; - } - - public int getTimeout() { - return timeout; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationRepository.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationRepository.java deleted file mode 100644 index 3fe7eadbc8..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/AbstractConversationRepository.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright 2002-2011 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; - -/** - * An abstract implementation for a conversation repository. Its implementation is based on the - * {@link org.springframework.conversation.manager.DefaultConversation} and manages its initial timeout and provides - * easy removal functionality. Internally, there is no explicit check for the conversation object implementing the - * {@link MutableConversation} interface, it is assumed to be implemented as the abstract repository also creates the - * conversation objects. - * - * @author Micha Kiener - * @since 3.1 - */ -public abstract class AbstractConversationRepository implements ConversationRepository { - - /** - * The default timeout in seconds for new conversations, can be setup using the Spring configuration of the - * repository. A value of 0 means there is no timeout. - */ - private int defaultTimeout = 0; - - /** - * Creates a new conversation object and initializes its timeout by using the default timeout being set on this - * repository. - */ - public MutableConversation createNewConversation() { - MutableConversation conversation = new DefaultConversation(); - conversation.setTimeout(getDefaultConversationTimeout()); - return conversation; - } - - /** - * Creates a new conversation, attaches it to the parent and initializes its timeout as being set on the parent. - */ - public MutableConversation createNewChildConversation(MutableConversation parentConversation, boolean isIsolated) { - MutableConversation childConversation = createNewConversation(); - parentConversation.addChildConversation(childConversation, isIsolated); - childConversation.setTimeout(parentConversation.getTimeout()); - return childConversation; - } - - /** - * Generic implementation of the remove method of a repository, handling the root flag automatically - * by invoking the {@link #removeConversation(org.springframework.conversation.Conversation)} by either passing in - * the root conversation or just the given conversation.
- * Concrete repository implementations can overwrite the - * {@link #removeConversation(org.springframework.conversation.Conversation)} method to finally remove the - * conversation object or they might provide their own custom implementation for the remove operation by overwriting - * this method completely. - * - * @param id the id of the conversation to be removed - * @param root flag indicating whether the whole conversation hierarchy should be removed (true) or just - * the specified conversation - */ - public void removeConversation(String id, boolean root) { - MutableConversation conversation = getConversation(id); - if (conversation == null) { - return; - } - - if (root) { - removeConversation((MutableConversation)conversation.getRoot()); - } - else { - removeConversation(conversation); - } - } - - /** - * Internal, final method recursively invoking this method for all children of the given conversation. - * - * @param conversation the conversation to be removed, including its children, if any - */ - protected final void removeConversation(MutableConversation conversation) { - // as recursively removing children will decrease the children list, always pick out - // the first child to be removed next - while (conversation.getChildren().size() > 0) { - removeConversation((MutableConversation)conversation.getChildren().get(0)); - } - - // remove the conversation from its parent, if any - MutableConversation parentConversation = (MutableConversation) conversation.getParent(); - if (parentConversation != null) { - parentConversation.removeChildConversation(conversation); - } - - // end the conversation (will internally clear the attributes, invoke destruction callbacks, if any, and - // invalidates the conversation - conversation.clear(); - conversation.invalidate(); - - // finally, remove the single object from the repository - removeSingleConversationObject((MutableConversation) conversation); - } - - /** - * Abstract removal method to be implemented by concrete repository implementations to remove the given, single - * conversation object. Any parent and child relations must not be handled within this method, just the removal of - * the given object. - * - * @param conversation the single conversation object to be removed from this repository - */ - protected abstract void removeSingleConversationObject(MutableConversation conversation); - - - public void setDefaultConversationTimeout(int defaultTimeout) { - this.defaultTimeout = defaultTimeout; - } - - public int getDefaultConversationTimeout() { - return defaultTimeout; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationRepository.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationRepository.java deleted file mode 100644 index 93eb8ee22c..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationRepository.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * Copyright 2002-2011 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; - -/** - * The conversation repository is responsible for creating new conversation objects, store them within its own storage - * and finally remove the after they have been ended.
- * The repository might be transient (most likely in a web environment) but might support long running, persisted - * conversations as well.
- * The repository is responsible for the timeout management of the conversation objects as well and might use an - * existing mechanism to do so (in a distributed, cached storage for instance).
- * Depending on the underlying storage mechanism, the repository might support destruction callbacks within the - * conversation objects or not. If they are not supported, make sure an appropriate warning will be logged if - * registering a destruction callback. - * - * @author Micha Kiener - * @since 3.1 - */ -public interface ConversationRepository { - - /** - * Creates a new root conversation object and returns it. Be aware that this method does not store the conversation, - * this has to be done using the {@link #storeConversation(MutableConversation)} method. The id of the conversation - * will typically be set within the store method rather than the creation method. - * - * @return the newly created conversation object - */ - MutableConversation createNewConversation(); - - /** - * Creates a new child conversation and attaches it as a child to the given parent conversation. Like the - * {@link #createNewConversation()} method, this one does not store the new child conversation object, this has to - * be done using the {@link #storeConversation(MutableConversation)} method. The id of the new child conversation - * will typically be set within the store method rather than the creation method. - * - * @param parentConversation the parent conversation to create and attach a new child conversation to - * @param isIsolated true if the new child conversation has to be isolated from its parent state, - * false if it will inherit the state from the given parent - * @return the newly created child conversation, attached to the given parent conversation - */ - MutableConversation createNewChildConversation(MutableConversation parentConversation, boolean isIsolated); - - /** - * Returns the conversation with the given id which has to be registered before. If no such conversation is found, - * null is returned rather than throwing an exception. - * - * @param id the id to return the conversation from this store - * @return the conversation, if found, null otherwise - */ - MutableConversation getConversation(String id); - - /** - * Stores the given conversation object within this repository. Depending on its implementation, the storage might be - * transient or persistent, it might relay on other mechanisms like a session (in the area of web conversations for - * instance). After the conversation has been stored, its id must be set hence the id of the conversation will be - * available only after the store method has been invoked. - * - * @param conversation the conversation to be stored within the repository - */ - void storeConversation(MutableConversation conversation); - - /** - * Removes the conversation with the given id from this store. Depending on the root flag, the whole - * conversation hierarchy is removed or just the specified conversation. - * - * @param id the id of the conversation to be removed - * @param root flag indicating whether the whole conversation hierarchy should be removed (true) or just - * the specified conversation (false) - */ - void removeConversation(String id, boolean root); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationResolver.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationResolver.java deleted file mode 100644 index 23d549f4be..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ConversationResolver.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2002-2011 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; - -/** - * The current conversation resolver is another extension point for the conversation manager to easily change the - * default behavior of storing the currently used conversation id. - * - * In a web environment, the current conversation id would most likely be bound to the current window / tab and hence be - * based on the window management. This makes it possible to run different conversations per browser window and - * isolating them from each other by default. - * - * In a unit-test or batch environment the current conversation could be bound to the current thread to make - * conversations be available in a non-web environment as well. - * - * @author Micha Kiener - * @since 3.1 - */ -public interface ConversationResolver { - - /** - * Returns the id of the currently used conversation, if any, null otherwise. - * - * @return the id of the current conversation, if any, null otherwise - */ - String getCurrentConversationId(); - - /** - * Set the given conversation id to be the currently used one. Replaces the current one, if any, but is not removing - * the current conversation. - * - * @param conversationId the id of the conversation to be made the current one - */ - void setCurrentConversationId(String conversationId); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversation.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversation.java deleted file mode 100644 index 4cb6d08c12..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversation.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2002-2011 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.io.Serializable; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; - -import org.springframework.beans.factory.config.DestructionAwareAttributeHolder; -import org.springframework.conversation.Conversation; - -/** - *

The default implementation of the {@link org.springframework.conversation.Conversation} and {@link - * MutableConversation} interfaces.
- * This default implementation is also used within the {@link AbstractConversationRepository}. - *

- *

- * The implementation supports destruction callbacks for attributes. The conversation object is serializable as long as - * all of its attributes are serializable as well. - *

- * - * @author Micha Kiener - * @since 3.1 - */ -public class DefaultConversation implements MutableConversation, Serializable { - /** Serializable identifier. */ - private static final long serialVersionUID = 1L; - - /** The conversation id which must be unique within the scope of its storage. The id is set by the repository. */ - private String id; - - /** The parent conversation, if this is a nested or isolated conversation. */ - private MutableConversation parent; - - /** The optional nested conversation(s), if this is a parent conversation. */ - private List children; - - /** The map with all the registered attributes and destruction callbacks. */ - private DestructionAwareAttributeHolder attributes = new DestructionAwareAttributeHolder(); - - /** - * If set to true, this conversation does not inherit the state of its parent but rather has its own, - * isolated state. This is set to true, if a new conversation with - * {@link org.springframework.conversation.ConversationType#ISOLATED} is created. - */ - private boolean isolated; - - /** The timeout in seconds or 0, if no timeout specified. */ - private int timeout; - - /** The system timestamp of the creation of this conversation. */ - private final long creationTime = System.currentTimeMillis(); - - /** The timestamp in milliseconds of the last access to this conversation. */ - private long lastAccess; - - /** Flag indicating whether this conversation has been invalidated already. */ - private boolean invalidated; - - - public DefaultConversation() { - touch(); - } - - /** - * Considers the internal attribute map as well as the map from the parent, if this is a nested conversation and only - * if it is not isolated. - */ - public Object getAttribute(String name) { - checkValidity(); - touch(); - - // first try to get the attribute from this conversation state - Object value = attributes.getAttribute(name); - if (value != null) { - return value; - } - - // the value was not found, try the parent conversation, if any and if - // not isolated - if (parent != null && !isolated) { - return parent.getAttribute(name); - } - - // this is the root conversation and the requested bean is not - // available, so return null instead - return null; - } - - public Object setAttribute(String name, Object value) { - checkValidity(); - touch(); - - return attributes.setAttribute(name, value); - } - - public Object removeAttribute(String name) { - checkValidity(); - touch(); - return attributes.removeAttribute(name); - } - - public void clear() { - attributes.clear(); - touch(); - } - - public void setId(String id) { - this.id = id; - } - - public String getId() { - return id; - } - - public Conversation getRoot() { - // check for having a parent to be returned as the root - if (parent != null) { - return parent.getRoot(); - } - - return this; - } - - public Conversation getParent() { - return parent; - } - - public List getChildren() { - if (children == null){ - return Collections.emptyList(); - } - - return children; - } - - protected void setParentConversation(MutableConversation parentConversation, boolean isIsolated) { - checkValidity(); - this.parent = parentConversation; - this.isolated = isIsolated; - } - - public void addChildConversation(MutableConversation conversation, boolean isIsolated) { - checkValidity(); - touch(); - - if (conversation instanceof DefaultConversation) { - // set this conversation as the parent within the given child conversation - ((DefaultConversation)conversation).setParentConversation(this, isIsolated); - } - - if (children == null) { - children = new ArrayList(); - } - - children.add(conversation); - } - - public void removeChildConversation(MutableConversation conversation) { - touch(); - if (children != null) { - children.remove(conversation); - if (children.size() == 0) { - children = null; - } - } - - // remove the parent conversation from the child relationship - ((DefaultConversation)conversation).removeParent(); - } - - protected void removeParent() { - parent = null; - } - - public boolean isNested() { - return (parent != null); - } - - public boolean isParent() { - return (children != null && children.size() > 0); - } - - public boolean isIsolated() { - return isolated; - } - - /** - * Always returns the timeout value being set on the root as the root conversation is responsible for the timeout management. - */ - public int getTimeout() { - if (parent == null) { - return timeout; - } - else { - return getRoot().getTimeout(); - } - } - - /** - * The timeout will be set on the root only. - */ - public void setTimeout(int timeout) { - if (parent == null) { - this.timeout = timeout; - } - else { - getRoot().setTimeout(timeout); - } - } - - public long getCreationTime() { - return creationTime; - } - - public long getLastAccessedTime() { - return lastAccess; - } - - public void invalidate() { - invalidated = true; - clear(); - } - - protected void checkValidity() { - if (invalidated) { - throw new IllegalStateException("The conversation has been invalidated!"); - } - } - - /** - * Return true if the top root conversation has expired as the timeout is only tracked on the - * root conversation. - * - * @return true if the root of this conversation has been expired - */ - public boolean isExpired() { - if (parent != null) { - return parent.isExpired(); - } - - return (timeout != 0 && (lastAccess + timeout * 1000 < System.currentTimeMillis())); - } - - public void touch() { - lastAccess = System.currentTimeMillis(); - - // if this is a nested conversation, also touch its parent to make sure - // the parent is never timed out, if the - // current conversation is one of its nested conversations - if (parent != null) { - parent.touch(); - } - } - - public void registerDestructionCallback(String name, Runnable callback) { - attributes.registerDestructionCallback(name, callback); - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversationManager.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversationManager.java deleted file mode 100644 index 3cc0011a41..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/DefaultConversationManager.java +++ /dev/null @@ -1,178 +0,0 @@ -/* - * Copyright 2002-2011 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 org.springframework.conversation.ConversationManager; -import org.springframework.conversation.ConversationType; - -/** - * The default implementation for the {@link org.springframework.conversation.ConversationManager} interface. - * - * @author Micha Kiener - * @since 3.1 - */ -public class DefaultConversationManager implements ConversationManager { - - /** - * The conversation resolver used to resolve and expose the currently used conversation id. Do not use this attribute - * directly, always use the {@link #getConversationResolver()} method as the getter could have been injected. - */ - private ConversationResolver conversationResolver; - - /** - * If the store was injected, this attribute holds the reference to it. Never use the attribute directly, always use - * the {@link #getConversationRepository()} getter as it could have been injected. - */ - private ConversationRepository conversationRepository; - - - public MutableConversation getCurrentConversation() { - return getCurrentConversation(true); - } - - public MutableConversation getCurrentConversation(boolean createNewIfNotExisting) { - ConversationResolver resolver = getConversationResolver(); - - MutableConversation currentConversation = null; - String conversationId = resolver.getCurrentConversationId(); - if (conversationId != null) { - ConversationRepository repository = getConversationRepository(); - currentConversation = repository.getConversation(conversationId); - } - - if (currentConversation == null && createNewIfNotExisting) { - currentConversation = beginConversation(ConversationType.NEW); - } - - return currentConversation; - } - - /** - * The implementation uses the conversation repository to create a new root or a new child conversation depending on - * the conversation type specified. - * - * @param conversationType the type used to start a new conversation - * @return the newly created conversation - */ - public MutableConversation beginConversation(ConversationType conversationType) { - ConversationRepository repository = getConversationRepository(); - ConversationResolver resolver = getConversationResolver(); - - MutableConversation newConversation = null; - - switch (conversationType) { - case NEW: - // end the current conversation and create a new root one - endCurrentConversation(true); - newConversation = repository.createNewConversation(); - break; - - case NESTED: - case ISOLATED: - MutableConversation parentConversation = getCurrentConversation(false); - - // if a parent conversation is available, add the new conversation as its child conversation - if (parentConversation != null) { - newConversation = repository.createNewChildConversation(parentConversation, - conversationType == ConversationType.ISOLATED); - } - else { - // if no parent conversation found, create a new root one - newConversation = repository.createNewConversation(); - } - break; - } - - - // store the newly created conversation within its store and make it the current one through the resolver - repository.storeConversation(newConversation); - resolver.setCurrentConversationId(newConversation.getId()); - - return newConversation; - } - - /** - * The implementation only resolves the current conversation object using the repository, if only the given - * current conversation object and not the whole conversation hierarchy should be removed which can improve the - * removal from the underlying storage mechanism. - * - * @param root true to end the whole current conversation hierarchy or false to just - * remove the current conversation - */ - public void endCurrentConversation(boolean root) { - // remove the conversation from the repository and clear the current conversation id through the resolver - ConversationResolver resolver = getConversationResolver(); - ConversationRepository repository = getConversationRepository(); - - String currentConversationId = resolver.getCurrentConversationId(); - if (currentConversationId == null) { - return; - } - - // if only the current conversation has to be removed without the full conversation hierarchy, the - // current conversation must be set to the parent, if available - if (!root) { - MutableConversation currentConversation = repository.getConversation(currentConversationId); - if (currentConversation != null && currentConversation.getParent() != null) { - MutableConversation parentConversation = (MutableConversation)currentConversation.getParent(); - resolver.setCurrentConversationId(parentConversation.getId()); - } - } - - repository.removeConversation(currentConversationId, root); - } - - /** - * Returns the conversation resolver used to resolve the currently used conversation id. If the resolver itself has - * another scope than the manager, this method must be injected. - * - * @return the conversation resolver - */ - public ConversationResolver getConversationResolver() { - return conversationResolver; - } - - /** - * Inject the conversation resolver, if the method {@link #getConversationResolver()} is not injected and if the - * resolver has the same scope as the manager or even a more wider scope. - * - * @param conversationResolver the resolver to be injected - */ - public void setConversationResolver(ConversationResolver conversationResolver) { - this.conversationResolver = conversationResolver; - } - - /** - * Returns the repository where conversation objects are being registered. If the manager is in a wider scope than the - * repository, this method has to be injected. - * - * @return the conversation repository used to register conversation objects - */ - public ConversationRepository getConversationRepository() { - return conversationRepository; - } - - /** - * Inject the conversation repository to this manager which should only be done, if the method {@link - * #getConversationRepository()} is not injected and hence the repository has the same scope as the manager or wider. - * - * @param conversationRepository the repository to be injected - */ - public void setConversationRepository(ConversationRepository conversationRepository) { - this.conversationRepository = conversationRepository; - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/LocalTransientConversationRepository.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/LocalTransientConversationRepository.java deleted file mode 100644 index da8e63b134..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/LocalTransientConversationRepository.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2002-2011 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.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; - -import org.springframework.conversation.Conversation; - -/** - * A {@link ConversationRepository} storing the conversations within an internal map and hence assuming the conversation - * objects being transient. - * - * @author Micha Kiener - * @since 3.1 - */ -public class LocalTransientConversationRepository extends AbstractConversationRepository { - - /** The map for the conversation storage. */ - private final ConcurrentMap conversationMap = new ConcurrentHashMap(); - - /** Using an atomic integer, there is no need for synchronization while increasing the number. */ - private final AtomicInteger nextAvailableConversationId = new AtomicInteger(0); - - - public MutableConversation getConversation(String id) { - return conversationMap.get(id); - } - - public void storeConversation(MutableConversation conversation) { - conversation.setId(createNextConversationId()); - conversationMap.put(conversation.getId(), conversation); - } - - @Override - protected void removeSingleConversationObject(MutableConversation conversation) { - conversationMap.remove(conversation.getId()); - } - - public List getConversations() { - return new ArrayList(conversationMap.values()); - } - - public int size() { - return conversationMap.size(); - } - - protected String createNextConversationId(){ - return Integer.toString(nextAvailableConversationId.incrementAndGet()); - } - -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/MutableConversation.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/MutableConversation.java deleted file mode 100644 index ad5a037dc4..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/MutableConversation.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * Copyright 2002-2011 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 org.springframework.conversation.Conversation; - -/** - *

- * This interface extends the {@link Conversation} interface and is most likely used internally to modify the - * conversation object. Should never be used outside of the conversation management infrastructure. - *

- * - * @author Micha Kiener - * @since 3.1 - */ -public interface MutableConversation extends Conversation { - - /** - * Set the id for this conversation which must be unique within the scope the conversation objects are being stored. - * The id of the conversation objects is usually managed by the {@link ConversationRepository}. - * - * @param id the id of the conversation - */ - void setId(String id); - - /** - * Method being invoked to add the given conversation as a child conversation to this parent conversation. If - * isIsolated is true, the state of the child conversation is isolated from its parent - * state, if it is set to false, the child conversation will inherit the state from its parent. - * - * @param conversation the conversation to be added as a child to this parent conversation - * @param isIsolated flag indicating whether this conversation should be isolated from the given parent conversation - */ - void addChildConversation(MutableConversation conversation, boolean isIsolated); - - /** - * Removes the given child conversation from this parent conversation. - * - * @param conversation the conversation to be removed from this one - */ - void removeChildConversation(MutableConversation conversation); - - /** - * Reset the last access timestamp using the current time in milliseconds from the system. This is usually done if a - * conversation is used behind a scope and beans are being accessed or added to it. - */ - void touch(); - - /** - * Clears the state of this conversation by removing all of its attributes. It will, however, not invalidate the - * conversation. All attributes having a destruction callback being registered will fire, if the underlying - * {@link ConversationRepository} supports destruction callbacks. - */ - void clear(); - - /** - * Returns true if this conversation has been expired. The expiration time (timeout) is only managed - * on the root conversation and is valid for the whole conversation hierarchy. - * - * @return true if this conversation has been expired, false otherwise - */ - boolean isExpired(); - - /** - * Invalidates this conversation object. An invalidated conversation will throw an {@link IllegalStateException}, - * if it is accessed or modified. - */ - void invalidate(); - - /** - * Registers the given callback to be invoked if the attribute having the specified name is being removed from this - * conversation. Supporting destruction callbacks is dependant of the underlying {@link ConversationRepository}, so - * this operation is optional and might not be supported. - * - * @param attributeName the name of the attribute to register the destruction callback for - * @param callback the callback to be invoked if the specified attribute is removed from this conversation - */ - void registerDestructionCallback(String attributeName, Runnable callback); -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ThreadLocalConversationResolver.java b/org.springframework.context/src/main/java/org/springframework/conversation/manager/ThreadLocalConversationResolver.java deleted file mode 100644 index c0063139e7..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/manager/ThreadLocalConversationResolver.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2002-2011 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 org.springframework.core.NamedThreadLocal; - -/** - * An implementation of the {@link org.springframework.conversation.manager.ConversationResolver} where the currently - * used conversation id is bound to the current thread. - * If this implementation is used in a web environment, make sure the current conversation id is set and removed through - * a filter accordingly as the id is bound to the current thread using a thread local. - * - * @author Micha Kiener - * @since 3.1 - */ -public class ThreadLocalConversationResolver implements ConversationResolver{ - - /** The thread local attribute where the current conversation id is stored. */ - private final NamedThreadLocal currentConversationId = - new NamedThreadLocal("Current Conversation"); - - public String getCurrentConversationId() { - return currentConversationId.get(); - } - - public void setCurrentConversationId(String conversationId) { - currentConversationId.set(conversationId); - if (conversationId == null) { - currentConversationId.remove(); - } - } -} diff --git a/org.springframework.context/src/main/java/org/springframework/conversation/scope/ConversationScope.java b/org.springframework.context/src/main/java/org/springframework/conversation/scope/ConversationScope.java deleted file mode 100644 index 7d8cd82017..0000000000 --- a/org.springframework.context/src/main/java/org/springframework/conversation/scope/ConversationScope.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright 2002-2011 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.scope; - -import org.springframework.beans.factory.ObjectFactory; -import org.springframework.beans.factory.config.Scope; -import org.springframework.conversation.Conversation; -import org.springframework.conversation.ConversationManager; -import org.springframework.conversation.manager.MutableConversation; - -/** - * The default implementation of a conversation scope most likely being exposed as "conversation" scope. - * It uses the {@link ConversationManager} to get access to the current conversation being used as the container for - * storing and retrieving attributes and beans. - * - * @author Micha Kiener - * @since 3.1 - */ -public class ConversationScope implements Scope { - - /** Holds the conversation manager reference, if statically injected. */ - private ConversationManager conversationManager; - - /** The name of the current conversation object, made available through {@link #resolveContextualObject(String)}. */ - public static final String CURRENT_CONVERSATION_ATTRIBUTE_NAME = "currentConversation"; - - - public Object get(String name, ObjectFactory objectFactory) { - Conversation conversation = getConversationManager().getCurrentConversation(true); - Object attribute = conversation.getAttribute(name); - if (attribute == null) { - attribute = objectFactory.getObject(); - conversation.setAttribute(name, attribute); - } - - return attribute; - } - - /** - * Will return null if there is no current conversation. It will not implicitly start a new one, if - * no current conversation object in place. - */ - public String getConversationId() { - Conversation conversation = getConversationManager().getCurrentConversation(false); - if (conversation != null) { - return conversation.getId(); - } - - return null; - } - - /** - * Registering a destruction callback is only possible, if supported by the underlying - * {@link org.springframework.conversation.manager.ConversationRepository}. - */ - public void registerDestructionCallback(String name, Runnable callback) { - Conversation conversation = getConversationManager().getCurrentConversation(false); - if (conversation instanceof MutableConversation) { - ((MutableConversation) conversation).registerDestructionCallback(name, callback); - } - } - - public Object remove(String name) { - Conversation conversation = getConversationManager().getCurrentConversation(false); - if (conversation != null) { - return conversation.removeAttribute(name); - } - - return null; - } - - /** - * Supports the following contextual objects: - *
    - *
  • "currentConversation", returns the current {@link org.springframework.conversation.Conversation}
  • - *
- * - * @see org.springframework.beans.factory.config.Scope#resolveContextualObject(String) - */ - public Object resolveContextualObject(String key) { - if (CURRENT_CONVERSATION_ATTRIBUTE_NAME.equals(key)) { - return getConversationManager().getCurrentConversation(true); - } - - return null; - } - - public void setConversationManager(ConversationManager conversationManager) { - this.conversationManager = conversationManager; - } - - public ConversationManager getConversationManager() { - return conversationManager; - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/conversation/ConversationManagerTest.java b/org.springframework.context/src/test/java/org/springframework/conversation/ConversationManagerTest.java deleted file mode 100644 index 2fee0cbbb2..0000000000 --- a/org.springframework.context/src/test/java/org/springframework/conversation/ConversationManagerTest.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright 2002-2011 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; - -import org.junit.Test; - -import org.springframework.conversation.manager.DefaultConversationManager; -import org.springframework.conversation.manager.LocalTransientConversationRepository; -import org.springframework.conversation.manager.ThreadLocalConversationResolver; - -import static org.junit.Assert.*; - -/** - * @author Micha Kiener - */ -public class ConversationManagerTest { - - @Test - public void testNewConversationCreation() { - ConversationManager manager = createConversationManager(); - assertNotNull("manager must not be null", manager); - - Conversation conversation = manager.getCurrentConversation(); - assertNotNull("implicit creation of a current conversation must not return null", conversation); - - Conversation conversation2 = manager.getCurrentConversation(); - assertSame("subsequent invocation of current conversation must return the same object", conversation, - conversation2); - - conversation2 = manager.getCurrentConversation(false); - assertSame("subsequent invocation of current conversation must return the same object", conversation, - conversation2); - - conversation2 = manager.getCurrentConversation(true); - assertSame("subsequent invocation of current conversation must return the same object", conversation, - conversation2); - } - - @Test - public void testNewConversationCreationAndRemoval() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - manager.endCurrentConversation(true); - Conversation conversation2 = manager.getCurrentConversation(); - - assertNotSame("an ended conversation must not be reused", conversation, conversation2); - manager.endCurrentConversation(true); - - conversation = manager.getCurrentConversation(false); - assertNull("Requesting the current conversation without implicit creation must not create one", conversation); - } - - @Test - public void testNewNestedConversation() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - Conversation childConversation = manager.beginConversation(ConversationType.NESTED); - assertNotSame("child conversation must be different from its parent", conversation, childConversation); - assertSame("child conversation must be linked to its parent", conversation, childConversation.getParent()); - assertSame("child conversation must be the current one", childConversation, manager.getCurrentConversation()); - assertTrue("child conversation must be nested", childConversation.isNested()); - assertFalse("child conversation must not be isolated", childConversation.isIsolated()); - } - - @Test - public void testNewIsolatedConversation() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - Conversation childConversation = manager.beginConversation(ConversationType.ISOLATED); - assertNotSame("child conversation must be different from its parent", conversation, childConversation); - assertSame("child conversation must be linked to its parent", conversation, childConversation.getParent()); - assertSame("child conversation must be the current one", childConversation, manager.getCurrentConversation()); - assertTrue("child conversation must be nested", childConversation.isNested()); - assertTrue("child conversation must be isolated", childConversation.isIsolated()); - } - - @Test - public void testAndEndNewNestedConversation() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - Conversation childConversation = manager.beginConversation(ConversationType.NESTED); - assertSame("child conversation must be the current one", childConversation, manager.getCurrentConversation()); - - manager.endCurrentConversation(false); - assertSame("after ending a child conversation, its parent has to be the current one", conversation, - manager.getCurrentConversation()); - } - - @Test - public void testAndRootEndNewNestedConversation() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - Conversation childConversation = manager.beginConversation(ConversationType.NESTED); - assertSame("child conversation must be the current one", childConversation, manager.getCurrentConversation()); - - manager.endCurrentConversation(true); - assertNull("ending a conversation with root mode, will end in having no current conversation", - manager.getCurrentConversation(false)); - } - - @Test - public void testImplicitEnding() { - ConversationManager manager = createConversationManager(); - Conversation conversation = manager.getCurrentConversation(); - - Conversation newConversation = manager.beginConversation(ConversationType.NEW); - assertSame("new conversation must be the current one", newConversation, manager.getCurrentConversation()); - - manager.endCurrentConversation(true); - assertNull("implicit ending must not reactivate previous conversation", manager.getCurrentConversation(false)); - } - - protected ConversationManager createConversationManager() { - DefaultConversationManager manager = new DefaultConversationManager(); - LocalTransientConversationRepository repository = new LocalTransientConversationRepository(); - ThreadLocalConversationResolver resolver = new ThreadLocalConversationResolver(); - - manager.setConversationRepository(repository); - manager.setConversationResolver(resolver); - - return manager; - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/conversation/ConversationRepositoryTest.java b/org.springframework.context/src/test/java/org/springframework/conversation/ConversationRepositoryTest.java deleted file mode 100644 index c47b15e842..0000000000 --- a/org.springframework.context/src/test/java/org/springframework/conversation/ConversationRepositoryTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Copyright 2002-2011 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; - -import java.util.List; - -import org.junit.Test; - -import org.springframework.conversation.manager.ConversationRepository; -import org.springframework.conversation.manager.LocalTransientConversationRepository; -import org.springframework.conversation.manager.MutableConversation; - -import static org.junit.Assert.*; - -/** - * @author Micha Kiener - */ -public class ConversationRepositoryTest { - - @Test - public void testConversationCreation() { - ConversationRepository repository = createRepository(); - assertNotNull("repository must not be null", repository); - - MutableConversation conversation = repository.createNewConversation(); - assertNotNull("conversation object must not be null", conversation); - assertNull("Id must not be set after creation", conversation.getId()); - assertNotNull("List of children must never be null", conversation.getChildren()); - assertEquals("Children list must be empty", 0, conversation.getChildren().size()); - } - - @Test - public void testConversationCreationAndStorage() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String conversationId = conversation.getId(); - assertNotNull("ID must not be null after storage of a conversation", conversationId); - - MutableConversation conversationRequested = repository.getConversation(conversationId); - assertNotNull("Conversation must be available after storage", conversationRequested); - assertSame("Conversation objects must be the same in a transient repository", conversation, - conversationRequested); - } - - @Test - public void testConversationCreationStorageAndRemoval() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String conversationId = conversation.getId(); - - repository.removeConversation(conversationId, true); - MutableConversation conversationRequested = repository.getConversation(conversationId); - assertNull("Conversation must no longer be available after removal", conversationRequested); - } - - @Test - public void testConversationHierarchyCreation() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String rootConversationId = conversation.getId(); - - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - assertNotNull("child conversation must not be null", childConversation); - assertNotNull("parent conversation must be available", childConversation.getParent()); - assertSame("parent conversation and root conversation must be the same", conversation, - childConversation.getParent()); - assertFalse("nested conversation must not be isolated", childConversation.isIsolated()); - - List children = conversation.getChildren(); - assertNotNull("children list must never be null", children); - assertEquals("children size must be one", 1, children.size()); - assertSame("child conversation must be available through the children list of the root conversation", - childConversation, children.get(0)); - - repository.storeConversation(childConversation); - String childConversationId = childConversation.getId(); - assertNotNull("child conversation id must be set after storage", childConversationId); - assertNotSame("root and child conversation id must be different", rootConversationId, childConversationId); - - assertNotNull("root conversation must be retrievable through repository", - repository.getConversation(rootConversationId)); - assertNotNull("child conversation must be retrievable through repository", - repository.getConversation(childConversationId)); - - assertSame("root conversation must be the same, if getRoot is invoked", conversation, conversation.getRoot()); - assertSame("root conversation must be the same, if getRoot is invoked", conversation, - childConversation.getRoot()); - } - - @Test - public void testConversationHierarchyCreationAndSingleRemoval() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String rootConversationId = conversation.getId(); - - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - repository.storeConversation(childConversation); - String childConversationId = childConversation.getId(); - - repository.removeConversation(childConversationId, false); - - assertNull("parent must not be available after removal", childConversation.getParent()); - assertEquals("list of children must be empty after removal", 0, conversation.getChildren().size()); - - assertNull("child conversation must not be available through the repository after removal", - repository.getConversation(childConversationId)); - assertNotNull("root conversation must still be available after removal of its child conversation", - repository.getConversation(rootConversationId)); - } - - @Test - public void testConversationHierarchyCreationAndRootThroughChildRemoval() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String rootConversationId = conversation.getId(); - - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - repository.storeConversation(childConversation); - String childConversationId = childConversation.getId(); - - repository.removeConversation(childConversationId, true); - - assertNull("parent must not be available after removal", childConversation.getParent()); - assertEquals("list of children must be empty after removal", 0, conversation.getChildren().size()); - - assertNull("child conversation must not be available through the repository after removal", - repository.getConversation(childConversationId)); - assertNull("root conversation must not be available after root removal", - repository.getConversation(rootConversationId)); - } - - @Test - public void testConversationHierarchyCreationAndRootThroughParentRemoval() { - ConversationRepository repository = createRepository(); - - MutableConversation conversation = repository.createNewConversation(); - repository.storeConversation(conversation); - String rootConversationId = conversation.getId(); - - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - repository.storeConversation(childConversation); - String childConversationId = childConversation.getId(); - - repository.removeConversation(rootConversationId, false); - - assertNull("parent must not be available after removal", childConversation.getParent()); - assertEquals("list of children must be empty after removal", 0, conversation.getChildren().size()); - - assertNull("child conversation must not be available through the repository after removal", - repository.getConversation(childConversationId)); - assertNull("root conversation must not be available after root removal", - repository.getConversation(rootConversationId)); - } - - @Test - public void testRepositoryDefaultTimeout() { - LocalTransientConversationRepository repository = new LocalTransientConversationRepository(); - repository.setDefaultConversationTimeout(100); - - MutableConversation conversation = repository.createNewConversation(); - assertEquals("default timeout of repository has to be set on newly created conversations", 100, - conversation.getTimeout()); - - MutableConversation conversation2 = repository.createNewConversation(); - conversation2.setTimeout(50); - assertEquals("setting a timeout on a conversation must not change the default one", 100, - conversation.getTimeout()); - } - - @Test - public void testRepositoryTimeoutInheritance() { - LocalTransientConversationRepository repository = new LocalTransientConversationRepository(); - repository.setDefaultConversationTimeout(100); - - MutableConversation conversation = repository.createNewConversation(); - conversation.setTimeout(50); - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - - assertEquals("timeout of a child conversation must be inherited from its parent", 50, - childConversation.getTimeout()); - } - - @Test - public void testRepositoryCustomTimeoutChildParentPropagation() { - LocalTransientConversationRepository repository = new LocalTransientConversationRepository(); - repository.setDefaultConversationTimeout(100); - - MutableConversation conversation = repository.createNewConversation(); - conversation.setTimeout(50); - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - childConversation.setTimeout(70); - - assertEquals("the custom timeout being set on a child conversation must be propagated to its parent", 70, - conversation.getTimeout()); - } - - @Test - public void testRepositoryCustomTimeoutParentChildPropagation() { - LocalTransientConversationRepository repository = new LocalTransientConversationRepository(); - repository.setDefaultConversationTimeout(100); - - MutableConversation conversation = repository.createNewConversation(); - MutableConversation childConversation = repository.createNewChildConversation(conversation, false); - conversation.setTimeout(50); - - assertEquals("the custom timeout being set on a parent conversation must be propagated to its children", 50, - childConversation.getTimeout()); - } - - protected ConversationRepository createRepository() { - return new LocalTransientConversationRepository(); - } -} diff --git a/org.springframework.context/src/test/java/org/springframework/conversation/DefaultConversationTest.java b/org.springframework.context/src/test/java/org/springframework/conversation/DefaultConversationTest.java deleted file mode 100644 index e75ec3a5b1..0000000000 --- a/org.springframework.context/src/test/java/org/springframework/conversation/DefaultConversationTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2002-2011 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; - -import org.junit.Test; - -import org.springframework.conversation.manager.DefaultConversation; -import org.springframework.conversation.manager.MutableConversation; - -import static org.junit.Assert.*; - -/** - * @author Micha Kiener - */ -public class DefaultConversationTest { - - @Test - public void testConversationAttribute() { - Conversation conversation = new DefaultConversation(); - - String test = new String("Test"); - conversation.setAttribute("test", test); - - assertSame("attribute must be accessible through conversation object", test, conversation.getAttribute("test")); - } - - @Test - public void testConversationAttributeInheritance() { - MutableConversation conversation = new DefaultConversation(); - - String test = new String("Test"); - conversation.setAttribute("test", test); - - MutableConversation childConversation = new DefaultConversation(); - conversation.addChildConversation(childConversation, false); - - assertSame("attribute must be accessible through child conversation object", test, - childConversation.getAttribute("test")); - } - - @Test - public void testConversationAttributeIsolation() { - MutableConversation conversation = new DefaultConversation(); - - String test = new String("Test"); - conversation.setAttribute("test", test); - - MutableConversation childConversation = new DefaultConversation(); - conversation.addChildConversation(childConversation, true); - - assertNull("attribute must not be accessible from within an isolated conversation", - childConversation.getAttribute("test")); - } - - @Test - public void testNewConversationAttributeIsolation() { - MutableConversation conversation = new DefaultConversation(); - - String test = new String("Test"); - conversation.setAttribute("test", test); - - MutableConversation childConversation = new DefaultConversation(); - conversation.addChildConversation(childConversation, true); - - String test2 = new String("Test2"); - childConversation.setAttribute("test2", test2); - - assertNull("newly added attribute on isolated conversation must not be accessible within its parent", - conversation.getAttribute("test2")); - } - - @Test - public void testConversationAttributeRemoval() { - Conversation conversation = new DefaultConversation(); - - String test = new String("Test"); - conversation.setAttribute("test", test); - - String test2 = (String)conversation.removeAttribute("test"); - assertNotNull("removed attribute must be returned", test2); - assertSame("removed attribute must be the same as being added", test, test2); - - assertNull("removed attribute must not be accessible after removal", conversation.getAttribute("test")); - } -} diff --git a/org.springframework.web/src/main/java/org/springframework/web/conversation/SessionBasedConversationRepository.java b/org.springframework.web/src/main/java/org/springframework/web/conversation/SessionBasedConversationRepository.java deleted file mode 100644 index 14c95da6a4..0000000000 --- a/org.springframework.web/src/main/java/org/springframework/web/conversation/SessionBasedConversationRepository.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright 2002-2011 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.web.conversation; - -import java.io.Serializable; - -import org.springframework.conversation.Conversation; -import org.springframework.conversation.manager.AbstractConversationRepository; -import org.springframework.conversation.manager.MutableConversation; -import org.springframework.util.Assert; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; - -/** - * A conversation store implementation ({@link org.springframework.conversation.manager.ConversationRepository}) based - * on a web environment where the conversations are most likely to be stored in the current session. - * - * @author Micha Kiener - * @since 3.1 - */ -public class SessionBasedConversationRepository extends AbstractConversationRepository { - - /** The name of the attribute for the conversation map within the session. */ - public static final String CONVERSATION_STORE_ATTR_NAME = SessionBasedConversationRepository.class.getName(); - - - public MutableConversation getConversation(String id) { - RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); - Object conversation = attributes - .getAttribute(getSessionAttributeNameForConversationId(id), RequestAttributes.SCOPE_GLOBAL_SESSION); - Assert.isInstanceOf(Conversation.class, conversation); - return (MutableConversation) conversation; - } - - public void storeConversation(MutableConversation conversation) { - conversation.setId(createNextConversationId()); - - RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); - String conversationSessionAttributeName = getSessionAttributeNameForConversationId(conversation.getId()); - - attributes.setAttribute(conversationSessionAttributeName, conversation, RequestAttributes.SCOPE_GLOBAL_SESSION); - attributes.registerDestructionCallback(conversationSessionAttributeName, - new ConversationDestructionCallback(conversation), RequestAttributes.SCOPE_GLOBAL_SESSION); - } - - @Override - protected void removeSingleConversationObject(MutableConversation conversation) { - RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); - attributes.removeAttribute(getSessionAttributeNameForConversationId(conversation.getId()), - RequestAttributes.SCOPE_GLOBAL_SESSION); - } - - protected String getSessionAttributeNameForConversationId(String conversationId) { - return CONVERSATION_STORE_ATTR_NAME + conversationId; - } - - protected String createNextConversationId() { - int nextAvailableConversationId = 1; - - RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); - synchronized (attributes.getSessionMutex()) { - String[] attributeNames = attributes.getAttributeNames(RequestAttributes.SCOPE_GLOBAL_SESSION); - for (String attributeName : attributeNames) { - if (attributeName.startsWith(CONVERSATION_STORE_ATTR_NAME)) { - - MutableConversation conversation = (MutableConversation) attributes - .getAttribute(attributeName, RequestAttributes.SCOPE_GLOBAL_SESSION); - if (conversation.isExpired()) { - conversation.clear(); - attributes.removeAttribute(attributeName, RequestAttributes.SCOPE_GLOBAL_SESSION); - } - - String conversationId = conversation.getId(); - int currentConversationId = Integer.parseInt(conversationId); - if (currentConversationId > nextAvailableConversationId) { - nextAvailableConversationId = currentConversationId; - } - } - } - } - return Integer.toString(nextAvailableConversationId); - } - - - private static final class ConversationDestructionCallback implements Runnable, Serializable { - - private final MutableConversation conversation; - - private ConversationDestructionCallback(MutableConversation conversation) { - this.conversation = conversation; - } - - public void run() { - conversation.clear(); - } - } -} diff --git a/org.springframework.web/src/main/java/org/springframework/web/conversation/WebAwareConversationScope.java b/org.springframework.web/src/main/java/org/springframework/web/conversation/WebAwareConversationScope.java deleted file mode 100644 index d5d777725b..0000000000 --- a/org.springframework.web/src/main/java/org/springframework/web/conversation/WebAwareConversationScope.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright 2002-2011 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.web.conversation; - -import org.springframework.conversation.scope.ConversationScope; -import org.springframework.web.context.request.RequestAttributes; -import org.springframework.web.context.request.RequestContextHolder; - -/** - * The extension of the default conversation scope ( {@link ConversationScope}) by supporting contextual web - * objects returned by overwriting {@link #resolveContextualObject(String)}. - * - * @author Micha Kiener - * @since 3.1 - */ -public class WebAwareConversationScope extends ConversationScope { - - /** @see org.springframework.conversation.scope.ConversationScope#resolveContextualObject(String) */ - @Override - public Object resolveContextualObject(String key) { - // invoke super to support the conversation context objects - Object object = super.resolveContextualObject(key); - if (object != null) { - return object; - } - - // support web context objects - RequestAttributes attributes = RequestContextHolder.currentRequestAttributes(); - return attributes.resolveReference(key); - } -}