/*
* Copyright (c) 2011, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* Licensed 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.wso2.carbon.bpel.core.ode.integration;
import org.apache.axiom.om.OMAbstractFactory;
import org.apache.axiom.soap.SOAP11Constants;
import org.apache.axiom.soap.SOAP12Constants;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axis2.AxisFault;
import org.apache.axis2.Constants;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.client.OperationClient;
import org.apache.axis2.context.ConfigurationContext;
import org.apache.axis2.context.MessageContext;
import org.apache.axis2.description.WSDL2Constants;
import org.apache.axis2.transport.http.HTTPConstants;
import org.apache.axis2.wsdl.WSDLConstants;
import org.apache.ode.bpel.epr.MutableEndpoint;
import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
import org.apache.ode.il.OMUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.wso2.carbon.bpel.core.ode.integration.axis2.WSDLAwareSOAPProcessor;
import org.wso2.carbon.bpel.core.ode.integration.utils.AxisServiceUtils;
import org.wso2.carbon.bpel.core.ode.integration.utils.Messages;
import java.util.List;
import javax.wsdl.Binding;
import javax.wsdl.BindingOperation;
import javax.wsdl.Definition;
import javax.wsdl.Port;
import javax.wsdl.Service;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.http.HTTPAddress;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.http.HTTPOperation;
import javax.xml.namespace.QName;
/**
* HTTP BindingHandler.
*/
public class HTTPBindingHandler {
private ConfigurationContext configurationContext;
private QName serviceName;
private String portName;
private Binding httpBinding;
private Definition wsdl;
public HTTPBindingHandler(ConfigurationContext configurationContext,
QName serviceName,
String portName,
Definition wsdl) throws AxisFault {
this.configurationContext = configurationContext;
this.serviceName = serviceName;
this.portName = portName;
this.wsdl = wsdl;
inferBinding();
}
public HTTPBindingResponse invoke(final PartnerRoleMessageExchange partnerRoleMessageExchange,
final BPELMessageContext bpelMessageContext) throws AxisFault {
MessageContext messageContext;
OperationClient operationClient = AxisServiceUtils.getOperationClient(bpelMessageContext,
configurationContext);
operationClient.getOptions().setAction("\"\"");
operationClient.getOptions().setExceptionToBeThrownOnSOAPFault(true);
addPropertyToOperationClient(operationClient,
WSDL2Constants.ATTR_WHTTP_QUERY_PARAMETER_SEPARATOR, "&");
addPropertyToOperationClient(operationClient, Constants.Configuration.ENABLE_REST, true);
addPropertyToOperationClient(operationClient,
Constants.Configuration.HTTP_METHOD, getVerb().trim());
addPropertyToOperationClient(operationClient,
WSDL2Constants.ATTR_WHTTP_LOCATION,
getHTTPLocation(partnerRoleMessageExchange.getOperationName()));
addPropertyToOperationClient(operationClient,
Constants.Configuration.CONTENT_TYPE, inferContentType(getVerb()));
addPropertyToOperationClient(operationClient,
Constants.Configuration.MESSAGE_TYPE, inferContentType(getVerb()));
SOAPEnvelope soapEnvelope =
getFactory(operationClient.getOptions().getSoapVersionURI()).getDefaultEnvelope();
messageContext = new MessageContext();
populateSOAPBody(soapEnvelope, partnerRoleMessageExchange);
messageContext.setEnvelope(soapEnvelope);
operationClient.addMessageContext(messageContext);
String mexEndpointUrl =
((MutableEndpoint) partnerRoleMessageExchange.getEndpointReference())
.getUrl();
if (!mexEndpointUrl.equals(getServiceLocation())) {
operationClient.getOptions().setTo(new EndpointReference(mexEndpointUrl));
}
operationClient.getOptions().setTo(bpelMessageContext.getUep());
operationClient.execute(true);
MessageContext responseMessageContext =
operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_IN_VALUE);
MessageContext faultMessageContext =
operationClient.getMessageContext(WSDLConstants.MESSAGE_LABEL_FAULT_VALUE);
return new HTTPBindingResponse(responseMessageContext, faultMessageContext);
}
private void populateSOAPBody(SOAPEnvelope soapEnvelope,
PartnerRoleMessageExchange partnerRoleMessageExchange) {
org.apache.ode.bpel.iapi.Message messageToSend = partnerRoleMessageExchange.getRequest();
if (messageToSend.getParts().size() == 1) {
soapEnvelope.getBody().addChild(OMUtils.toOM(
getPartContent(messageToSend.getPart(messageToSend.getParts().get(0))),
soapEnvelope.getOMFactory()));
} else {
throw new IllegalArgumentException("HTTP Binding doesn't support multiple message part as the input.");
}
}
private Element getPartContent(Element part) {
if (part.getFirstChild().getNodeType() == Node.ELEMENT_NODE) {
return (Element) part.getFirstChild();
}
throw new IllegalArgumentException("Cannot find message content in part element of ODE request to " +
"the external service.");
}
private static SOAPFactory getFactory(String soapVersionURI) {
if (SOAP11Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapVersionURI)) {
return OMAbstractFactory.getSOAP11Factory();
} else if (SOAP12Constants.SOAP_ENVELOPE_NAMESPACE_URI.equals(soapVersionURI)) {
return OMAbstractFactory.getSOAP12Factory();
} else {
throw new RuntimeException(org.apache.axis2.i18n.Messages
.getMessage("unknownsoapversion"));
}
}
private String getVerb() {
ExtensibilityElement extElement = WSDLAwareSOAPProcessor.getBindingExtension(httpBinding);
if (extElement instanceof HTTPBinding) {
return ((HTTPBinding) extElement).getVerb();
}
throw new IllegalArgumentException("Current binding is not a HTTP Binding.");
}
private String inferContentType(String httpVerb) {
if (httpVerb.trim().equals("GET") || httpVerb.trim().equals("DELETE")) {
return HTTPConstants.MEDIA_TYPE_X_WWW_FORM;
}
return HTTPConstants.MEDIA_TYPE_APPLICATION_XML;
}
private String getHTTPLocation(String operationName) {
for (Object bindingOperation : httpBinding.getBindingOperations()) {
if (((BindingOperation) bindingOperation).getName().equals(operationName)) {
List<Object> extElements = ((BindingOperation) bindingOperation).getExtensibilityElements();
if (extElements.size() == 0) {
throw new RuntimeException();
} else if (extElements.size() > 1) {
throw new RuntimeException();
} else {
return ((HTTPOperation) extElements.get(0)).getLocationURI();
}
}
}
throw new NullPointerException("HTTP Operation's location attribute is null.");
}
private void addPropertyToOperationClient(OperationClient operationClient,
String propertyKey,
Object propertyValue) {
operationClient.getOptions().setProperty(propertyKey, propertyValue);
}
protected void addPropertyToOperationClient(OperationClient operationClient,
String propertyKey,
boolean value) {
addPropertyToOperationClient(operationClient, propertyKey, Boolean.valueOf(value));
}
// protected void addPropertyToOperationClient(OperationClient operationClient,
// String propertyKey,
// int value) {
// addPropertyToOperationClient(operationClient, propertyKey, Integer.valueOf(value));
// }
private String getServiceLocation() {
for (Object extElement : getPortDefinition().getExtensibilityElements()) {
if (extElement instanceof HTTPAddress) {
return ((HTTPAddress) extElement).getLocationURI();
}
}
throw new NullPointerException("Service Location is null. Cannot find HTTP Address from WSDL definition");
}
private Port getPortDefinition() {
Service serviceDef = wsdl.getService(serviceName);
if (serviceDef == null) {
throw new NullPointerException(Messages.msgServiceDefinitionNotFound(
serviceName.getLocalPart()));
}
return serviceDef.getPort(portName);
}
private void inferBinding() {
Service serviceDef = wsdl.getService(serviceName);
if (serviceDef == null) {
throw new NullPointerException(Messages.msgServiceDefinitionNotFound(
serviceName.getLocalPart()));
}
Port port = serviceDef.getPort(portName);
if (port == null) {
throw new NullPointerException(Messages.msgServicePortNotFound(
serviceName.getLocalPart(), portName));
}
httpBinding = port.getBinding();
if (httpBinding == null) {
throw new NullPointerException(Messages.msgBindingNotFound(
serviceName.getLocalPart(), portName));
}
}
// private void populateAxisService() {
// service = AnonymousServiceFactory.getAnonymousService(serviceName,
// portName,
// configurationContext.getAxisConfiguration(), caller);
//
// String targetNamesapce = getTargetNamesapce();
//
// List<BindingOperation> bindingOperations = httpBinding.getBindingOperations();
// for (BindingOperation bindingOperation : bindingOperations) {
// String operationName = bindingOperation.getName();
// AxisOperation operation = createAxisOperation(operationName, targetNamesapce, isOutOnly
// (bindingOperation));
// operations.put(new QName(targetNamesapce, operationName), operation);
// service.addOperation(operation);
// }
// }
// private boolean isOutOnly(BindingOperation bindingOperation) {
// if (bindingOperation.getBindingInput() != null && bindingOperation.getBindingOutput() == null) {
// return true;
// } else if (bindingOperation.getBindingOutput() != null && bindingOperation.getBindingInput() == null) {
// throw new IllegalArgumentException("Outonly services are not supported.");
// }
//
// return false;
//
// }
// private String getTargetNamesapce() {
// return httpBinding.getQName().getNamespaceURI();
// }
//
// private AxisOperation createAxisOperation(String name, String nsUrl, boolean outOnly) {
// AxisOperation operation;
//
// if (outOnly) {
// operation = new OutOnlyAxisOperation();
// } else {
// operation = new OutInAxisOperation();
// }
//
// operation.setName(new QName(nsUrl, name));
// return operation;
// }
/**
* HTTPBindingResponse.
*/
public static class HTTPBindingResponse {
private MessageContext responseMessageContext;
private MessageContext faultMessageContext;
public HTTPBindingResponse(MessageContext responseMessageContext,
MessageContext faultMessageContext) {
this.responseMessageContext = responseMessageContext;
this.faultMessageContext = faultMessageContext;
}
public boolean isFault() {
return faultMessageContext != null;
}
public MessageContext getReponseMessageContext() {
return responseMessageContext;
}
public MessageContext getFaultMessageContext() {
return faultMessageContext;
}
}
}