| AxisInvocationHandler.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
// $Id: AxisInvocationHandler.java,v 1.16.6.2 2005/04/03 07:19:23 starksm Exp $
package org.jboss.net.axis;
import org.jboss.axis.ConfigurationException;
import org.jboss.axis.EngineConfiguration;
import org.jboss.axis.EngineConfigurationFactory;
import org.jboss.axis.client.Call;
import org.jboss.axis.client.Service;
import org.jboss.axis.configuration.EngineConfigurationFactoryFinder;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
/**
* <p>
* An invocation handler that allows typed and persistent
* client access to remote SOAP/Axis services.
* Adds method/interface to name resolution
* to the axis client engine. Unfortunately the
* AxisClientProxy has a package-protected
* constructor, otherwise we could inherit from there.
* </p>
* @deprecated Due to the inherent deficiencies in
* using pure reflection meat-data to access web services, we recommend
* using the full-blown jaxrpc/wsdl approach.
* @created 1. Oktober 2001, 09:29
* @author <a href="mailto:Christoph.Jung@infor.de">Christoph G. Jung</a>
* @version $Revision: 1.16.6.2 $
*/
public class AxisInvocationHandler implements InvocationHandler, Serializable
{
static final long serialVersionUID = -8250523938712824229L;
//
// Attributes
//
/** mapping of methods to interface names */
protected Map methodToInterface;
/** mapping of methods to method names */
protected Map methodToName;
/** the call object to which we delegate */
transient protected Call call;
/** if attached to a server-engine, we can reattach */
protected String rootContext;
/** the endpoint to which we are attached */
protected String endPoint;
//
// Constructors
//
/**
* Creates a new AxisInvocationHandler and
* save some origin information to re-attach to the
* engine after being serialized.
* @param call the Axis call object
* @param methodMap a map of Java method to service method names
* @param interfaceMap a map of Java interface to service names
*/
public AxisInvocationHandler(Call call, Map methodMap, Map interfaceMap)
{
this.call = call;
this.methodToInterface = interfaceMap;
this.methodToName = methodMap;
// we obtain the configuration of the service
EngineConfiguration myEngineConfig = call.getService().getEngine().getConfig();
try
{
rootContext = (String)myEngineConfig.getGlobalOptions().get(Constants.CONFIGURATION_CONTEXT);
}
catch (ConfigurationException e)
{
// access problem
}
catch (NullPointerException e)
{
// no global options
}
// if the endpoint has already been specified,
// save it for re-attachement
if (call.getTargetEndpointAddress() != null)
{
endPoint = call.getTargetEndpointAddress().toString();
}
}
/**
* Creates a new AxisInvocationHandler
* @param endpoint target address of the service
* @param service an Axis service object
* @param methodMap a map of Java method to service method names
* @param interfaceMap a map of Java interface to service names
*/
public AxisInvocationHandler(URL endpoint,
String soapAction,
Service service,
Map methodMap,
Map interfaceMap)
{
this(new Call(service), methodMap, interfaceMap);
call.setTargetEndpointAddress(endpoint);
call.setSOAPActionURI(soapAction);
setBasicAuthentication(endpoint);
endPoint = endpoint.toString();
}
/**
* Creates a new AxisInvocationHandler
* @param endPoint target url of the web service
* @param methodMap a map of Java method to service method names
* @param interfaceMap a map of Java interface to service names
* @param maintainSession a flag that indicates whether this handler
* should keep a persistent session with the service endpoint
*/
public AxisInvocationHandler(URL endPoint,
String soapAction,
Map methodMap,
Map interfaceMap,
boolean maintainSession)
{
this(endPoint, soapAction, new Service(), methodMap, interfaceMap);
call.setMaintainSession(maintainSession);
}
/**
* Creates a new AxisInvocationHandler that keeps a persistent session with
* the service endpoint
* @param endPoint target url of the web service
* @param methodMap a map of Java method to service method names
* @param interfaceMap a map of Java interface to service names
*/
public AxisInvocationHandler(URL endPoint, String soapAction, Map methodMap, Map interfaceMap)
{
this(endPoint, soapAction, methodMap, interfaceMap, true);
}
/**
* Creates a new AxisInvocationHandler that keeps a persistent session with
* the service endpoint. The unqualified name of the
* intercepted Java interface will be the used service name.
* @param endPoint target url of the web service
* @param methodMap a map of Java method to service method names
*/
public AxisInvocationHandler(URL endPoint, String soapAction, Map methodMap)
{
this(endPoint, soapAction, methodMap, new DefaultInterfaceMap());
}
/**
* Creates a new AxisInvocationHandler that keeps a persistent session with
* the service endpoint. The unqualified name of the
* intercepted Java interface will be the used service name.
* Intercepted methods are mapped straightforwardly to web service names.
* @param endPoint target url of the web service
* @param methodMap a map of Java method to service method names
*/
public AxisInvocationHandler(URL endPoint, String soapAction)
{
this(endPoint, soapAction, new DefaultMethodMap());
}
//
// Helpers
//
/** helper to transfer url authentication information into engine */
protected void setBasicAuthentication(URL target)
{
String userInfo = target.getUserInfo();
if (userInfo != null)
{
java.util.StringTokenizer tok = new java.util.StringTokenizer(userInfo, ":");
if (tok.hasMoreTokens())
{
call.setUsername(tok.nextToken());
if (tok.hasMoreTokens())
{
call.setPassword(tok.nextToken());
}
}
}
}
//
// Invocationhandling API
//
/** invoke given namespace+method+args */
public Object invoke(String serviceName, String methodName, Object[] args)
throws java.rmi.RemoteException
{
try
{
return call.invoke(serviceName, methodName, args);
}
finally
{
call.setReturnType(null);
call.removeAllParameters();
}
}
/** invoke with additional method parameter signature */
public Object invoke(String serviceName,
String methodName,
Object[] args,
Class[] parameters)
throws java.rmi.RemoteException
{
// classes are normally ignored
return invoke(serviceName, methodName, args);
}
/** generic invocation method */
public java.lang.Object invoke(java.lang.Object target,
java.lang.reflect.Method method,
java.lang.Object[] args)
throws java.lang.Throwable
{
return invoke((String)methodToInterface.get(method),
(String)methodToName.get(method),
args,
method.getParameterTypes());
}
//
// Static API
//
/** default creation of service */
public static Object createAxisService(Class _interface, URL endpoint, String soapAction)
{
return createAxisService(_interface, new AxisInvocationHandler(endpoint, soapAction));
}
/** default creation of service */
public static Object createAxisService(Class _interface,
URL endpoint, String soapAction, Service service)
{
return createAxisService(_interface,
new AxisInvocationHandler(endpoint, soapAction, service, new DefaultMethodMap(), new DefaultInterfaceMap()));
}
/** default creation of service */
public static Object createAxisService(Class _interface,
Call call)
{
return createAxisService(_interface,
new AxisInvocationHandler(call, new DefaultMethodMap(), new DefaultInterfaceMap()));
}
/** default creation of service */
public static Object createAxisService(Class _interface,
AxisInvocationHandler handler)
{
return Proxy.newProxyInstance(_interface.getClassLoader(),
new Class[]{_interface},
handler);
}
/**
* a tiny helper that does some default mapping of methods to interface names
* we do not hash the actual reflection information because
* we could collide with proxy serialisation holding fucking
* old classes
*/
public static class DefaultInterfaceMap extends HashMap
{
/** no entries is the default */
public DefaultInterfaceMap()
{
super(0);
}
/** returns default interface if no mapping of method/interface is defined */
public Object get(Object key)
{
// first try a direct lookup
Object result = super.get(((Method)key).getName());
if (result == null)
{
// if that is unsuccessful, we try to
// lookup the class/interface itself
result = super.get(((Method)key).getDeclaringClass().getName());
// if that is not specified, we simply extract the
// un-qualified classname
if (result == null)
{
String sresult = ((Method)key).getDeclaringClass().getName();
if (sresult.indexOf(".") != -1)
sresult = sresult.substring(sresult.lastIndexOf(".") + 1);
result = sresult;
}
}
return result;
}
/** registers an interface name for a given class or method */
public Object put(Object key, Object value)
{
if (key instanceof Method)
{
return super.put(((Method)key).getName(), value);
}
else if (key instanceof Class)
{
return super.put(((Class)key).getName(), value);
}
else
{
return super.put(key, value);
}
}
}
/**
* a tiny helper that does some default mapping of methods to method names
* we do not hash the actual reflection information because
* we could collide with proxy serialisation holding fucking
* old classes
*/
public static class DefaultMethodMap extends HashMap
{
/** no entries is the default */
public DefaultMethodMap()
{
super(0);
}
/** returns default interface if no mapping is defined */
public Object get(Object key)
{
Object result = super.get(((Method)key).getName());
if (result == null)
{
result = ((Method)key).getName();
}
return result;
}
/** registers a new method */
public Object put(Object key, Object value)
{
if (key instanceof Method)
{
return super.put(((Method)key).getName(), value);
}
else
{
return super.put(key, value);
}
}
}
/**
* serialization helper to reattach to engine, must be private
* to be called correctly
*/
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException
{
stream.defaultReadObject();
// try to find the engine that we were attached to
try
{
EngineConfigurationFactory factory = EngineConfigurationFactoryFinder.
newFactory(new ObjectName(rootContext));
EngineConfiguration engine = null;
if (factory != null)
{
engine = factory.getClientEngineConfig();
}
if (engine != null)
{
call = new Call(new Service(engine));
}
else
{
// not there, try the default config
call = new Call(new Service());
}
}
catch (MalformedObjectNameException e)
{
throw new IOException("Could not contact jmx configuration factory." + e);
}
URL endpoint = new URL(endPoint);
call.setTargetEndpointAddress(endpoint);
setBasicAuthentication(endpoint);
}
}
| AxisInvocationHandler.java |