Skip to content

Commit 2f31222

Browse files
committed
SPR-6416 - Changed conversation management form AspectJ Aspect to interceptor based approach.
1 parent 8cc5001 commit 2f31222

32 files changed

+1569
-275
lines changed

org.springframework.context/src/main/java/org/springframework/conversation/Conversation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,5 +248,5 @@ public interface Conversation {
248248
* @param timeout the timeout in milliseconds after inactivity of the
249249
* conversation or <code>0</code>, if there should be no timeout
250250
*/
251-
void setTimeout(long timeout);
251+
void setTimeout(int timeout);
252252
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2002-2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.conversation;
18+
19+
/**
20+
* Interface that defines all Spring-specific properties of a conversation. The underlying conversation system will
21+
* start and manage a conversation based on this definition. This definition can be built up from different sources like
22+
* annotations or xml meta-data.
23+
*
24+
* @author Agim Emruli
25+
*/
26+
public interface ConversationDefinition {
27+
28+
/**
29+
* The default timeout for a conversation, means there is no timeout defined for the conversation. It is up to the
30+
* concrete conversation manager implementation to handle conversation without a timeout, like a indefinite
31+
* conversation or some other system specific timeout
32+
*/
33+
int DEFAULT_TIMEOUT = -1;
34+
35+
/**
36+
* Returns the {@link JoinMode} used to start a new conversation. See {@link JoinMode} for a more detailed description
37+
* of the different modes available.<br/> Default join mode is {@link JoinMode#NEW} which will create a new root
38+
* conversation and will automatically end the current one, if not ended before.
39+
*
40+
* @return the join mode to use for creating a new conversation
41+
*/
42+
JoinMode getJoinMode();
43+
44+
/**
45+
* Returns the qualifier on how the conversation is about to be ended. This value will be passed on to any {@link
46+
* ConversationListener} registered with the conversation being ended.
47+
*
48+
* @return the type of ending, {@link ConversationEndingType#SUCCESS} if not explicitly specified
49+
*/
50+
ConversationEndingType getConversationEndingType();
51+
52+
/**
53+
* Returns the timeout to be set within the newly created conversation, default is <code>-1</code> which means to use
54+
* the default timeout as being configured on the {@link org.springframework.conversation.manager.ConversationManager}.
55+
* A value of <code>0</code> means there is no timeout any other positive value is interpreted as a timeout in
56+
* milliseconds.
57+
*
58+
* @return the timeout in milliseconds to be set on the new conversation
59+
*/
60+
int getTimeout();
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2002-2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.conversation.annotation;
18+
19+
import java.lang.reflect.Method;
20+
import java.util.Collections;
21+
import java.util.LinkedHashSet;
22+
import java.util.Set;
23+
24+
import org.springframework.aop.support.AopUtils;
25+
import org.springframework.conversation.interceptor.ConversationAttribute;
26+
import org.springframework.conversation.interceptor.ConversationAttributeSource;
27+
import org.springframework.util.Assert;
28+
29+
/**
30+
* ConversationAttributeSource implementation that uses annotation meta-data to provide a ConversationAttribute instance
31+
* for a particular method.
32+
*
33+
* @author Agim Emruli
34+
*/
35+
public class AnnotationConversationAttributeSource implements ConversationAttributeSource {
36+
37+
private final Set<ConversationAnnotationParser> conversationAnnotationParsers;
38+
39+
/**
40+
* Default constructor that uses the Spring standard ConversationAnnotationParser instances to parse the annotation
41+
* meta-data.
42+
*
43+
* @see org.springframework.conversation.annotation.BeginConversationAnnotationParser
44+
* @see org.springframework.conversation.annotation.EndConversationAnnotationParser
45+
* @see org.springframework.conversation.annotation.ConversationAnnotationParser
46+
*/
47+
public AnnotationConversationAttributeSource() {
48+
Set<ConversationAnnotationParser> defaultParsers = new LinkedHashSet<ConversationAnnotationParser>();
49+
Collections
50+
.addAll(defaultParsers, new BeginConversationAnnotationParser(), new EndConversationAnnotationParser(),
51+
new ConversationalAnnotationParser());
52+
conversationAnnotationParsers = defaultParsers;
53+
}
54+
55+
/**
56+
* Constructor that uses the custom ConversationAnnotationParser to parse the annotation meta-data.
57+
*
58+
* @param conversationAnnotationParsers The ConversationAnnotationParser instance that will be used to parse annotation
59+
* meta-data
60+
*/
61+
public AnnotationConversationAttributeSource(ConversationAnnotationParser conversationAnnotationParsers) {
62+
this(Collections.singleton(conversationAnnotationParsers));
63+
}
64+
65+
/**
66+
* Constructor that uses a pre-built set with annotation parsers to retrieve the conversation meta-data. It is up to
67+
* the caller to provide a sorted set of annotation parsers if the order of them is important.
68+
*
69+
* @param parsers The Set of annotation parsers used to retrieve conversation meta-data.
70+
*/
71+
public AnnotationConversationAttributeSource(Set<ConversationAnnotationParser> parsers) {
72+
Assert.notNull(parsers, "ConversationAnnotationParsers must not be null");
73+
conversationAnnotationParsers = parsers;
74+
}
75+
76+
/**
77+
* Resolves the conversation meta-data by delegating to the ConversationAnnotationParser instances. This implementation
78+
* returns the first ConversationAttribute instance that will be returned by a ConversationAnnotationParser. This
79+
* method returns null if no ConversationAnnotationParser returns a non-null result.
80+
*
81+
* The implementation searches for the most specific method (e.g. if there is a interface method this methods searches
82+
* for the implementation method) before calling the underlying ConversationAnnotationParser instances. If there is no
83+
* Annotation available on the implementation method, this methods falls back to the interface method.
84+
*
85+
* @param method The method for which the ConversationAttribute should be returned.
86+
* @param targetClass The target class where the implementation should look for.
87+
*/
88+
public ConversationAttribute getConversationAttribute(Method method, Class<?> targetClass) {
89+
Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
90+
91+
for (ConversationAnnotationParser parser : conversationAnnotationParsers) {
92+
ConversationAttribute attribute = parser.parseConversationAnnotation(specificMethod);
93+
if (attribute != null) {
94+
return attribute;
95+
}
96+
97+
if(method != specificMethod){
98+
attribute = parser.parseConversationAnnotation(method);
99+
if(attribute != null){
100+
return attribute;
101+
}
102+
}
103+
}
104+
return null;
105+
}
106+
}

org.springframework.context/src/main/java/org/springframework/conversation/annotation/BeginConversation.java

Lines changed: 14 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,30 @@
2525
import org.springframework.conversation.Conversation;
2626
import org.springframework.conversation.ConversationEndingType;
2727
import org.springframework.conversation.JoinMode;
28+
import org.springframework.conversation.interceptor.ConversationAttribute;
2829
import org.springframework.conversation.manager.ConversationManager;
2930

3031
/**
31-
* This annotation can be placed on any method to start a new conversation. This
32-
* has the same effect as invoking
33-
* {@link ConversationManager#beginConversation(boolean, JoinMode)} using
34-
* <code>false</code> for the temporary mode and the join mode as being
35-
* specified within the annotation or {@link JoinMode#NEW} as the default.<br/>
36-
* The new conversation is always long running (not a temporary one) and is
37-
* ended by either manually invoke
38-
* {@link ConversationManager#endCurrentConversation(ConversationEndingType)},
39-
* invoking the {@link Conversation#end(ConversationEndingType)} method on the
40-
* conversation itself or by placing the {@link EndConversation} annotation on a
41-
* method.<br/>
42-
* The new conversation is created BEFORE the method itself is invoked as a
43-
* before-advice.
44-
*
32+
* This annotation can be placed on any method to start a new conversation. This has the same effect as invoking {@link
33+
* ConversationManager#beginConversation(boolean, JoinMode)} using <code>false</code> for the temporary mode and the
34+
* join mode as being specified within the annotation or {@link JoinMode#NEW} as the default.<br/> The new conversation
35+
* is always long running (not a temporary one) and is ended by either manually invoke {@link
36+
* ConversationManager#endCurrentConversation(ConversationEndingType)}, invoking the {@link
37+
* Conversation#end(ConversationEndingType)} method on the conversation itself or by placing the {@link EndConversation}
38+
* annotation on a method.<br/> The new conversation is created BEFORE the method itself is invoked as a before-advice.
39+
*
4540
* @author Micha Kiener
41+
* @author Agim Emruli
4642
* @since 3.1
4743
*/
4844
@Retention(RetentionPolicy.RUNTIME)
4945
@Target(ElementType.METHOD)
5046
@Documented
5147
public @interface BeginConversation {
52-
/**
53-
* Returns the {@link JoinMode} used to start a new conversation. See
54-
* {@link JoinMode} for a more detailed description of the different modes
55-
* available.<br/>
56-
* Default join mode is {@link JoinMode#NEW} which will create a new root
57-
* conversation and will automatically end the current one, if not ended
58-
* before.
59-
*
60-
* @return the join mode to use for creating a new conversation
61-
*/
48+
49+
/** The {@link JoinMode} used for this conversation. */
6250
JoinMode value() default JoinMode.NEW;
6351

64-
/**
65-
* Returns the timeout to be set within the newly created conversation,
66-
* default is <code>-1</code> which means to use the default timeout as
67-
* being configured on the {@link ConversationManager}. A value of
68-
* <code>0</code> means there is no timeout any other positive value is
69-
* interpreted as a timeout in milliseconds.
70-
*
71-
* @return the timeout in milliseconds to be set on the new conversation
72-
*/
73-
long timeout() default -1;
52+
/** The timeout for this conversation. */
53+
int timeout() default ConversationAttribute.DEFAULT_TIMEOUT;
7454
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright 2002-2010 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.conversation.annotation;
18+
19+
import java.lang.reflect.AnnotatedElement;
20+
21+
import org.springframework.conversation.interceptor.ConversationAttribute;
22+
import org.springframework.conversation.interceptor.DefaultConversationAttribute;
23+
24+
/**
25+
* ConversationAnnotationParser for the BeginConversation annotation
26+
*
27+
* @author Agim Emruli
28+
* @see org.springframework.conversation.annotation.BeginConversation
29+
*/
30+
public class BeginConversationAnnotationParser implements ConversationAnnotationParser {
31+
32+
public ConversationAttribute parseConversationAnnotation(AnnotatedElement annotatedElement) {
33+
BeginConversation beginConversation = annotatedElement.getAnnotation(BeginConversation.class);
34+
if (beginConversation != null) {
35+
return new DefaultConversationAttribute(beginConversation.value(), beginConversation.timeout());
36+
}
37+
38+
return null;
39+
}
40+
}

0 commit comments

Comments
 (0)