View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.orchestra.conversation;
21  
22  import org.aopalliance.intercept.MethodInterceptor;
23  import org.aopalliance.intercept.MethodInvocation;
24  
25  /***
26   * An advice which is added to all conversation scoped beans.
27   * 
28   * <p>It does the following:
29   * <ul>
30   * <li>Maintain the {@link Conversation#getCurrentInstance()}</li>
31   * <li>End the conversation if it has been invalidated</li>
32   * </ul>
33   * </p>
34   * 
35   * <p>A bean that is declared as belonging to a particular conversation is
36   * always wrapped by the IOC system in a proxy object. When any method is
37   * called on that proxy, the call is forwarded to the "invoke" method here.
38   * This class then ensures that the "current conversation" is set to the
39   * conversation configured for that target bean. The result is that the real
40   * bean can call Conversation.getCurrentInstance() and always receives a
41   * reference to the conversation object that has been configured for it.</p>
42   * 
43   * <p>In addition, on return from the target bean method, this object
44   * checks whether the conversation has been marked as invalid. If so (and
45   * the conversation is not in use by something further up the call stack)
46   * then destroy the conversation object.</p>
47   */
48  public class CurrentConversationAdvice implements MethodInterceptor
49  {
50  	private final CurrentConversationInfo conversationInfo;
51  
52  	public CurrentConversationAdvice(Conversation conversation, String beanName)
53  	{
54  		conversationInfo = new CurrentConversationInfo(conversation, beanName);
55  	}
56  
57  	public Object invoke(MethodInvocation methodInvocation) throws Throwable
58  	{
59  		// Save the current conversation so it can be restored later.
60  		// Note that for "top-level" calls, the saved value is null.
61  		CurrentConversationInfo previous = Conversation.getCurrentInstanceInfo();
62  
63  		// Set the appropriate conversation for the target object. 
64  		Conversation.setCurrentInstance(conversationInfo);
65  
66  		try
67  		{
68  			conversationInfo.getConversation().enterConversation();
69  
70  			return methodInvocation.proceed();
71  		}
72  		finally
73  		{
74  			// Always restore the previous conversation (which may be null).
75  			// Do this before anything else in case other methods throw exceptions.
76  			Conversation.setCurrentInstance(previous);
77  
78  			conversationInfo.getConversation().leaveConversation();
79  
80  			if (conversationInfo.getConversation().isQueueInvalid())
81  			{
82  				conversationInfo.getConversation().invalidate();
83  			}
84  		}
85  	}
86  }