blob: 20f5e004cc10b26522025259ac65c391ddba6727 [file] [log] [blame]
/*
* 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;
}
}