[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