package org.jboss.invocation.jrmp.server;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.lang.reflect.Method;
import javax.management.ObjectName;
import javax.naming.InitialContext;
import org.jboss.invocation.InvokerInterceptor;
import org.jboss.invocation.Invocation;
import org.jboss.invocation.MarshalledInvocation;
import org.jboss.naming.Util;
import org.jboss.proxy.ClientMethodInterceptor;
import org.jboss.proxy.GenericProxyFactory;
import org.jboss.system.Registry;
import org.jboss.system.ServiceMBeanSupport;
import org.jboss.metadata.MetaData;
import org.w3c.dom.Element;
public class JRMPProxyFactory extends ServiceMBeanSupport
implements JRMPProxyFactoryMBean
{
private ObjectName invokerName;
private ObjectName targetName;
protected Object theProxy;
private String jndiName;
private Class[] exportedInterfaces;
private Element interceptorConfig;
private ArrayList interceptorClasses = new ArrayList();
private boolean invokeTargetMethod;
private final Map methodMap = new HashMap();
private final Map signatureMap = new HashMap();
public JRMPProxyFactory()
{
interceptorClasses.add(ClientMethodInterceptor.class);
interceptorClasses.add(InvokerInterceptor.class);
}
public ObjectName getInvokerName()
{
return invokerName;
}
public void setInvokerName(ObjectName invokerName)
{
this.invokerName = invokerName;
}
public ObjectName getTargetName()
{
return targetName;
}
public void setTargetName(ObjectName targetName)
{
this.targetName = targetName;
}
public String getJndiName()
{
return jndiName;
}
public void setJndiName(String jndiName)
{
this.jndiName = jndiName;
}
public Class getExportedInterface()
{
return exportedInterfaces[0];
}
public void setExportedInterface(Class exportedInterface)
{
this.exportedInterfaces = new Class[] {exportedInterface};
}
public Class[] getExportedInterfaces()
{
return exportedInterfaces;
}
public void setExportedInterfaces(Class[] exportedInterfaces)
{
this.exportedInterfaces = exportedInterfaces;
}
public boolean getInvokeTargetMethod()
{
return invokeTargetMethod;
}
public void setInvokeTargetMethod(boolean invokeTargetMethod)
{
this.invokeTargetMethod = invokeTargetMethod;
}
public Element getClientInterceptors()
{
return interceptorConfig;
}
public void setClientInterceptors(Element config) throws Exception
{
this.interceptorConfig = config;
Iterator interceptorElements = MetaData.getChildrenByTagName(interceptorConfig, "interceptor");
ClassLoader loader = Thread.currentThread().getContextClassLoader();
interceptorClasses.clear();
while( interceptorElements != null && interceptorElements.hasNext() )
{
Element ielement = (Element) interceptorElements.next();
String className = null;
className = MetaData.getElementContent(ielement);
Class clazz = loader.loadClass(className);
interceptorClasses.add(clazz);
log.debug("added interceptor type: "+clazz);
}
}
public Object getProxy()
{
return theProxy;
}
public Object invoke(Invocation mi) throws Exception
{
final boolean remoteInvocation = mi instanceof MarshalledInvocation;
if(remoteInvocation)
{
((MarshalledInvocation)mi).setMethodMap(methodMap);
}
final Object result;
if(invokeTargetMethod)
{
String signature[] = (String[])signatureMap.get(mi.getMethod());
result = server.invoke(targetName, mi.getMethod().getName(), mi.getArguments(), signature);
}
else
{
result = server.invoke(targetName, "invoke", new Object[]{mi}, Invocation.INVOKE_SIGNATURE);
}
return result;
}
protected void startService() throws Exception
{
Integer nameHash = new Integer(getServiceName().hashCode());
Registry.bind(nameHash, getServiceName());
Object cacheID = null;
String proxyBindingName = null;
Class[] ifaces = exportedInterfaces;
ClassLoader loader = Thread.currentThread().getContextClassLoader();
createProxy(cacheID, proxyBindingName, loader, ifaces);
log.debug("Created JRMPPRoxy for service="+targetName
+", nameHash="+nameHash+", invoker="+invokerName);
if( jndiName != null )
{
InitialContext iniCtx = new InitialContext();
Util.bind(iniCtx, jndiName, theProxy);
log.debug("Bound proxy under jndiName="+jndiName);
}
for(int i = 0; i < exportedInterfaces.length; ++i)
{
final Method[] methods = exportedInterfaces[i].getMethods();
for(int j = 0; j < methods.length; ++j)
{
methodMap.put(new Long(MarshalledInvocation.calculateHash(methods[j])), methods[j]);
String signature[];
final Class[] types = methods[j].getParameterTypes();
if(types == null || types.length == 0)
{
signature = null;
}
else
{
signature = new String[types.length];
for(int typeInd = 0; typeInd < types.length; ++typeInd)
{
signature[typeInd] = types[typeInd].getName();
}
}
signatureMap.put(methods[j], signature);
}
}
}
protected void stopService() throws Exception
{
Integer nameHash = new Integer(getServiceName().hashCode());
Registry.unbind(nameHash);
if( jndiName != null )
{
InitialContext iniCtx = new InitialContext();
Util.unbind(iniCtx, jndiName);
}
this.theProxy = null;
}
protected void destroyService() throws Exception
{
interceptorClasses.clear();
}
protected void createProxy
(
Object cacheID,
String proxyBindingName,
ClassLoader loader,
Class[] ifaces
)
{
GenericProxyFactory proxyFactory = new GenericProxyFactory();
theProxy = proxyFactory.createProxy(cacheID, getServiceName(), invokerName,
jndiName, proxyBindingName, interceptorClasses, loader, ifaces);
}
protected void rebind() throws Exception
{
log.debug("(re-)Binding " + jndiName);
Util.rebind(new InitialContext(), jndiName, theProxy);
}
protected ArrayList getInterceptorClasses()
{
return interceptorClasses;
}
}