[jboss-cvs] JBossAS SVN: r76155 - projects/jboss-aspects/trunk/remoting/src/main/java/org/jboss/aspects/remoting.

jboss-cvs-commits at lists.jboss.org jboss-cvs-commits at lists.jboss.org
Wed Jul 23 21:13:42 EDT 2008


Author: ron_sigal
Date: 2008-07-23 21:13:42 -0400 (Wed, 23 Jul 2008)
New Revision: 76155

Added:
   projects/jboss-aspects/trunk/remoting/src/main/java/org/jboss/aspects/remoting/RemotingProxyFactory.java
Log:
JBAS-4456: A replacement for JRMPProxyFactory.

Added: projects/jboss-aspects/trunk/remoting/src/main/java/org/jboss/aspects/remoting/RemotingProxyFactory.java
===================================================================
--- projects/jboss-aspects/trunk/remoting/src/main/java/org/jboss/aspects/remoting/RemotingProxyFactory.java	                        (rev 0)
+++ projects/jboss-aspects/trunk/remoting/src/main/java/org/jboss/aspects/remoting/RemotingProxyFactory.java	2008-07-24 01:13:42 UTC (rev 76155)
@@ -0,0 +1,455 @@
+
+/*
+* 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.aspects.remoting;
+
+import java.lang.reflect.Field;
+import java.net.MalformedURLException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+
+import javax.naming.InitialContext;
+
+import org.jboss.aop.Dispatcher;
+import org.jboss.aop.advice.Interceptor;
+import org.jboss.aop.proxy.Proxy;
+import org.jboss.logging.Logger;
+import org.jboss.remoting.InvokerLocator;
+import org.jboss.remoting.transport.Connector;
+import org.jboss.util.naming.Util;
+
+
+/**
+ * <code>RemotingProxyFactory</code> is an AOP / Remoting replacement for 
+ * <code>org.jboss.invocation.jrmp.server.JRMPProxyFactory</code>.
+ * <p>
+ * Given the following parameters
+ * <p>
+ * <ul>
+ *   <li>a list of interfaces,</li>
+ *   <li>an array of interceptor class names or interceptor POJOs,</li>
+ *   <li>an <code>org.jboss.remoting.InvokerLocator</code> pointing to an
+ *       <code>org.jboss.remoting.transport.Connector</code> running
+ *       an <code>org.jboss.aspects.remoting.AOPRemotingInvocationHandler</code>,</li>
+ *   <li>a target object, and</li>
+ *   <li>a JNDI name,</li>
+ * </ul>
+ * <p>
+ * RemotingProxyFactory will create a proxy that
+ * <p>
+ * <ol>
+ *   <li>implements the interfaces,</li>
+ *   <li>makes invocations through the chain of client side interceptors,<li>
+ *   <li>sends invocations to the remote <code>Connector</code> where they are processed
+ *       by the provided target,</li>
+ * </ol>
+ * <p>
+ * and it will bind the proxy to the provided name in JNDI.
+ * 
+ * @author <a href="ron.sigal at jboss.com">Ron Sigal</a>
+ * @version $Revision: 1.1 $
+ * <p>
+ * Copyright Jun 6, 2008
+ * </p>
+ */
+public class RemotingProxyFactory
+{
+   private static final Logger log = Logger.getLogger(RemotingProxyFactory.class);
+   private Object target;
+   private Class<?>[] interfaces;
+   private String dispatchName;
+   private String jndiName;
+   private InvokerLocator invokerLocator;
+   private Connector connector;
+   private String subsystem = "AOP";
+   private ArrayList<?> interceptors;
+   private ArrayList<Interceptor> verifiedInterceptors;
+   private Proxy proxy;
+
+   /**
+    * Returns the target to which the AOP dispatcher will direct invocations
+    * <p>
+    * @return the target to which the AOP dispatcher will direct invocations
+    */
+   public Object getTarget()
+   {
+      return target;
+   }
+
+   /**
+    * Sets the target to which the AOP dispatcher will direct invocations
+    * <p>
+    * @param target the target to which the AOP dispatcher will direct invocations
+    */
+   public void setTarget(Object target)
+   {
+      this.target = target;
+   }
+
+   /**
+    * Returns the interfaces implemented by the proxy created by this instance
+    * of <code>RemotingProxyFactory</code>
+    * <p>
+    * @return the interfaces implemented by the proxy created by this instance
+    *         of <code>RemotingProxyFactory</code>s
+    */
+   public Class<?>[] getInterfaces()
+   {
+      return interfaces;
+   }
+
+   /**
+    * Sets the interfaces implemented by the proxy created by this
+    * instance of <code>RemotingProxyFactory</code>
+    * <p>
+    * @param interfaces the interfaces implemented by the proxy created by this
+    *        instance of <code>RemotingProxyFactory</code>
+    */
+   public void setInterfaces(Class<?>[] interfaces)
+   {
+      this.interfaces = interfaces;
+      for (int i = 0; i < interfaces.length; i++)
+         log.debug("interface[" + i + "]: " + interfaces[i]);
+   }
+   
+   /** 
+    * Returns the name under which the AOP dispatcher will register the target
+    * <p>
+    * @return the name under which the AOP dispatcher will register the target
+    */
+   public String getDispatchName()
+   {
+      return dispatchName;
+   }
+
+   /**
+    * Sets the name under which the AOP dispatcher will register the target
+    * <p>
+    * @param dispatchName the name under which the AOP dispatcher will register the target
+    */
+   public void setDispatchName(String dispatchName)
+   {
+      this.dispatchName = dispatchName;
+   }
+
+   /**
+    * Returns the name to which the proxy will be bound in JNDI
+    * <p>
+    * @return the name to which the proxy will be bound in JNDI 
+    */
+   public String getJndiName()
+   {
+      return jndiName;
+   }
+
+   /**
+    * Sets the name to which the proxy will be bound in JNDI 
+    * <p>
+    * @param jndiName the name to which the proxy will be bound in JNDI 
+    */
+   public void setJndiName(String jndiName)
+   {
+      this.jndiName = jndiName;
+   }
+
+   /**
+    * Returns the String form of the <code>InvokerLocator</code> that identifies the
+    *         Remoting <code>Connector</code> that directs invocations to the
+    *         <code>AOPRemotingInvocationHandler</code>, which then directs
+    *         invocations to the target
+    * <p>
+    * @return the String form of the <code>InvokerLocator</code> that identifies the
+    *         Remoting <code>Connector</code> that directs invocations to the
+    *         <code>AOPRemotingInvocationHandler</code>, which then directs
+    *         invocations to the target
+    */
+   public String getInvokerLocator()
+   {
+      return invokerLocator.toString();
+   }
+
+   /**
+    * Sets the String form of the <code>InvokerLocator</code> that identifies the
+    *                Remoting <code>Connector</code> that directs invocations to the
+    *                <code>AOPRemotingInvocationHandler</code>, which then directs
+    *                invocations to the target
+    * <p>  
+    * @param locator the String form of the <code>InvokerLocator</code> that identifies the
+    *                Remoting <code>Connector</code> that directs invocations to the
+    *                <code>AOPRemotingInvocationHandler</code>, which then directs
+    *                invocations to the target
+    * @throws MalformedURLException
+    */
+   public void setInvokerLocator(String locator) throws MalformedURLException
+   {
+      this.invokerLocator = new InvokerLocator(locator);
+   }
+   
+   /**
+    * Returns the Remoting <code>Connector</code> that directs invocations to the
+    *         <code>AOPRemotingInvocationHandler</code>, which then directs
+    *         invocations to the target
+    * <p>
+    * @return the Remoting <code>Connector</code> that directs invocations to the
+    *         <code>AOPRemotingInvocationHandler</code>, which then directs
+    *         invocations to the target
+    */
+   public Connector getConnector()
+   {
+      return connector;
+   }
+
+   /**
+    * Sets the Remoting <code>Connector</code> that directs invocations to the
+    *                  <code>AOPRemotingInvocationHandler</code>, which then directs
+    *                  invocations to the target
+    * <p>
+    * @param connector the Remoting <code>Connector</code> that directs invocations to the
+    *                  <code>AOPRemotingInvocationHandler</code>, which then directs
+    *                  invocations to the target
+    */
+   public void setConnector(Connector connector)
+   {
+      this.connector = connector;
+   }
+
+   /**
+    * Returns the subsystem name that identifes the <code>AOPRemotingInvocationHandler</code>
+    *         running in the Remoting <code>Connector</code>.  Defaults to "AOP".
+    * <p>
+    * @return the subsystem name that identifes the <code>AOPRemotingInvocationHandler</code>
+    *         running in the Remoting <code>Connector</code>.  Defaults to "AOP".
+    */
+   public String getSubsystem()
+   {
+      return subsystem;
+   }
+
+   /**
+    * Sets the subsystem name that identifes the <code>AOPRemotingInvocationHandler</code>
+    *                  running in the Remoting <code>Connector</code>.  Defaults to "AOP".
+    * <p>
+    * @param subsystem the subsystem name that identifes the <code>AOPRemotingInvocationHandler</code>
+    *                  running in the Remoting <code>Connector</code>.  Defaults to "AOP".
+    */
+   public void setSubsystem(String subsystem)
+   {
+      this.subsystem = subsystem;
+   }
+
+   /**
+    * Returns the interceptors through which an invocation will pass on the client side.
+    * <p>
+    * <b>N.B.</b> Each element of the list is either
+    * <p>
+    * <ol>
+    *   <li>the fully qualified class name of an interceptor, or</li>
+    *   <li>an interceptor POJO.</li>
+    * </ol>
+    * <p>
+    * @return the interceptors through which an invocation will pass on the client side.
+    * 
+    */
+   public ArrayList<?> getInterceptors()
+   {
+      return interceptors;
+   }
+
+   /** 
+    * Sets the interceptors through which an invocation will pass on the client side.
+    * <p>
+    * <b>N.B.</b> Each element of the list must be either
+    * <p>
+    * <ol>
+    *   <li>the fully qualified class name of an interceptor, or</li>
+    *   <li>an interceptor POJO.</li>
+    * </ol>
+    * <p>
+    * If the element is a class name, then the class must have either
+    * <p>
+    * <ol>
+    *   <li>a public static field named "singleton" that holds an instance of the interceptor, or</li>
+    *   <li>a default constructor.</li>
+    * </ol>
+    * <p>
+    * <b>N.B.</b>The interceptors <code>MergeMetaDataInterceptor</code> and
+    * <code>InvokeRemoteInterceptor</code> are automatically appended to the end of the list.
+    * <p>
+    * @param interceptors the interceptors through which an invocation will pass on the client side.
+    */
+   public void setInterceptors(ArrayList<?> interceptors)
+   {
+      this.interceptors = interceptors;
+   }
+
+   /**
+    * Returns the proxy created by this instance of <code>RemotingProxyFactory</code>
+    * <p>
+    * @return the proxy created by this instance of <code>RemotingProxyFactory</code>
+    */
+   public Proxy getProxy()
+   {
+      return proxy;
+   }
+
+   /**
+    * Lifecycle method.
+    * <p>
+    * The lifecycle method that 
+    * <ol>
+    *   <li>registers the target with the AOP dispatcher</li>
+    *   <li>creates the proxy</li>
+    *   <li>binds the proxy in JNDI</li>
+    * </ol>
+    * <p>
+    * @throws Exception
+    */
+   public void start() throws Exception
+   {  
+      doSanityChecks();
+      
+      verifyInterceptors();
+
+      // Register invocation target.
+      Dispatcher.singleton.registerTarget(dispatchName, target);
+
+      // Create proxy.
+      ClassLoader loader = getContextClassLoader();
+      proxy = Remoting.createRemoteProxy(dispatchName, loader, interfaces, invokerLocator, verifiedInterceptors, subsystem);
+      log.debug("Created proxy for " + dispatchName);
+      
+      // Bind proxy in JNDI.
+      InitialContext ctx = new InitialContext();
+      Util.bind(ctx, jndiName, proxy);
+      log.debug("Bound proxy for " + dispatchName + " to " + jndiName);
+   }
+
+   /**
+    * Lifecycle method.
+    * <p>
+    * The lifecycle method that 
+    * <p>
+    * <ol>
+    *   <li>unregisters the target with AOP dispatcher</li>
+    *   <li>unbinds the proxy from JNDI</li>
+    * </ol>
+    * <p>
+    * @throws Exception
+    */
+   public void stop() throws Exception
+   {
+      Dispatcher.singleton.unregisterTarget(dispatchName);
+      InitialContext ctx = new InitialContext();
+      Util.unbind(ctx, jndiName);
+      log.debug("Unbound proxy for " + dispatchName);
+   }   
+   
+   private void doSanityChecks() throws Exception
+   {
+      if (target == null)
+         throw new Exception("Cannot start factory: target == null");
+      
+      if (interfaces == null)
+         throw new Exception("Cannot start factory: interfaces == null");
+      
+      if (interfaces.length == 0)
+         throw new Exception("Cannot start factory: interfaces is empty array");
+      
+      for (int i = 0; i < interfaces.length; i++)
+      {
+         if (!(interfaces[i].isInstance(target)))
+            throw new Exception("Cannot start factory: " + target + " does not implement " + interfaces[i]);
+      }
+     
+      if (dispatchName == null)
+         throw new Exception("Cannot start factory: dispatchName == null");
+      
+      if (jndiName == null)
+         throw new Exception("Cannot start factory: jndiName == null");
+      
+      if (invokerLocator == null && connector == null)
+         throw new Exception("Cannot start factory: locator == null and connector == null");
+      
+      if (invokerLocator == null)
+         invokerLocator = connector.getLocator();
+   }
+   
+   
+   private void verifyInterceptors() throws Exception
+   {
+      verifiedInterceptors = new ArrayList<Interceptor>(interceptors.size());
+      Interceptor interceptor = null;
+      ClassLoader tcl = getContextClassLoader();
+      
+      for (Object o : interceptors)
+      {
+         log.debug("processing interceptor: " + o);
+         if (o instanceof String)
+         {
+            Class<?> c = Class.forName((String) o, true, tcl);
+            try
+            {
+               Field field = c.getDeclaredField("singleton");
+               interceptor = (Interceptor) field.get(null);
+            }
+            catch (Exception e)
+            {
+               log.debug(c.getName() + " has no singleton element: trying default constructor");
+               interceptor = (Interceptor) c.newInstance();
+            }
+            if (o == null)
+            {
+               throw new Exception("Cannot start factory: unable to create instance of " + c.getName());
+            }
+         }
+         else if (o instanceof Interceptor)
+         {
+            interceptor = (Interceptor) o;
+         }
+         else
+         {
+            throw new Exception(o + " is neither String nor Interceptor");
+         }
+         verifiedInterceptors.add(interceptor);
+         log.debug("added interceptor: " + interceptor);
+      }
+      
+      interceptor = MergeMetaDataInterceptor.singleton;
+      verifiedInterceptors.add(interceptor);
+      log.debug("added interceptor: " + interceptor);
+      interceptor = InvokeRemoteInterceptor.singleton;
+      verifiedInterceptors.add(interceptor);
+      log.debug("added interceptor: " + interceptor);
+   }
+   
+   private ClassLoader getContextClassLoader()
+   {
+      return (ClassLoader) AccessController.doPrivileged(new PrivilegedAction<Object>()
+      {
+         public Object run()
+         { 
+            return Thread.currentThread().getContextClassLoader();
+         }
+      });
+   }
+}
\ No newline at end of file




More information about the jboss-cvs-commits mailing list