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/10/07 15:49:03 UTC
svn commit: r702480 - in
/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation:
./ spring/
Author: skitching
Date: Tue Oct 7 06:49:03 2008
New Revision: 702480
URL: http://svn.apache.org/viewvc?rev=702480&view=rev
Log:
Add ability to "bind" any object to a conversation, causing the conversation to be "entered" when a method on the object is invoked.
Added:
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java (with props)
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java (with props)
Modified:
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/AbstractSpringOrchestraScope.java
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java
myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringSingleConversationScope.java
Added: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java?rev=702480&view=auto
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java (added)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java Tue Oct 7 06:49:03 2008
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.orchestra.conversation;
+
+/**
+ * An object that is able to bind beans to a specific conversation.
+ * <p>
+ * Only code that extends Orchestra to support new dependency-injection frameworks should need
+ * to implement this interface.
+ */
+public interface BeanBinder
+{
+ /**
+ * Return a proxy object that "binds" the specified instance to a specific conversation.
+ * <p>
+ * Whenever a method is executed on the returned proxy the conversation is "entered" before the method
+ * is invoked on the actual instance, as if the specified instance were a bean that was defined
+ * in the dependency-injection framework as belonging to the conversation.
+ * <p>
+ * This interface is expected to be used only via calls to Conversation.bind(Object).
+ */
+ Object bind(Object instance);
+}
Propchange: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/BeanBinder.java
------------------------------------------------------------------------------
svn:executable = *
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java?rev=702480&r1=702479&r2=702480&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/Conversation.java Tue Oct 7 06:49:03 2008
@@ -74,6 +74,11 @@
// when restarting the conversation.
private final ConversationContext conversationContext;
+ // The object that can bind arbitrary beans to this conversation so that all calls to
+ // methods on the target bean cause this conversation to become the active conversation,
+ // and for any other optional "entry actions" (Advices) to be applied.
+ private BeanBinder beanBinder;
+
// The set of managed beans that are associated with this conversation.
private Map beans = new TreeMap();
@@ -108,6 +113,17 @@
}
/**
+ * Define the (optional) beanBinder used by this instance in method bind(Object).
+ * <p>
+ * Expected to be called by code that creates instances of this type immediately
+ * after the constructor is invoked. See bind(Object) for more details.
+ */
+ public void setBeanBinder(BeanBinder beanBinder)
+ {
+ this.beanBinder = beanBinder;
+ }
+
+ /**
* Mark this conversation as having been used at the current time.
* <p>
* Conversations can have "timeouts" associated with them, so that when a user stops
@@ -496,4 +512,44 @@
this.beans = beans;
}
}
+
+ /**
+ * Return a proxy object that "binds" the specified instance to this conversation.
+ * <p>
+ * Whenever a method is executed on the proxy, this conversation is "entered" before the method
+ * is invoked on the actual instance, as if the specified instance were a bean that was defined
+ * in the dependency-injection framework as belonging to this conversation.
+ * <p>
+ * The specified bean is NOT added to the set of beans belonging to the conversation, ie its
+ * lifecycle is still independent of the conversation. The returned proxy does hold a reference
+ * to the Conversation object so it should not be stored for a long time; while a reference to
+ * it exists the memory allocated to the conversation will not be recycled even though the
+ * conversation may have been invalidated.
+ * <p>
+ * This is useful when a conversation-scoped object creates an object instance via new() or via
+ * calling some other library, and then wants all operations on that object to run within its own
+ * conversation. In particular, when a backing-bean returns a persistent object that has been loaded
+ * via a DAO class, it is often desirable for all methods on the persistent object to run within
+ * the backing-bean's persistence context, ie within the same persistence context set up which
+ * existed when the DAO class loaded the instance. For example, a JSF EL expression may retrieve
+ * a persistent object from a backing bean then navigate through its properties; walking lazy
+ * relations in this way will fail unless calls to methods of the persistent object cause the
+ * correct persistence-context to be set up.
+ * <p>
+ * This method is theoretically an optional operation; the orchestra adapter layer for some specific
+ * dependency-injection frameworks might choose not to support this, in which case an
+ * UnsupportedOperationException will be thrown. The default Orchestra-Spring integration
+ * certainly does support it.
+ *
+ * @throw {@link UnsupportedOperationException}
+ * @since 1.3
+ */
+ public Object bind(Object instance)
+ {
+ if (beanBinder == null)
+ {
+ throw new UnsupportedOperationException("No beanBinder instance");
+ }
+ return beanBinder.bind(instance);
+ }
}
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=702480&r1=702479&r2=702480&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 Oct 7 06:49:03 2008
@@ -35,6 +35,8 @@
import org.apache.myfaces.orchestra.conversation.CurrentConversationAdvice;
import org.apache.myfaces.orchestra.frameworkAdapter.FrameworkAdapter;
import org.springframework.aop.Advisor;
+import org.springframework.aop.SpringProxy;
+import org.springframework.aop.framework.ProxyFactory;
import org.springframework.aop.framework.autoproxy.AutoProxyUtils;
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.beans.BeansException;
@@ -667,4 +669,34 @@
return advisors;
}
+
+ /**
+ * Return a proxy object that "enters" the specified conversation before forwarding the
+ * method call on to the specified instance.
+ * <p>
+ * Entering the conversation means running all the Advices associated with the conversation.
+ * The specified conversation object is assumed to use this Scope object.
+ */
+ Object createProxyFor(Conversation conversation, Object instance)
+ {
+ // The currentConversationAdvice constructor requires a beanName parameter. As the
+ // instance we are wrapping here is usually not defined in the dependency-injection
+ // framework configuration at all, we have to invent a dummy name here.
+ //
+ // The beanName affects ConversationUtils methods getCurrentBean and invalidateAndRestartCurrent.
+ // Neither should ever be called by beans artificially wrapped in a proxy like this, so any old
+ // "bean name" will do. Including the class-name of the bean we wrap seems helpful here..
+ String beanName = "dummy$" + instance.getClass().getName();
+
+ ProxyFactory proxyFactory = new ProxyFactory(instance);
+ proxyFactory.setProxyTargetClass(true);
+ Advisor[] advisors = getAdvisors(conversation, beanName);
+ for(int i=0; i<advisors.length; ++i)
+ {
+ proxyFactory.addAdvisor(advisors[i]);
+ }
+
+ proxyFactory.addInterface(SpringProxy.class);
+ return proxyFactory.getProxy(instance.getClass().getClassLoader());
+ }
}
Added: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java?rev=702480&view=auto
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java (added)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java Tue Oct 7 06:49:03 2008
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.myfaces.orchestra.conversation.spring;
+
+import org.apache.myfaces.orchestra.conversation.BeanBinder;
+import org.apache.myfaces.orchestra.conversation.Conversation;
+
+/**
+ * Adapter class that forwards calls to the createProxyFor method of the specified
+ * AbstractSpringOrchestraScope instance.
+ */
+class SpringBeanBinder implements BeanBinder
+{
+ AbstractSpringOrchestraScope scope;
+ Conversation c;
+
+ public SpringBeanBinder(AbstractSpringOrchestraScope scope, Conversation c)
+ {
+ this.scope = scope;
+ this.c = c;
+ }
+
+ public Object bind(Object instance)
+ {
+ return scope.createProxyFor(c, instance);
+ }
+}
Propchange: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java
------------------------------------------------------------------------------
svn:eol-style = native
Propchange: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringBeanBinder.java
------------------------------------------------------------------------------
svn:executable = *
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java?rev=702480&r1=702479&r2=702480&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringConversationScope.java Tue Oct 7 06:49:03 2008
@@ -148,6 +148,7 @@
public Conversation createConversation(ConversationContext context, String name)
{
Conversation conversation = new Conversation(context, name, this);
+ conversation.setBeanBinder(new SpringBeanBinder(this, conversation));
// invoke child scope classes so they can add any aspects they desire.
initAspects(conversation);
Modified: myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringSingleConversationScope.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringSingleConversationScope.java?rev=702480&r1=702479&r2=702480&view=diff
==============================================================================
--- myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringSingleConversationScope.java (original)
+++ myfaces/orchestra/trunk/core/src/main/java/org/apache/myfaces/orchestra/conversation/spring/SpringSingleConversationScope.java Tue Oct 7 06:49:03 2008
@@ -45,6 +45,7 @@
public Conversation createConversation(ConversationContext context, String name)
{
Conversation conversation = new Conversation(context, name, this);
+ conversation.setBeanBinder(new SpringBeanBinder(this, conversation));
return conversation;
}
}