/*
* JBoss, Home of Professional Open Source.
* Copyright 2008, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file 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.proxy;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import javax.management.ObjectName;
import org.jboss.invocation.InvocationContext;
import org.jboss.invocation.InvocationKey;
import org.jboss.invocation.Invoker;
import org.jboss.logging.Logger;
import org.jboss.system.Registry;
import org.jboss.util.NestedRuntimeException;
/** A generic factory of java.lang.reflect.Proxy that constructs a proxy
* that is a composite of ClientContainer/Interceptors/Invoker
*
* @todo generalize the proxy/invoker factory object
* @author Scott.Stark@jboss.org
* @author <a href="mailto:galder.zamarreno@jboss.com">Galder Zamarreno</a>
* @version $Revision: 81030 $
*/
public class GenericProxyFactory
{
private static final Logger log = Logger.getLogger(GenericProxyFactory.class);
/** Create a composite proxy for the given interfaces, invoker.
@param id the cache id for the target object if any
@param targetName the name of the server side service
@param invoker the detached invoker stub to embed in the proxy
@param jndiName the JNDI name the proxy will be bound under if not null
@param proxyBindingName the invoker-proxy-binding name if not null
@param interceptorClasses the Class objects for the interceptors
@param loader the ClassLoader to associate the the Proxy
@param ifaces the Class objects for the interfaces the Proxy implements
*/
public Object createProxy(Object id, ObjectName targetName,
Invoker invoker, String jndiName, String proxyBindingName,
ArrayList interceptorClasses, ClassLoader loader, Class[] ifaces)
{
return createProxy(id, targetName, invoker, jndiName, proxyBindingName, interceptorClasses, loader, ifaces, null);
}
/** Create a composite proxy for the given interfaces, invoker.
@param id the cache id for the target object if any
@param targetName the name of the server side service
@param invokerName the name of the server side JMX invoker
@param jndiName the JNDI name the proxy will be bound under if not null
@param proxyBindingName the invoker-proxy-binding name if not null
@param interceptorClasses the Class objects for the interceptors
@param loader the ClassLoader to associate the the Proxy
@param ifaces the Class objects for the interfaces the Proxy implements
*/
public Object createProxy(Object id, ObjectName targetName, ObjectName invokerName,
String jndiName, String proxyBindingName,
ArrayList interceptorClasses, ClassLoader loader, Class[] ifaces)
{
Invoker invoker = (Invoker) Registry.lookup(invokerName);
if (invoker == null)
throw new RuntimeException("Failed to find invoker for name: " + invokerName);
return createProxy(id, targetName, invoker, jndiName, proxyBindingName, interceptorClasses, loader, ifaces, null);
}
/** Create a composite proxy for the given interfaces, invoker.
@param id the cache id for the target object if any
@param targetName the name of the server side service
@param invoker the detached invoker stub to embed in the proxy
@param jndiName the JNDI name the proxy will be bound under if not null
@param proxyBindingName the invoker-proxy-binding name if not null
@param interceptorClasses the Class objects for the interceptors
@param loader the ClassLoader to associate the the Proxy
@param ifaces the Class objects for the interfaces the Proxy implements
@param ctx any context to add the invocation context proxy
*/
public Object createProxy(Object id, ObjectName targetName,
Invoker invoker, String jndiName, String proxyBindingName,
ArrayList interceptorClasses, ClassLoader loader, Class[] ifaces, HashMap ctx)
{
InvocationContext context;
if (ctx != null)
context = new InvocationContext(ctx);
else
context = new InvocationContext();
Integer nameHash = new Integer(targetName.hashCode());
if (log.isTraceEnabled())
{
log.trace("Target name " + targetName + " and corresponding hash code" + nameHash);
}
context.setObjectName(nameHash);
context.setCacheId(id);
if( jndiName != null )
context.setValue(InvocationKey.JNDI_NAME, jndiName);
if( invoker == null )
throw new RuntimeException("Null invoker given for name: " + targetName);
context.setInvoker(invoker);
if( proxyBindingName != null )
context.setInvokerProxyBinding(proxyBindingName);
// If the IClientContainer interceptor was specified, use the ClientContainerEx
boolean wantIClientAccess = false;
for(int n = 0; wantIClientAccess == false && n < interceptorClasses.size(); n ++)
{
Class type = (Class) interceptorClasses.get(n);
wantIClientAccess = type.isAssignableFrom(IClientContainer.class);
}
ClientContainer client;
if( wantIClientAccess )
{
client = new ClientContainerEx(context);
}
else
{
client = new ClientContainer(context);
}
try
{
loadInterceptorChain(interceptorClasses, client);
}
catch(Exception e)
{
throw new NestedRuntimeException("Failed to load interceptor chain", e);
}
ArrayList tmp = new ArrayList(Arrays.asList(ifaces));
Class[] ifaces2 = new Class[tmp.size()];
tmp.toArray(ifaces2);
return Proxy.newProxyInstance(
// Classloaders
loader,
// Interfaces
ifaces2,
// Client container as invocation handler
client);
}
/** The loadInterceptorChain create instances of interceptor
* classes from the list of classes given by the chain array.
*
* @exception Exception if an error occurs
*/
protected void loadInterceptorChain(ArrayList chain, ClientContainer client)
throws Exception
{
Interceptor last = null;
for (int i = 0; i < chain.size(); i++)
{
Class clazz = (Class)chain.get(i);
Interceptor interceptor = (Interceptor) clazz.newInstance();
if (last == null)
{
last = interceptor;
client.setNext(interceptor);
}
else
{
last.setNext(interceptor);
last = interceptor;
}
}
}
}