/* * 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.security.AccessController; import java.security.PrivilegedAction; import java.util.Collection; import java.util.List; import javax.wsdl.Binding; import javax.wsdl.BindingOperation; import javax.wsdl.Definition; import javax.wsdl.Port; import javax.wsdl.extensions.soap.SOAPAddress; import javax.wsdl.extensions.soap.SOAPBinding; import javax.wsdl.extensions.soap.SOAPOperation; import javax.wsdl.extensions.soap12.SOAP12Address; import javax.wsdl.extensions.soap12.SOAP12Binding; import javax.xml.namespace.QName; import javax.xml.stream.FactoryConfigurationError; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; import javax.xml.transform.dom.DOMSource; import org.apache.axiom.om.OMAbstractFactory; import org.apache.axiom.om.OMElement; import org.apache.axiom.om.impl.builder.StAXOMBuilder; import org.apache.axiom.soap.SOAPFactory; import org.apache.axis2.AxisFault; import org.apache.axis2.addressing.EndpointReferenceHelper; import org.apache.axis2.client.Options; import org.apache.axis2.client.ServiceClient; import org.apache.axis2.description.AxisService; import org.apache.axis2.transport.http.HTTPConstants; import org.apache.axis2.util.threadpool.ThreadPool; import org.apache.commons.httpclient.HttpClient; import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager; import org.apache.commons.httpclient.params.HttpConnectionManagerParams; import org.apache.tuscany.sca.assembly.EndpointReference; import org.apache.tuscany.sca.assembly.xml.Constants; import org.apache.tuscany.sca.binding.ws.WebServiceBinding; import org.apache.tuscany.sca.binding.ws.axis2.transport.TransportReferenceInterceptor; import org.apache.tuscany.sca.core.ExtensionPointRegistry; import org.apache.tuscany.sca.interfacedef.InterfaceContract; import org.apache.tuscany.sca.interfacedef.Operation; import org.apache.tuscany.sca.invocation.InvocationChain; import org.apache.tuscany.sca.invocation.Invoker; import org.apache.tuscany.sca.invocation.Phase; import org.apache.tuscany.sca.policy.util.PolicyHelper; import org.apache.tuscany.sca.provider.EndpointReferenceProvider; import org.apache.tuscany.sca.provider.PolicyProvider; import org.apache.tuscany.sca.runtime.RuntimeComponent; import org.apache.tuscany.sca.runtime.RuntimeComponentReference; import org.apache.tuscany.sca.runtime.RuntimeEndpointReference; import org.oasisopen.sca.ServiceRuntimeException; public class Axis2ReferenceBindingProvider extends Axis2BaseBindingProvider implements EndpointReferenceProvider { // the endpoint reference configuration that's driving this binding provider // and some convenience data retrieved from the endpoint reference private RuntimeEndpointReference endpointReference; private RuntimeComponent component; private RuntimeComponentReference reference; private WebServiceBinding wsBinding; // The Axis2 configuration that the binding creates private ServiceClient serviceClient; private AxisService axisClientSideService; public Axis2ReferenceBindingProvider(ExtensionPointRegistry extensionPoints, EndpointReference endpointReference) { super(extensionPoints); this.endpointReference = (RuntimeEndpointReference)endpointReference; this.wsBinding = (WebServiceBinding)endpointReference.getBinding(); this.component = (RuntimeComponent)endpointReference.getComponent(); this.reference = (RuntimeComponentReference)endpointReference.getReference(); // A WSDL document should always be present in the binding if (wsBinding.getGeneratedWSDLDocument() == null) { throw new ServiceRuntimeException("No WSDL document for " + component.getName() + "/" + reference.getName()); } // Set to use the Axiom data binding InterfaceContract contract = wsBinding.getBindingInterfaceContract(); if (contract.getInterface() != null) { contract.getInterface().resetDataBinding(OMElement.class.getName()); } isSOAP11Required = PolicyHelper.isIntentRequired(wsBinding, Constants.SOAP11_INTENT); isSOAP12Required = PolicyHelper.isIntentRequired(wsBinding, Constants.SOAP12_INTENT); isMTOMRequired = PolicyHelper.isIntentRequired(wsBinding, Axis2BindingProviderFactory.MTOM_INTENT); // TODO - this is not correct as there may be other, custom, policies that // require rampart. For example this is not going to pick up the case // of external policy attachment isRampartRequired = PolicyHelper.isIntentRequired(wsBinding, Constants.AUTHENTICATION_INTENT) || PolicyHelper.isIntentRequired(wsBinding, Constants.CONFIDENTIALITY_INTENT) || PolicyHelper.isIntentRequired(wsBinding, Constants.INTEGRITY_INTENT); // Apply the configuration from any other policies for (PolicyProvider pp : this.endpointReference.getPolicyProviders()) { pp.configureBinding(this); } // check the WSDL style as we currently only support some of them if (wsBinding.isRpcEncoded()){ throw new ServiceRuntimeException("rpc/encoded WSDL style not supported. Component " + endpointReference.getComponent().getName() + " Reference " + endpointReference.getReference() + " Binding " + endpointReference.getBinding().getName()); } if (wsBinding.isDocEncoded()){ throw new ServiceRuntimeException("doc/encoded WSDL style not supported. Component " + endpointReference.getComponent().getName() + " Reference " + endpointReference.getReference() + " Binding " + endpointReference.getBinding().getName()); } if (wsBinding.isDocLiteralUnwrapped()){ //throw new ServiceRuntimeException("doc/literal/unwrapped WSDL style not supported for endpoint reference " + endpointReference); } // Validate that the WSDL is not using SOAP v1.2 if requires="SOAP.v1_1" has been specified if ( isSOAP11Required ) { Definition def = wsBinding.getGeneratedWSDLDocument(); Binding binding = def.getBinding(wsBinding.getBinding().getQName()); for ( Object ext : binding.getExtensibilityElements() ) { if ( ext instanceof SOAP12Binding ) throw new ServiceRuntimeException("WSDL document is using SOAP v1.2 but SOAP v1.1 " + "is required by the specified policy intents"); } } // Validate that the WSDL is not using SOAP v1.1 if requires="SOAP.v1_2" has been specified if ( isSOAP12Required ) { Definition def = wsBinding.getGeneratedWSDLDocument(); Binding binding = def.getBinding(wsBinding.getBinding().getQName()); for ( Object ext : binding.getExtensibilityElements() ) { if ( ext instanceof SOAPBinding ) throw new ServiceRuntimeException("WSDL document is using SOAP v1.1 but SOAP v1.2 " + "is required by the specified policy intents"); } } } public void start() { configContext = Axis2EngineIntegration.getAxisConfigurationContext(extensionPoints.getServiceDiscovery()); try { Definition definition = wsBinding.getGeneratedWSDLDocument(); QName serviceQName = wsBinding.getService().getQName(); Port port = wsBinding.getPort(); if (port == null) { // service has multiple ports, select one port to use // TODO - it feels like there is much more to this than is // here at the moment as need to match with the service side // assuming that it's available Collection<Port> ports = wsBinding.getService().getPorts().values(); for (Port p : ports) { // look for a SOAP 1.1 port first if (p.getExtensibilityElements().get(0) instanceof SOAPAddress) { port = p; break; } } if (port == null) { // no SOAP 1.1 port available, so look for a SOAP 1.2 port for (Port p : ports) { if (p.getExtensibilityElements().get(0) instanceof SOAP12Address) { port = p; break; } } } } axisClientSideService = Axis2EngineIntegration.createClientSideAxisService(definition, serviceQName, port.getName(), new Options()); HttpClient httpClient = (HttpClient)configContext.getProperty(HTTPConstants.CACHED_HTTP_CLIENT); if (httpClient == null) { MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager(); HttpConnectionManagerParams connectionManagerParams = new HttpConnectionManagerParams(); connectionManagerParams.setDefaultMaxConnectionsPerHost(2); connectionManagerParams.setTcpNoDelay(true); connectionManagerParams.setStaleCheckingEnabled(true); connectionManagerParams.setLinger(0); connectionManager.setParams(connectionManagerParams); httpClient = new HttpClient(connectionManager); configContext.setThreadPool(new ThreadPool(1, 5)); configContext.setProperty(HTTPConstants.REUSE_HTTP_CLIENT, Boolean.TRUE); configContext.setProperty(HTTPConstants.CACHED_HTTP_CLIENT, httpClient); } serviceClient = new ServiceClient(configContext, axisClientSideService); } catch (AxisFault e) { throw new RuntimeException(e); // TODO: better exception } } public void stop() { if (serviceClient != null) { // close all connections that we have initiated, so that the jetty server // can be restarted without seeing ConnectExceptions HttpClient httpClient = (HttpClient)serviceClient.getServiceContext().getConfigurationContext() .getProperty(HTTPConstants.CACHED_HTTP_CLIENT); if (httpClient != null) ((MultiThreadedHttpConnectionManager)httpClient.getHttpConnectionManager()).shutdown(); serviceClient = null; } } public InterfaceContract getBindingInterfaceContract() { return wsBinding.getBindingInterfaceContract(); } public boolean supportsOneWayInvocation() { return true; } public Invoker createInvoker(Operation operation) { Options options = new Options(); org.apache.axis2.addressing.EndpointReference epTo = getWSATOEPR(wsBinding); if (epTo != null) { options.setTo(epTo); } options.setProperty(HTTPConstants.CHUNKED, Boolean.FALSE); String operationName = operation.getName(); String soapAction = getSOAPAction(operationName); if (soapAction != null && soapAction.length() > 1) { options.setAction(soapAction); } options.setTimeOutInMilliSeconds(30 * 1000); // 30 seconds // Allow privileged access to read properties. Requires PropertiesPermission read in // security policy. SOAPFactory soapFactory = AccessController.doPrivileged(new PrivilegedAction<SOAPFactory>() { public SOAPFactory run() { if (isSOAP12Required) return OMAbstractFactory.getSOAP12Factory(); else return OMAbstractFactory.getSOAP11Factory(); } }); QName wsdlOperationQName = new QName(operationName); if (isMTOMRequired) { options.setProperty(org.apache.axis2.Constants.Configuration.ENABLE_MTOM, org.apache.axis2.Constants.VALUE_TRUE); } return new Axis2ReferenceBindingInvoker(endpointReference, serviceClient, wsdlOperationQName, options, soapFactory, wsBinding); /* if (operation.isNonBlocking()) { invoker = new Axis2OneWayBindingInvoker(this, wsdlOperationQName, options, soapFactory, wsBinding); } else { invoker = new Axis2BindingInvoker(endpointReference, serviceClient, wsdlOperationQName, options, soapFactory, wsBinding); } return invoker; */ } /* * set up the reference binding wire with the right set of ws reference * interceptors */ public void configure() { InvocationChain bindingChain = endpointReference.getBindingInvocationChain(); // add transport interceptor bindingChain.addInterceptor(Phase.REFERENCE_BINDING_TRANSPORT, new TransportReferenceInterceptor()); } // Reference specific utility operations protected org.apache.axis2.addressing.EndpointReference getWSATOEPR(WebServiceBinding binding) { org.apache.axis2.addressing.EndpointReference epr = getEPR(binding); if (epr == null) { epr = getPortLocationEPR(binding); } else if (epr.getAddress() == null || epr.getAddress().length() < 1) { org.apache.axis2.addressing.EndpointReference bindingEPR = getPortLocationEPR(binding); if (bindingEPR != null) { epr.setAddress(bindingEPR.getAddress()); } } return epr; } protected org.apache.axis2.addressing.EndpointReference getPortLocationEPR(WebServiceBinding binding) { String ep = null; if (binding.getPort() != null) { List<?> wsdlPortExtensions = binding.getPort().getExtensibilityElements(); for (final Object extension : wsdlPortExtensions) { if (extension instanceof SOAPAddress) { ep = ((SOAPAddress)extension).getLocationURI(); break; } if (extension instanceof SOAP12Address) { SOAP12Address address = (SOAP12Address)extension; ep = address.getLocationURI(); break; } } } if(ep == null || ep.equals("")) { ep = binding.getURI(); } return ep == null || "".equals(ep) ? null : new org.apache.axis2.addressing.EndpointReference(ep); } protected org.apache.axis2.addressing.EndpointReference getEPR(WebServiceBinding wsBinding) { if (wsBinding.getEndPointReference() == null) { return null; } try { XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(new DOMSource(wsBinding.getEndPointReference())); StAXOMBuilder builder = new StAXOMBuilder(parser); OMElement omElement = builder.getDocumentElement(); org.apache.axis2.addressing.EndpointReference epr = EndpointReferenceHelper.fromOM(omElement); return epr; } catch (IOException e) { throw new RuntimeException(e); } catch (XMLStreamException e) { throw new RuntimeException(e); } catch (FactoryConfigurationError e) { throw new RuntimeException(e); } } protected String getSOAPAction(String operationName) { Binding binding = wsBinding.getBinding(); if (binding != null) { for (Object o : binding.getBindingOperations()) { BindingOperation bop = (BindingOperation)o; if (bop.getName().equalsIgnoreCase(operationName)) { for (Object o2 : bop.getExtensibilityElements()) { if (o2 instanceof SOAPOperation) { return ((SOAPOperation)o2).getSoapActionURI(); } } } } } return null; } }