[jboss-cvs] JBossAS SVN: r92304 - in projects/ejb3/trunk: proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/jndiregistrar and 6 other directories.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Thu Aug 13 08:17:46 EDT 2009


Author: jaikiran
Date: 2009-08-13 08:17:45 -0400 (Thu, 13 Aug 2009)
New Revision: 92304

Added:
   projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/
   projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/unit/
   projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/unit/RemoteProxyFactoryJNDIBindingTestCase.java
Modified:
   projects/ejb3/trunk/proxy-clustered/pom.xml
   projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/jndiregistrar/JndiClusteredSessionRegistrarBase.java
   projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/objectfactory/session/SessionClusteredProxyObjectFactory.java
   projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/jndiregistrar/JndiSessionRegistrarBase.java
   projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/objectfactory/ProxyObjectFactory.java
Log:
EJBTHREE-1884 Remote proxyfactories will now be bound to the JNDI

Modified: projects/ejb3/trunk/proxy-clustered/pom.xml
===================================================================
--- projects/ejb3/trunk/proxy-clustered/pom.xml	2009-08-13 11:43:08 UTC (rev 92303)
+++ projects/ejb3/trunk/proxy-clustered/pom.xml	2009-08-13 12:17:45 UTC (rev 92304)
@@ -90,7 +90,7 @@
     <dependency>
       <groupId>org.jboss.ejb3</groupId>
       <artifactId>jboss-ejb3-proxy-impl</artifactId>
-      <version>1.0.1</version>
+      <version>1.0.4-SNAPSHOT</version>
     </dependency>
     
     <dependency>
@@ -100,6 +100,19 @@
     </dependency>
     
     <dependency>
+        <groupId>org.jboss.naming</groupId>
+        <artifactId>jnpserver</artifactId>
+        <version>5.0.0.CR1</version>
+        <scope>compile</scope>
+        <exclusions>
+            <exclusion>
+              <groupId>org.jboss</groupId>
+              <artifactId>jboss-common-core</artifactId>            
+            </exclusion>
+        </exclusions>
+    </dependency>
+    
+    <dependency>
       <groupId>org.jboss.cluster</groupId>
       <artifactId>jboss-ha-client</artifactId>
       <version>1.1.1.GA</version>

Modified: projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/jndiregistrar/JndiClusteredSessionRegistrarBase.java
===================================================================
--- projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/jndiregistrar/JndiClusteredSessionRegistrarBase.java	2009-08-13 11:43:08 UTC (rev 92303)
+++ projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/jndiregistrar/JndiClusteredSessionRegistrarBase.java	2009-08-13 12:17:45 UTC (rev 92304)
@@ -22,6 +22,8 @@
 
 package org.jboss.ejb3.proxy.clustered.jndiregistrar;
 
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
@@ -29,27 +31,36 @@
 import java.util.concurrent.atomic.AtomicInteger;
 
 import javax.naming.Context;
+import javax.naming.NamingException;
 import javax.naming.RefAddr;
 import javax.naming.Reference;
 import javax.naming.StringRefAddr;
 
 import org.jboss.aop.Advisor;
+import org.jboss.aop.advice.Interceptor;
+import org.jboss.aspects.remoting.ClusterChooserInterceptor;
+import org.jboss.aspects.remoting.ClusteredPojiProxy;
+import org.jboss.aspects.remoting.FamilyWrapper;
+import org.jboss.aspects.remoting.InvokeRemoteInterceptor;
 import org.jboss.ejb3.proxy.clustered.objectfactory.ClusteredProxyFactoryReferenceAddressTypes;
 import org.jboss.ejb3.proxy.clustered.registry.ProxyClusteringInfo;
 import org.jboss.ejb3.proxy.clustered.registry.ProxyClusteringRegistry;
 import org.jboss.ejb3.proxy.clustered.registry.ProxyClusteringRegistryListener;
+import org.jboss.ejb3.proxy.impl.factory.ProxyFactory;
 import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiReferenceBinding;
 import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiReferenceBindingSet;
 import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiSessionRegistrarBase;
 import org.jboss.ejb3.proxy.impl.objectfactory.ProxyFactoryReferenceAddressTypes;
+import org.jboss.ejb3.proxy.impl.remoting.IsLocalProxyFactoryInterceptor;
+import org.jboss.ha.client.loadbalance.LoadBalancePolicy;
 import org.jboss.ha.framework.interfaces.FamilyClusterInfo;
 import org.jboss.logging.Logger;
 import org.jboss.metadata.ejb.jboss.ClusterConfigMetaData;
+import org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData;
 import org.jboss.metadata.ejb.jboss.JBossSessionBeanMetaData;
+import org.jboss.naming.Util;
 import org.jboss.remoting.InvokerLocator;
 
-
-
 /**
  * Responsible for binding of ObjectFactories and creation/registration of 
  * associated ProxyFactories, centralizing operations common to that of all 
@@ -57,23 +68,24 @@
  * 
  * @author Brian Stansberry
  */
-public abstract class JndiClusteredSessionRegistrarBase 
-   extends JndiSessionRegistrarBase
-   implements ProxyClusteringRegistryListener
+public abstract class JndiClusteredSessionRegistrarBase extends JndiSessionRegistrarBase
+      implements
+         ProxyClusteringRegistryListener
 {
    // --------------------------------------------------------------------------------||
    // Class Members ------------------------------------------------------------------||
    // --------------------------------------------------------------------------------||
-   
+
    private static final Logger log = Logger.getLogger(JndiClusteredSessionRegistrarBase.class);
-   
+
    // --------------------------------------------------------------------------------||
    // Instance Members ---------------------------------------------------------------||
    // --------------------------------------------------------------------------------||
-   
+
    private final ProxyClusteringRegistry registry;
-   private final Map<String, BeanClusteringRegistryInfo> bindingsByContainer = new ConcurrentHashMap<String, BeanClusteringRegistryInfo>(); 
 
+   private final Map<String, BeanClusteringRegistryInfo> bindingsByContainer = new ConcurrentHashMap<String, BeanClusteringRegistryInfo>();
+
    // --------------------------------------------------------------------------------||
    // Constructor --------------------------------------------------------------------||
    // --------------------------------------------------------------------------------||
@@ -84,11 +96,10 @@
     * @param sessionProxyObjectFactoryType
     * @param registry registry of clustering information about deployed containers
     */
-   public JndiClusteredSessionRegistrarBase(String sessionProxyObjectFactoryType, 
-                                            ProxyClusteringRegistry registry)
+   public JndiClusteredSessionRegistrarBase(String sessionProxyObjectFactoryType, ProxyClusteringRegistry registry)
    {
       super(sessionProxyObjectFactoryType);
-      
+
       assert registry != null : "registry is null";
       this.registry = registry;
       this.registry.registerListener(this);
@@ -110,45 +121,90 @@
       BeanClusteringRegistryInfo registryEntry = bindingsByContainer.get(beanClusteringInfo.getContainerName());
       if (registryEntry != null)
       {
-         bindings= registryEntry.bindings;
+         bindings = registryEntry.bindings;
       }
-      
+
       if (bindings == null)
       {
          // We aren't handling this bean
          return;
       }
-      
+
       Context context = bindings.getContext();
-      
-      FamilyClusterInfo fci = beanClusteringInfo.getFamilyWrapper().get();     
+
+      FamilyClusterInfo fci = beanClusteringInfo.getFamilyWrapper().get();
       String familyName = fci.getFamilyName();
-      
+      log.debug("Cluster topology changed for family " + familyName + " new view id " + fci.getCurrentViewId()
+            + " - Updating JNDI bindings for container " + beanClusteringInfo.getContainerName());
+
       for (JndiReferenceBinding binding : bindings.getDefaultRemoteBindings())
       {
-         RefAddr refAddr = getFirstRefAddr(binding.getReference(), ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
+         RefAddr refAddr = getFirstRefAddr(binding.getReference(),
+               ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
          if (refAddr != null && familyName.equals(refAddr.getContent()))
          {
             redecorateReferenceForClusteringTargets(binding.getReference(), fci);
             rebind(context, binding.getJndiName(), binding.getReference());
          }
+
+         // The remote proxyfactory in JNDI too needs to be updated with the changes in the
+         // clustering family. This involves unbinding the remote proxyfactory from JNDI,
+         // creating a new proxy for the proxyfactory with this new FamilyCluster info
+         // and finally binding this new proxy for the proxyfactory to the JNDI
+         String proxyFactoryKey = this.getSingleRequiredRefAddr(binding.getReference(),
+               ProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_PROXY_FACTORY_REGISTRY_KEY);
+         // first create a new proxy. if we run into problems creating a new proxy,
+         // let's NOT unbind the existing one since a change in topology should not
+         // result in loss of proxy factory
+         ProxyFactory existingProxyFactoryInJNDI = null;
+         try
+         {
+            existingProxyFactoryInJNDI = (ProxyFactory) context.lookup(proxyFactoryKey);
+
+         }
+         catch (NamingException ne)
+         {
+            // ignore and skip. If there is not proxyfactory bound or if there is some other
+            // issue related to naming, let's not try to "update" the proxy factory.
+            log.debug("Could not update the cluster topology changes to proxyfactory at key " + proxyFactoryKey);
+            continue;
+         }
+         // create a new proxy to proxyfactory with the available information in JNDI Reference,
+         // the previously bound proxy to the proxyfactory and the beanClusteringInfo which has
+         // contains the updated information of the cluster topology
+         ProxyFactory updatedProxyToProxyFactory = this.updateProxyForRemoteProxyFactory(proxyFactoryKey, binding
+               .getReference(), existingProxyFactoryInJNDI, beanClusteringInfo);
+         try
+         {
+            Util.rebind(context, proxyFactoryKey, updatedProxyToProxyFactory);
+            log.debug("Bound an updated proxyfactory at key " + proxyFactoryKey);
+         }
+         catch (NamingException ne)
+         {
+            // let's just log a WARN since we don't want the other operations to fail because of this
+            log.warn("Exception while rebinding a new proxyfactory at key " + proxyFactoryKey
+                  + " with updated clustered topology", ne);
+         }
+
       }
-      
+
       for (JndiReferenceBinding binding : bindings.getHomeRemoteBindings())
       {
-         RefAddr refAddr = getFirstRefAddr(binding.getReference(), ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
+         RefAddr refAddr = getFirstRefAddr(binding.getReference(),
+               ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
          if (refAddr != null && familyName.equals(refAddr.getContent()))
          {
             redecorateReferenceForClusteringTargets(binding.getReference(), fci);
             rebind(context, binding.getJndiName(), binding.getReference());
          }
       }
-      
+
       for (Set<JndiReferenceBinding> businessBindings : bindings.getBusinessRemoteBindings().values())
-      {         
+      {
          for (JndiReferenceBinding binding : businessBindings)
          {
-            RefAddr refAddr = getFirstRefAddr(binding.getReference(), ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
+            RefAddr refAddr = getFirstRefAddr(binding.getReference(),
+                  ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME);
             if (refAddr != null && familyName.equals(refAddr.getContent()))
             {
                redecorateReferenceForClusteringTargets(binding.getReference(), fci);
@@ -156,6 +212,7 @@
             }
          }
       }
+
    }
 
    public void beanClusteringInfoAdded(ProxyClusteringInfo beanClusteringInfo)
@@ -172,7 +229,7 @@
       {
          bindingsByContainer.remove(containerName);
       }
-   }   
+   }
 
    // --------------------------------------------------------------------------------||
    // Accessors / Mutators -----------------------------------------------------------||
@@ -200,27 +257,92 @@
       }
       return key;
    }
-   
+
    /**
     * Overrides the superclass version to add clustering related {@link RefAddr}s
     * to the binding references.
     */
    @Override
-   protected JndiReferenceBindingSet createJndiReferenceBindingSet(final Context context, 
-         final JBossSessionBeanMetaData smd, final ClassLoader cl,
-         final String containerName, final String containerGuid, final Advisor advisor)
+   protected JndiReferenceBindingSet createJndiReferenceBindingSet(final Context context,
+         final JBossSessionBeanMetaData smd, final ClassLoader cl, final String containerName,
+         final String containerGuid, final Advisor advisor)
    {
-      JndiReferenceBindingSet bindings = super.createJndiReferenceBindingSet(context, smd, cl, containerName, containerGuid, advisor);
-      
+      JndiReferenceBindingSet bindings = super.createJndiReferenceBindingSet(context, smd, cl, containerName,
+            containerGuid, advisor);
+
       decorateReferencesForClustering(bindings);
-      
+
       // Store ref to bindings so we can rebind upon topology changes
-      BeanClusteringRegistryInfo registryInfo = getBeanClusteringRegistryInfo(containerName);      
+      BeanClusteringRegistryInfo registryInfo = getBeanClusteringRegistryInfo(containerName);
       registryInfo.bindings = bindings;
-      
+
       return bindings;
    }
 
+   @Override
+   protected ProxyFactory createProxyToProxyFactory(String proxyFactoryKey, String remotingUrl,
+         ProxyFactory proxyFactory, ClassLoader cl, JBossEnterpriseBeanMetaData smd)
+   {
+      InvokerLocator locator = null;
+      try
+      {
+         locator = new InvokerLocator(remotingUrl);
+      }
+      catch (MalformedURLException mue)
+      {
+         throw new RuntimeException("Unable to create a remoting proxy for ProxyFactory " + proxyFactoryKey
+               + " with remoting url " + remotingUrl, mue);
+
+      }
+
+      ProxyClusteringInfo bci = registry.getBeanClusteringInfo(proxyFactoryKey);
+
+      if (bci == null)
+      {
+         throw new IllegalStateException("Cannot find " + ProxyClusteringInfo.class.getSimpleName()
+               + " for proxyFactoryKey " + proxyFactoryKey);
+      }
+
+      String partitionName = bci.getPartitionName();
+
+      assert partitionName != null && !partitionName.trim().equals("") : " Partition name is required, but is not available in ProxyClusteringInfo";
+
+      String lbpClass = bci.getHomeLoadBalancePolicy().getName();
+
+      assert lbpClass != null && !lbpClass.trim().equals("") : LoadBalancePolicy.class.getSimpleName()
+            + " class name is required, but is not available in ProxyClusteringInfo";
+
+      LoadBalancePolicy loadBalancePolicy;
+      try
+      {
+         log.debug("Instantiating loadbalancer policy " + lbpClass + " for remote proxyfactory bound at key "
+               + proxyFactoryKey);
+         loadBalancePolicy = (LoadBalancePolicy) cl.loadClass(lbpClass).newInstance();
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException("Could not load loadbalancer policy " + lbpClass
+               + " while creating a proxy to remote proxyfactory", e);
+      }
+
+      FamilyWrapper wrapper = bci.getFamilyWrapper();
+      FamilyClusterInfo familyClusterInfo = wrapper.get();
+      log.debug("Remote proxyfactory for key " + proxyFactoryKey + " will be associated with family name "
+            + familyClusterInfo.getFamilyName() + " view id " + familyClusterInfo.getCurrentViewId()
+            + " with available targets " + familyClusterInfo.getTargets());
+
+      Class<ProxyFactory>[] interfaces = this.getAllProxyFactoryInterfaces((Class<ProxyFactory>) proxyFactory
+            .getClass());
+      Interceptor[] interceptors =
+      {IsLocalProxyFactoryInterceptor.singleton, ClusterChooserInterceptor.singleton, InvokeRemoteInterceptor.singleton};
+
+      ClusteredPojiProxy handler = new ClusteredPojiProxy(proxyFactoryKey, locator, interceptors, wrapper,
+            loadBalancePolicy, partitionName, null);
+      // register the handler
+
+      return (ProxyFactory) Proxy.newProxyInstance(interfaces[0].getClassLoader(), interfaces, handler);
+   }
+
    // --------------------------------------------------------------------------------||
    // Private ------------------------------------------------------------------------||
    // --------------------------------------------------------------------------------||
@@ -248,12 +370,12 @@
       {
          decorateReferenceForClustering(binding.getReference());
       }
-      
+
       for (JndiReferenceBinding binding : bindings.getHomeRemoteBindings())
       {
          decorateReferenceForClustering(binding.getReference());
       }
-      
+
       for (Set<JndiReferenceBinding> businessBindings : bindings.getBusinessRemoteBindings().values())
       {
          for (JndiReferenceBinding binding : businessBindings)
@@ -262,7 +384,7 @@
          }
       }
    }
-   
+
    /**
     * Add clustering related <code>RefAddr</code>s to <code>Reference</code>
     * 
@@ -270,24 +392,28 @@
     */
    private void decorateReferenceForClustering(Reference ref)
    {
-      String proxyFactoryKey = getSingleRequiredRefAddr(ref, ProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_PROXY_FACTORY_REGISTRY_KEY);
+      String proxyFactoryKey = getSingleRequiredRefAddr(ref,
+            ProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_PROXY_FACTORY_REGISTRY_KEY);
       ProxyClusteringInfo bci = registry.getBeanClusteringInfo(proxyFactoryKey);
-      
+
       if (bci == null)
       {
-         throw new IllegalStateException("Cannot find " + ProxyClusteringInfo.class.getSimpleName() + 
-                                         " for proxyFactoryKey " + proxyFactoryKey);
+         throw new IllegalStateException("Cannot find " + ProxyClusteringInfo.class.getSimpleName()
+               + " for proxyFactoryKey " + proxyFactoryKey);
       }
-      
-      RefAddr partitionRef = new StringRefAddr(ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_PARTITION_NAME, bci.getPartitionName());
+
+      RefAddr partitionRef = new StringRefAddr(
+            ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_PARTITION_NAME, bci.getPartitionName());
       addRefAddrToReference(ref, partitionRef);
-      RefAddr lbpRef = new StringRefAddr(ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_PROXY_FACTORY_LOAD_BALANCE_POLICY, bci.getHomeLoadBalancePolicy().getName());
+      RefAddr lbpRef = new StringRefAddr(
+            ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_PROXY_FACTORY_LOAD_BALANCE_POLICY, bci
+                  .getHomeLoadBalancePolicy().getName());
       addRefAddrToReference(ref, lbpRef);
       FamilyClusterInfo fci = bci.getFamilyWrapper().get();
-      RefAddr familyNameRef = new StringRefAddr(ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME, 
-                                                fci.getFamilyName());
+      RefAddr familyNameRef = new StringRefAddr(
+            ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_FAMILY_NAME, fci.getFamilyName());
       addRefAddrToReference(ref, familyNameRef);
-      
+
       decorateReferenceForClusteringTargets(ref, fci);
    }
 
@@ -304,7 +430,8 @@
       for (int i = 0; i < ref.size(); i++)
       {
          RefAddr refAddr = ref.get(i);
-         if (ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_TARGET_INVOKER_LOCATOR_URL.equals(refAddr.getType()))
+         if (ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_TARGET_INVOKER_LOCATOR_URL.equals(refAddr
+               .getType()))
          {
             ref.remove(i);
             i--;
@@ -312,7 +439,7 @@
       }
       decorateReferenceForClusteringTargets(ref, fci);
    }
-   
+
    /**
     * Adds a <code>RefAddr</code> of type {@link ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_TARGET_INVOKER_LOCATOR_URL}
     * to <code>ref</code> for each target associated with <code>fci</code>.
@@ -332,18 +459,18 @@
          assert correctType : target + " is not an instance of InvokerLocator";
          if (!correctType)
             throw new IllegalStateException(target + " is not an instance of InvokerLocator");
-         
+
          String url = ((InvokerLocator) target).getOriginalURI();
-         RefAddr targetRef = new StringRefAddr(ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_TARGET_INVOKER_LOCATOR_URL, url);
+         RefAddr targetRef = new StringRefAddr(
+               ClusteredProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_CLUSTER_TARGET_INVOKER_LOCATOR_URL, url);
          addRefAddrToReference(ref, targetRef);
       }
    }
-   
+
    private void addRefAddrToReference(Reference ref, RefAddr refAddr)
    {
-      log.debug("Adding " + RefAddr.class.getSimpleName() + " to "
-            + Reference.class.getSimpleName() + ": Type \"" + refAddr.getType() + "\", Content \""
-            + refAddr.getContent() + "\"");
+      log.debug("Adding " + RefAddr.class.getSimpleName() + " to " + Reference.class.getSimpleName() + ": Type \""
+            + refAddr.getType() + "\", Content \"" + refAddr.getContent() + "\"");
       ref.add(refAddr);
    }
 
@@ -365,12 +492,12 @@
             }
          }
       }
-      
+
       if (result == null)
       {
          throw new IllegalStateException(ref + " has no RefAddr object of type " + refAddrType);
       }
-      
+
       return (String) result.getContent();
    }
 
@@ -386,11 +513,96 @@
       }
       return null;
    }
-   
+
    private static class BeanClusteringRegistryInfo
    {
       private final AtomicInteger familyCount = new AtomicInteger();
+
       private JndiReferenceBindingSet bindings;
-   }   
+   }
 
+   /**
+    * Utility method to create an updated proxy for the remote proxyfactory.
+    * <br>
+    * Note that this method is expected to be used at runtime (i.e. when the EJB container bindings are
+    * available in JNDI)  for recreation of an existing proxy to the proxyfactory. This method must 
+    * not be used during deployment (when the JNDI bindings are not yet available). For deployment time
+    * creation of proxy for the proxyFactory is handled by the other method 
+    * {@link JndiClusteredSessionRegistrarBase#createProxyToProxyFactory(String, String, ProxyFactory, ClassLoader, JBossEnterpriseBeanMetaData)}
+    * 
+    * <p>
+    *   Also see {@link JndiClusteredSessionRegistrarBase#clusterTopologyChanged(ProxyClusteringInfo)} method
+    *   where this is used. Internally this method uses a combination of information available in JNDI and also
+    *   the latest clustering topology (that is available in the passed <code>clusteringInfo</code> parameter),
+    *   to (re)create an updated proxy for the proxyfactory.
+    * </p>
+    *   
+    * @param proxyFactoryKey
+    * @param reference
+    * @param proxyFactory
+    * @param clusteringInfo
+    * @return
+    */
+   private ProxyFactory updateProxyForRemoteProxyFactory(String proxyFactoryKey, Reference reference,
+         ProxyFactory proxyFactory, ProxyClusteringInfo clusteringInfo)
+   {
+      // Obtain the URL for invoking upon the Registry
+      String url = this.getSingleRequiredRefAddr(reference,
+            ProxyFactoryReferenceAddressTypes.REF_ADDR_TYPE_INVOKER_LOCATOR_URL);
+
+      // Create an InvokerLocator
+      assert url != null && !url.trim().equals("") : InvokerLocator.class.getSimpleName()
+            + " URL is required, but is not specified; improperly bound reference in JNDI";
+      InvokerLocator locator;
+      try
+      {
+         locator = new InvokerLocator(url);
+      }
+      catch (MalformedURLException mue)
+      {
+         throw new RuntimeException("Unable to create a remoting proxy for ProxyFactory " + proxyFactoryKey
+               + " with remoting url " + url, mue);
+      }
+
+      // get the partition name
+      String partitionName = clusteringInfo.getPartitionName();
+
+      assert partitionName != null && !partitionName.trim().equals("") : " Partition name is required, but was not available in ProxyClusteringInfo "
+            + clusteringInfo;
+
+      // load balancer policy - Note we are creating a proxyfactory so we use the *home* loadbalance policy
+      // and not the loadbalance policy
+      Class<? extends LoadBalancePolicy> lbpClass = clusteringInfo.getHomeLoadBalancePolicy();
+
+      assert lbpClass != null : " LoadBalancePolicy is required, but is not available in the ProxyClusteringInfo "
+            + clusteringInfo;
+
+      LoadBalancePolicy loadBalancePolicyInstance = null;
+
+      try
+      {
+         // create a loadbalancer policy instance using the classloader associated with the
+         // previous proxy
+         loadBalancePolicyInstance = lbpClass.newInstance();
+      }
+      catch (Exception e)
+      {
+         throw new RuntimeException("Could not create loadbalancer policy instance for " + lbpClass
+               + " while creating a proxy to remote proxyfactory", e);
+      }
+      // family wrapper (which contains the latest information of the cluster topology)
+      FamilyWrapper wrapper = clusteringInfo.getFamilyWrapper();
+      // the interfaces to be exposed by the proxy for the proxyfactory
+      Class<?>[] interfaces = this.getAllProxyFactoryInterfaces((Class<ProxyFactory>) proxyFactory.getClass());
+      // interceptors to the proxy
+      Interceptor[] interceptors =
+      {IsLocalProxyFactoryInterceptor.singleton, ClusterChooserInterceptor.singleton, InvokeRemoteInterceptor.singleton};
+      // an invocation handler which internally will apply the interceptors and do other magic :)
+      ClusteredPojiProxy handler = new ClusteredPojiProxy(proxyFactoryKey, locator, interceptors, wrapper,
+            loadBalancePolicyInstance, partitionName, null);
+
+      // finally the proxy for the proxyfactory
+      return (ProxyFactory) Proxy.newProxyInstance(interfaces[0].getClassLoader(), interfaces, handler);
+   }
+
 }

Modified: projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/objectfactory/session/SessionClusteredProxyObjectFactory.java
===================================================================
--- projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/objectfactory/session/SessionClusteredProxyObjectFactory.java	2009-08-13 11:43:08 UTC (rev 92303)
+++ projects/ejb3/trunk/proxy-clustered/src/main/java/org/jboss/ejb3/proxy/clustered/objectfactory/session/SessionClusteredProxyObjectFactory.java	2009-08-13 12:17:45 UTC (rev 92304)
@@ -37,7 +37,9 @@
 import org.jboss.aspects.remoting.InvokeRemoteInterceptor;
 import org.jboss.ejb3.proxy.clustered.objectfactory.ClusteredProxyFactoryReferenceAddressTypes;
 import org.jboss.ejb3.proxy.impl.factory.ProxyFactory;
+import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiSessionRegistrarBase;
 import org.jboss.ejb3.proxy.impl.objectfactory.ProxyFactoryReferenceAddressTypes;
+import org.jboss.ejb3.proxy.impl.objectfactory.ProxyObjectFactory;
 import org.jboss.ejb3.proxy.impl.objectfactory.session.SessionProxyObjectFactory;
 import org.jboss.ejb3.proxy.impl.remoting.IsLocalProxyFactoryInterceptor;
 import org.jboss.ha.client.loadbalance.LoadBalancePolicy;
@@ -91,8 +93,18 @@
     * Here we replace the superclass implementation to create a cluster aware
     * proxy that will load balance requests to the server-side proxy factory.
     * 
+    * Deprecated since https://jira.jboss.org/jira/browse/EJBTHREE-1884 - The
+    * {@link ProxyObjectFactory} is no longer responsible for creating a proxy
+    * to the {@link ProxyFactory}. Instead the {@link ProxyObjectFactory} will
+    * lookup in the JNDI for the {@link ProxyFactory} using the
+    * <code>proxyFactoryRegistryKey</code>. The responsibility of
+    * binding the proxyfactory to jndi will rest with the {@link JndiSessionRegistrarBase}
+    * 
+    * @see The new {@link #getProxyFactoryFromJNDI(String, javax.naming.Context, java.util.Hashtable) 
+    *  
     * {@inheritDoc}
     */
+   @Deprecated
    @Override
    protected ProxyFactory createProxyFactoryProxy(Name name, Map<String, List<String>> refAddrs,
          String proxyFactoryRegistryKey) throws Exception

Modified: projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/jndiregistrar/JndiSessionRegistrarBase.java
===================================================================
--- projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/jndiregistrar/JndiSessionRegistrarBase.java	2009-08-13 11:43:08 UTC (rev 92303)
+++ projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/jndiregistrar/JndiSessionRegistrarBase.java	2009-08-13 12:17:45 UTC (rev 92304)
@@ -21,8 +21,12 @@
  */
 package org.jboss.ejb3.proxy.impl.jndiregistrar;
 
+import java.lang.reflect.Proxy;
+import java.net.MalformedURLException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -36,12 +40,16 @@
 
 import org.jboss.aop.Advisor;
 import org.jboss.aop.Dispatcher;
+import org.jboss.aop.advice.Interceptor;
+import org.jboss.aspects.remoting.InvokeRemoteInterceptor;
+import org.jboss.aspects.remoting.PojiProxy;
 import org.jboss.ejb3.common.registrar.spi.DuplicateBindException;
 import org.jboss.ejb3.common.registrar.spi.Ejb3RegistrarLocator;
 import org.jboss.ejb3.common.registrar.spi.NotBoundException;
 import org.jboss.ejb3.common.string.StringUtils;
 import org.jboss.ejb3.proxy.impl.factory.ProxyFactory;
 import org.jboss.ejb3.proxy.impl.objectfactory.ProxyFactoryReferenceAddressTypes;
+import org.jboss.ejb3.proxy.impl.remoting.IsLocalProxyFactoryInterceptor;
 import org.jboss.ejb3.proxy.impl.remoting.ProxyRemotingUtils;
 import org.jboss.logging.Logger;
 import org.jboss.metadata.ejb.jboss.JBossEnterpriseBeanMetaData;
@@ -56,9 +64,9 @@
 
 /**
  * JndiSessionRegistrarBase
- * 
+ *
  * Responsible for binding of ObjectFactories and
- * creation/registration of associated ProxyFactories, 
+ * creation/registration of associated ProxyFactories,
  * centralizing operations common to that of all Session
  * EJB Implementations
  *
@@ -96,8 +104,8 @@
    /**
     * Creates a JNDI Registrar from the specified configuration properties, none of
     * which may be null.
-    * 
-    * @param sessionProxyObjectFactoryType String representation of the JNDI Object 
+    *
+    * @param sessionProxyObjectFactoryType String representation of the JNDI Object
     *           Factory Class Name (fully-qualified) to use for this Session EJB
     */
    public JndiSessionRegistrarBase(final String sessionProxyObjectFactoryType)
@@ -130,11 +138,11 @@
    // --------------------------------------------------------------------------------||
 
    /**
-    * Binds into JNDI all appropriate objects required 
+    * Binds into JNDI all appropriate objects required
     * by the EJB described by the specified metadata.  Additionally
     * responsible for creation and registration of any all ProxyFactory
     * implementations required by the EJB
-    * 
+    *
     * @param context The JNDI Context to use for binding
     * @param smd the Container's metadata
     * @param cl The CL of the Container
@@ -154,7 +162,7 @@
    /**
     * Creates all of the <code>Reference</code> objects that should be bound
     * in JNDI for the EJB, and determines the correct JNDI name for each.
-    * Additionally responsible for creation and registration of any all 
+    * Additionally responsible for creation and registration of any all
     * ProxyFactory implementations required by the EJB.
     *
     * @param smd the Container's metadata
@@ -162,14 +170,14 @@
     * @param containerName The name under which the target container is registered
     * @param containerGuid The globally-unique name of the container
     * @param advisor The advisor to use for generated proxies
-    * 
+    *
     * @return data object encapsulating the references and their JNDI names
     */
    protected JndiReferenceBindingSet createJndiReferenceBindingSet(final Context context,
          final JBossSessionBeanMetaData smd, final ClassLoader cl, final String containerName,
          final String containerGuid, final Advisor advisor)
    {
-      // Log 
+      // Log
       String ejbName = smd.getEjbName();
       log.debug("Found Session Bean: " + ejbName);
 
@@ -252,6 +260,8 @@
          Reference defaultRemoteRef = createStandardReference(JndiSessionRegistrarBase.OBJECT_FACTORY_CLASSNAME_PREFIX
                + defaultRemoteClassName, defaultRemoteProxyFactoryKey, containerName, false);
 
+         // Also bind remote proxy factory to jndi
+         this.bindRemoteProxyFactory(context, defaultRemoteProxyFactoryKey, defaultClientBindUrl, factory, cl, smd);
          /*
           * Set up references for Home
           */
@@ -288,7 +298,7 @@
          }
 
          /*
-          * If no @RemoteBindings are defined, make a default remote binding 
+          * If no @RemoteBindings are defined, make a default remote binding
           */
 
          // Get RemoteBindings
@@ -327,7 +337,7 @@
          }
 
          /*
-          * If there are @RemoteBindings and a remote view 
+          * If there are @RemoteBindings and a remote view
           */
 
          // Remote Bindings are defined, create a binding for each
@@ -432,6 +442,13 @@
                      JndiSessionRegistrarBase.OBJECT_FACTORY_CLASSNAME_PREFIX + defaultRemoteClassName,
                      remoteBindingProxyFactoryKey, containerName, false);
 
+               // Also bind the remote proxy factory to jndi (after unbinding any existing instances)
+               if (reregister)
+               {
+                  unbind(context, remoteBindingProxyFactoryKey);
+               }
+               this.bindRemoteProxyFactory(context, remoteBindingProxyFactoryKey, clientBindUrl, remoteBindingProxyFactory, cl, smd);
+
                // Add a Reference Address for the Remoting URL
                log.debug("Adding " + RefAddr.class.getSimpleName() + " to @RemoteBinding "
                      + Reference.class.getSimpleName() + ": Type \"" + remoteBindingRemotingRefAddr.getType()
@@ -585,17 +602,17 @@
    }
 
    /**
-    * Unbinds from JNDI all appropriate objects registered 
+    * Unbinds from JNDI all appropriate objects registered
     * by the EJB described by the specified metadata.  Additionally
     * responsible for destruction and deregistration of any all ProxyFactory
     * implementations required by the EJB
-    * 
+    *
     * @param context The JNDI Context to use for unbinding
     * @param smd
     */
    public void unbindEjb(final Context context, final JBossSessionBeanMetaData smd)
    {
-      // Log 
+      // Log
       String ejbName = smd.getEjbName();
       log.debug("Unbinding JNDI References for Session Bean: " + ejbName);
 
@@ -635,6 +652,8 @@
          // Find and deregister a remote proxy factory
          String remoteProxyFactoryKey = this.getProxyFactoryRegistryKey(defaultRemoteJndiName, smd, false);
          this.deregisterProxyFactory(remoteProxyFactoryKey);
+         // also remove the remote proxy factory from jndi
+         this.unbind(context, remoteProxyFactoryKey);
 
          // Determine if remote home and business remotes are bound to same JNDI Address
          boolean bindRemoteAndHomeTogether = this.isHomeAndBusinessBoundTogether(smd, false);
@@ -671,6 +690,8 @@
                   String remoteBindingProxyFactoryKey = this.getProxyFactoryRegistryKey(remoteBindingJndiName, smd,
                         false);
                   this.deregisterProxyFactory(remoteBindingProxyFactoryKey);
+                  // also remove the remote proxy factory from jndi
+                  this.unbind(context, remoteBindingProxyFactoryKey);
                }
             }
          }
@@ -739,9 +760,9 @@
 
    /**
     * Creates and returns a new local proxy factory for this Session Bean
-    * 
+    *
     * @param name The unique name for the ProxyFactory
-    * @param containerName The name of the Container upon which Proxies 
+    * @param containerName The name of the Container upon which Proxies
     *   from the returned ProxyFactory will invoke
     * @param containerGuid The globally-unique name of the container
     * @param smd The metadata representing this Session EJB
@@ -753,9 +774,9 @@
 
    /**
     * Creates and returns a new remote proxy factory for this Session Bean
-    * 
+    *
     * @param name The unique name for the ProxyFactory
-    * @param containerName The name of the Container upon which Proxies 
+    * @param containerName The name of the Container upon which Proxies
     *   from the returned ProxyFactory will invoke
     * @param containerGuid The globally-unique name of the container
     * @param smd The metadata representing this Session EJB
@@ -775,8 +796,8 @@
 
    /**
     * Creates a new <code>Reference</code> whose <code>classname</code> is
-    * the given <code>referenceName</code> and whose <code>classFactory</code> 
-    * is {@link #getSessionProxyObjectFactoryType()}, adding 
+    * the given <code>referenceName</code> and whose <code>classFactory</code>
+    * is {@link #getSessionProxyObjectFactoryType()}, adding
     * the requisite Registry key for the ProxyFactory and the requisite
     * target EJB Container Name as ReferenceAddresses.
     */
@@ -898,7 +919,7 @@
 
    /**
     * Binds the specified Reference into JNDI at the specified address
-    * 
+    *
     * @param context The JNDI Context to use
     * @param address the address
     * @param ref the reference to bind
@@ -918,7 +939,7 @@
 
    /**
     * Re-binds the specified Reference into JNDI at the specified address
-    * 
+    *
     * @param context The JNDI Context to use
     * @param address the address
     * @param object the object to bind
@@ -938,7 +959,7 @@
 
    /**
     * Unbinds the specified address from JNDI
-    * 
+    *
     * @param context The JNDI Context to use
     * @param address
     */
@@ -960,9 +981,9 @@
    }
 
    /**
-    * Returns whether the business interfaces and EJB2.x Home should be bound to 
-    * the same JNDI Name 
-    * 
+    * Returns whether the business interfaces and EJB2.x Home should be bound to
+    * the same JNDI Name
+    *
     * @param smd
     * @param isLocal
     * @return
@@ -1022,8 +1043,8 @@
    /**
     * Creates and returns a new RefAddr to flag the proper
     * InvokerLocator URL used by remoting for the EJB represented
-    * by the specified metadata 
-    * 
+    * by the specified metadata
+    *
     * @param clientBindUrl
     * @return
     */
@@ -1040,11 +1061,11 @@
    }
 
    /**
-    * Returns the name of the unique key under which a Proxy Factory will 
+    * Returns the name of the unique key under which a Proxy Factory will
     * be registered.  Will follow form:
-    * 
+    *
     * ProxyFactory/{ejbName}/{jndiName}
-    * 
+    *
     * @param jndiName
     * @param smd
     * @param isLocal
@@ -1077,10 +1098,10 @@
    }
 
    /**
-    * Makes a comma-delimited list of interfaces bound for setting the 
-    * Classname of the Reference.  This will show up in JNDIView and make 
+    * Makes a comma-delimited list of interfaces bound for setting the
+    * Classname of the Reference.  This will show up in JNDIView and make
     * it clear to application developers what will be castable from the lookup result
-    * 
+    *
     * @param refAddrs
     * @return
     */
@@ -1110,8 +1131,8 @@
    }
 
    /**
-    * Returns whether the specified RefAddr type denotes an EJB Interface 
-    * 
+    * Returns whether the specified RefAddr type denotes an EJB Interface
+    *
     * @param refAddrType
     * @return
     */
@@ -1124,8 +1145,8 @@
    }
 
    /**
-    * Registers the specified proxy factory into the registry 
-    * 
+    * Registers the specified proxy factory into the registry
+    *
     * @param name The unique name for the ProxyFactory
     * @param factory
     * @param smd Metadata describing the EJB
@@ -1143,8 +1164,8 @@
       {
          /*
           * Note on registry key collisions:
-          * 
-          * Indicates that either the keys created are not unique or that we're attempting to redeploy 
+          *
+          * Indicates that either the keys created are not unique or that we're attempting to redeploy
           * an EJB that was not properly deregistered.  Either way, this is a programmatic problem
           * and not the fault of the bean provider/developer/deployer
           */
@@ -1154,9 +1175,111 @@
       }
    }
 
-   /** 
+   /**
+    * The remote proxy factory will be bound to the jndi at the key <code>proxyFactoryKey</code>.
+    *
+    * Internally this method creates a Remoting proxy for the remote proxyfactory, fronted by
+    * the {@link IsLocalProxyFactoryInterceptor} and the {@link InvokeRemoteInterceptor} interceptors
+    *
+    * @param context
+    * @param proxyFactoryKey
+    * @param remotingUrl
+    * @param proxyFactory
+    * @param cl
+    * @param smd
+    */
+   protected void bindRemoteProxyFactory(Context context, String proxyFactoryKey, String remotingUrl,
+         ProxyFactory proxyFactory, ClassLoader cl, JBossEnterpriseBeanMetaData smd)
+   {
+
+      ProxyFactory proxyToProxyFactory = this.createProxyToProxyFactory(proxyFactoryKey, remotingUrl, proxyFactory, cl, smd);
+      // now bind
+      try
+      {
+         log.debug("Binding remote ProxyFactory to JNDI, at key " + proxyFactoryKey);
+         Util.bind(context, proxyFactoryKey, proxyToProxyFactory);
+      }
+      catch (NamingException ne)
+      {
+         throw new RuntimeException("Could not bind remote proxy factory to JNDI, at key " + proxyFactoryKey, ne);
+      }
+
+   }
+
+   /**
+    * Creates a remoting {@link PojiProxy} for the proxy factory and fronts it with
+    * the {@link IsLocalProxyFactoryInterceptor} and {@link InvokeRemoteInterceptor} interceptors
+    *
+    * @param proxyFactoryKey
+    * @param remotingUrl
+    * @param proxyFactory
+    * @param cl
+    * @param smd
+    * 
+    * @return
+    */
+   protected ProxyFactory createProxyToProxyFactory(String proxyFactoryKey, String remotingUrl,
+         ProxyFactory proxyFactory, ClassLoader cl, JBossEnterpriseBeanMetaData smd)
+   {
+      try
+      {
+         InvokerLocator locator = new InvokerLocator(remotingUrl);
+         // Create a POJI Proxy to the Registrar
+         Interceptor[] interceptors =
+         {IsLocalProxyFactoryInterceptor.singleton, InvokeRemoteInterceptor.singleton};
+         PojiProxy handler = new PojiProxy(proxyFactoryKey, locator, interceptors);
+         // The proxy should me marked as implementing interface(s) of type ProxyFactory
+         // and the other sub-interfaces of ProxyFactory (whichever applicable for this specific
+         // proxyfactory). We need the specific sub-interfaces to ensure that the ObjectFactories
+         // can invoke the APIs on the sub-interfaces
+         Class<ProxyFactory>[] proxyFactoryInterfaces = this.getAllProxyFactoryInterfaces((Class<ProxyFactory>)proxyFactory.getClass());
+
+         return (ProxyFactory) Proxy.newProxyInstance(proxyFactoryInterfaces[0].getClassLoader(), proxyFactoryInterfaces, handler);
+      }
+      catch (MalformedURLException mue)
+      {
+         throw new RuntimeException("Unable to create a remoting proxy for ProxyFactory " + proxyFactoryKey
+               + " with remoting url " + remotingUrl, mue);
+
+      }
+   }
+
+   /**
+    * Returns all the interfaces of type {@link ProxyFactory} that are implemented
+    * by the proxyFactory klass
+    *
+    * @param klass
+    * @return
+    */
+   protected Class<ProxyFactory>[] getAllProxyFactoryInterfaces(Class<ProxyFactory> klass)
+   {
+      Set<Class<ProxyFactory>> proxyFactoryInterfaces = new HashSet<Class<ProxyFactory>>();
+
+      // See if super class implements and ProxyFactory interface(s)
+      if (klass.getSuperclass() != null && ProxyFactory.class.isAssignableFrom(klass.getSuperclass()))
+      {
+         Class<ProxyFactory>[] intfs = getAllProxyFactoryInterfaces((Class<ProxyFactory>)(klass.getSuperclass()));
+         proxyFactoryInterfaces.addAll(Arrays.asList(intfs));
+
+      }
+      // Iterate through the directly implemented interfaces and
+      // check whether any ProxyFactory interface is being implemented
+      Class<?>[] allInterfaces = klass.getInterfaces();
+      for (Class<?> intf : allInterfaces)
+      {
+         if (ProxyFactory.class.isAssignableFrom(intf))
+         {
+            proxyFactoryInterfaces.add((Class<ProxyFactory>)intf);
+         }
+      }
+      return (Class<ProxyFactory>[]) proxyFactoryInterfaces.toArray(new Class<?>[proxyFactoryInterfaces.size()]);
+   }
+
+
+
+   /**
     * Deregisters the proxy factory with the specified name from the registry
-    * 
+    *
     * @param name
     */
    protected void deregisterProxyFactory(String name)
@@ -1178,7 +1301,7 @@
       // Deregister with AOP if registered
       //TODO This should probably be in a cleaner location, ie.
       // implement a callback for AOP Registration/Deregistration
-      // that decouples JNDI Registration and abstracts whether 
+      // that decouples JNDI Registration and abstracts whether
       // a Proxy Factory is Remote or not
       if (Dispatcher.singleton.isRegistered(name))
       {

Modified: projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/objectfactory/ProxyObjectFactory.java
===================================================================
--- projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/objectfactory/ProxyObjectFactory.java	2009-08-13 11:43:08 UTC (rev 92303)
+++ projects/ejb3/trunk/proxy-impl/src/main/java/org/jboss/ejb3/proxy/impl/objectfactory/ProxyObjectFactory.java	2009-08-13 12:17:45 UTC (rev 92304)
@@ -35,6 +35,8 @@
 
 import javax.naming.Context;
 import javax.naming.Name;
+import javax.naming.NameNotFoundException;
+import javax.naming.NamingException;
 import javax.naming.RefAddr;
 import javax.naming.Reference;
 import javax.naming.spi.ObjectFactory;
@@ -46,6 +48,7 @@
 import org.jboss.ejb3.common.registrar.spi.Ejb3RegistrarLocator;
 import org.jboss.ejb3.common.registrar.spi.NotBoundException;
 import org.jboss.ejb3.proxy.impl.factory.ProxyFactory;
+import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiSessionRegistrarBase;
 import org.jboss.ejb3.proxy.impl.remoting.IsLocalProxyFactoryInterceptor;
 import org.jboss.logging.Logger;
 import org.jboss.remoting.InvokerLocator;
@@ -53,14 +56,12 @@
 /**
  * ProxyObjectFactory
  *
- * Base upon which Proxy Object Factories may build.  Defines 
- * abstractions to:
- * 
+ * Base upon which Proxy Object Factories may build. Defines abstractions to:
+ *
  * <ul>
- *  <li>Obtain a proxy based on metadata received 
- *  from Reference Address information associated with the bound 
- *  Reference</li> 
- *  <li>Use a pluggable ProxyFactoryRegistry</li>
+ * <li>Obtain a proxy based on metadata received from Reference Address
+ * information associated with the bound Reference</li>
+ * <li>Use a pluggable ProxyFactoryRegistry</li>
  * </ul>
  *
  * @author <a href="mailto:andrew.rubinger at jboss.org">ALR</a>
@@ -73,7 +74,7 @@
    // --------------------------------------------------------------------------------||
 
    private static final long serialVersionUID = 1L;
-   
+
    /**
     * Logger
     */
@@ -85,11 +86,11 @@
 
    /**
     * Returns an appropriate Proxy based on the Reference Address information
-    * associated with the Reference (obj) bound at name in the specified nameCtx with 
-    * specified environment.
-    * 
-    * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object, 
-    *       javax.naming.Name, javax.naming.Context, java.util.Hashtable)
+    * associated with the Reference (obj) bound at name in the specified nameCtx
+    * with specified environment.
+    *
+    * @see javax.naming.spi.ObjectFactory#getObjectInstance(java.lang.Object,
+    *      javax.naming.Name, javax.naming.Context, java.util.Hashtable)
     */
    public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment)
          throws Exception
@@ -131,7 +132,7 @@
       {
          try
          {
-            // Get local EJB3 Registrar 
+            // Get local EJB3 Registrar
             Ejb3Registrar registrar = Ejb3RegistrarLocator.locateRegistrar();
 
             Object pfObj = registrar.lookup(proxyFactoryRegistryKey);
@@ -145,13 +146,13 @@
          // in an inner try/catch; let it propagate to the outer catch.
          catch (NotBoundException nbe)
          {
-            proxyFactory = createProxyFactoryProxy(name, refAddrs, proxyFactoryRegistryKey);
+            proxyFactory = this.getProxyFactoryFromJNDI(proxyFactoryRegistryKey, nameCtx, environment);
          }
       }
       // Registrar is not local, so use Remoting to Obtain Proxy Factory
       else
       {
-         proxyFactory = createProxyFactoryProxy(name, refAddrs, proxyFactoryRegistryKey);
+         proxyFactory = this.getProxyFactoryFromJNDI(proxyFactoryRegistryKey, nameCtx, environment);
       }
 
       // Get the proxy returned from the ProxyFactory
@@ -164,13 +165,23 @@
 
    /**
     * Creates a remoting proxy to the proxy factory.
-    * 
+    *
+    * Deprecated since https://jira.jboss.org/jira/browse/EJBTHREE-1884 - The
+    * {@link ProxyObjectFactory} is no longer responsible for creating a proxy
+    * to the {@link ProxyFactory}. Instead the {@link ProxyObjectFactory} will
+    * lookup in the JNDI for the {@link ProxyFactory} using the
+    * <code>proxyFactoryRegistryKey</code>. The responsibility of
+    * binding the proxyfactory to jndi will rest with the {@link JndiSessionRegistrarBase}
+    * and it's sub-implementations.
+    *
     * @param name
     * @param refAddrs
     * @param proxyFactoryRegistryKey
     * @return
     * @throws Exception
+    *
     */
+   @Deprecated
    protected ProxyFactory createProxyFactoryProxy(Name name, Map<String, List<String>> refAddrs,
          String proxyFactoryRegistryKey) throws Exception
    {
@@ -200,10 +211,44 @@
    }
 
    /**
-    * Obtains the single value of the specified type as obtained from the specified reference 
-    * addresses bound at the specified Name.  Asserts that the value exists and is the only one
-    * for the specified type. 
-    * 
+    * Returns the {@link ProxyFactory} from the JNDI.
+    *
+    * @param proxyFactoryKey
+    *           The key to {@link ProxyFactory} in the JNDI
+    * @param context
+    *           The JNDI context
+    * @param environment
+    *           JNDI environment
+    * @return
+    */
+   protected ProxyFactory getProxyFactoryFromJNDI(String proxyFactoryKey, Context context, Hashtable<?, ?> environment)
+   {
+      try
+      {
+         Object factory = context.lookup(proxyFactoryKey);
+
+         assert factory instanceof ProxyFactory : "Unexpected object of type " + factory.getClass()
+               + " in JNDI, at key " + proxyFactoryKey + " Expected type " + ProxyFactory.class;
+
+         return (ProxyFactory) factory;
+      }
+      catch (NameNotFoundException nnfe)
+      {
+         throw new RuntimeException("Could not find proxyfactory in JNDI at " + proxyFactoryKey
+               + " -looking up local Proxy from Remote JVM?");
+      }
+      catch (NamingException e)
+      {
+         throw new RuntimeException("Exception while trying to locate proxy factory in JNDI, at key " + proxyFactoryKey);
+      }
+
+   }
+
+   /**
+    * Obtains the single value of the specified type as obtained from the
+    * specified reference addresses bound at the specified Name. Asserts that
+    * the value exists and is the only one for the specified type.
+    *
     * @param name
     * @param referenceAddresses
     * @param refAddrType
@@ -222,10 +267,10 @@
    }
 
    /**
-    * Obtains the single value of the specified type as obtained from the specified reference 
-    * addresses bound at the specified Name.  Asserts that the value exists and is the only one
-    * for the specified type. 
-    * 
+    * Obtains the single value of the specified type as obtained from the
+    * specified reference addresses bound at the specified Name. Asserts that
+    * the value exists and is the only one for the specified type.
+    *
     * @param name
     * @param referenceAddresses
     * @param refAddrType
@@ -250,9 +295,9 @@
 
    /**
     * Looks to the metadata specified by the reference addresses to determine if
-    * an EJB3 Business View is defined here.  Additionally checks that both local 
+    * an EJB3 Business View is defined here. Additionally checks that both local
     * and remote business interfaces are not bound to the same JNDI Address
-    * 
+    *
     * @param name
     * @param referenceAddresses
     * @return
@@ -275,7 +320,7 @@
          throw new RuntimeException(errorMessage);
       }
 
-      // Set 
+      // Set
       hasBusiness = hasLocalBusiness || hasRemoteBusiness;
 
       // Return
@@ -284,11 +329,11 @@
    }
 
    /**
-    * If the specified proxy has been defined outside of 
-    * this naming Context's ClassLoader, it must be reconstructed
-    * using the TCL so we avoid CCE.  This is especially vital using
-    * a scope ClassLoader (ie. has defined by Servlet spec during Web Injection)
-    * 
+    * If the specified proxy has been defined outside of this naming Context's
+    * ClassLoader, it must be reconstructed using the TCL so we avoid CCE. This
+    * is especially vital using a scope ClassLoader (ie. has defined by Servlet
+    * spec during Web Injection)
+    *
     * @param proxy
     */
    protected Object redefineProxyInTcl(Object proxy)
@@ -362,7 +407,7 @@
 
    /**
     * Determines if the specified metadata contains a type of local business
-    * 
+    *
     * @param referenceAddresses
     * @return
     */
@@ -374,7 +419,7 @@
 
    /**
     * Determines if the specified metadata contains a type of remote business
-    * 
+    *
     * @param referenceAddresses
     * @return
     */
@@ -391,7 +436,9 @@
    protected abstract Object getProxy(ProxyFactory proxyFactory, Name name, Map<String, List<String>> referenceAddresses);
 
    /**
-    * Obtains the type or supertype used by proxy factories for this Object Factory
+    * Obtains the type or supertype used by proxy factories for this Object
+    * Factory
+    *
     * @return
     */
    protected abstract Class<?> getProxyFactoryClass();
@@ -401,12 +448,13 @@
    // --------------------------------------------------------------------------------||
 
    /**
-    * Underlying Enumeration for handling Reference Addresses is clumsy (though ordered properly);
-    * iterate through and put in a useful form for this implementation
-    * 
+    * Underlying Enumeration for handling Reference Addresses is clumsy (though
+    * ordered properly); iterate through and put in a useful form for this
+    * implementation
+    *
     * @param ref
     * @return A Map consisting of keys holding reference types, and values of
-    *   Lists containing their contents
+    *         Lists containing their contents
     */
    private Map<String, List<String>> getReferenceAddresses(Reference ref)
    {

Added: projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/unit/RemoteProxyFactoryJNDIBindingTestCase.java
===================================================================
--- projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/unit/RemoteProxyFactoryJNDIBindingTestCase.java	                        (rev 0)
+++ projects/ejb3/trunk/proxy-impl/src/test/java/org/jboss/ejb3/test/proxy/impl/ejbthree1884/unit/RemoteProxyFactoryJNDIBindingTestCase.java	2009-08-13 12:17:45 UTC (rev 92304)
@@ -0,0 +1,334 @@
+/*
+* JBoss, Home of Professional Open Source
+* Copyright 2005, JBoss Inc., and individual contributors as indicated
+* by the @authors tag. See the copyright.txt in the distribution for a
+* full listing of individual contributors.
+*
+* This is free software; you can redistribute it and/or modify it
+* under the terms of the GNU Lesser General Public License as
+* published by the Free Software Foundation; either version 2.1 of
+* the License, or (at your option) any later version.
+*
+* This software is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+* Lesser General Public License for more details.
+*
+* You should have received a copy of the GNU Lesser General Public
+* License along with this software; if not, write to the Free
+* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+*/
+package org.jboss.ejb3.test.proxy.impl.ejbthree1884.unit;
+
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import javax.naming.NameNotFoundException;
+
+import org.jboss.ejb3.common.registrar.spi.Ejb3RegistrarLocator;
+import org.jboss.ejb3.common.registrar.spi.NotBoundException;
+import org.jboss.ejb3.proxy.impl.factory.ProxyFactory;
+import org.jboss.ejb3.proxy.impl.factory.session.stateless.StatelessSessionRemoteProxyFactory;
+import org.jboss.ejb3.proxy.impl.jndiregistrar.JndiStatelessSessionRegistrar;
+import org.jboss.ejb3.test.proxy.impl.common.SessionTestCaseBase;
+import org.jboss.ejb3.test.proxy.impl.common.Utils;
+import org.jboss.ejb3.test.proxy.impl.common.container.SessionContainer;
+import org.jboss.ejb3.test.proxy.impl.common.container.StatefulContainer;
+import org.jboss.ejb3.test.proxy.impl.common.container.StatelessContainer;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.service.MyServiceBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.sfsb.MyStateful2xOnlyBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.sfsb.MyStateful2xOnlyWithBindingsBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.sfsb.MyStateful30OnlyBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.sfsb.MyStatefulLocalBusiness;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.sfsb.MyStatefulLocalOnlyBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.slsb.MyStateless2xOnlyWithBindingsBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.slsb.MyStateless30OnlyBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.slsb.MyStatelessBean;
+import org.jboss.ejb3.test.proxy.impl.common.ejb.slsb.MyStatelessBeanWithBindings;
+import org.jboss.logging.Logger;
+import org.jboss.metadata.ejb.jboss.JBossSessionBeanMetaData;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+/**
+ * RemoteProxyFactoryJNDIBindingTestCase
+ *
+ * Test case to ensure that the remote proxy factory of 
+ * a bean is bound in JNDI
+ * 
+ * @see https://jira.jboss.org/jira/browse/EJBTHREE-1884
+ * @author Jaikiran Pai
+ * @version $Revision: $
+ */
+public class RemoteProxyFactoryJNDIBindingTestCase extends SessionTestCaseBase
+{
+
+   /**
+    * Logger
+    */
+   private static Logger logger = Logger.getLogger(RemoteProxyFactoryJNDIBindingTestCase.class);
+
+   /**
+    * The {@link SessionContainer} which is instantiated by each test. Depending
+    * on the test, its either a {@link StatefulContainer} or a {@link StatelessContainer}
+    */
+   private SessionContainer sessionContainer;
+
+   @BeforeClass
+   public static void beforeClass() throws Throwable
+   {
+      SessionTestCaseBase.setUpBeforeClass();
+      bootstrap.deploy(SessionTestCaseBase.class);
+   }
+
+   @AfterClass
+   public static void afterClass() throws Throwable
+   {
+      if (bootstrap != null)
+      {
+         bootstrap.shutdown();
+      }
+      bootstrap = null;
+   }
+
+   /**
+    * This method takes care of any cleanup required after each test.
+    */
+   @After
+   public void cleanupAfterEachTest()
+   {
+      // There might be a case when while running the test, a bean was registered to JNDI
+      // but before it got unbound, the test failed (either a "Failure" or an "Error").
+      // In such cases, ensure that the bean is unbound from the JNDI, so that if the 
+      // subsequent test tries to bind the same EJB again then it won't run into a 
+      // name already bound error.
+      if (sessionContainer != null)
+      {
+         logger.info("Unbinding: " + sessionContainer.getName());
+         try
+         {
+            Ejb3RegistrarLocator.locateRegistrar().unbind(sessionContainer.getName());
+         }
+         catch (NotBoundException nbe)
+         {
+            // we are ok with this exception, which indicates that the test case had 
+            // already unbound the ejb related bindings.
+            logger.debug(sessionContainer.getName() + " was already unbound");
+
+         }
+      }
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a EJB3 view SLSB
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB3SLSBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateless30OnlyBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a EJB2.x view SLSB
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB2xSLSBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateful2xOnlyBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a EJB3 view SFSB
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB3SFSBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateful30OnlyBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a EJB2.x view SFSB
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB2xSFSBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateful2xOnlyBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a Service bean
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForServiceBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyServiceBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a SLSB which exposes both EJB2.x and EJB3 view.
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForMixedSLSBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStatelessBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a bean which exposes EJB3 view with RemoteBindings
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForMixedBeanWithRemoteBindings() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStatelessBeanWithBindings.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a SFSB which exposes EJB2.x view with RemoteBindings
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB2xSFSBWithRemoteBindings() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateful2xOnlyWithBindingsBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is bound in the JNDI for 
+    * a SLSB which exposes EJB2.x view with RemoteBindings
+    * @throws Throwable
+    */
+   @Test
+   public void testRemoteProxyFactoryForEJB2xSLSBWithRemoteBindings() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStateless2xOnlyWithBindingsBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      testRemoteProxyFactoryBinding(smd);
+
+   }
+
+   /**
+    * Tests that a remote proxyfactory is NOT bound in the JNDI for 
+    * a bean which only exposes a local view
+    * @throws Throwable
+    */
+   @Test
+   public void testAbsenceOfRemoteProxyFactoryLocalOnlyBean() throws Throwable
+   {
+      this.sessionContainer = Utils.createSlsb(MyStatefulLocalOnlyBean.class);
+      JBossSessionBeanMetaData smd = this.sessionContainer.getMetaData();
+      // bind to JNDI
+      Ejb3RegistrarLocator.locateRegistrar().bind(sessionContainer.getName(), sessionContainer);
+      try
+      {
+         testRemoteProxyFactoryBinding(smd);
+         Assert.fail("Found a remote proxyfactory in JNDI for a local-only view bean");
+      }
+      catch (NameNotFoundException nnfe)
+      {
+         // expected, since the bean has only local view. So no remote proxyfactory
+      }
+      // Further lookup the local bean and invoke a method
+      Context ctx = new InitialContext();
+      String localJndiName = smd.getLocalJndiName();
+      logger.debug("Looking up local bean at " + localJndiName);
+      Object obj = ctx.lookup(localJndiName);
+
+      Assert.assertNotNull("Lookup of local bean at " + localJndiName + " returned null", obj);
+      Assert.assertTrue("Lookup at " + localJndiName + " returned unexpected object " + obj,
+            obj instanceof MyStatefulLocalBusiness);
+
+      MyStatefulLocalBusiness bean = (MyStatefulLocalBusiness) obj;
+      int counter = bean.getNextCounter();
+      logger.debug("Got counter " + counter);
+
+      Assert.assertEquals("Unexpected counter value = " + counter, counter, 0);
+
+   }
+
+   /**
+    * Helper method to construct the correct remote proxyfactory JNDI name
+    * and lookup the remote proxyfactory with that jndi name
+    * @param smd
+    * @throws Exception
+    */
+   private void testRemoteProxyFactoryBinding(JBossSessionBeanMetaData smd) throws Exception
+   {
+      // A bit of a hack. These are actually internal classes of proxy-impl,
+      // but since the proxyfactory jndi name generation is part of these
+      // classes, we hence have to rely on them.
+      JndiStatelessSessionRegistrar jndiRegistrar = new JndiStatelessSessionRegistrar(
+            StatelessSessionRemoteProxyFactory.class.getName());
+      String remoteProxyFactoryJNDIName = jndiRegistrar.getProxyFactoryRegistryKey(smd.getJndiName(), smd, false);
+
+      Assert.assertNotNull("Could not get remote proxyfactory jndi name from jndi registrar",
+            remoteProxyFactoryJNDIName);
+
+      Context ctx = new InitialContext();
+      logger.debug("Looking up remote proxy factory at " + remoteProxyFactoryJNDIName + " for EJB " + smd.getEjbName());
+      Object remoteProxyFactory = ctx.lookup(remoteProxyFactoryJNDIName);
+
+      Assert.assertNotNull("Null returned from JNDI for remote proxyfactory key " + remoteProxyFactoryJNDIName,
+            remoteProxyFactory);
+      Assert.assertTrue("Unexpected object type " + remoteProxyFactory.getClass() + " for JNDI name "
+            + remoteProxyFactoryJNDIName, remoteProxyFactory instanceof ProxyFactory);
+
+   }
+}




More information about the jboss-cvs-commits mailing list