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 2008/02/21 21:32:43 UTC
svn commit: r629975 [3/4] - in
/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation:
./ basic/ spring/
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=629975&r1=629974&r2=629975&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 Thu Feb 21 12:32:37 2008
@@ -61,322 +61,322 @@
* as the createBean method needs to invoke it.
*/
public abstract class AbstractSpringOrchestraScope implements ConversationFactory,
- Scope, BeanFactoryAware, ApplicationContextAware
+ Scope, BeanFactoryAware, ApplicationContextAware
{
- private final Log log = LogFactory.getLog(AbstractSpringOrchestraScope.class);
- private static final String POST_PROCESSOR_BEAN_NAME = AbstractSpringOrchestraScope.class.getName() + "_BeanPostProcessor";
+ private final Log log = LogFactory.getLog(AbstractSpringOrchestraScope.class);
+ private static final String POST_PROCESSOR_BEAN_NAME = AbstractSpringOrchestraScope.class.getName() + "_BeanPostProcessor";
- private ConfigurableApplicationContext applicationContext;
- private Advice[] advices;
- private boolean autoProxy = true;
-
- public AbstractSpringOrchestraScope()
- {
- }
-
- /**
- * The advices (interceptors) which will be applied to the conversation scoped bean.
- * These are applied whenever a method is invoked on the bean [1].
- * <p>
- * An application's spring configuration uses this method to control what advices are
- * applied to beans generated from this scope. One commonly applied advice is the
- * Orchestra persistence interceptor, which ensures that whenever a method on a
- * conversation-scoped bean is invoked the "global persistence context" is set
- * to the context for the conversation that bean is in.
- * <p>
- * Note [1]: the advices are only applied when the bean is invoked via its proxy. If
- * invoked via the "this" pointer of the object the interceptors will not run. This
- * is generally a good thing, as they are not wanted when a method on the bean invokes
- * another method on the same bean. However it is bad if the bean passes "this" as a
- * parameter to some other object that makes a callback on it at some later time. In
- * that case, the bean must take care to pass its proxy to the remote object, not
- * itself. See method ConversationUtils.getCurrentBean().
- */
- public void setAdvices(Advice[] advices)
- {
- this.advices = advices;
- }
-
- /**
- * @since 1.1
- */
- protected Advice[] getAdvices()
- {
- return advices;
- }
-
- /**
- * Configuration for a scope object to control whether "scoped proxy" objects are
- * automatically wrapped around each conversation bean.
- * <p>
- * Automatically applying scope proxies solves a lot of tricky problems with "stale"
- * beans, and should generally be used. However it does require CGLIB to be present
- * in the classpath. It also can impact performance in some cases. Where this is a
- * problem, this flag can turn autoproxying off. Note that the standard spring
- * aop:scoped-proxy bean can then be used on individual beans to re-enable
- * proxying for specific beans if desired.
- * <p>
- * This defaults to true.
- *
- * @since 1.1
- */
- public void setAutoProxy(boolean state)
- {
- autoProxy = state;
- }
-
- /**
- * Return the conversation context id.
- * <p>
- * Note: This conversationId is something spring requires. It has nothing to do with the Orchestra
- * conversation id.
- * <p>
- * TODO: what does Spring use this for????
- */
- public String getConversationId()
- {
- ConversationManager manager = ConversationManager.getInstance();
- if (manager.hasConversationContext())
- {
- return Long.toString(manager.getConversationContextId().longValue(), 10);
- }
-
- return null;
- }
-
- /**
- * This is invoked by Spring whenever someone calls getBean(name) on a bean-factory
- * and the bean-definition for that bean has a scope attribute that maps to an
- * instance of this class.
- * <p>
- * In the normal case, this method returns an internally-created proxy object
- * that fetches the "real" bean every time a method is invoked on the proxy
- * (see method getRealBean). This does obviously have some performance impact.
- * However it is necessary when beans from one conversation are referencing beans
- * from another conversation as the conversation lifetimes are not the same;
- * without this proxying there are many cases where "stale" references end up
- * being used. Most references to conversation-scoped objects are made via EL
- * expressions, and in this case the performance impact is not significant
- * relative to the overhead of EL. Note that there is one case where this
- * proxying is not "transparent" to user code: if a proxied object passes a
- * "this" pointer to a longer-lived object that retains that pointer then
- * that reference can be "stale", as it points directly to an instance rather
- * than to the proxy.
- * <p>
- * When the Spring aop:scoped-proxy feature is applied to conversation-scoped
- * beans, then this functionality is disabled as aop:scoped-proxy has a very
- * similar effect. Therefore, when this method detects that it has been invoked
- * by a proxy object generated by aop:scoped-proxy then it returns the real
- * object (see getRealBean) rather than another proxy. Using aop:scoped-proxy
- * is somewhat less efficient than Orchestra's customised proxying.
- * <p>
- * And when the orchestra proxy needs to access the real object, it won't
- * call this method; instead, getRealBean is called directly. See class
- * ScopedBeanTargetSource.
- */
- public Object get(String name, ObjectFactory objectFactory)
- {
- if (log.isDebugEnabled())
- {
- log.debug("Method get called for bean " + name);
- }
-
- if (_SpringUtils.isModifiedBeanName(name))
- {
- // Backwards compatibility with aop:scoped-proxy tag.
- //
- // The user must have included an aop:scoped-proxy within the bean definition,
- // and here the proxy is firing to try to get the underlying bean. In this
- // case, return a non-proxied instance of the referenced bean.
- try
- {
- String originalBeanName = _SpringUtils.getOriginalBeanName(name);
- String conversationName = getConversationNameForBean(name);
- return getRealBean(conversationName, originalBeanName, objectFactory);
- }
- catch(RuntimeException e)
- {
- log.error("Exception while accessing bean '" + name + "'");
- throw e;
- }
- }
- else if (!autoProxy)
- {
- String conversationName = getConversationNameForBean(name);
- return getRealBean(conversationName, name, objectFactory);
- }
- else
- {
- // A call has been made by the user to the Spring getBean method
- // (directly, or via an EL expression). Or the bean is being fetched
- // as part of spring injection into another object.
- //
- // In all these cases, just return a proxy.
- return getProxy(name, objectFactory);
- }
- }
-
- /**
- * Return a CGLIB-generated proxy class for the beanclass that is
- * specified by the provided beanName.
- * <p>
- * When any method is invoked on this proxy, it invokes method
- * getRealBean on this same instance in order to locate a proper
- * instance, then forwards the method call to it.
- * <p>
- * There is a separate proxy instance per beandef (shared across all
- * instances of that bean). This instance is created when first needed,
- * and cached for reuse.
- *
- * @since 1.1
- */
- protected Object getProxy(String beanName, ObjectFactory objectFactory)
- {
- if (log.isDebugEnabled())
- {
- log.debug("getProxy called for bean " + beanName);
- }
-
- BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
- String conversationName = getConversationNameForBean(beanName);
-
- // deal with proxies required for multiple conversations.
- // This is required to make the viewController scope work where proxies are
- // required for each conversation a bean has been requested.
- Map proxies = (Map) beanDefinition.getAttribute(ScopedBeanTargetSource.class.getName());
- if (proxies == null)
- {
- proxies = new HashMap();
- beanDefinition.setAttribute(ScopedBeanTargetSource.class.getName(), proxies);
- }
-
- Object proxy = proxies.get(conversationName);
- if (proxy == null)
- {
- if (log.isDebugEnabled())
- {
- log.debug("getProxy: creating proxy for " + beanName);
- }
- BeanFactory beanFactory = applicationContext.getBeanFactory();
- proxy = _SpringUtils.newProxy(this, conversationName, beanName, objectFactory, beanFactory);
- proxies.put(conversationName, proxy);
- }
-
- // Register the proxy in req scope. The first lookup of a variable using an EL expression during a
- // request will therefore take the "long" path through JSF's VariableResolver and Spring to get here.
- // But later lookups of this variable in the same request find the proxy directly in the request scope.
- // The proxy could potentially be placed in the session or app scope, as there is just one instance
- // for this spring context, and there is normally only one spring context for a webapp. However
- // using the request scope is almost as efficient and seems safer.
- //
- // Note that the framework adapter might not be initialised during the Spring context initialisation
- // phase (ie instantiation of singletons during startup), so just skip registration in those cases.
- FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
- if (fa != null)
- {
- fa.setRequestAttribute(beanName, proxy);
- }
-
-
- return proxy;
- }
-
- /**
- * Get a real bean instance (not a scoped-proxy).
- * <p>
- * The appropriate Conversation is retrieved; if it does not yet exist then
- * it is created and started. The conversation name is either specified on the
- * bean-definition via a custom attribute, or defaults to the bean name.
- * <p>
- * Then if the bean already exists in the Conversation it is returned. Otherwise
- * a new instance is created, stored into the Conversation and returned.
- * <p>
- * When a bean is created, a proxy is actually created for it which has one or
- * more AOP "advices" (ie method interceptors). The CurrentConversationAdvice class
- * is always attached. Note that if the bean definition contains the aop:proxy
- * tag (and most do) then the bean that spring creates is already a proxy, ie
- * what is returned is a proxy of a proxy.
- *
- * @param conversationName
- * @param beanName is the key within the conversation of the bean we are interested in.
- *
- * @since 1.1
- */
- protected Object getRealBean(String conversationName, String beanName, ObjectFactory objectFactory)
- {
- if (log.isDebugEnabled())
- {
- log.debug("getRealBean called for bean " + beanName);
- }
- ConversationManager manager = ConversationManager.getInstance();
- Conversation conversation;
-
- // check if we have a conversation
- synchronized(manager)
- {
- conversation = manager.getConversation(conversationName);
- if (conversation == null)
- {
- // Start the conversation. This eventually results in a
- // callback to the createConversation method on this class.
- conversation = manager.startConversation(conversationName, this);
- }
- else
- {
- // sanity check: verify that two beans with the different scopes
- // do not declare the same conversationName.
+ private ConfigurableApplicationContext applicationContext;
+ private Advice[] advices;
+ private boolean autoProxy = true;
+
+ public AbstractSpringOrchestraScope()
+ {
+ }
+
+ /**
+ * The advices (interceptors) which will be applied to the conversation scoped bean.
+ * These are applied whenever a method is invoked on the bean [1].
+ * <p>
+ * An application's spring configuration uses this method to control what advices are
+ * applied to beans generated from this scope. One commonly applied advice is the
+ * Orchestra persistence interceptor, which ensures that whenever a method on a
+ * conversation-scoped bean is invoked the "global persistence context" is set
+ * to the context for the conversation that bean is in.
+ * <p>
+ * Note [1]: the advices are only applied when the bean is invoked via its proxy. If
+ * invoked via the "this" pointer of the object the interceptors will not run. This
+ * is generally a good thing, as they are not wanted when a method on the bean invokes
+ * another method on the same bean. However it is bad if the bean passes "this" as a
+ * parameter to some other object that makes a callback on it at some later time. In
+ * that case, the bean must take care to pass its proxy to the remote object, not
+ * itself. See method ConversationUtils.getCurrentBean().
+ */
+ public void setAdvices(Advice[] advices)
+ {
+ this.advices = advices;
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected Advice[] getAdvices()
+ {
+ return advices;
+ }
+
+ /**
+ * Configuration for a scope object to control whether "scoped proxy" objects are
+ * automatically wrapped around each conversation bean.
+ * <p>
+ * Automatically applying scope proxies solves a lot of tricky problems with "stale"
+ * beans, and should generally be used. However it does require CGLIB to be present
+ * in the classpath. It also can impact performance in some cases. Where this is a
+ * problem, this flag can turn autoproxying off. Note that the standard spring
+ * aop:scoped-proxy bean can then be used on individual beans to re-enable
+ * proxying for specific beans if desired.
+ * <p>
+ * This defaults to true.
+ *
+ * @since 1.1
+ */
+ public void setAutoProxy(boolean state)
+ {
+ autoProxy = state;
+ }
+
+ /**
+ * Return the conversation context id.
+ * <p>
+ * Note: This conversationId is something spring requires. It has nothing to do with the Orchestra
+ * conversation id.
+ * <p>
+ * TODO: what does Spring use this for????
+ */
+ public String getConversationId()
+ {
+ ConversationManager manager = ConversationManager.getInstance();
+ if (manager.hasConversationContext())
+ {
+ return Long.toString(manager.getConversationContextId().longValue(), 10);
+ }
+
+ return null;
+ }
+
+ /**
+ * This is invoked by Spring whenever someone calls getBean(name) on a bean-factory
+ * and the bean-definition for that bean has a scope attribute that maps to an
+ * instance of this class.
+ * <p>
+ * In the normal case, this method returns an internally-created proxy object
+ * that fetches the "real" bean every time a method is invoked on the proxy
+ * (see method getRealBean). This does obviously have some performance impact.
+ * However it is necessary when beans from one conversation are referencing beans
+ * from another conversation as the conversation lifetimes are not the same;
+ * without this proxying there are many cases where "stale" references end up
+ * being used. Most references to conversation-scoped objects are made via EL
+ * expressions, and in this case the performance impact is not significant
+ * relative to the overhead of EL. Note that there is one case where this
+ * proxying is not "transparent" to user code: if a proxied object passes a
+ * "this" pointer to a longer-lived object that retains that pointer then
+ * that reference can be "stale", as it points directly to an instance rather
+ * than to the proxy.
+ * <p>
+ * When the Spring aop:scoped-proxy feature is applied to conversation-scoped
+ * beans, then this functionality is disabled as aop:scoped-proxy has a very
+ * similar effect. Therefore, when this method detects that it has been invoked
+ * by a proxy object generated by aop:scoped-proxy then it returns the real
+ * object (see getRealBean) rather than another proxy. Using aop:scoped-proxy
+ * is somewhat less efficient than Orchestra's customised proxying.
+ * <p>
+ * And when the orchestra proxy needs to access the real object, it won't
+ * call this method; instead, getRealBean is called directly. See class
+ * ScopedBeanTargetSource.
+ */
+ public Object get(String name, ObjectFactory objectFactory)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("Method get called for bean " + name);
+ }
+
+ if (_SpringUtils.isModifiedBeanName(name))
+ {
+ // Backwards compatibility with aop:scoped-proxy tag.
+ //
+ // The user must have included an aop:scoped-proxy within the bean definition,
+ // and here the proxy is firing to try to get the underlying bean. In this
+ // case, return a non-proxied instance of the referenced bean.
+ try
+ {
+ String originalBeanName = _SpringUtils.getOriginalBeanName(name);
+ String conversationName = getConversationNameForBean(name);
+ return getRealBean(conversationName, originalBeanName, objectFactory);
+ }
+ catch(RuntimeException e)
+ {
+ log.error("Exception while accessing bean '" + name + "'");
+ throw e;
+ }
+ }
+ else if (!autoProxy)
+ {
+ String conversationName = getConversationNameForBean(name);
+ return getRealBean(conversationName, name, objectFactory);
+ }
+ else
+ {
+ // A call has been made by the user to the Spring getBean method
+ // (directly, or via an EL expression). Or the bean is being fetched
+ // as part of spring injection into another object.
+ //
+ // In all these cases, just return a proxy.
+ return getProxy(name, objectFactory);
+ }
+ }
+
+ /**
+ * Return a CGLIB-generated proxy class for the beanclass that is
+ * specified by the provided beanName.
+ * <p>
+ * When any method is invoked on this proxy, it invokes method
+ * getRealBean on this same instance in order to locate a proper
+ * instance, then forwards the method call to it.
+ * <p>
+ * There is a separate proxy instance per beandef (shared across all
+ * instances of that bean). This instance is created when first needed,
+ * and cached for reuse.
+ *
+ * @since 1.1
+ */
+ protected Object getProxy(String beanName, ObjectFactory objectFactory)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("getProxy called for bean " + beanName);
+ }
+
+ BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
+ String conversationName = getConversationNameForBean(beanName);
+
+ // deal with proxies required for multiple conversations.
+ // This is required to make the viewController scope work where proxies are
+ // required for each conversation a bean has been requested.
+ Map proxies = (Map) beanDefinition.getAttribute(ScopedBeanTargetSource.class.getName());
+ if (proxies == null)
+ {
+ proxies = new HashMap();
+ beanDefinition.setAttribute(ScopedBeanTargetSource.class.getName(), proxies);
+ }
+
+ Object proxy = proxies.get(conversationName);
+ if (proxy == null)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("getProxy: creating proxy for " + beanName);
+ }
+ BeanFactory beanFactory = applicationContext.getBeanFactory();
+ proxy = _SpringUtils.newProxy(this, conversationName, beanName, objectFactory, beanFactory);
+ proxies.put(conversationName, proxy);
+ }
+
+ // Register the proxy in req scope. The first lookup of a variable using an EL expression during a
+ // request will therefore take the "long" path through JSF's VariableResolver and Spring to get here.
+ // But later lookups of this variable in the same request find the proxy directly in the request scope.
+ // The proxy could potentially be placed in the session or app scope, as there is just one instance
+ // for this spring context, and there is normally only one spring context for a webapp. However
+ // using the request scope is almost as efficient and seems safer.
+ //
+ // Note that the framework adapter might not be initialised during the Spring context initialisation
+ // phase (ie instantiation of singletons during startup), so just skip registration in those cases.
+ FrameworkAdapter fa = FrameworkAdapter.getCurrentInstance();
+ if (fa != null)
+ {
+ fa.setRequestAttribute(beanName, proxy);
+ }
+
+
+ return proxy;
+ }
+
+ /**
+ * Get a real bean instance (not a scoped-proxy).
+ * <p>
+ * The appropriate Conversation is retrieved; if it does not yet exist then
+ * it is created and started. The conversation name is either specified on the
+ * bean-definition via a custom attribute, or defaults to the bean name.
+ * <p>
+ * Then if the bean already exists in the Conversation it is returned. Otherwise
+ * a new instance is created, stored into the Conversation and returned.
+ * <p>
+ * When a bean is created, a proxy is actually created for it which has one or
+ * more AOP "advices" (ie method interceptors). The CurrentConversationAdvice class
+ * is always attached. Note that if the bean definition contains the aop:proxy
+ * tag (and most do) then the bean that spring creates is already a proxy, ie
+ * what is returned is a proxy of a proxy.
+ *
+ * @param conversationName
+ * @param beanName is the key within the conversation of the bean we are interested in.
+ *
+ * @since 1.1
+ */
+ protected Object getRealBean(String conversationName, String beanName, ObjectFactory objectFactory)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("getRealBean called for bean " + beanName);
+ }
+ ConversationManager manager = ConversationManager.getInstance();
+ Conversation conversation;
+
+ // check if we have a conversation
+ synchronized(manager)
+ {
+ conversation = manager.getConversation(conversationName);
+ if (conversation == null)
+ {
+ // Start the conversation. This eventually results in a
+ // callback to the createConversation method on this class.
+ conversation = manager.startConversation(conversationName, this);
+ }
+ else
+ {
+ // sanity check: verify that two beans with the different scopes
+ // do not declare the same conversationName.
assertSameScope(beanName, conversation);
}
- }
+ }
- // get the conversation
- notifyAccessConversation(conversation);
- synchronized(conversation)
- {
- if (!conversation.hasAttribute(beanName))
- {
- Object value;
-
- // Set the magic property that forces all proxies of this bean to be CGLIB proxies.
- // It doesn't matter if we do this multiple times..
- BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
- beanDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
-
- try
- {
- // Create the new bean. Note that this will run the
- // OrchestraAdvisorBeanPostProcessor processor, which
- // will cause the returned object to actually be a proxy
- // with the CurrentConversationAdvice (at least) attached to it.
- value = objectFactory.getObject();
- }
- catch(org.springframework.aop.framework.AopConfigException e)
- {
- throw new IllegalStateException(
- "Unable to create Orchestra proxy"
- + " for bean " + beanName, e);
- }
-
- conversation.setAttribute(beanName, value);
-
- if (value instanceof ConversationAware)
- {
- ((ConversationAware) value).setConversation(conversation);
- }
- }
- }
-
- // get the bean
- return conversation.getAttribute(beanName);
- }
-
- /**
- * Verify that the specified conversation was created by this scope object.
- *
- * @param beanName is just used when generating an error message on failure.
- * @param conversation is the conversation to validate.
- */
- protected void assertSameScope(String beanName, Conversation conversation)
+ // get the conversation
+ notifyAccessConversation(conversation);
+ synchronized(conversation)
+ {
+ if (!conversation.hasAttribute(beanName))
+ {
+ Object value;
+
+ // Set the magic property that forces all proxies of this bean to be CGLIB proxies.
+ // It doesn't matter if we do this multiple times..
+ BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
+ beanDefinition.setAttribute(AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE, Boolean.TRUE);
+
+ try
+ {
+ // Create the new bean. Note that this will run the
+ // OrchestraAdvisorBeanPostProcessor processor, which
+ // will cause the returned object to actually be a proxy
+ // with the CurrentConversationAdvice (at least) attached to it.
+ value = objectFactory.getObject();
+ }
+ catch(org.springframework.aop.framework.AopConfigException e)
+ {
+ throw new IllegalStateException(
+ "Unable to create Orchestra proxy"
+ + " for bean " + beanName, e);
+ }
+
+ conversation.setAttribute(beanName, value);
+
+ if (value instanceof ConversationAware)
+ {
+ ((ConversationAware) value).setConversation(conversation);
+ }
+ }
+ }
+
+ // get the bean
+ return conversation.getAttribute(beanName);
+ }
+
+ /**
+ * Verify that the specified conversation was created by this scope object.
+ *
+ * @param beanName is just used when generating an error message on failure.
+ * @param conversation is the conversation to validate.
+ */
+ protected void assertSameScope(String beanName, Conversation conversation)
{
// Check that the conversation's factory is this one.
//
@@ -404,8 +404,8 @@
}
protected void notifyAccessConversation(Conversation conversation)
- {
- }
+ {
+ }
/**
* Invoked by Spring to notify this object of the BeanFactory it is associated with.
@@ -414,218 +414,218 @@
* method (and the BeanFactoryAware interface on this class) were present in release
* 1.0 this needs to be kept for backwards compatibility.
*/
- public void setBeanFactory(BeanFactory beanFactory) throws BeansException
- {
- }
-
- /**
- * Register any BeanPostProcessors that are needed by this scope.
- * <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.
- *
- * @since 1.1
- */
- public void defineBeanPostProcessors(ConfigurableListableBeanFactory cbf) throws BeansException
- {
- if (!cbf.containsSingleton(POST_PROCESSOR_BEAN_NAME))
- {
- BeanPostProcessor processor = new OrchestraAdvisorBeanPostProcessor(applicationContext);
-
- // 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.
- // And we need the singleton registration in order to avoid registering this once
- // for each scope object defined in spring.
- cbf.registerSingleton(POST_PROCESSOR_BEAN_NAME, processor);
- }
- }
-
- /**
- * Get the conversation for the given beanName.
- * Returns null if the conversation does not exist.
- */
- protected Conversation getConversationForBean(String beanDefName)
- {
- ConversationManager manager = ConversationManager.getInstance();
- String conversationName = getConversationNameForBean(beanDefName);
- Conversation conversation = manager.getConversation(conversationName);
- return conversation;
- }
-
- /**
- * Get the conversation-name for bean instances created using the specified
- * bean definition.
- */
- protected String getConversationNameForBean(String beanName)
- {
- if (applicationContext == null)
- {
- throw new IllegalStateException("Null application context");
- }
-
- // Look up the definition with the specified name.
- BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
-
- if (ScopedProxyFactoryBean.class.getName().equals(beanDefinition.getBeanClassName()))
- {
- // Handle unusual case.
- //
- // The user bean must have been defined like this:
- // <bean name="foo" class="example.Foo">
- // <....>
- // <aop:scopedProxy/>
- // </bean>
- // In this case, Spring's ScopedProxyUtils class creates two BeanDefinition objects, one
- // with name "foo" that creates a proxy object, and one with name "scopedTarget.foo"
- // that actually defines the bean of type example.Foo.
- //
- // So what we do here is find the renamed bean definition and look there.
- //
- // This case does not occur when this method is invoked from within this class; the
- // spring scope-related callbacks always deal with the beandef that is scoped to
- // this scope - which is the original (though renamed) beandef.
- beanName = _SpringUtils.getModifiedBeanName(beanName);
- beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName); // NON-NLS
- }
-
- String convName = getExplicitConversationName(beanDefinition);
- if (convName == null)
- {
- // The beanname might have been of form "scopedTarget.foo" (esp from registerDestructionCallback).
- // But in this case, the conversation name will just be "foo", so strip the prefix off.
- //
- // Note that this does happen quite often for calls from within this class when aop:scoped-proxy
- // is being used (which is not recommended but is supported).
- convName = _SpringUtils.getOriginalBeanName(beanName);
- }
- return convName;
- }
-
- /**
- * Return the explicit conversation name for this bean definition, or null if there is none.
- * <p>
- * This is a separate method so that subclasses can determine conversation names via alternate methods.
- * In particular, a subclass may want to look for an annotation on the class specified by the definition.
- *
- * @since 1.1
- */
- protected String getExplicitConversationName(BeanDefinition beanDef)
- {
- String attr = (String) beanDef.getAttribute(
- BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE);
- return attr;
- }
-
- /**
- * Strip off any Spring namespace (eg scopedTarget).
- * <p>
- * This method will simply strip off anything before the first dot.
- *
- * @deprecated Should not be necessary in user code.
- */
- protected String buildBeanName(String name)
- {
- if (name == null)
- {
- return null;
- }
-
- int pos = name.indexOf('.');
- if (pos < 0)
- {
- return name;
- }
-
- return name.substring(pos + 1);
- }
-
- public Object remove(String name)
- {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add the given runnable wrapped within an
- * {@link org.apache.myfaces.orchestra.conversation.ConversationBindingListener} to
- * the conversation map.
- * <p>
- * This ensures it will be called during conversation destroy.
- * <p>
- * Spring calls this method whenever a bean in this scope is created, if that bean
- * has a "destroy method". Note however that it appears that it can also call it even
- * for beans that do not have a destroy method when there is a "destruction aware"
- * BeanPostProcessor attached to the context (spring version 2.5 at least).
- * <p>
- * When an aop:scoped-proxy has been used inside the bean, then the "new" definition
- * does not have any scope attribute, so orchestra is not invoked for it. However
- * the "renamed" bean does, and so this is called.
- */
- public void registerDestructionCallback(String name, final Runnable runnable)
- {
- if (log.isDebugEnabled())
- {
- log.debug("registerDestructionCallback for [" + name + "]");
- }
-
- Conversation conversation = getConversationForBean(name);
- if (conversation == null)
- {
- // This should never happen because this should only be called after the bean
- // instance has been created via scope.getBean, which always creates the
- // conversation for the bean.
- throw new IllegalStateException("No conversation for bean [" + name + "]");
- }
- if (runnable == null)
- {
- throw new IllegalStateException("No runnable object for bean [" + name + "]");
- }
-
- // Add an object to the conversation as a bean so that when the conversation is removed
- // its valueUnbound method will be called. However we never need to retrieve this object
- // from the context by name, so use a totally unique name as the bean key.
- conversation.setAttribute(
- runnable.getClass().getName() + "@" + System.identityHashCode(runnable),
- new ConversationBindingListener()
- {
- public void valueBound(ConversationBindingEvent event)
- {
- }
-
- public void valueUnbound(ConversationBindingEvent event)
- {
- runnable.run();
- }
- }
- );
- }
-
- /**
- * Get an ApplicationContext injected by Spring. See ApplicationContextAware interface.
- */
- public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
- {
- if (!(applicationContext instanceof ConfigurableApplicationContext))
- {
- throw new IllegalArgumentException("a ConfigurableApplicationContext is required");
- }
-
- this.applicationContext = (ConfigurableApplicationContext) applicationContext;
- defineBeanPostProcessors(this.applicationContext.getBeanFactory());
- }
-
- /**
- * @since 1.1
- */
- protected ApplicationContext getApplicationContext()
- {
- return applicationContext;
- }
-}
\ No newline at end of file
+ public void setBeanFactory(BeanFactory beanFactory) throws BeansException
+ {
+ }
+
+ /**
+ * Register any BeanPostProcessors that are needed by this scope.
+ * <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.
+ *
+ * @since 1.1
+ */
+ public void defineBeanPostProcessors(ConfigurableListableBeanFactory cbf) throws BeansException
+ {
+ if (!cbf.containsSingleton(POST_PROCESSOR_BEAN_NAME))
+ {
+ BeanPostProcessor processor = new OrchestraAdvisorBeanPostProcessor(applicationContext);
+
+ // 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.
+ // And we need the singleton registration in order to avoid registering this once
+ // for each scope object defined in spring.
+ cbf.registerSingleton(POST_PROCESSOR_BEAN_NAME, processor);
+ }
+ }
+
+ /**
+ * Get the conversation for the given beanName.
+ * Returns null if the conversation does not exist.
+ */
+ protected Conversation getConversationForBean(String beanDefName)
+ {
+ ConversationManager manager = ConversationManager.getInstance();
+ String conversationName = getConversationNameForBean(beanDefName);
+ Conversation conversation = manager.getConversation(conversationName);
+ return conversation;
+ }
+
+ /**
+ * Get the conversation-name for bean instances created using the specified
+ * bean definition.
+ */
+ protected String getConversationNameForBean(String beanName)
+ {
+ if (applicationContext == null)
+ {
+ throw new IllegalStateException("Null application context");
+ }
+
+ // Look up the definition with the specified name.
+ BeanDefinition beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName);
+
+ if (ScopedProxyFactoryBean.class.getName().equals(beanDefinition.getBeanClassName()))
+ {
+ // Handle unusual case.
+ //
+ // The user bean must have been defined like this:
+ // <bean name="foo" class="example.Foo">
+ // <....>
+ // <aop:scopedProxy/>
+ // </bean>
+ // In this case, Spring's ScopedProxyUtils class creates two BeanDefinition objects, one
+ // with name "foo" that creates a proxy object, and one with name "scopedTarget.foo"
+ // that actually defines the bean of type example.Foo.
+ //
+ // So what we do here is find the renamed bean definition and look there.
+ //
+ // This case does not occur when this method is invoked from within this class; the
+ // spring scope-related callbacks always deal with the beandef that is scoped to
+ // this scope - which is the original (though renamed) beandef.
+ beanName = _SpringUtils.getModifiedBeanName(beanName);
+ beanDefinition = applicationContext.getBeanFactory().getBeanDefinition(beanName); // NON-NLS
+ }
+
+ String convName = getExplicitConversationName(beanDefinition);
+ if (convName == null)
+ {
+ // The beanname might have been of form "scopedTarget.foo" (esp from registerDestructionCallback).
+ // But in this case, the conversation name will just be "foo", so strip the prefix off.
+ //
+ // Note that this does happen quite often for calls from within this class when aop:scoped-proxy
+ // is being used (which is not recommended but is supported).
+ convName = _SpringUtils.getOriginalBeanName(beanName);
+ }
+ return convName;
+ }
+
+ /**
+ * Return the explicit conversation name for this bean definition, or null if there is none.
+ * <p>
+ * This is a separate method so that subclasses can determine conversation names via alternate methods.
+ * In particular, a subclass may want to look for an annotation on the class specified by the definition.
+ *
+ * @since 1.1
+ */
+ protected String getExplicitConversationName(BeanDefinition beanDef)
+ {
+ String attr = (String) beanDef.getAttribute(
+ BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE);
+ return attr;
+ }
+
+ /**
+ * Strip off any Spring namespace (eg scopedTarget).
+ * <p>
+ * This method will simply strip off anything before the first dot.
+ *
+ * @deprecated Should not be necessary in user code.
+ */
+ protected String buildBeanName(String name)
+ {
+ if (name == null)
+ {
+ return null;
+ }
+
+ int pos = name.indexOf('.');
+ if (pos < 0)
+ {
+ return name;
+ }
+
+ return name.substring(pos + 1);
+ }
+
+ public Object remove(String name)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Add the given runnable wrapped within an
+ * {@link org.apache.myfaces.orchestra.conversation.ConversationBindingListener} to
+ * the conversation map.
+ * <p>
+ * This ensures it will be called during conversation destroy.
+ * <p>
+ * Spring calls this method whenever a bean in this scope is created, if that bean
+ * has a "destroy method". Note however that it appears that it can also call it even
+ * for beans that do not have a destroy method when there is a "destruction aware"
+ * BeanPostProcessor attached to the context (spring version 2.5 at least).
+ * <p>
+ * When an aop:scoped-proxy has been used inside the bean, then the "new" definition
+ * does not have any scope attribute, so orchestra is not invoked for it. However
+ * the "renamed" bean does, and so this is called.
+ */
+ public void registerDestructionCallback(String name, final Runnable runnable)
+ {
+ if (log.isDebugEnabled())
+ {
+ log.debug("registerDestructionCallback for [" + name + "]");
+ }
+
+ Conversation conversation = getConversationForBean(name);
+ if (conversation == null)
+ {
+ // This should never happen because this should only be called after the bean
+ // instance has been created via scope.getBean, which always creates the
+ // conversation for the bean.
+ throw new IllegalStateException("No conversation for bean [" + name + "]");
+ }
+ if (runnable == null)
+ {
+ throw new IllegalStateException("No runnable object for bean [" + name + "]");
+ }
+
+ // Add an object to the conversation as a bean so that when the conversation is removed
+ // its valueUnbound method will be called. However we never need to retrieve this object
+ // from the context by name, so use a totally unique name as the bean key.
+ conversation.setAttribute(
+ runnable.getClass().getName() + "@" + System.identityHashCode(runnable),
+ new ConversationBindingListener()
+ {
+ public void valueBound(ConversationBindingEvent event)
+ {
+ }
+
+ public void valueUnbound(ConversationBindingEvent event)
+ {
+ runnable.run();
+ }
+ }
+ );
+ }
+
+ /**
+ * Get an ApplicationContext injected by Spring. See ApplicationContextAware interface.
+ */
+ public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
+ {
+ if (!(applicationContext instanceof ConfigurableApplicationContext))
+ {
+ throw new IllegalArgumentException("a ConfigurableApplicationContext is required");
+ }
+
+ this.applicationContext = (ConfigurableApplicationContext) applicationContext;
+ defineBeanPostProcessors(this.applicationContext.getBeanFactory());
+ }
+
+ /**
+ * @since 1.1
+ */
+ protected ApplicationContext getApplicationContext()
+ {
+ return applicationContext;
+ }
+}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/BeanDefinitionConversationNameAttrDecorator.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/BeanDefinitionConversationNameAttrDecorator.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/BeanDefinitionConversationNameAttrDecorator.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/BeanDefinitionConversationNameAttrDecorator.java Thu Feb 21 12:32:37 2008
@@ -33,29 +33,29 @@
*/
public class BeanDefinitionConversationNameAttrDecorator implements BeanDefinitionDecorator
{
- /**
- * The name of the xml attribute in the spring bean definition that is used by
- * orchestra as the conversation name.
- */
- public final static String XSD_CONVERSATION_NAME_ATTRIBUTE = "conversationName"; // NON-NLS
-
- /**
- * A unique key used to store the orchestra conversationName within the attributes map
- * of a spring bean definition.
- */
- public final static String CONVERSATION_NAME_ATTRIBUTE = "org.apache.myfaces.orchestra.spring.conversationName"; // NON-NLS
+ /**
+ * The name of the xml attribute in the spring bean definition that is used by
+ * orchestra as the conversation name.
+ */
+ public final static String XSD_CONVERSATION_NAME_ATTRIBUTE = "conversationName"; // NON-NLS
+
+ /**
+ * A unique key used to store the orchestra conversationName within the attributes map
+ * of a spring bean definition.
+ */
+ public final static String CONVERSATION_NAME_ATTRIBUTE = "org.apache.myfaces.orchestra.spring.conversationName"; // NON-NLS
- public BeanDefinitionHolder decorate(
- Node node,
- BeanDefinitionHolder definition,
- ParserContext parserContext)
- {
- String conversationName = node.getTextContent();
- if (conversationName != null && conversationName.length() > 0)
- {
- definition.getBeanDefinition().setAttribute(CONVERSATION_NAME_ATTRIBUTE, conversationName);
- }
+ public BeanDefinitionHolder decorate(
+ Node node,
+ BeanDefinitionHolder definition,
+ ParserContext parserContext)
+ {
+ String conversationName = node.getTextContent();
+ if (conversationName != null && conversationName.length() > 0)
+ {
+ definition.getBeanDefinition().setAttribute(CONVERSATION_NAME_ATTRIBUTE, conversationName);
+ }
- return definition;
- }
+ return definition;
+ }
}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/JpaPersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/JpaPersistenceContextFactory.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/JpaPersistenceContextFactory.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/JpaPersistenceContextFactory.java Thu Feb 21 12:32:37 2008
@@ -40,92 +40,92 @@
*/
public class JpaPersistenceContextFactory implements PersistenceContextFactory
{
- private EntityManagerFactory entityManagerFactory;
+ private EntityManagerFactory entityManagerFactory;
- public PersistenceContext create()
- {
- final EntityManager em = entityManagerFactory.createEntityManager();
- em.setFlushMode(FlushModeType.COMMIT);
-
- return new PersistenceContext()
- {
- private final Stack bindings = new Stack();
-
- // Store the current EntityManagerHolder on a stack, then install our own as the
- // current EntityManagerHolder. Storing the old one allows us to restore it when
- // this context is "unbound".
- //
- // Orchestra calls bind every time a method is invoked on a bean which has
- // a conversation with a persistence context. The unbind is invoked when the
- // invoked method on that bean returns.
- //
- // When a bean has a property that has been annotated as @PersistenceContext,
- // Spring injects a proxy that looks up the "current" persistence context whenever
- // a method is invoked on it. Because Orchestra has called persistencecontext.bind
- // when the bean was first entered, and this object's bind method has installed
- // itself as the "current" spring persistence context object, the bean sees the
- // persistence context that is associated with its conversation.
- //
- // TODO: what happens when a bean invokes a method on itself? Does bind get called
- // again? If so, then this implementation is inefficient as it will push itself
- // onto the stack over and over again. This could be optimised by checking whether
- // this is the current context, and if so just incrementing a counter rather than
- // pushing onto a stack...
- public void bind()
- {
- synchronized(bindings)
- {
- EntityManagerHolder current = (EntityManagerHolder)
- TransactionSynchronizationManager.getResource(entityManagerFactory);
-
- if (current != null)
- {
- TransactionSynchronizationManager.unbindResource(entityManagerFactory);
- }
-
- bindings.push(current);
-
- TransactionSynchronizationManager.bindResource(entityManagerFactory,
- new EntityManagerHolder(em));
- }
- }
-
- public void unbind()
- {
- synchronized(bindings)
- {
- if (TransactionSynchronizationManager.hasResource(entityManagerFactory))
- {
- TransactionSynchronizationManager.unbindResource(entityManagerFactory);
- }
-
- Object holder = null;
- if (bindings.size() > 0)
- {
- holder = bindings.pop();
- }
- if (holder != null)
- {
- TransactionSynchronizationManager.bindResource(entityManagerFactory,
- holder);
- }
- }
- }
-
- public void close()
- {
- em.close();
- }
- };
- }
-
- public EntityManagerFactory getEntityManagerFactory()
- {
- return entityManagerFactory;
- }
-
- public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory)
- {
- this.entityManagerFactory = entityManagerFactory;
- }
-}
\ No newline at end of file
+ public PersistenceContext create()
+ {
+ final EntityManager em = entityManagerFactory.createEntityManager();
+ em.setFlushMode(FlushModeType.COMMIT);
+
+ return new PersistenceContext()
+ {
+ private final Stack bindings = new Stack();
+
+ // Store the current EntityManagerHolder on a stack, then install our own as the
+ // current EntityManagerHolder. Storing the old one allows us to restore it when
+ // this context is "unbound".
+ //
+ // Orchestra calls bind every time a method is invoked on a bean which has
+ // a conversation with a persistence context. The unbind is invoked when the
+ // invoked method on that bean returns.
+ //
+ // When a bean has a property that has been annotated as @PersistenceContext,
+ // Spring injects a proxy that looks up the "current" persistence context whenever
+ // a method is invoked on it. Because Orchestra has called persistencecontext.bind
+ // when the bean was first entered, and this object's bind method has installed
+ // itself as the "current" spring persistence context object, the bean sees the
+ // persistence context that is associated with its conversation.
+ //
+ // TODO: what happens when a bean invokes a method on itself? Does bind get called
+ // again? If so, then this implementation is inefficient as it will push itself
+ // onto the stack over and over again. This could be optimised by checking whether
+ // this is the current context, and if so just incrementing a counter rather than
+ // pushing onto a stack...
+ public void bind()
+ {
+ synchronized(bindings)
+ {
+ EntityManagerHolder current = (EntityManagerHolder)
+ TransactionSynchronizationManager.getResource(entityManagerFactory);
+
+ if (current != null)
+ {
+ TransactionSynchronizationManager.unbindResource(entityManagerFactory);
+ }
+
+ bindings.push(current);
+
+ TransactionSynchronizationManager.bindResource(entityManagerFactory,
+ new EntityManagerHolder(em));
+ }
+ }
+
+ public void unbind()
+ {
+ synchronized(bindings)
+ {
+ if (TransactionSynchronizationManager.hasResource(entityManagerFactory))
+ {
+ TransactionSynchronizationManager.unbindResource(entityManagerFactory);
+ }
+
+ Object holder = null;
+ if (bindings.size() > 0)
+ {
+ holder = bindings.pop();
+ }
+ if (holder != null)
+ {
+ TransactionSynchronizationManager.bindResource(entityManagerFactory,
+ holder);
+ }
+ }
+ }
+
+ public void close()
+ {
+ em.close();
+ }
+ };
+ }
+
+ public EntityManagerFactory getEntityManagerFactory()
+ {
+ return entityManagerFactory;
+ }
+
+ public void setEntityManagerFactory(EntityManagerFactory entityManagerFactory)
+ {
+ this.entityManagerFactory = entityManagerFactory;
+ }
+}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraAdvisorBeanPostProcessor.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraAdvisorBeanPostProcessor.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraAdvisorBeanPostProcessor.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraAdvisorBeanPostProcessor.java Thu Feb 21 12:32:37 2008
@@ -54,178 +54,178 @@
*/
class OrchestraAdvisorBeanPostProcessor extends AbstractAutoProxyCreator
{
- private static final long serialVersionUID = 1;
- private final Log log = LogFactory.getLog(OrchestraAdvisorBeanPostProcessor.class);
- private ConfigurableApplicationContext appContext;
-
- /**
- * Define a trivial Advisor object that always applies to the class passed to it.
- * <p>
- * Spring requires Advisor objects to be returned rather than Advices. Advisors
- * can implement various interfaces to control which classes or methods they
- * get applied to, but here the OrchestraAdvisorBeanPostProcessor only returns an
- * instance of this for classes that it really *should* apply to, and the advices
- * always apply to all methods, so there is really nothing for this Advisor to do.
- * <p>
- * TODO: maybe it would be nice to allow an orchestra scope object to hold Advisors
- * as well as just Advices, so that users can configure specific code to run only
- * for specific methods of orchestra beans.
- * <p>
- * NB: In Spring2.5, this class can simply implement Advisor, and it will be applied to
- * all methods. However in Spring2.0, class DefaultAdvisorChainFactory only accepts
- * PointcutAdvisor or IntroductionAdvisor, and silently ignores Advisor classes that
- * are not of those types. So here for Spring2.x compatibility we need to make this
- * class a PointcutAdvisor with a dummy pointcut that matches all methods...
- */
- private static class SimpleAdvisor implements PointcutAdvisor
- {
- private Advice advice;
-
- public SimpleAdvisor(Advice advice)
- {
- this.advice = advice;
- }
-
- public Advice getAdvice()
- {
- return advice;
- }
-
- public boolean isPerInstance()
- {
- return false;
- }
-
- public Pointcut getPointcut()
- {
- return Pointcut.TRUE;
- }
- }
-
- public OrchestraAdvisorBeanPostProcessor(ConfigurableApplicationContext appContext)
- {
- this.appContext = appContext;
-
- // Always force CGLIB to be used to generate proxies, rather than java.lang.reflect.Proxy.
- //
- // Without this, the Orchestra scoped-proxy instance will not work; it requires
- // the target to fully implement the same class it is proxying, not just the
- // interfaces on the target class.
- //
- //
- // Alas, this is not sufficient to solve all the problems. If a BeanPostProcessor runs
- // before this processor, and it creates a CGLIB based proxy, then this class creates
- // a new proxy that *replaces* that one by peeking into the preceding proxy to find
- // its real target class/interfaces and its advices and merging that data with the
- // settings here (see method Cglib2AopProxy.getProxy for details). However if an
- // earlier BeanPostProcessor has created a java.lang.reflect.Proxy proxy instance
- // then this merging does not occur; instead this class just tries to wrap that proxy
- // in another cglib proxy, but that fails because java.lang.reflect.Proxy creates
- // final (unsubclassable) classes. So in short either this BeanPostProcessor needs to
- // be the *first* processor, or some trick is needed to force all BeanPostProcessors
- // to use cglib. This can be done by setting a special attribute in the BeanDefinition
- // for a bean, and AbstractSpringOrchestraScope does this.
- //
- // Note that forging cglib to be used for proxies is also necessary when creating a
- // "scoped proxy" for an object. The aop:scoped-proxy class also has the same needs
- // as the Orchestra scoped-proxy, and also forces CGLIB usage, using the same method
- // (setting AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE in the attributes of the
- // BeanDefinition of the target bean).
- setProxyTargetClass(true);
- }
-
- protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName,
- TargetSource customTargetSource) throws BeansException
- {
- BeanDefinition bd;
- try
- {
- bd = appContext.getBeanFactory().getBeanDefinition(beanName);
- }
- catch(NoSuchBeanDefinitionException e)
- {
- // odd. However it appears that there are some "special" beans that Spring
- // creates that cause the BeanPostProcessor to be run even though they do
- // not have a corresponding definition. The name "(inner bean)" is one of them,
- // but there are also names of form "example.classname#xyz123" passed to here.
- if (log.isDebugEnabled())
- {
- log.debug("Bean has no definition:" + beanName);
- }
- return null;
- }
-
- String scopeName = bd.getScope();
- if (scopeName == null)
- {
- // does this ever happen?
- if (log.isDebugEnabled())
- {
- log.debug("no scope associated with bean " + beanName);
- }
- return null;
- }
-
- if (log.isDebugEnabled())
- {
- log.debug("Processing scope [" + scopeName + "]");
- }
-
- Object scopeObj = appContext.getBeanFactory().getRegisteredScope(scopeName);
- if (scopeObj == null)
- {
- // Ok, this is not an orchestra-scoped bean. This happens for standard scopes
- // like Singleton.
- if (log.isDebugEnabled())
- {
- log.debug("No scope object for scope [" + scopeName + "]");
- }
- return null;
- }
- else if (scopeObj instanceof AbstractSpringOrchestraScope == false)
- {
- // ok, this is not an orchestra-scoped bean
- if (log.isDebugEnabled())
- {
- log.debug("scope associated with bean " + beanName + " is not orchestra:" + scopeObj.getClass().getName());
- }
- return null;
- }
-
- AbstractSpringOrchestraScope scopeForThisBean = (AbstractSpringOrchestraScope) scopeObj;
- Conversation conversation = scopeForThisBean.getConversationForBean(beanName);
-
- if (conversation == null)
- {
- // In general, getConversationForBean is allowed to return null. However in this case
- // that is really not expected. Calling getBean for a bean in a scope only ever calls
- // the get method on the scope object. The only way an instance can *really* be
- // created is by invoking the ObjectFactory that is passed to the scope object. And
- // the AbstractSpringOrchestraScope type only ever does that after ensuring that the
- // conversation object has been created.
- //
- // Therefore, this is theoretically impossible..
- throw new IllegalStateException("Internal error: null conversation for bean " + beanName);
- }
-
- Advice[] advices = scopeForThisBean.getAdvices();
- if ((advices == null) || (advices.length == 0))
- {
- advices = new Advice[0];
- }
-
- // wrap every Advice in an Advisor instance that returns it in all cases
- int len = advices.length + 1;
- Advisor[] advisors = new Advisor[len];
-
- // always add the standard CurrentConversationAdvice, and do it FIRST, so it runs first
- advisors[0] = new SimpleAdvisor(new CurrentConversationAdvice(conversation, beanName));
-
- for(int i=0; i<advices.length; ++i)
- {
- advisors[i+1] = new SimpleAdvisor(advices[i]);
- }
+ private static final long serialVersionUID = 1;
+ private final Log log = LogFactory.getLog(OrchestraAdvisorBeanPostProcessor.class);
+ private ConfigurableApplicationContext appContext;
+
+ /**
+ * Define a trivial Advisor object that always applies to the class passed to it.
+ * <p>
+ * Spring requires Advisor objects to be returned rather than Advices. Advisors
+ * can implement various interfaces to control which classes or methods they
+ * get applied to, but here the OrchestraAdvisorBeanPostProcessor only returns an
+ * instance of this for classes that it really *should* apply to, and the advices
+ * always apply to all methods, so there is really nothing for this Advisor to do.
+ * <p>
+ * TODO: maybe it would be nice to allow an orchestra scope object to hold Advisors
+ * as well as just Advices, so that users can configure specific code to run only
+ * for specific methods of orchestra beans.
+ * <p>
+ * NB: In Spring2.5, this class can simply implement Advisor, and it will be applied to
+ * all methods. However in Spring2.0, class DefaultAdvisorChainFactory only accepts
+ * PointcutAdvisor or IntroductionAdvisor, and silently ignores Advisor classes that
+ * are not of those types. So here for Spring2.x compatibility we need to make this
+ * class a PointcutAdvisor with a dummy pointcut that matches all methods...
+ */
+ private static class SimpleAdvisor implements PointcutAdvisor
+ {
+ private Advice advice;
+
+ public SimpleAdvisor(Advice advice)
+ {
+ this.advice = advice;
+ }
+
+ public Advice getAdvice()
+ {
+ return advice;
+ }
+
+ public boolean isPerInstance()
+ {
+ return false;
+ }
+
+ public Pointcut getPointcut()
+ {
+ return Pointcut.TRUE;
+ }
+ }
+
+ public OrchestraAdvisorBeanPostProcessor(ConfigurableApplicationContext appContext)
+ {
+ this.appContext = appContext;
+
+ // Always force CGLIB to be used to generate proxies, rather than java.lang.reflect.Proxy.
+ //
+ // Without this, the Orchestra scoped-proxy instance will not work; it requires
+ // the target to fully implement the same class it is proxying, not just the
+ // interfaces on the target class.
+ //
+ //
+ // Alas, this is not sufficient to solve all the problems. If a BeanPostProcessor runs
+ // before this processor, and it creates a CGLIB based proxy, then this class creates
+ // a new proxy that *replaces* that one by peeking into the preceding proxy to find
+ // its real target class/interfaces and its advices and merging that data with the
+ // settings here (see method Cglib2AopProxy.getProxy for details). However if an
+ // earlier BeanPostProcessor has created a java.lang.reflect.Proxy proxy instance
+ // then this merging does not occur; instead this class just tries to wrap that proxy
+ // in another cglib proxy, but that fails because java.lang.reflect.Proxy creates
+ // final (unsubclassable) classes. So in short either this BeanPostProcessor needs to
+ // be the *first* processor, or some trick is needed to force all BeanPostProcessors
+ // to use cglib. This can be done by setting a special attribute in the BeanDefinition
+ // for a bean, and AbstractSpringOrchestraScope does this.
+ //
+ // Note that forging cglib to be used for proxies is also necessary when creating a
+ // "scoped proxy" for an object. The aop:scoped-proxy class also has the same needs
+ // as the Orchestra scoped-proxy, and also forces CGLIB usage, using the same method
+ // (setting AutoProxyUtils.PRESERVE_TARGET_CLASS_ATTRIBUTE in the attributes of the
+ // BeanDefinition of the target bean).
+ setProxyTargetClass(true);
+ }
+
+ protected Object[] getAdvicesAndAdvisorsForBean(Class beanClass, String beanName,
+ TargetSource customTargetSource) throws BeansException
+ {
+ BeanDefinition bd;
+ try
+ {
+ bd = appContext.getBeanFactory().getBeanDefinition(beanName);
+ }
+ catch(NoSuchBeanDefinitionException e)
+ {
+ // odd. However it appears that there are some "special" beans that Spring
+ // creates that cause the BeanPostProcessor to be run even though they do
+ // not have a corresponding definition. The name "(inner bean)" is one of them,
+ // but there are also names of form "example.classname#xyz123" passed to here.
+ if (log.isDebugEnabled())
+ {
+ log.debug("Bean has no definition:" + beanName);
+ }
+ return null;
+ }
+
+ String scopeName = bd.getScope();
+ if (scopeName == null)
+ {
+ // does this ever happen?
+ if (log.isDebugEnabled())
+ {
+ log.debug("no scope associated with bean " + beanName);
+ }
+ return null;
+ }
+
+ if (log.isDebugEnabled())
+ {
+ log.debug("Processing scope [" + scopeName + "]");
+ }
+
+ Object scopeObj = appContext.getBeanFactory().getRegisteredScope(scopeName);
+ if (scopeObj == null)
+ {
+ // Ok, this is not an orchestra-scoped bean. This happens for standard scopes
+ // like Singleton.
+ if (log.isDebugEnabled())
+ {
+ log.debug("No scope object for scope [" + scopeName + "]");
+ }
+ return null;
+ }
+ else if (scopeObj instanceof AbstractSpringOrchestraScope == false)
+ {
+ // ok, this is not an orchestra-scoped bean
+ if (log.isDebugEnabled())
+ {
+ log.debug("scope associated with bean " + beanName + " is not orchestra:" + scopeObj.getClass().getName());
+ }
+ return null;
+ }
+
+ AbstractSpringOrchestraScope scopeForThisBean = (AbstractSpringOrchestraScope) scopeObj;
+ Conversation conversation = scopeForThisBean.getConversationForBean(beanName);
+
+ if (conversation == null)
+ {
+ // In general, getConversationForBean is allowed to return null. However in this case
+ // that is really not expected. Calling getBean for a bean in a scope only ever calls
+ // the get method on the scope object. The only way an instance can *really* be
+ // created is by invoking the ObjectFactory that is passed to the scope object. And
+ // the AbstractSpringOrchestraScope type only ever does that after ensuring that the
+ // conversation object has been created.
+ //
+ // Therefore, this is theoretically impossible..
+ throw new IllegalStateException("Internal error: null conversation for bean " + beanName);
+ }
+
+ Advice[] advices = scopeForThisBean.getAdvices();
+ if ((advices == null) || (advices.length == 0))
+ {
+ advices = new Advice[0];
+ }
+
+ // wrap every Advice in an Advisor instance that returns it in all cases
+ int len = advices.length + 1;
+ Advisor[] advisors = new Advisor[len];
+
+ // always add the standard CurrentConversationAdvice, and do it FIRST, so it runs first
+ advisors[0] = new SimpleAdvisor(new CurrentConversationAdvice(conversation, beanName));
+
+ for(int i=0; i<advices.length; ++i)
+ {
+ advisors[i+1] = new SimpleAdvisor(advices[i]);
+ }
- return advisors;
- }
+ return advisors;
+ }
}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraNamespaceHandler.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraNamespaceHandler.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraNamespaceHandler.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/OrchestraNamespaceHandler.java Thu Feb 21 12:32:37 2008
@@ -32,10 +32,10 @@
*/
public class OrchestraNamespaceHandler extends NamespaceHandlerSupport
{
- public void init()
- {
- registerBeanDefinitionDecoratorForAttribute(
- BeanDefinitionConversationNameAttrDecorator.XSD_CONVERSATION_NAME_ATTRIBUTE,
- new BeanDefinitionConversationNameAttrDecorator());
- }
+ public void init()
+ {
+ registerBeanDefinitionDecoratorForAttribute(
+ BeanDefinitionConversationNameAttrDecorator.XSD_CONVERSATION_NAME_ATTRIBUTE,
+ new BeanDefinitionConversationNameAttrDecorator());
+ }
}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextCloser.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextCloser.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextCloser.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextCloser.java Thu Feb 21 12:32:37 2008
@@ -32,24 +32,24 @@
*/
public class PersistenceContextCloser implements ConversationBindingListener
{
- private final PersistenceContext persistenceContext;
+ private final PersistenceContext persistenceContext;
- public PersistenceContextCloser(PersistenceContext persistenceContext)
- {
- this.persistenceContext = persistenceContext;
- }
+ public PersistenceContextCloser(PersistenceContext persistenceContext)
+ {
+ this.persistenceContext = persistenceContext;
+ }
- public PersistenceContext getPersistenceContext()
- {
- return persistenceContext;
- }
+ public PersistenceContext getPersistenceContext()
+ {
+ return persistenceContext;
+ }
- public void valueBound(ConversationBindingEvent event)
- {
- }
+ public void valueBound(ConversationBindingEvent event)
+ {
+ }
- public void valueUnbound(ConversationBindingEvent event)
- {
- persistenceContext.close();
- }
+ public void valueUnbound(ConversationBindingEvent event)
+ {
+ persistenceContext.close();
+ }
}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextConversationInterceptor.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextConversationInterceptor.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextConversationInterceptor.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextConversationInterceptor.java Thu Feb 21 12:32:37 2008
@@ -45,92 +45,92 @@
*/
public class PersistenceContextConversationInterceptor implements MethodInterceptor
{
- private final static String PERSISTENCE_CONTEXT_CONV_ATTRIBUTE = PersistenceContextConversationInterceptor.class.getName() + ".PERSISTENCE_CONTEXT";
- public final static String REQUEST_ATTRIBUTE = PersistenceContextConversationInterceptor.class.getName() + ".USED_PERSISTENCE_CONTEXTS";
+ private final static String PERSISTENCE_CONTEXT_CONV_ATTRIBUTE = PersistenceContextConversationInterceptor.class.getName() + ".PERSISTENCE_CONTEXT";
+ public final static String REQUEST_ATTRIBUTE = PersistenceContextConversationInterceptor.class.getName() + ".USED_PERSISTENCE_CONTEXTS";
- private PersistenceContextFactory persistenceContextFactory;
+ private PersistenceContextFactory persistenceContextFactory;
- public PersistenceContextConversationInterceptor()
- {
- }
-
- public void setPersistenceContextFactory(PersistenceContextFactory persistenceContextFactory)
- {
- this.persistenceContextFactory = persistenceContextFactory;
- }
-
- public Object invoke(MethodInvocation methodInvocation) throws Throwable
- {
- PersistenceContext persistenceContext = null;
-
- Conversation conversation = Conversation.getCurrentInstance();
- if (conversation != null)
- {
- PersistenceContextCloser persistenceContextCloser = (PersistenceContextCloser) conversation.getAttribute(PERSISTENCE_CONTEXT_CONV_ATTRIBUTE);
- if (persistenceContextCloser != null)
- {
- persistenceContext = persistenceContextCloser.getPersistenceContext();
- }
-
- if (persistenceContext == null)
- {
- persistenceContext = persistenceContextFactory.create();
-
- conversation.setAttribute(PERSISTENCE_CONTEXT_CONV_ATTRIBUTE, new PersistenceContextCloser(persistenceContext));
- }
- }
-
- if (persistenceContext != null)
- {
- // registerPersistenceContextUsage(persistenceContext);
-
- persistenceContext.bind();
- }
-
- try
- {
- return methodInvocation.proceed();
- }
- finally
- {
- if (persistenceContext != null)
- {
- persistenceContext.unbind();
- }
- }
- }
-
- /*
- protected void registerPersistenceContextUsage(PersistenceContext persistenceContext)
- {
- FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
- Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
- if (persistencesContexts == null)
- {
- persistencesContexts = new HashSet();
- fai.setRequestAttribute(REQUEST_ATTRIBUTE, persistencesContexts);
- }
- if (!persistencesContexts.contains(persistenceContext))
- {
- persistencesContexts.add(persistenceContext);
- }
- }
-
- public static void cleanupPersistence()
- {
- FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
- Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
- if (persistencesContexts == null)
- {
- return;
- }
-
- Iterator iterPersistencesContexts = persistencesContexts.iterator();
- while (iterPersistencesContexts.hasNext())
- {
- PersistenceContext persistenceContext = (PersistenceContext) iterPersistencesContexts.next();
- persistenceContext.unbind();
- }
- }
- */
+ public PersistenceContextConversationInterceptor()
+ {
+ }
+
+ public void setPersistenceContextFactory(PersistenceContextFactory persistenceContextFactory)
+ {
+ this.persistenceContextFactory = persistenceContextFactory;
+ }
+
+ public Object invoke(MethodInvocation methodInvocation) throws Throwable
+ {
+ PersistenceContext persistenceContext = null;
+
+ Conversation conversation = Conversation.getCurrentInstance();
+ if (conversation != null)
+ {
+ PersistenceContextCloser persistenceContextCloser = (PersistenceContextCloser) conversation.getAttribute(PERSISTENCE_CONTEXT_CONV_ATTRIBUTE);
+ if (persistenceContextCloser != null)
+ {
+ persistenceContext = persistenceContextCloser.getPersistenceContext();
+ }
+
+ if (persistenceContext == null)
+ {
+ persistenceContext = persistenceContextFactory.create();
+
+ conversation.setAttribute(PERSISTENCE_CONTEXT_CONV_ATTRIBUTE, new PersistenceContextCloser(persistenceContext));
+ }
+ }
+
+ if (persistenceContext != null)
+ {
+ // registerPersistenceContextUsage(persistenceContext);
+
+ persistenceContext.bind();
+ }
+
+ try
+ {
+ return methodInvocation.proceed();
+ }
+ finally
+ {
+ if (persistenceContext != null)
+ {
+ persistenceContext.unbind();
+ }
+ }
+ }
+
+ /*
+ protected void registerPersistenceContextUsage(PersistenceContext persistenceContext)
+ {
+ FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
+ Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
+ if (persistencesContexts == null)
+ {
+ persistencesContexts = new HashSet();
+ fai.setRequestAttribute(REQUEST_ATTRIBUTE, persistencesContexts);
+ }
+ if (!persistencesContexts.contains(persistenceContext))
+ {
+ persistencesContexts.add(persistenceContext);
+ }
+ }
+
+ public static void cleanupPersistence()
+ {
+ FrameworkAdapterInterface fai = FrameworkAdapter.getInstance();
+ Set persistencesContexts = (Set) fai.getRequestAttribute(REQUEST_ATTRIBUTE);
+ if (persistencesContexts == null)
+ {
+ return;
+ }
+
+ Iterator iterPersistencesContexts = persistencesContexts.iterator();
+ while (iterPersistencesContexts.hasNext())
+ {
+ PersistenceContext persistenceContext = (PersistenceContext) iterPersistencesContexts.next();
+ persistenceContext.unbind();
+ }
+ }
+ */
}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextFactory.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextFactory.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextFactory.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/PersistenceContextFactory.java Thu Feb 21 12:32:37 2008
@@ -24,5 +24,5 @@
*/
public interface PersistenceContextFactory
{
- public PersistenceContext create();
-}
\ No newline at end of file
+ public PersistenceContext create();
+}
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/ScopedBeanTargetSource.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/ScopedBeanTargetSource.java?rev=629975&r1=629974&r2=629975&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/ScopedBeanTargetSource.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/ScopedBeanTargetSource.java Thu Feb 21 12:32:37 2008
@@ -44,30 +44,30 @@
* @since 1.1
*/
public class ScopedBeanTargetSource extends AbstractBeanFactoryBasedTargetSource {
- private AbstractSpringOrchestraScope scope;
- private String conversationName;
- private String targetBeanName;
- private ObjectFactory objectFactory;
+ private AbstractSpringOrchestraScope scope;
+ private String conversationName;
+ private String targetBeanName;
+ private ObjectFactory objectFactory;
- public ScopedBeanTargetSource(
- AbstractSpringOrchestraScope scope,
- String conversationName,
- String targetBeanName,
- ObjectFactory objectFactory,
- BeanFactory beanFactory) {
+ public ScopedBeanTargetSource(
+ AbstractSpringOrchestraScope scope,
+ String conversationName,
+ String targetBeanName,
+ ObjectFactory objectFactory,
+ BeanFactory beanFactory) {
- this.scope = scope;
- this.conversationName = conversationName;
- this.targetBeanName = targetBeanName;
- this.objectFactory = objectFactory;
-
- super.setTargetBeanName(targetBeanName);
- super.setBeanFactory(beanFactory);
- }
+ this.scope = scope;
+ this.conversationName = conversationName;
+ this.targetBeanName = targetBeanName;
+ this.objectFactory = objectFactory;
+
+ super.setTargetBeanName(targetBeanName);
+ super.setBeanFactory(beanFactory);
+ }
- public Object getTarget() throws Exception {
- final Log log = LogFactory.getLog(ScopedBeanTargetSource.class);
- log.debug("getRealBean for " + targetBeanName);
- return scope.getRealBean(conversationName, targetBeanName, objectFactory);
- }
+ public Object getTarget() throws Exception {
+ final Log log = LogFactory.getLog(ScopedBeanTargetSource.class);
+ log.debug("getRealBean for " + targetBeanName);
+ return scope.getRealBean(conversationName, targetBeanName, objectFactory);
+ }
}