package org.jboss.webservice.client;
import org.jboss.logging.Logger;
import org.jboss.mx.util.MBeanServerLocator;
import org.jboss.system.server.ServerConfig;
import org.jboss.webservice.AxisServiceMBean;
import org.jboss.webservice.PortComponentInfo;
import org.jboss.webservice.deployment.ServiceDescription;
import org.jboss.webservice.metadata.HandlerMetaData;
import org.jboss.webservice.metadata.InitParamMetaData;
import org.jboss.webservice.metadata.PortComponentRefMetaData;
import org.jboss.webservice.metadata.ServiceRefMetaData;
import org.jboss.webservice.metadata.jaxrpcmapping.JavaWsdlMapping;
import org.jboss.webservice.util.WSDLUtilities;
import javax.management.MBeanServer;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.spi.NamingManager;
import javax.naming.spi.ObjectFactory;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.xml.namespace.QName;
import javax.xml.rpc.JAXRPCException;
import javax.xml.rpc.handler.HandlerInfo;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.ObjectInputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Properties;
public class ServiceObjectFactory implements ObjectFactory
{
private static final Logger log = Logger.getLogger(ServiceObjectFactory.class);
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable environment)
throws Exception
{
Reference ref = (Reference)obj;
ServiceRefMetaData serviceRef = null;
RefAddr metaRefAddr = ref.get(ServiceReferenceable.SERVICE_REF_META_DATA);
ByteArrayInputStream bais = new ByteArrayInputStream((byte[])metaRefAddr.getContent());
try
{
ObjectInputStream ois = new ObjectInputStream(bais);
serviceRef = (ServiceRefMetaData)ois.readObject();
ois.close();
}
catch (IOException e)
{
throw new NamingException("Cannot unmarshall service ref meta data, cause: " + e.toString());
}
URL url = new URL((String)ref.get(ServiceReferenceable.DEPLOYMENT_URL).getContent());
ClassLoader contextCL = Thread.currentThread().getContextClassLoader();
URLClassLoader resourceCl = new URLClassLoader(new URL[]{url}, contextCL);
serviceRef.setResourceCl(resourceCl);
URL wsdlURL = serviceRef.getWsdlOverride();
if (wsdlURL == null && serviceRef.getWsdlFile() != null)
{
String wsdlFile = serviceRef.getWsdlFile();
wsdlURL = resourceCl.findResource(wsdlFile);
if (wsdlURL == null)
throw new NamingException("Cannot load wsdl file '" + wsdlFile + "' from: " + url);
}
JavaWsdlMapping javaWsdlMapping = serviceRef.getJavaWsdlMapping();
URL ws4eeMetaData = findTypeMappingMetaData(resourceCl);
ServiceImpl jaxrpcService = null;
Definition wsdlDefinition = null;
Service wsdlService = null;
if (wsdlURL != null)
{
log.debug("Create jaxrpc service for wsdl: " + wsdlURL);
wsdlDefinition = serviceRef.getWsdlDefinition();
QName serviceName = serviceRef.getServiceQName();
if (serviceName == null && wsdlDefinition.getServices().values().size() == 1)
serviceName = (QName)wsdlDefinition.getServices().keySet().iterator().next();
if (serviceName == null)
throw new IllegalStateException("Cannot obtain service name, use <service-qname> in your <service-ref>");
jaxrpcService = new ServiceImpl(wsdlURL, serviceName);
jaxrpcService.setWsdlDefinition(wsdlDefinition);
jaxrpcService.setJavaWsdlMapping(javaWsdlMapping);
wsdlService = getServiceForName(wsdlDefinition, serviceName);
}
else
{
log.debug("Create jaxrpc service with no wsdl");
jaxrpcService = new ServiceImpl();
jaxrpcService.setJavaWsdlMapping(javaWsdlMapping);
}
if (wsdlService != null)
{
PortComponentRefMetaData[] pcRefs = serviceRef.getPortComponentRefs();
if (pcRefs.length > 0)
{
for (int i = 0; i < pcRefs.length; i++)
{
PortComponentRefMetaData pcRef = pcRefs[i];
String seiName = pcRef.getServiceEndpointInterface();
QName portTypeQName = null;
if (javaWsdlMapping != null)
portTypeQName = javaWsdlMapping.getPortTypeQNameForServiceEndpointInterface(seiName);
List portNames = getPortNameForType(wsdlService, portTypeQName);
for (Iterator j = portNames.iterator(); j.hasNext();)
{
String portName = (String)j.next();
ServiceDescription serviceDesc = new ServiceDescription(wsdlDefinition, javaWsdlMapping, ws4eeMetaData, portName);
serviceDesc.setCallProperties(pcRef.getCallProperties());
jaxrpcService.initService(serviceDesc, portName);
}
}
}
else
{
ServiceDescription serviceDesc = new ServiceDescription(wsdlDefinition, javaWsdlMapping, ws4eeMetaData, null);
jaxrpcService.initService(serviceDesc, null);
}
setupHandlerChain(jaxrpcService, serviceRef, wsdlService);
}
Properties callProps = serviceRef.getCallProperties();
jaxrpcService.setCallProperties(callProps);
RefAddr pclinkRef = ref.get(ServiceReferenceable.PORT_COMPONENT_LINK);
if (pclinkRef != null)
{
String serviceID = (String)pclinkRef.getContent();
log.debug("Resolving port-component-link: " + serviceID);
String targetEndpointAddress = null;
try
{
MBeanServer server = MBeanServerLocator.locateJBoss();
PortComponentInfo pcInfo = (PortComponentInfo)server.invoke(AxisServiceMBean.OBJECT_NAME, "getPortComponentInfo",
new Object[]{serviceID}, new String[]{String.class.getName()});
targetEndpointAddress = pcInfo.getServiceEndpointURL();
}
catch (Exception ignore)
{
}
if (targetEndpointAddress == null)
{
String servletPath = (String)ref.get(ServiceReferenceable.PORT_COMPONENT_LINK_SERVLET).getContent();
servletPath += "?serviceID=" + URLEncoder.encode(serviceID, "UTF-8");
InputStream is = new URL(servletPath).openStream();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
targetEndpointAddress = br.readLine();
is.close();
}
log.debug("Resolved to: " + targetEndpointAddress);
jaxrpcService.setTargetEndpointAddress(targetEndpointAddress);
}
Class siClass = serviceRef.getServiceInterfaceClass();
if (javax.xml.rpc.Service.class.isAssignableFrom(siClass) == false)
throw new JAXRPCException("The service interface does not implement javax.xml.rpc.Service: " + siClass.getName());
PortComponentRefMetaData[] pcrArray = serviceRef.getPortComponentRefs();
for (int i = 0; i < pcrArray.length; i++)
{
PortComponentRefMetaData pcr = pcrArray[i];
Class seiClass = pcr.getServiceEndpointInterfaceClass();
if (java.rmi.Remote.class.isAssignableFrom(seiClass) == false)
throw new IllegalArgumentException("The SEI does not implement java.rmi.Remote: " + seiClass.getName());
if (wsdlDefinition != null)
WSDLUtilities.endorseServiceEndpointInterface(wsdlDefinition, seiClass, javaWsdlMapping);
}
InvocationHandler handler = new ServiceProxy(jaxrpcService, siClass);
return (javax.xml.rpc.Service)Proxy.newProxyInstance(contextCL, new Class[]{siClass}, handler);
}
private List getPortNameForType(javax.wsdl.Service wsdlService, QName portType)
{
List portNames = new ArrayList();
if (portType != null)
{
for (Iterator i = wsdlService.getPorts().values().iterator(); i.hasNext();)
{
Port wsdlPort = (Port)i.next();
if (wsdlPort.getBinding().getPortType().getQName().equals(portType))
portNames.add(wsdlPort.getName());
}
}
else if (wsdlService.getPorts().values().size() == 1)
{
for (Iterator i = wsdlService.getPorts().values().iterator(); i.hasNext();)
{
Port wsdlPort = (Port)i.next();
portNames.add(wsdlPort.getName());
}
}
if (portNames.isEmpty())
throw new IllegalArgumentException("Cannot obtatin portName for binding: " + portType);
return portNames;
}
private javax.wsdl.Service getServiceForName(Definition wsdlDefinition, QName serviceName)
{
javax.wsdl.Service wsdlService = null;
if (serviceName != null)
{
wsdlService = wsdlDefinition.getService(serviceName);
}
else if (wsdlDefinition.getServices().values().size() == 1)
{
wsdlService = (javax.wsdl.Service)wsdlDefinition.getServices().values().iterator().next();
}
if (wsdlService == null)
throw new IllegalArgumentException("Cannot obtain WSDL service for name: " + serviceName);
return wsdlService;
}
private URL findTypeMappingMetaData(URLClassLoader resourceCL)
{
URL resourceURL = null;
String dataDir = System.getProperty(ServerConfig.SERVER_DATA_DIR);
File resourceFile = new File(dataDir + "/wsdl/ws4ee-deployment.xml");
if (resourceFile.exists())
{
try
{
resourceURL = resourceFile.toURL();
}
catch (MalformedURLException e)
{
log.warn("Could not get url to ws4ee-deployment.xml.", e);
}
}
if (resourceURL == null)
{
String[] infDirs = new String[]{"META-INF", "WEB-INF"};
for (int i = 0; resourceURL == null && i < infDirs.length; i++)
{
String resName = infDirs[i] + "/ws4ee-deployment.xml";
resourceURL = resourceCL.findResource(resName);
}
}
return resourceURL;
}
private void setupHandlerChain(ServiceImpl jaxrpcService, ServiceRefMetaData serviceRef, javax.wsdl.Service wsdlService) throws Exception
{
HandlerMetaData[] handlers = serviceRef.getHandlers();
ClientEngine engine = (ClientEngine)jaxrpcService.getAxisClient();
Iterator itPorts = wsdlService.getPorts().values().iterator();
while (itPorts.hasNext())
{
Port wsdlPort = (Port)itPorts.next();
String portName = wsdlPort.getName();
ServiceDescription serviceDesc = jaxrpcService.getServiceDescription(portName);
if (serviceDesc != null)
{
HashSet handlerRoles = new HashSet();
ArrayList handlerInfos = new ArrayList();
for (int i = 0; i < handlers.length; i++)
{
HandlerMetaData hMetaData = handlers[i];
handlerRoles.addAll(Arrays.asList(hMetaData.getSoapRoles()));
List hPortNames = Arrays.asList(hMetaData.getPortNames());
if (hPortNames.size() == 0 || hPortNames.contains(portName))
{
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class hClass = cl.loadClass(hMetaData.getHandlerClass());
HashMap hConfig = new HashMap();
InitParamMetaData[] params = hMetaData.getInitParams();
for (int j = 0; j < params.length; j++)
{
InitParamMetaData param = params[j];
hConfig.put(param.getParamName(), param.getParamValue());
}
QName[] hHeaders = hMetaData.getSoapHeaders();
HandlerInfo info = new HandlerInfo(hClass, hConfig, hHeaders);
log.debug("Adding client side handler to port '" + portName + "': " + info);
handlerInfos.add(info);
}
}
if (handlerInfos.size() > 0)
engine.registerHandlerChain(portName, handlerInfos, handlerRoles);
}
}
}
}