You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2007/12/04 15:16:26 UTC

svn commit: r600960 - /myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java

Author: skitching
Date: Tue Dec  4 06:16:26 2007
New Revision: 600960

URL: http://svn.apache.org/viewvc?rev=600960&view=rev
Log:
ORCHESTRA-11 fix multiple calls to the ConversationAware interface.
Also improve diagnostics when bean creation fails.

Modified:
    myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java

Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java?rev=600960&r1=600959&r2=600960&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java Tue Dec  4 06:16:26 2007
@@ -62,6 +62,7 @@
 	Scope, BeanFactoryAware, ApplicationContextAware
 {
 	private final Log log = LogFactory.getLog(AbstractSpringOrchestraScope.class);
+	private static final String POST_PROCESSOR_BEAN_NAME = AbstractSpringOrchestraScope.class.getName() + "_BeanPostProcessor";
 
 	private BeanFactory beanFactory;
 	private ConfigurableApplicationContext applicationContext;
@@ -316,7 +317,7 @@
 			if (conversation == null)
 			{
 				// Start the conversation. This eventually results in a 
-				// callback to the createConversation method on t, beanFactoryhis class.
+				// callback to the createConversation method on this class.
 				conversation = manager.startConversation(conversationName, this);
 			}
 			else
@@ -348,7 +349,17 @@
 					}
 				}
 
-				value = factory.getProxy();
+				try
+				{
+					value = factory.getProxy();
+				}
+				catch(org.springframework.aop.framework.AopConfigException e)
+				{
+					throw new IllegalStateException(
+						"Unable to create Orchestra proxy"
+							+ " for bean " + beanName
+							+ " of type " + value.getClass().getName(), e);
+				}
 
 				conversation.setAttribute(beanName, value);
 			}
@@ -399,6 +410,9 @@
 	 * When this scope object's declaration is first processed by Spring, take the opportunity to
 	 * register a global BeanPostProcessor.
 	 * <p>
+	 * This is an alternative to requiring users to also add an orchestra BeanPostProcessor element
+	 * to their xml configuration file manually.
+	 * <p>
 	 * When a bean <i>instance</i> is created by Spring, it always runs every single BeanPostProcessor
 	 * that has been registered with it.
 	 * <p>
@@ -412,32 +426,47 @@
 	 * an instance creation. If it does, then the BeanPostProcessor also runs for that instance; in this
 	 * case the beanName parameter passed to the methods will be the "scopedTarget" beanname as that is
 	 * the object that the ScopedProxyFactoryBean has asked Spring to fetch.
-	 * <p>
-	 * For Orchestra's "internal" scoped proxying, 
 	 */
 	public void setBeanFactory(BeanFactory beanFactory) throws BeansException
 	{
-		((ConfigurableBeanFactory) beanFactory).addBeanPostProcessor(
-			new BeanPostProcessor()
-			{
-				public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
+		ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanFactory;
+		if (!cbf.containsSingleton(POST_PROCESSOR_BEAN_NAME)) 
+		{
+			// TODO: this processor instance is implicitly bound to *this* scope instance, and
+			// it calls the non-static getConversationNameForBean method on *this* instance, even
+			// though the bean it is invoking may be handled by some other scope object. This
+			// doesn't actually matter, as the getConversationForBean method is actually stateless,
+			// but it is not elegant and should be fixed.
+			BeanPostProcessor processor = 
+				new BeanPostProcessor()
 				{
-					if (bean instanceof ConversationAware)
+					public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException
 					{
-						Conversation conversation = getConversationForBean(beanName);
-
-						((ConversationAware) bean).setConversation(conversation);
+						if (bean instanceof ConversationAware)
+						{
+							Conversation conversation = getConversationForBean(beanName);
+	
+							((ConversationAware) bean).setConversation(conversation);
+						}
+	
+						return bean;
 					}
-
-					return bean;
-				}
-
-				public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
-				{
-					return bean;
-				}
-			}
-		);
+	
+					public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException
+					{
+						return bean;
+					}
+				};
+				
+			// Adding the bean to the singletons set causes it to be picked up by the standard
+			// AbstractApplicationContext.RegisterBeanPostProcessors method; that calls
+			// getBeanNamesForType(BeanPostProcessor.class, ...) which finds stuff in the
+			// singleton map even when there is no actual BeanDefinition for it.
+			//
+			// We cannot call cbf.addBeanPostProcessor even if we want to, as the singleton
+			// registration will be added again, making the processor run twice on each bean..
+			cbf.registerSingleton(POST_PROCESSOR_BEAN_NAME, processor);
+		}
 		
 		this.beanFactory = beanFactory;
 	}