/*
* Copyright (c) 2009, 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.b4p.utils;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMNode;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPHeader;
import org.apache.axis2.AxisFault;
import org.apache.axis2.addressing.EndpointReference;
import org.apache.axis2.context.MessageContext;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ode.axis2.OdeFault;
import org.apache.ode.bpel.common.FaultException;
import org.apache.ode.il.OMUtils;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.stl.CollectionsX;
import org.w3c.dom.Element;
import org.wso2.carbon.bpel.b4p.coordination.context.CoordinationContext;
import org.wso2.carbon.bpel.b4p.coordination.context.impl.HumanTaskCoordinationContextImpl;
import org.wso2.carbon.bpel.b4p.extension.BPEL4PeopleConstants;
import org.wso2.carbon.bpel.common.constants.Constants;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.wsdl.Binding;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Part;
import javax.wsdl.extensions.ElementExtensible;
import javax.wsdl.extensions.ExtensibilityElement;
import javax.wsdl.extensions.http.HTTPBinding;
import javax.wsdl.extensions.soap.SOAPBinding;
import javax.wsdl.extensions.soap.SOAPBody;
import javax.wsdl.extensions.soap12.SOAP12Binding;
import javax.xml.namespace.QName;
/**
* TODO: Analyze the implementation copied from ODE source.
*/
public class SOAPHelper {
private static Log log = LogFactory.getLog(SOAPHelper.class);
private Binding binding;
private SOAPFactory soapFactory;
private boolean isRPC;
public SOAPHelper(Binding binding, SOAPFactory soapFactory,
boolean isRPC) {
this.binding = binding;
this.soapFactory = soapFactory;
this.isRPC = isRPC;
}
public static ExtensibilityElement getBindingExtension(Binding binding) {
Collection bindings = new ArrayList();
CollectionsX.filter(bindings, binding.getExtensibilityElements(), HTTPBinding.class);
CollectionsX.filter(bindings, binding.getExtensibilityElements(), SOAPBinding.class);
CollectionsX.filter(bindings, binding.getExtensibilityElements(), SOAP12Binding.class);
if (bindings.size() == 0) {
return null;
} else if (bindings.size() > 1) {
// exception if multiple bindings found
throw new IllegalArgumentException("Multiple bindings: " + binding.getQName());
} else {
// retrieve the single element
return (ExtensibilityElement) bindings.iterator().next();
}
}
public static String parseResponseFeedback(org.apache.axiom.soap.SOAPBody soapBody) throws FaultException {
/* Sample feedback response
* <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Body><part><axis2ns3:correlation xmlns:axis2ns3="http://wso2.org/humantask/feedback">
<axis2ns3:taskid>10001</axis2ns3:taskid></axis2ns3:correlation></part></soapenv:Body></soapenv:Envelope>
* */
Iterator<OMElement> srcParts = soapBody.getChildElements();
if (srcParts.hasNext()) {
OMElement srcPart = srcParts.next();
if (!srcPart.getQName().equals(new QName(null, "part"))) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Unexpected element in SOAP body: " + srcPart.toString());
}
OMElement hifb = srcPart.getFirstChildWithName(
new QName(BPEL4PeopleConstants.B4P_NAMESPACE,
BPEL4PeopleConstants.B4P_CORRELATION_HEADER));
if (hifb == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Unexpected element in SOAP body: " + srcPart.toString());
}
OMElement taskIDele = hifb.getFirstChildWithName(
new QName(BPEL4PeopleConstants.B4P_NAMESPACE,
BPEL4PeopleConstants.B4P_CORRELATION_HEADER_ATTRIBUTE));
if (taskIDele == null) {
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"Unexpected element in SOAP body: " + srcPart.toString());
}
return taskIDele.getText();
// Document doc = DOMUtils.newDocument();
// Element destPart = doc.createElementNS(null, "part");
// destPart.appendChild(doc.importNode(OMUtils.toDOM(srcPart), true));
// message.setPart("part", destPart);
}
throw new FaultException(BPEL4PeopleConstants.B4P_FAULT,
"TaskID not found in the feedback message");
}
public static SOAPBody getSOAPBody(ElementExtensible ee) {
return getFirstExtensibilityElement(ee, SOAPBody.class);
}
public static <T> T getFirstExtensibilityElement(ElementExtensible parent, Class<T> cls) {
Collection<T> ee = CollectionsX.filter(parent.getExtensibilityElements(), cls);
return ee.isEmpty() ? null : ee.iterator().next();
}
/**
* Create a SOAP request and add a list of attachment ids to the SOAP Header
*
* @param msgCtx base message context which will be manipulated through out the operation
* @param message element to be included in the SOAP Body
* @param op operation incorporated with the request
* @param attachmentIDList list of attachment ids to be included in the SOAP header
* @throws AxisFault Exception if operation/input not found for the binding or if any exception thrown from
* the axis2 level operations
*/
public void createSoapRequest(MessageContext msgCtx, Element message, Operation op, List<Long> attachmentIDList)
throws AxisFault {
createSoapRequest(msgCtx, message, op);
SOAPHeader header = msgCtx.getEnvelope().getHeader();
if (attachmentIDList != null && !attachmentIDList.isEmpty()) {
addAttachmentIDHeader(header, attachmentIDList);
}
}
/**
* Adding ws-Coordination context to soap request.
*
* @param msgCtx MessageContext
* @param messageID UUID as a WS-Coordination identifier
* @param registrationService URL of the ws-coordination registration service.
*/
public void addCoordinationContext(MessageContext msgCtx, String messageID, String registrationService) {
SOAPHeader header = msgCtx.getEnvelope().getHeader();
EndpointReference epr = new EndpointReference();
epr.setAddress(registrationService);
CoordinationContext context = new HumanTaskCoordinationContextImpl(messageID, epr);
header.addChild(context.toOM());
}
public void addOverridingHumanTaskAttributes(MessageContext msgCtx, boolean isSkipable) {
SOAPHeader header = msgCtx.getEnvelope().getHeader();
OMNamespace omNs = soapFactory.createOMNamespace(
BPEL4PeopleConstants.HT_CONTEXT_NAMESPACE, BPEL4PeopleConstants.HT_CONTEXT_DEFAULT_PREFIX);
OMElement contextRequest = header.getFirstChildWithName(
new QName(BPEL4PeopleConstants.HT_CONTEXT_NAMESPACE, BPEL4PeopleConstants.HT_CONTEXT_REQUEST));
//If context element is not exist create new one.
if (contextRequest == null) {
contextRequest = soapFactory.createOMElement(BPEL4PeopleConstants.HT_CONTEXT_REQUEST, omNs);
}
OMElement isSkipableElement = soapFactory.createOMElement(BPEL4PeopleConstants.HT_CONTEXT_IS_SKIPABLE, omNs);
isSkipableElement.setText(Boolean.toString(isSkipable));
contextRequest.addChild(isSkipableElement);
header.addChild(contextRequest);
}
/**
* Adding the attachment ids iteratively to the SOAP Header
*
* @param header Header Element where the child elements going to be included
* @param attachmentIDList attachment ids
*/
private void addAttachmentIDHeader(SOAPHeader header, List<Long> attachmentIDList) {
final String namespace = Constants.ATTACHMENT_ID_NAMESPACE;
final String namespacePrefix = Constants.ATTACHMENT_ID_NAMESPACE_PREFIX;
final String parentElementName = Constants.ATTACHMENT_ID_PARENT_ELEMENT_NAME;
final String childElementName = Constants.ATTACHMENT_ID_CHILD_ELEMENT_NAME;
OMNamespace omNs = soapFactory.createOMNamespace(namespace, namespacePrefix);
OMElement headerElement = soapFactory.createOMElement(parentElementName, omNs);
for (Long id : attachmentIDList) {
OMElement idElement = soapFactory.createOMElement(childElementName, omNs);
idElement.setText(String.valueOf(id));
headerElement.addChild(idElement);
}
header.addChild(headerElement);
}
public void createSoapRequest(MessageContext msgCtx, Element message, Operation op)
throws AxisFault {
if (op == null) {
throw new NullPointerException("Null operation");
}
// The message can be null if the input message has no part
if (op.getInput().getMessage().getParts().size() > 0 && message == null) {
throw new NullPointerException("Null message.");
}
if (msgCtx == null) {
throw new NullPointerException("Null msgCtx");
}
BindingOperation bop = binding.getBindingOperation(op.getName(), null, null);
if (bop == null) {
throw new OdeFault("BindingOperation not found.");
}
BindingInput bi = bop.getBindingInput();
if (bi == null) {
throw new OdeFault("BindingInput not found.");
}
SOAPEnvelope soapEnv = msgCtx.getEnvelope();
if (soapEnv == null) {
soapEnv = soapFactory.getDefaultEnvelope();
msgCtx.setEnvelope(soapEnv);
}
// createSoapHeaders(soapEnv, getSOAPHeaders(bi), op.getInput().getMessage(), message);
SOAPBody soapBody = getSOAPBody(bi);
if (soapBody != null) {
org.apache.axiom.soap.SOAPBody sb = soapEnv.getBody() == null ?
soapFactory.createSOAPBody(soapEnv) : soapEnv.getBody();
createSoapBody(sb, soapBody, op.getInput().getMessage(), message, op.getName());
}
}
public void createSoapBody(org.apache.axiom.soap.SOAPBody sb, SOAPBody soapBody, Message msgDef,
Element message, String rpcWrapper) throws AxisFault {
OMElement partHolder = isRPC ? soapFactory
.createOMElement(new QName(soapBody.getNamespaceURI(), rpcWrapper, "odens"), sb) : sb;
List<Part> parts = msgDef.getOrderedParts(soapBody.getParts());
for (Part part : parts) {
Element srcPartEl = DOMUtils.findChildByName(message, new QName(null, part.getName()));
if (srcPartEl == null) {
throw new AxisFault("Missing required part in ODE Message");
}
OMElement omPart = OMUtils.toOM(srcPartEl, soapFactory);
if (isRPC) {
partHolder.addChild(omPart);
} else {
for (Iterator<OMNode> i = omPart.getChildren(); i.hasNext(); ) {
partHolder.addChild(i.next());
}
}
}
}
}