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;
     }
 }