Package org.jboss.aspects.remoting

Source Code of org.jboss.aspects.remoting.RemotingProxyFactory

/*
* 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@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();
         }
      });
   }
}
TOP

Related Classes of org.jboss.aspects.remoting.RemotingProxyFactory

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.