/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.tuscany.sca.binding.ws.axis2.provider; import java.io.IOException; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.security.AccessController; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Vector; import javax.wsdl.Definition; import javax.wsdl.Import; import javax.wsdl.Port; import javax.wsdl.Types; import javax.wsdl.extensions.UnknownExtensibilityElement; import javax.wsdl.extensions.soap.SOAPAddress; import javax.wsdl.extensions.soap12.SOAP12Address; import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.stream.XMLInputFactory; import org.apache.axis2.AxisFault; import org.apache.axis2.Constants; import org.apache.axis2.addressing.AddressingConstants; import org.apache.axis2.addressing.EndpointReference; import org.apache.axis2.client.Options; import org.apache.axis2.context.ConfigurationContext; import org.apache.axis2.context.ConfigurationContextFactory; import org.apache.axis2.deployment.URLBasedAxisConfigurator; import org.apache.axis2.deployment.util.Utils; import org.apache.axis2.description.AxisEndpoint; import org.apache.axis2.description.AxisOperation; import org.apache.axis2.description.AxisService; import org.apache.axis2.description.Parameter; import org.apache.axis2.description.WSDL11ToAxisServiceBuilder; import org.apache.axis2.description.WSDL2Constants; import org.apache.axis2.description.WSDLToAxisServiceBuilder; import org.apache.axis2.engine.MessageReceiver; import org.apache.axis2.transport.local.LocalResponder; import org.apache.tuscany.sca.assembly.AbstractContract; import org.apache.tuscany.sca.binding.ws.WebServiceBinding; import org.apache.tuscany.sca.common.xml.XMLDocumentHelper; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.extensibility.ClassLoaderContext; import org.apache.tuscany.sca.extensibility.ServiceDiscovery; import org.apache.tuscany.sca.interfacedef.Interface; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.interfacedef.java.JavaInterface; import org.apache.tuscany.sca.interfacedef.wsdl.WSDLDefinition; import org.apache.tuscany.sca.runtime.RuntimeEndpoint; import org.apache.tuscany.sca.xsd.XSDefinition; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaExternal; import org.apache.ws.commons.schema.resolver.URIResolver; import org.oasisopen.sca.ServiceRuntimeException; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; public class Axis2EngineIntegration { //========================================================= // most of the following is related to rewriting WSDL imports // I'd like to move this but don't know where to yet. public static final String IMPORT_TAG = "import"; public static final String INCLUDE_TAG = "include"; public static final QName QNAME_WSA_ADDRESS = new QName(AddressingConstants.Final.WSA_NAMESPACE, AddressingConstants.EPR_ADDRESS); public static final QName QNAME_WSA_FROM = new QName(AddressingConstants.Final.WSA_NAMESPACE, AddressingConstants.WSA_FROM); public static final QName QNAME_WSA_REFERENCE_PARAMETERS = new QName(AddressingConstants.Final.WSA_NAMESPACE, AddressingConstants.EPR_REFERENCE_PARAMETERS); //Schema element names public static final String ELEM_SCHEMA = "schema"; //Schema URI public static final String NS_URI_XSD_1999 = "http://www.w3.org/1999/XMLSchema"; public static final String NS_URI_XSD_2000 = "http://www.w3.org/2000/10/XMLSchema"; public static final String NS_URI_XSD_2001 = "http://www.w3.org/2001/XMLSchema"; //Schema QNames public static final QName Q_ELEM_XSD_1999 = new QName(NS_URI_XSD_1999, ELEM_SCHEMA); public static final QName Q_ELEM_XSD_2000 = new QName(NS_URI_XSD_2000, ELEM_SCHEMA); public static final QName Q_ELEM_XSD_2001 = new QName(NS_URI_XSD_2001, ELEM_SCHEMA); public static final List<QName> XSD_QNAME_LIST = Arrays.asList(new QName[] {Q_ELEM_XSD_1999, Q_ELEM_XSD_2000, Q_ELEM_XSD_2001}); //========================================================= /* * Create the whole configuration context for the Axis engine */ private static class Axis2Config { private ClassLoaderContext classLoaderContext; private URL axis2xmlURL; private URL repositoryURL; } // Cache the discovered axis2 configuration but we need to create a new instance of ConfigurationContext every time private static Axis2Config axis2Config; public synchronized static ConfigurationContext getAxisConfigurationContext(final ServiceDiscovery serviceDiscovery) { // get the axis configuration context from the Tuscany axis2.xml file // Allow privileged access to read properties. Requires PropertyPermission read in // security policy. if (axis2Config == null) { try { axis2Config = AccessController.doPrivileged(new PrivilegedExceptionAction<Axis2Config>() { public Axis2Config run() throws AxisFault, MalformedURLException { // collect together the classloaders that Axis2 requireds in order to load // pluggable items such as the Tuscany MessageReceivers and the xerces // document builder. ClassLoader wsBindingCL = getClass().getClassLoader(); ClassLoader axis2CL = URLBasedAxisConfigurator.class.getClassLoader(); ClassLoader localtransportCL = LocalResponder.class.getClassLoader(); ClassLoaderContext classLoaderContext = new ClassLoaderContext(wsBindingCL, axis2CL, localtransportCL); classLoaderContext = new ClassLoaderContext(classLoaderContext.getClassLoader(), serviceDiscovery, XMLInputFactory.class, DocumentBuilderFactory.class); URL axis2xmlURL = wsBindingCL .getResource("org/apache/tuscany/sca/binding/ws/axis2/engine/conf/tuscany-axis2.xml"); if (axis2xmlURL != null) { URL repositoryURL = new URL(axis2xmlURL, "../repository/"); Axis2Config config = new Axis2Config(); config.classLoaderContext = classLoaderContext; config.axis2xmlURL = axis2xmlURL; config.repositoryURL = repositoryURL; return config; } else { return null; } } }); } catch (PrivilegedActionException e) { throw new ServiceRuntimeException(e.getException()); } } if (axis2Config == null) { return null; } try { return AccessController.doPrivileged(new PrivilegedExceptionAction<ConfigurationContext>() { public ConfigurationContext run() throws AxisFault { ClassLoader oldTCCL = axis2Config.classLoaderContext.setContextClassLoader(); try { ConfigurationContext configurationContext = ConfigurationContextFactory.createConfigurationContextFromURIs(axis2Config.axis2xmlURL, axis2Config.repositoryURL); return configurationContext; } finally { if (oldTCCL != null) { Thread.currentThread().setContextClassLoader(oldTCCL); } } } }); } catch (PrivilegedActionException e) { throw new ServiceRuntimeException(e.getException()); } } //========================================================= /** * Create an AxisService from the Java interface class of the SCA service interface */ public static AxisService createJavaAxisService(String endpointURL, ConfigurationContext configContext, AbstractContract contract) throws AxisFault { AxisService axisService = new AxisService(); String path = URI.create(endpointURL).getPath(); axisService.setName(path); axisService.setServiceDescription("Tuscany configured AxisService for service: " + endpointURL); axisService.setClientSide(false); Parameter classParam = new Parameter(Constants.SERVICE_CLASS, ((JavaInterface)contract.getInterfaceContract().getInterface()).getJavaClass().getName()); axisService.addParameter(classParam); try { Utils.fillAxisService(axisService, configContext.getAxisConfiguration(), null, null); } catch (Exception e) { throw new RuntimeException(e); } return axisService; } //========================================================= /** * Create an AxisService from the WSDL doc used by ws binding */ public static AxisService createWSDLAxisService(String endpointURL, Port port, WebServiceBinding wsBinding) throws AxisFault { Definition definition = wsBinding.getGeneratedWSDLDocument(); QName serviceQName = wsBinding.getService().getQName(); Definition def = getDefinition(definition, serviceQName); final WSDLToAxisServiceBuilder builder = new WSDL11ToAxisServiceBuilder(def, serviceQName, port.getName()); builder.setServerSide(true); // [rfeng] Add a custom resolver to work around WSCOMMONS-228 // TODO - 228 is resolved, is this still required builder.setCustomResolver(new URIResolverImpl(def)); builder.setBaseUri(def.getDocumentBaseURI()); // [rfeng] // AxisService axisService = builder.populateService(); // Allow privileged access to read properties. Requires PropertiesPermission read in // security policy. AxisService axisService; try { axisService = AccessController.doPrivileged(new PrivilegedExceptionAction<AxisService>() { public AxisService run() throws AxisFault { return builder.populateService(); } }); } catch (PrivilegedActionException e) { throw (AxisFault)e.getException(); } String name = URI.create(endpointURL).getPath(); //[nash] HTTP endpoints need a leading slash for WSDL imports to work with ?wsdl if (endpointURL.startsWith("jms")) { name = name.startsWith("/") ? name.substring(1) : name; } axisService.setName(name); axisService.setEndpointURL(endpointURL); axisService.setDocumentation("Tuscany configured AxisService for service: " + endpointURL); // TODO - again, do we ever have more than one endpoint // on the service side? for (Iterator i = axisService.getEndpoints().values().iterator(); i.hasNext();) { AxisEndpoint ae = (AxisEndpoint)i.next(); if (endpointURL.startsWith("jms")) { // not in Axis2 1.5.1 // Parameter qcf = new Parameter(JMSConstants.CONFAC_PARAM, null); // qcf.setValue(DEFAULT_QUEUE_CONNECTION_FACTORY); // axisService.addParameter(qcf); break; } } // Add schema information to the AxisService (needed for "?xsd=" support) addSchemas(wsBinding.getUserSpecifiedWSDLDefinition(), axisService); // Use the existing WSDL Parameter wsdlParam = new Parameter("wsdl4jDefinition", null); wsdlParam.setValue(definition); axisService.addParameter(wsdlParam); Parameter userWSDL = new Parameter("useOriginalwsdl", "true"); axisService.addParameter(userWSDL); // Modify schema imports and includes to add "servicename?xsd=" prefix. // Axis2 does this for schema extensibility elements, but Tuscany has // overriden the WSDl4J deserializer to create UnknownExtensibilityElement // elements in place of these. modifySchemaImportsAndIncludes(definition, name); // Axis2 1.3 has a bug with returning incorrect values for the port // addresses. To work around this, compute the values here. Parameter modifyAddr = new Parameter("modifyUserWSDLPortAddress", "false"); axisService.addParameter(modifyAddr); return axisService; } /** * Workaround for https://issues.apache.org/jira/browse/AXIS2-3205 */ private static Definition getDefinition(Definition definition, QName serviceName) { if (serviceName == null) { return definition; } if (definition == null) { return null; } Object service = definition.getServices().get(serviceName); if (service != null) { return definition; } for (Object i : definition.getImports().values()) { List<Import> imports = (List<Import>)i; for (Import imp : imports) { Definition d = getDefinition(imp.getDefinition(), serviceName); if (d != null) { return d; } } } return null; } private static void addSchemas(WSDLDefinition wsdlDef, AxisService axisService) { for (XSDefinition xsDef : wsdlDef.getXmlSchemas()) { if (xsDef.getSchema() != null) { axisService.addSchema(xsDef.getSchema()); updateSchemaRefs(xsDef.getSchema(), axisService.getName()); } } for (WSDLDefinition impDef : wsdlDef.getImportedDefinitions()) { addSchemas(impDef, axisService); } } private static void updateSchemaRefs(XmlSchema parentSchema, String name) { for (Iterator iter = parentSchema.getIncludes().getIterator(); iter.hasNext();) { Object obj = iter.next(); if (obj instanceof XmlSchemaExternal) { XmlSchemaExternal extSchema = (XmlSchemaExternal)obj; String location = extSchema.getSchemaLocation(); if (location.length() > 0 && location.indexOf(":/") < 0 && location.indexOf("?xsd=") < 0) { extSchema.setSchemaLocation(name + "?xsd=" + location); } if (extSchema.getSchema() != null) { updateSchemaRefs(extSchema.getSchema(), name); } } } } private static void modifySchemaImportsAndIncludes(Definition definition, String name) { // adjust the schema locations in types section Types types = definition.getTypes(); if (types != null) { for (Iterator iter = types.getExtensibilityElements().iterator(); iter.hasNext();) { Object ext = iter.next(); if (ext instanceof UnknownExtensibilityElement && XSD_QNAME_LIST .contains(((UnknownExtensibilityElement)ext).getElementType())) { changeLocations(((UnknownExtensibilityElement)ext).getElement(), name); } } } for (Iterator iter = definition.getImports().values().iterator(); iter.hasNext();) { Vector values = (Vector)iter.next(); for (Iterator valuesIter = values.iterator(); valuesIter.hasNext();) { Import wsdlImport = (Import)valuesIter.next(); modifySchemaImportsAndIncludes(wsdlImport.getDefinition(), name); } } } private static void changeLocations(Element element, String name) { NodeList nodeList = element.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { String tagName = nodeList.item(i).getLocalName(); if (IMPORT_TAG.equals(tagName) || INCLUDE_TAG.equals(tagName)) { processImport(nodeList.item(i), name); } } } private static void processImport(Node importNode, String name) { NamedNodeMap nodeMap = importNode.getAttributes(); for (int i = 0; i < nodeMap.getLength(); i++) { Node attribute = nodeMap.item(i); if (attribute.getNodeName().equals("schemaLocation")) { String location = attribute.getNodeValue(); if (location.indexOf(":/") < 0 & location.indexOf("?xsd=") < 0) { attribute.setNodeValue(name + "?xsd=" + location); } } } } //========================================================= /* * Create the service message receivers and the service provider that will push * messages out onto the binding wire */ public static void createAxisServiceProviders(AxisService axisService, RuntimeEndpoint endpoint, WebServiceBinding wsBinding, ExtensionPointRegistry extensionPoints) { for (Iterator<?> i = axisService.getOperations(); i.hasNext();) { AxisOperation axisOp = (AxisOperation)i.next(); Operation op = getOperation(axisOp, wsBinding); if (op != null) { if (op.isNonBlocking()) { axisOp.setMessageExchangePattern(WSDL2Constants.MEP_URI_IN_ONLY); } else { axisOp.setMessageExchangePattern(WSDL2Constants.MEP_URI_IN_OUT); } MessageReceiver msgrec = null; TuscanyServiceProvider serviceProvider = new TuscanyServiceProvider(extensionPoints, endpoint, wsBinding, op); if (op.isNonBlocking()) { msgrec = new Axis2ServiceInMessageReceiver(serviceProvider); } else { msgrec = new Axis2ServiceInOutSyncMessageReceiver(serviceProvider); } axisOp.setMessageReceiver(msgrec); } } } private static Operation getOperation(AxisOperation axisOp,WebServiceBinding wsBinding) { String operationName = axisOp.getName().getLocalPart(); Interface iface = wsBinding.getBindingInterfaceContract().getInterface(); for (Operation op : iface.getOperations()) { if (op.getName().equalsIgnoreCase(operationName)) { return op; } } return null; } //========================================================= public static String getPortAddress(Port port) { Object ext = port.getExtensibilityElements().get(0); if (ext instanceof SOAPAddress) { return ((SOAPAddress)ext).getLocationURI(); } if (ext instanceof SOAP12Address) { return ((SOAP12Address)ext).getLocationURI(); } return null; } public static void setPortAddress(Port port, String locationURI) { Object ext = port.getExtensibilityElements().get(0); if (ext instanceof SOAPAddress) { ((SOAPAddress)ext).setLocationURI(locationURI); } if (ext instanceof SOAP12Address) { ((SOAP12Address)ext).setLocationURI(locationURI); } } /** * This method is copied from AxisService.createClientSideAxisService to * work around http://issues.apache.org/jira/browse/WSCOMMONS-228 * * @param wsdlDefinition * @param wsdlServiceName * @param portName * @param options * @return * @throws AxisFault */ @Deprecated public static AxisService createClientSideAxisService(Definition definition, QName serviceName, String portName, Options options) throws AxisFault { Definition def = getDefinition(definition, serviceName); final WSDL11ToAxisServiceBuilder serviceBuilder = new WSDL11ToAxisServiceBuilder(def, serviceName, portName); serviceBuilder.setServerSide(false); // [rfeng] Add a custom resolver to work around WSCOMMONS-228 serviceBuilder.setCustomResolver(new URIResolverImpl(def)); serviceBuilder.setBaseUri(def.getDocumentBaseURI()); // [rfeng] // Allow access to read properties. Requires PropertiesPermission in security policy. AxisService axisService; try { axisService = AccessController.doPrivileged(new PrivilegedExceptionAction<AxisService>() { public AxisService run() throws AxisFault { return serviceBuilder.populateService(); } }); } catch ( PrivilegedActionException e ) { throw (AxisFault) e.getException(); } AxisEndpoint axisEndpoint = (AxisEndpoint)axisService.getEndpoints().get(axisService.getEndpointName()); options.setTo(new EndpointReference(axisEndpoint.getEndpointURL())); if (axisEndpoint != null) { options.setSoapVersionURI((String)axisEndpoint.getBinding().getProperty(WSDL2Constants.ATTR_WSOAP_VERSION)); } return axisService; } /** * URI resolver implementation for XML schema */ public static class URIResolverImpl implements URIResolver { private Definition definition; public URIResolverImpl(Definition definition) { this.definition = definition; } public org.xml.sax.InputSource resolveEntity(java.lang.String targetNamespace, java.lang.String schemaLocation, java.lang.String baseUri) { try { if (baseUri == null) { baseUri = definition.getDocumentBaseURI(); } URL url = new URL(new URL(baseUri), schemaLocation); return XMLDocumentHelper.getInputSource(url); } catch (IOException e) { return null; } } } }