package org.jboss.webservice.client;
import org.jboss.axis.EngineConfiguration;
import org.jboss.axis.client.AxisClient;
import org.jboss.axis.wsdl.gen.Parser;
import org.jboss.logging.Logger;
import org.jboss.webservice.EngineConfigurationFinder;
import org.jboss.webservice.deployment.BeanXMLMetaData;
import org.jboss.webservice.deployment.ServiceDescription;
import org.jboss.webservice.deployment.TypeMappingDescription;
import org.jboss.webservice.deployment.WSDDGenerator;
import org.jboss.webservice.encoding.ser.MetaDataBeanDeserializerFactory;
import org.jboss.webservice.encoding.ser.MetaDataBeanSerializerFactory;
import org.jboss.webservice.metadata.jaxrpcmapping.JavaWsdlMapping;
import org.jboss.webservice.metadata.jaxrpcmapping.ServiceEndpointInterfaceMapping;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.xml.namespace.QName;
import javax.xml.rpc.Call;
import javax.xml.rpc.ServiceException;
import javax.xml.rpc.encoding.DeserializerFactory;
import javax.xml.rpc.encoding.SerializerFactory;
import javax.xml.rpc.encoding.TypeMapping;
import javax.xml.rpc.encoding.TypeMappingRegistry;
import javax.xml.rpc.handler.HandlerRegistry;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
import java.net.URL;
import java.rmi.Remote;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
public class ServiceImpl extends org.jboss.axis.client.Service
{
static final long serialVersionUID = -340351073471390974L;
private static final Logger log = Logger.getLogger(ServiceImpl.class);
private static final String DEFAULT_PORT = "DEFAULT_PORT";
private String targetEndpointAddress;
private Map serviceDescMap = new HashMap();
private JavaWsdlMapping javaWsdlMapping;
private Definition wsdlDefinition;
private Properties callProperties;
public ServiceImpl()
{
super();
}
public ServiceImpl(QName serviceName)
{
super(serviceName);
if (serviceName == null)
throw new IllegalStateException("service name cannot be null");
}
public ServiceImpl(URL wsdlDoc, QName serviceName) throws ServiceException
{
super(wsdlDoc, serviceName);
if (serviceName == null)
throw new IllegalStateException("service name cannot be null");
}
public void initService(ServiceDescription serviceDesc, String portName) throws ServiceException
{
log.debug("initService: port=" + portName);
if (portName == null)
portName = DEFAULT_PORT;
if (wsdlDefinition != null && wsdlDefinition != serviceDesc.getWsdlDefinition())
throw new IllegalArgumentException("Cannot redefine the wsdl definition for this service");
if (javaWsdlMapping != null && javaWsdlMapping != serviceDesc.getJavaWsdlMapping())
throw new IllegalArgumentException("Cannot redefine the jaxrpc-mapping definition for this service");
if (serviceDescMap.get(portName) != null)
throw new IllegalArgumentException("A service decription for this tport is already registered");
wsdlDefinition = serviceDesc.getWsdlDefinition();
javaWsdlMapping = serviceDesc.getJavaWsdlMapping();
serviceDescMap.put(portName, serviceDesc);
if (log.isTraceEnabled())
{
WSDDGenerator wsddGenerator = new WSDDGenerator(serviceDesc);
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
wsddGenerator.appendOperations(pw);
wsddGenerator.appendTypeMappings(pw);
log.trace("Service configuration:\n" + sw);
}
setupTypeMapping(serviceDesc);
}
public HandlerRegistry getHandlerRegistry()
{
throw new UnsupportedOperationException("Components should not use the getHandlerRegistry() method.");
}
public TypeMappingRegistry getTypeMappingRegistry()
{
throw new UnsupportedOperationException("Components should not use the getTypeMappingRegistry() method.");
}
public Remote getPort(Class seiClass) throws ServiceException
{
Remote port = (Remote)super.getPort(seiClass);
InvocationHandler handler = new PortProxy(port, seiClass);
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
Class[] ifaces = {seiClass, org.jboss.webservice.client.Stub.class};
return (Remote)Proxy.newProxyInstance(contextCL, ifaces, handler);
}
public Remote getPort(QName portName, Class seiClass) throws ServiceException
{
Remote port = (Remote)super.getPort(portName, seiClass);
InvocationHandler handler = new PortProxy(port, seiClass);
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
Class[] ifaces = {seiClass, org.jboss.webservice.client.Stub.class};
return (Remote)Proxy.newProxyInstance(contextCL, ifaces, handler);
}
protected Remote getGeneratedStub(QName portName, Class proxyInterface) throws ServiceException
{
Remote stub = super.getGeneratedStub(portName, proxyInterface);
if (stub != null)
throw new ServiceException("Axis generated stubs not supported in WS4EE clients: " + stub.getClass().getName());
return null;
}
public void setCallProperties(Properties callProperties)
{
this.callProperties = callProperties;
}
public ServiceDescription getServiceDescription(String portName)
{
ServiceDescription serviceDesc = null;
if (serviceDescMap.size() == 1 && DEFAULT_PORT.equals(serviceDescMap.keySet().iterator().next()))
serviceDesc = (ServiceDescription)serviceDescMap.values().iterator().next();
else if (portName != null)
serviceDesc = (ServiceDescription)serviceDescMap.get(portName);
if (serviceDesc == null)
log.warn("Cannot get ServiceDescription for: portName=" + portName + " we have " + serviceDescMap.keySet());
return serviceDesc;
}
public Definition getWsdlDefinition()
{
return wsdlDefinition;
}
public void setWsdlDefinition(Definition wsdlDefinition)
{
this.wsdlDefinition = wsdlDefinition;
}
public JavaWsdlMapping getJavaWsdlMapping()
{
return javaWsdlMapping;
}
public void setJavaWsdlMapping(JavaWsdlMapping javaWsdlMapping)
{
this.javaWsdlMapping = javaWsdlMapping;
}
public Call createCall() throws ServiceException
{
CallImpl call = new CallImpl(this);
if (callProperties != null)
{
Iterator keys = callProperties.keySet().iterator();
while (keys.hasNext())
{
String key = (String)keys.next();
String value = callProperties.getProperty(key);
call.setProperty(key, value);
}
}
return call;
}
public Iterator getPorts() throws ServiceException
{
if (wsdlService == null)
throw new UnsupportedOperationException("wsdl service is not available");
return wsdlService.getPorts().keySet().iterator();
}
public QName getServiceName()
{
if (serviceName != null)
return serviceName;
if (wsdlService == null)
throw new UnsupportedOperationException("wsdl service is not available");
return wsdlService.getQName();
}
protected AxisClient getAxisClient()
{
if (engine == null)
{
engine = new ClientEngine(getEngineConfiguration());
}
return (AxisClient)engine;
}
protected EngineConfiguration getEngineConfiguration()
{
if (config == null)
{
config = EngineConfigurationFinder.getClientEngineConfiguration();
if (config == null)
throw new IllegalStateException("Cannot obtain client config");
}
return config;
}
protected Parser getParser()
{
Parser parser = super.getParser();
parser.setNowrap(true);
return parser;
}
protected String getTargetEnpointAddress()
{
return targetEndpointAddress;
}
public void setTargetEndpointAddress(String targetEndpointAddress)
{
this.targetEndpointAddress = targetEndpointAddress;
}
protected Port getWSDLPort(Class seiClass) throws ServiceException
{
if (wsdlService == null)
return null;
Map wsdlPorts = wsdlService.getPorts();
if (wsdlPorts == null || wsdlPorts.size() == 0)
throw new ServiceException("Cannot obtain wsdl wsdlPorts for service: " + wsdlService.getQName());
Port wsdlPort = null;
if (wsdlPorts.values().size() == 1)
{
wsdlPort = (Port)wsdlPorts.values().iterator().next();
return wsdlPort;
}
if (javaWsdlMapping != null)
{
log.debug("Trying to get jaxrpc port mapping for: " + seiClass.getName());
ServiceEndpointInterfaceMapping[] seiMappings = javaWsdlMapping.getServiceEndpointInterfaceMappings();
for (int i = 0; wsdlPort == null && i < seiMappings.length; i++)
{
ServiceEndpointInterfaceMapping seiMapping = seiMappings[i];
if (seiClass.getName().equals(seiMapping.getServiceEndpointInterface()))
{
QName bindingName = seiMapping.getWsdlBinding();
Iterator it = wsdlPorts.values().iterator();
while (wsdlPort == null && it.hasNext())
{
Port auxPort = (Port)it.next();
if (auxPort.getBinding().getQName().equals(bindingName))
wsdlPort = auxPort;
}
}
}
}
if (wsdlPort == null)
{
log.warn("Cannot obtain jaxrpc port mapping for: " + seiClass.getName());
wsdlPort = super.getWSDLPort(seiClass);
}
return wsdlPort;
}
private void setupTypeMapping(ServiceDescription serviceDesc) throws ServiceException
{
TypeMappingRegistry tmRegistry = super.getTypeMappingRegistry();
if (tmRegistry == null)
throw new IllegalStateException("Cannot obtain TypeMappingRegistry");
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Iterator it = serviceDesc.getTypMappings();
while (it.hasNext())
{
TypeMappingDescription typeMapping = (TypeMappingDescription)it.next();
QName typeQName = typeMapping.getTypeQName();
String javaType = typeMapping.getJavaType();
String encodingURI = typeMapping.getEncodingURI();
BeanXMLMetaData metaData = typeMapping.getMetaData();
TypeMapping tm = tmRegistry.getTypeMapping(encodingURI);
SerializerFactory serFactory = null;
DeserializerFactory desFactory = null;
try
{
Class typeClass = typeMapping.loadJavaType(cl);
if (typeClass != null)
{
String serFactoryName = typeMapping.getSerializerFactoryName();
String desFactoryName = typeMapping.getDeserializerFactoryName();
if (tm.isRegistered(typeClass, typeQName) == false || typeMapping.isUserDefined())
{
if (serFactoryName != null)
{
Class serFactoryClass = cl.loadClass(serFactoryName);
if (hasQualifiedConstructor(serFactoryClass))
{
Constructor ctor = serFactoryClass.getConstructor(new Class[]{Class.class, QName.class});
serFactory = (SerializerFactory)ctor.newInstance(new Object[]{typeClass, typeQName});
if (serFactory instanceof MetaDataBeanSerializerFactory)
((MetaDataBeanSerializerFactory)serFactory).setMetaData(metaData);
}
else
{
serFactory = (SerializerFactory)serFactoryClass.newInstance();
}
}
if (desFactoryName != null)
{
Class desFactoryClass = cl.loadClass(desFactoryName);
if (hasQualifiedConstructor(desFactoryClass))
{
Constructor ctor = desFactoryClass.getConstructor(new Class[]{Class.class, QName.class});
desFactory = (DeserializerFactory)ctor.newInstance(new Object[]{typeClass, typeQName});
if (desFactory instanceof MetaDataBeanDeserializerFactory)
((MetaDataBeanDeserializerFactory)desFactory).setMetaData(metaData);
}
else
{
desFactory = (DeserializerFactory)desFactoryClass.newInstance();
}
}
if (serFactory != null && desFactory != null)
{
log.debug("Register type mapping [qname=" + typeQName + ",class=" + javaType + "," + serFactoryName + "," + desFactoryName + "]");
tm.register(typeClass, typeQName, serFactory, desFactory);
}
}
else
{
log.debug("Ignore type mapping [qname=" + typeQName + ",class=" + javaType + "," + serFactoryName + "," + desFactoryName + "]");
}
}
}
catch (InvocationTargetException e)
{
log.error("Cannot setup type mapping", e.getTargetException());
throw new ServiceException(e.getTargetException());
}
catch (Exception e)
{
log.error("Cannot setup type mapping", e);
throw new ServiceException(e);
}
}
}
private boolean hasQualifiedConstructor(Class factoryClass)
{
try
{
Constructor ctor = factoryClass.getConstructor(new Class[]{Class.class, QName.class});
return ctor != null;
}
catch (Exception ignore)
{
}
return false;
}
}