/*
* JBoss, Home of Professional Open Source
* Copyright 2005, JBoss Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt 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.ws.metadata.builder.jaxws;
//$Id: JAXWSClientMetaDataBuilder.java 4119 2007-08-02 18:40:08Z thomas.diesler@jboss.com $
import java.io.IOException;
import java.net.URL;
import java.util.*;
import javax.jws.soap.SOAPBinding;
import javax.xml.namespace.QName;
import javax.xml.ws.BindingType;
import org.jboss.ws.Constants;
import org.jboss.ws.WSException;
import org.jboss.ws.core.jaxws.client.ServiceObjectFactoryJAXWS;
import org.jboss.ws.core.soap.Style;
import org.jboss.ws.extensions.policy.metadata.PolicyMetaDataBuilder;
import org.jboss.ws.metadata.umdm.ClientEndpointMetaData;
import org.jboss.ws.metadata.umdm.EndpointMetaData;
import org.jboss.ws.metadata.umdm.OperationMetaData;
import org.jboss.ws.metadata.umdm.ServiceMetaData;
import org.jboss.ws.metadata.umdm.UnifiedMetaData;
import org.jboss.ws.metadata.umdm.EndpointMetaData.Type;
import org.jboss.ws.metadata.wsdl.WSDLBinding;
import org.jboss.ws.metadata.wsdl.WSDLBindingOperation;
import org.jboss.ws.metadata.wsdl.WSDLDefinitions;
import org.jboss.ws.metadata.wsdl.WSDLEndpoint;
import org.jboss.ws.metadata.wsdl.WSDLInterface;
import org.jboss.ws.metadata.wsdl.WSDLInterfaceOperation;
import org.jboss.ws.metadata.wsdl.WSDLService;
import org.jboss.ws.metadata.wsdl.WSDLUtils;
import org.jboss.ws.metadata.wsdl.xmlschema.JBossXSModel;
import org.jboss.wsf.common.ResourceLoaderAdapter;
import org.jboss.wsf.spi.deployment.UnifiedVirtualFile;
import org.jboss.wsf.spi.metadata.j2ee.serviceref.UnifiedCallPropertyMetaData;
import org.jboss.wsf.spi.metadata.j2ee.serviceref.UnifiedPortComponentRefMetaData;
import org.jboss.wsf.spi.metadata.j2ee.serviceref.UnifiedServiceRefMetaData;
import org.jboss.wsf.spi.metadata.j2ee.serviceref.UnifiedStubPropertyMetaData;
import org.jboss.ws.annotation.EndpointConfig;
/**
* A client side meta data builder.
*
* @author Thomas.Diesler@jboss.org
* @since 19-May-2005
*/
public class JAXWSClientMetaDataBuilder extends JAXWSMetaDataBuilder
{
public ServiceMetaData buildMetaData(QName serviceName, URL wsdlURL, UnifiedVirtualFile vfsRoot)
{
if (wsdlURL == null)
throw new IllegalArgumentException("Invalid wsdlURL: " + wsdlURL);
log.debug("START buildMetaData: [service=" + serviceName + "]");
try
{
UnifiedMetaData wsMetaData = new UnifiedMetaData(vfsRoot);
ServiceMetaData serviceMetaData = new ServiceMetaData(wsMetaData, serviceName);
wsMetaData.addService(serviceMetaData);
serviceMetaData.setWsdlLocation(wsdlURL);
WSDLDefinitions wsdlDefinitions = serviceMetaData.getWsdlDefinitions();
buildMetaDataInternal(serviceMetaData, wsdlDefinitions);
//Setup policies for each endpoint
for (EndpointMetaData epMetaData : serviceMetaData.getEndpoints())
{
PolicyMetaDataBuilder policyBuilder = PolicyMetaDataBuilder.getClientSidePolicyMetaDataBuilder();
policyBuilder.processPolicyExtensions(epMetaData, wsdlDefinitions);
}
// Read the WSDL and initialize the schema model
// This should only be needed for debuging purposes of the UMDM
JBossXSModel schemaModel = WSDLUtils.getSchemaModel(wsdlDefinitions.getWsdlTypes());
serviceMetaData.getTypesMetaData().setSchemaModel(schemaModel);
log.debug("END buildMetaData: " + wsMetaData);
return serviceMetaData;
}
catch (RuntimeException rte)
{
throw rte;
}
catch (Exception ex)
{
throw new WSException("Cannot build meta data: " + ex.getMessage(), ex);
}
}
/** Build from WSDL and service name
*/
public ServiceMetaData buildMetaData(QName serviceName, URL wsdlURL)
{
return buildMetaData(serviceName, wsdlURL, new ResourceLoaderAdapter());
}
private void buildMetaDataInternal(ServiceMetaData serviceMetaData, WSDLDefinitions wsdlDefinitions) throws IOException
{
QName serviceName = serviceMetaData.getServiceName();
// Get the WSDL service
WSDLService wsdlService = null;
if (serviceName == null)
{
if (wsdlDefinitions.getServices().length != 1)
throw new IllegalArgumentException("Expected a single service element");
wsdlService = wsdlDefinitions.getServices()[0];
serviceMetaData.setServiceName(wsdlService.getName());
}
else
{
wsdlService = wsdlDefinitions.getService(serviceName);
}
if (wsdlService == null)
{
List<QName> serviceNames = new ArrayList<QName>();
for (WSDLService wsdls : wsdlDefinitions.getServices())
serviceNames.add(wsdls.getName());
throw new IllegalArgumentException("Cannot obtain wsdl service: " + serviceName + " we have " + serviceNames);
}
// Build endpoint meta data
for (WSDLEndpoint wsdlEndpoint : wsdlService.getEndpoints())
{
QName portName = wsdlEndpoint.getName();
QName interfaceQName = wsdlEndpoint.getInterface().getName();
ClientEndpointMetaData epMetaData = new ClientEndpointMetaData(serviceMetaData, portName, interfaceQName, Type.JAXWS);
epMetaData.setEndpointAddress(wsdlEndpoint.getAddress());
serviceMetaData.addEndpoint(epMetaData);
// Init the endpoint binding
initEndpointBinding(wsdlEndpoint, epMetaData);
// Init the service encoding style
initEndpointEncodingStyle(epMetaData);
setupOperationsFromWSDL(epMetaData, wsdlEndpoint);
// service-ref contributions
bufferServiceRefContributions(epMetaData);
}
}
/**
* Buffer portComponent information that it can be reused
* when rebuild is called (actually getPort(...))
* @param epMetaData
*/
private void bufferServiceRefContributions(EndpointMetaData epMetaData)
{
UnifiedServiceRefMetaData serviceRefMetaData = ServiceObjectFactoryJAXWS.getServiceRefAssociation();
if(serviceRefMetaData!=null)
{
for(UnifiedPortComponentRefMetaData portComp : serviceRefMetaData.getPortComponentRefs())
{
epMetaData.getServiceRefContrib().add(portComp);
}
}
}
/**
* ServiceRef deployment descriptor elements may override the endpoint metadata.
* @param epMetaData
*/
private void processServiceRefContributions(EndpointMetaData epMetaData)
{
Iterator<UnifiedPortComponentRefMetaData> it = epMetaData.getServiceRefContrib().iterator();
while(it.hasNext())
{
UnifiedPortComponentRefMetaData portComp = it.next();
if(epMetaData.matches(portComp))
{
log.debug("Processing service-ref contribution on portType: "+epMetaData.getPortTypeName());
// process MTOM overrides
if(portComp.getEnableMTOM())
{
String bindingId = epMetaData.getBindingId();
if(bindingId.equals(Constants.SOAP11HTTP_BINDING))
epMetaData.setBindingId(Constants.SOAP11HTTP_MTOM_BINDING);
else if(bindingId.equals(Constants.SOAP12HTTP_BINDING))
epMetaData.setBindingId(Constants.SOAP12HTTP_MTOM_BINDING);
}
// process stub properties
for(UnifiedStubPropertyMetaData stubProp: portComp.getStubProperties())
{
epMetaData.getProperties().put(stubProp.getPropName(), stubProp.getPropValue());
}
// process call properties
for(UnifiedCallPropertyMetaData callProp: portComp.getCallProperties())
{
epMetaData.getProperties().put(callProp.getPropName(), callProp.getPropValue());
}
}
}
}
protected void setupOperationsFromWSDL(EndpointMetaData epMetaData, WSDLEndpoint wsdlEndpoint)
{
WSDLDefinitions wsdlDefinitions = wsdlEndpoint.getInterface().getWsdlDefinitions();
// For every WSDL interface operation build the OperationMetaData
WSDLInterface wsdlInterface = wsdlEndpoint.getInterface();
for (WSDLInterfaceOperation wsdlOperation : wsdlInterface.getOperations())
{
String opName = wsdlOperation.getName().toString();
QName opQName = wsdlOperation.getName();
// Set java method name
String javaName = opName.substring(0, 1).toLowerCase() + opName.substring(1);
OperationMetaData opMetaData = new OperationMetaData(epMetaData, opQName, javaName);
epMetaData.addOperation(opMetaData);
// Set the operation style
String style = wsdlOperation.getStyle();
epMetaData.setStyle((Constants.URI_STYLE_DOCUMENT.equals(style) ? Style.DOCUMENT : Style.RPC));
// Set the operation MEP
if (Constants.WSDL20_PATTERN_IN_ONLY.equals(wsdlOperation.getPattern()))
opMetaData.setOneWay(true);
// Set the operation SOAPAction
WSDLBinding wsdlBinding = wsdlDefinitions.getBindingByInterfaceName(wsdlInterface.getName());
WSDLBindingOperation wsdlBindingOperation = wsdlBinding.getOperationByRef(opQName);
if (wsdlBindingOperation != null)
opMetaData.setSOAPAction(wsdlBindingOperation.getSOAPAction());
}
}
public void rebuildEndpointMetaData(EndpointMetaData epMetaData, Class<?> wsClass)
{
if(log.isDebugEnabled()) log.debug("START: rebuildMetaData");
// Clear the java types, etc.
resetMetaDataBuilder(epMetaData.getClassLoader());
// Nuke parameterStyle
epMetaData.setParameterStyle(null);
// Process an optional @BindingType annotation
if (wsClass.isAnnotationPresent(BindingType.class))
processBindingType(epMetaData, wsClass);
// Process @SOAPBinding
if (wsClass.isAnnotationPresent(SOAPBinding.class))
processSOAPBinding(epMetaData, wsClass);
// process config, this will as well setup the handler
processEndpointConfig(epMetaData, wsClass);
epMetaData.initEndpointConfig();
// Process an optional @HandlerChain annotation
processHandlerChain(epMetaData, wsClass);
// Process @WebMethod
processWebMethods(epMetaData, wsClass);
// Initialize types
createJAXBContext(epMetaData);
populateXmlTypes(epMetaData);
// Set SEI name
epMetaData.setServiceEndpointInterfaceName(wsClass.getName());
// service-ref contributions
processServiceRefContributions(epMetaData);
//epMetaData.getServiceRefContrib().clear();
// Eager initialization
epMetaData.eagerInitialize();
if(log.isDebugEnabled()) log.debug("END: rebuildMetaData\n" + epMetaData.getServiceMetaData());
}
/**
* Process config contribution through service endpoint interfaces
* @param epMetaData
* @param wsClass - the service endpoint interface
*/
private void processEndpointConfig(EndpointMetaData epMetaData, Class<?> wsClass)
{
if (wsClass.isAnnotationPresent(EndpointConfig.class))
{
EndpointConfig anConfig = wsClass.getAnnotation(EndpointConfig.class);
epMetaData.setConfigName(anConfig.configName(), anConfig.configFile());
}
}
}