/*
 * 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.ode.axis2.httpbinding;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.PutMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.StringRequestEntity;
import org.apache.commons.httpclient.params.HostParams;
import org.apache.commons.httpclient.params.HttpParams;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.ode.utils.Properties;
import org.apache.ode.axis2.util.URLEncodedTransformer;
import org.apache.ode.axis2.util.UrlReplacementTransformer;
import org.apache.ode.bpel.epr.MutableEndpoint;
import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
import org.apache.ode.utils.DOMUtils;
import org.apache.ode.utils.Namespaces;
import org.apache.ode.utils.http.HttpUtils;
import static org.apache.ode.utils.http.HttpUtils.bodyAllowed;
import static org.apache.ode.utils.http.StatusCode._202_ACCEPTED;
import org.apache.ode.utils.wsdl.Messages;
import org.apache.ode.utils.wsdl.WsdlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.SAXException;

import javax.wsdl.Binding;
import javax.wsdl.BindingInput;
import javax.wsdl.BindingOperation;
import javax.wsdl.BindingOutput;
import javax.wsdl.Definition;
import javax.wsdl.Fault;
import javax.wsdl.Message;
import javax.wsdl.Operation;
import javax.wsdl.Part;
import javax.wsdl.extensions.UnknownExtensibilityElement;
import javax.wsdl.extensions.http.HTTPOperation;
import javax.wsdl.extensions.mime.MIMEContent;
import javax.xml.namespace.QName;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.HashSet;

public class HttpMethodConverter {

    private static final Logger log = LoggerFactory.getLogger(HttpMethodConverter.class);

    protected static final Messages msgs = Messages.getMessages(Messages.class);
    protected Definition definition;
    protected Binding binding;
    protected QName serviceName;
    protected String portName;

    public HttpMethodConverter(Definition definition, QName serviceName, String portName) {
        this.definition = definition;
        this.binding = definition.getService(serviceName).getPort(portName).getBinding();
        this.serviceName = serviceName;
        this.portName = portName;
    }


    public HttpMethod createHttpRequest(PartnerRoleMessageExchange odeMex, HttpParams params) throws UnsupportedEncodingException {
        return createHttpRequest(odeMex, params, ((MutableEndpoint) odeMex.getEndpointReference()).getUrl());
    }

    public HttpMethod createHttpRequest(PartnerRoleMessageExchange odeMex, HttpParams params, String baseUrl) throws UnsupportedEncodingException {
        Operation operation = odeMex.getOperation();
        BindingOperation bindingOperation = binding.getBindingOperation(operation.getName(), operation.getInput().getName(), operation.getOutput().getName());

        // message to be sent
        Element message = odeMex.getRequest().getMessage();
        Message msgDef = operation.getInput().getMessage();

        // extract part values into a map and check that all parts are assigned a value
        Map<String, Element> partElements = extractPartElements(msgDef, message);

        // http method type
        // the operation may override the verb, this is an extension for RESTful BPEL
        String verb = WsdlUtils.resolveVerb(binding, bindingOperation);

        // build the http method itself
        HttpMethod method = prepareHttpMethod(bindingOperation, verb, partElements, odeMex.getRequest().getHeaderParts(), baseUrl, params);

        return method;
    }


    /**
     * create and initialize the http method.
     * Http Headers that may been passed in the params are not set in this method.
     * Headers will be automatically set by HttpClient.
     * See usages of HostParams.DEFAULT_HEADERS
     * See org.apache.commons.httpclient.HttpMethodDirector#executeMethod(org.apache.commons.httpclient.HttpMethod)
     */
    protected HttpMethod prepareHttpMethod(BindingOperation opBinding, String verb, Map<String, Element> partValues, Map<String, Node> headers,
                                           final String rootUri, HttpParams params) throws UnsupportedEncodingException {
        if (log.isDebugEnabled()) log.debug("Preparing http request...");
        // convenience variables...
        BindingInput bindingInput = opBinding.getBindingInput();
        HTTPOperation httpOperation = (HTTPOperation) WsdlUtils.getOperationExtension(opBinding);
        MIMEContent content = WsdlUtils.getMimeContent(bindingInput.getExtensibilityElements());
        String contentType = content == null ? null : content.getType();
        boolean useUrlEncoded = WsdlUtils.useUrlEncoded(bindingInput) || PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(contentType);
        boolean useUrlReplacement = WsdlUtils.useUrlReplacement(bindingInput);

        // the http method to be built and returned
        HttpMethod method = null;

        // the 4 elements the http method may be made of
        String relativeUri = httpOperation.getLocationURI();
        String queryPath = null;
        RequestEntity requestEntity;
        String encodedParams = null;

        // ODE supports uri template in both port and operation location.
        // so assemble the final url *before* replacement
        String completeUri = rootUri;
        if (StringUtils.isNotEmpty(relativeUri)) {
            completeUri = completeUri + (completeUri.endsWith("/") || relativeUri.startsWith("/") ? "" : "/") + relativeUri;
        }

        if (useUrlReplacement) {
            // insert part values in the url
            completeUri = new UrlReplacementTransformer().transform(completeUri, partValues);
        } else if (useUrlEncoded) {
            // encode part values
            encodedParams = new URLEncodedTransformer().transform(partValues);
        }

        // http-client api is not really neat
        // something similar to the following would save some if/else manipulations.
        // But we have to deal with it as-is.
        //
        //  method = new Method(verb);
        //  method.setRequestEnity(..)
        //  etc...
        if ("GET".equalsIgnoreCase(verb) || "DELETE".equalsIgnoreCase(verb)) {
            if ("GET".equalsIgnoreCase(verb)) {
                method = new GetMethod();
            } else if ("DELETE".equalsIgnoreCase(verb)) {
                method = new DeleteMethod();
            }
            method.getParams().setDefaults(params);
            if (useUrlEncoded) {
                queryPath = encodedParams;
            }

            // Let http-client manage the redirection
            // see org.apache.commons.httpclient.params.HttpClientParams.MAX_REDIRECTS
            // default is 100
            method.setFollowRedirects(true);
        } else if ("POST".equalsIgnoreCase(verb) || "PUT".equalsIgnoreCase(verb)) {

            if ("POST".equalsIgnoreCase(verb)) {
                method = new PostMethod();
            } else if ("PUT".equalsIgnoreCase(verb)) {
                method = new PutMethod();
            }
            method.getParams().setDefaults(params);
            // some body-building...
            final String contentCharset = method.getParams().getContentCharset();
            if (log.isDebugEnabled()) log.debug("Content-Type [" + contentType + "] Charset [" + contentCharset + "]");
            if (useUrlEncoded) {
                requestEntity = new StringRequestEntity(encodedParams, PostMethod.FORM_URL_ENCODED_CONTENT_TYPE, contentCharset);
            } else {
                // get the part to be put in the body
                Part part = opBinding.getOperation().getInput().getMessage().getPart(content.getPart());
                Element partValue = partValues.get(part.getName());

                if (part.getElementName() == null) {
                    String errMsg = "XML Types are not supported. Parts must use elements.";
                    if (log.isErrorEnabled()) log.error(errMsg);
                    throw new RuntimeException(errMsg);
                } else if (HttpUtils.isXml(contentType)) {
                    if (log.isDebugEnabled()) log.debug("Content-Type [" + contentType + "] equivalent to 'text/xml'");
                    // stringify the first element
                    String xmlString = DOMUtils.domToString(DOMUtils.getFirstChildElement(partValue));
                    requestEntity = new StringRequestEntity(xmlString, contentType, contentCharset);
                } else {
                    if (log.isDebugEnabled())
                        log.debug("Content-Type [" + contentType + "] NOT equivalent to 'text/xml'. The text content of part value will be sent as text");
                    // encoding conversion is managed by StringRequestEntity if necessary
                    requestEntity = new StringRequestEntity(DOMUtils.getTextContent(partValue), contentType, contentCharset);
                }
            }

            // cast safely, PUT and POST are subclasses of EntityEnclosingMethod
            final EntityEnclosingMethod enclosingMethod = (EntityEnclosingMethod) method;
            enclosingMethod.setRequestEntity(requestEntity);
            enclosingMethod.setContentChunked(params.getBooleanParameter(Properties.PROP_HTTP_REQUEST_CHUNK, false));

        } else {
            // should not happen because of HttpBindingValidator, but never say never
            throw new IllegalArgumentException("Unsupported HTTP method: " + verb);
        }

        method.setPath(completeUri); // assumes that the path is properly encoded (URL safe).
        method.setQueryString(queryPath);

        // set headers
        setHttpRequestHeaders(method, opBinding, partValues, headers, params);
        return method;
    }

    /**
     * First go through the list of default headers set in the method params. This param is then remove to avoid interference with HttpClient.
     * Actually the default headers should be overriden by any headers set from the process.
     * Not to mention that, for a given header, HttpClient do not overwrite any previous values but simply append the default value.<br/>
     *  See {@link see org.apache.commons.httpclient.params.HostParams.DEFAULT_HEADERS}
     * <p/>
     * Then go through the list of message headers and set them if empty.
     * <p/>
     * Finally go through the list of {@linkplain Namespaces.ODE_HTTP_EXTENSION_NS}{@code :header} elements included in the input binding.
     * For each of them, set the HTTP Request Header with the static value defined by the attribute {@linkplain Namespaces.ODE_HTTP_EXTENSION_NS}{@code :value},
     * or the part value mentioned in the attribute {@linkplain Namespaces.ODE_HTTP_EXTENSION_NS}{@code :part}.
     * <p/>
     * Finally, set the 'Accept' header if the output content type of the operation exists.
     * <p/>
     * Notice that the last header value overrides any values set previoulsy. Meaning that message headers might get overriden by parts bound to headers.
     *
     */
    public void setHttpRequestHeaders(HttpMethod method, BindingOperation opBinding, Map<String, Element> partValues, Map<String, Node> headers, HttpParams params) {
        BindingInput inputBinding = opBinding.getBindingInput();
        Message inputMessage = opBinding.getOperation().getInput().getMessage();

        // Do not let HttpClient manage the default headers
        // Actually the default headers should be overriden by any headers set from the process.
        // (Not to mention that, for a given header, HttpClient do not overwrite any previous values but simply append the default value)
        Collection defaultHeaders = (Collection) params.getParameter(HostParams.DEFAULT_HEADERS);
        if (defaultHeaders != null) {
            Iterator i = defaultHeaders.iterator();
            while (i.hasNext()) {
                method.setRequestHeader((Header) i.next());
            }
        }

        // process message headers
        for (Iterator<Map.Entry<String, Node>> iterator = headers.entrySet().iterator(); iterator.hasNext();) {
            Map.Entry<String, Node> e = iterator.next();
            String headerName = e.getKey();
            Node headerNode = e.getValue();
            String headerValue = DOMUtils.domToString(headerNode);
            method.setRequestHeader(headerName, HttpHelper.replaceCRLFwithLWS(headerValue));
        }

        // process parts that are bound to message parts
        Collection<UnknownExtensibilityElement> headerBindings = WsdlUtils.getHttpHeaders(inputBinding.getExtensibilityElements());
        for (Iterator<UnknownExtensibilityElement> iterator = headerBindings.iterator(); iterator.hasNext();) {
            Element binding = iterator.next().getElement();
            String headerName = binding.getAttribute("name");
            String partName = binding.getAttribute("part");
            String value = binding.getAttribute("value");

            /* Header binding may use a part or a static value */
            String headerValue;
            if (StringUtils.isNotEmpty(partName)) {
                // 'part' attribute is used
                // get the part to be put in the header
                Part part = inputMessage.getPart(partName);
                Element partWrapper = partValues.get(part.getName());
                if (DOMUtils.isEmptyElement(partWrapper)) {
                    headerValue = "";
                } else {
                    /*
                    The expected part value could be a simple type
                    or an element of a simple type.
                    So if a element is there, take its text content
                    else take the text content of the part element itself
                    */
                    Element childElement = DOMUtils.getFirstChildElement(partWrapper);
                    if (childElement != null) {
                        if (DOMUtils.getFirstChildElement(childElement) != null) {
                            String errMsg = "Complex types are not supported. Header Parts must be simple types or elements of a simple type.";
                            if (log.isErrorEnabled()) log.error(errMsg);
                            throw new RuntimeException(errMsg);
                        } else {
                            headerValue = DOMUtils.getTextContent(childElement);
                        }
                    } else {
                        headerValue = DOMUtils.getTextContent(partWrapper);
                    }
                }
            } else if (StringUtils.isNotEmpty(value)) {
                // 'value' attribute is used, this header is a static value
                headerValue = value;
            } else {
                String errMsg = "Invalid binding: missing attribute! Expecting " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "part") + " or " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "value");
                if (log.isErrorEnabled()) log.error(errMsg);
                throw new RuntimeException(errMsg);
            }
            // do not set the header isf the value is empty
            if (StringUtils.isNotEmpty(headerValue))
                method.setRequestHeader(headerName, HttpHelper.replaceCRLFwithLWS(headerValue));
        }

        MIMEContent outputContent = WsdlUtils.getMimeContent(opBinding.getBindingOutput().getExtensibilityElements());
        // set Accept header if output content type is set
        if (outputContent != null) {
            method.setRequestHeader("Accept", outputContent.getType());
        }

    }


    protected Map<String, Element> extractPartElements(Message msgDef, Element message) {
        if (msgDef.getParts().size() != 0 && message == null) {
            throw new IllegalArgumentException(msgs.msgOdeMessageExpected());
        }
        Map<String, Element> partValues = new HashMap<String, Element>();
        for (Iterator iterator = msgDef.getParts().values().iterator(); iterator.hasNext();) {
            Part part = (Part) iterator.next();
            Element partEl = DOMUtils.findChildByName(message, new QName(null, part.getName()));
            if (partEl == null)
                throw new IllegalArgumentException(msgs.msgOdeMessageMissingRequiredPart(part.getName()));
            partValues.put(part.getName(), partEl);
        }
        return partValues;
    }


    /**
     * Create the element to be associated with this part into the {@link org.apache.ode.bpel.iapi.Message}.
     * <br/>An element named with the part name will be returned. the content of this element depends on the part.
     * <p/>If the part has a non-null element name, a new element will be created and named accordingly then the text value is inserted in this new element.
     * <br/>else the given text content is simply set on the part element.
     *
     * @param part
     * @param textContent
     * @return an element named with the part name will be returned
     */
    public Element createPartElement(Part part, String textContent) {
        Document doc = DOMUtils.newDocument();
        Element partElement = doc.createElementNS(null, part.getName());
        if (part.getElementName() != null) {
            Element element = doc.createElementNS(part.getElementName().getNamespaceURI(), part.getElementName().getLocalPart());
            element.setTextContent(textContent);
            partElement.appendChild(element);
        } else {
            partElement.setTextContent(textContent);
        }
        return partElement;
    }


    /**
     * Create the element to be associated with this part into the {@link org.apache.ode.bpel.iapi.Message}.
     * <p/>If the part has a non-null element name, the bodyElement is simply appended.
     * Else if the bodyElement has a text content, the value is set to the message.
     * Else append all nodes of bodyElement to the returned element. Attributes are ignored.
     * <p/>
     * The name of the returned element is the part name.
     *
     * @param part
     * @param receivedElement
     * @return the element to insert "as is" to ODE message
     */
    public Element createPartElement(Part part, Element receivedElement) {
        Document doc = DOMUtils.newDocument();
        Element partElement = doc.createElementNS(null, part.getName());
        if (part.getElementName() != null) {
            partElement.appendChild(doc.importNode(receivedElement, true));
        } else {
            if (DOMUtils.isEmptyElement(receivedElement)) {
                // Append an empty text node.
                // Warning! setting an empty string with setTextContent has not effect. See javadoc.
                partElement.appendChild(doc.createTextNode(""));
            } else {
                // No need to make the distinction between simple and complex types, importNode will handle it
                // !!! Attributes are ignored
                for (int m = 0; m < receivedElement.getChildNodes().getLength(); m++) {
                    Node child = receivedElement.getChildNodes().item(m);
                    partElement.appendChild(doc.importNode(child, true));
                }
            }
        }
        return partElement;
    }

    /**
     * Process the HTTP Response Headers.
     * <p/>
     * First go through the list of {@linkplain Namespaces.ODE_HTTP_EXTENSION_NS}{@code :header} elements included in the output binding.
     * For each of them, set the header value as the value of the message part.
     * <p/>
     * Then add all HTTP headers as header part in the message. The name of the header would be the part name.
     * <p/>
     * Finally, insert a header names 'Status-Line'. This header contains an element as returned by {@link HttpHelper#statusLineToElement(String)} .
     *
     * @param odeMessage
     * @param method
     * @param operationDef
     */
    public void extractHttpResponseHeaders(org.apache.ode.bpel.iapi.Message odeMessage, HttpMethod method, Operation operationDef) {
        Message messageDef = operationDef.getOutput().getMessage();

        BindingOutput outputBinding = binding.getBindingOperation(operationDef.getName(), operationDef.getInput().getName(), operationDef.getOutput().getName()).getBindingOutput();
        Collection<UnknownExtensibilityElement> headerBindings = WsdlUtils.getHttpHeaders(outputBinding.getExtensibilityElements());

        // iterate through the list of header bindings
        // and set the message parts accordingly
        for (Iterator<UnknownExtensibilityElement> iterator = headerBindings.iterator(); iterator.hasNext();) {
            Element binding = iterator.next().getElement();
            String partName = binding.getAttribute("part");
            String headerName = binding.getAttribute("name");

            Part part = messageDef.getPart(partName);
            if (StringUtils.isNotEmpty(partName)) {
                Header responseHeader = method.getResponseHeader(headerName);
                // if the response header is not set, just skip it. no need to fail.
                if (responseHeader != null) {
                    odeMessage.setPart(partName, createPartElement(part, responseHeader.getValue()));
                }
            } else {
                String errMsg = "Invalid binding: missing required attribute! Part name: " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "part");
                if (log.isErrorEnabled()) log.error(errMsg);
                throw new RuntimeException(errMsg);
            }
        }

        // add all HTTP response headers (in their condensed form) into the message as header parts
        Set<String> headerNames = new HashSet<String>();
        for (Header header : method.getResponseHeaders()) headerNames.add(header.getName());
        for(String hname:headerNames) odeMessage.setHeaderPart(hname, method.getResponseHeader(hname).getValue());

        // make the status line information available as a single element
        odeMessage.setHeaderPart("Status-Line", HttpHelper.statusLineToElement(method.getStatusLine()));
    }

    public void parseHttpResponse(org.apache.ode.bpel.iapi.Message odeResponse, HttpMethod method, Operation opDef) throws SAXException, IOException {
        BindingOperation opBinding = binding.getBindingOperation(opDef.getName(), opDef.getInput().getName(), opDef.getOutput().getName());
        /* process headers */
        extractHttpResponseHeaders(odeResponse, method, opDef);

        /* process the body if any */

        // assumption is made that a response may have at most one body. HttpBindingValidator checks this.
        MIMEContent outputContent = WsdlUtils.getMimeContent(opBinding.getBindingOutput().getExtensibilityElements());
        int status = method.getStatusCode();

        boolean xmlExpected = outputContent != null && HttpUtils.isXml(outputContent.getType());
        // '202/Accepted' and '204/No Content' status codes explicitly state that there is no body, so we should not fail even if a part is bound to the body response
        boolean isBodyExpected = outputContent != null;
        boolean isBodyMandatory = isBodyExpected && bodyAllowed(status) && status != _202_ACCEPTED;
        final String body;
        try {
            body = method.getResponseBodyAsString();
        } catch (IOException e) {
            throw new RuntimeException("Unable to get the request body : " + e.getMessage());
        }

        final boolean emptyBody = StringUtils.isEmpty(body);
        if (emptyBody) {
            if (isBodyMandatory) {
                throw new RuntimeException("Response body is mandatory but missing!");
            }
        } else {
            if (isBodyExpected) {
                Part partDef = opDef.getOutput().getMessage().getPart(outputContent.getPart());
                Element partElement;

                if (xmlExpected) {

                    Header h = method.getResponseHeader("Content-Type");
                    String receivedType = h != null ? h.getValue() : null;
                    boolean contentTypeSet = receivedType != null;
                    boolean xmlReceived = contentTypeSet && HttpUtils.isXml(receivedType);

                    // a few checks
                    if (!contentTypeSet) {
                        if (log.isDebugEnabled())
                            log.debug("Received Response with a body but no 'Content-Type' header!");
                    } else if (!xmlReceived) {
                        if (log.isDebugEnabled())
                            log.debug("Xml type was expected but non-xml type received! Expected Content-Type=" + outputContent.getType() + " Received Content-Type=" + receivedType);
                    }

                    // parse the body and create the message part
                    Element bodyElement = DOMUtils.stringToDOM(body);
                    partElement = createPartElement(partDef, bodyElement);
                } else {
                    // if not xml, process it as text
                    partElement = createPartElement(partDef, body);
                }

                // set the part
                odeResponse.setPart(partDef.getName(), partElement);

            } else {
                // the body was not expected but we don't know how to deal with it
                if (log.isDebugEnabled()) log.debug("Body received but not mapped to any part! Body=\n" + body);
            }
        }
    }

    public Object[] parseFault(PartnerRoleMessageExchange odeMex, HttpMethod method) {
        Operation opDef = odeMex.getOperation();
        BindingOperation opBinding = binding.getBindingOperation(opDef.getName(), opDef.getInput().getName(), opDef.getOutput().getName());

        final String body;
        try {
            body = method.getResponseBodyAsString();
        } catch (IOException e) {
            throw new RuntimeException("Unable to get the request body : " + e.getMessage(), e);
        }
        Header h = method.getResponseHeader("Content-Type");
        String receivedType = h != null ? h.getValue() : null;
        if (opDef.getFaults().isEmpty()) {
            throw new RuntimeException("Operation [" + opDef.getName() + "] has no fault. This " + method.getStatusCode() + " error will be considered as a failure.");
        } else if (opBinding.getBindingFaults().isEmpty()) {
            throw new RuntimeException("No fault binding. This " + method.getStatusCode() + " error will be considered as a failure.");
        } else if (StringUtils.isEmpty(body)) {
            throw new RuntimeException("No body in the response. This " + method.getStatusCode() + " error will be considered as a failure.");
        } else if (receivedType != null && !HttpUtils.isXml(receivedType)) {
            throw new RuntimeException("Response Content-Type [" + receivedType + "] does not describe XML entities. Faults must be XML. This " + method.getStatusCode() + " error will be considered as a failure.");
        } else {

            if (receivedType == null) {
                if (log.isWarnEnabled())
                    log.warn("[Service: " + serviceName + ", Port: " + portName + ", Operation: " + opDef.getName() + "] Received Response with a body but no 'Content-Type' header! Will try to parse nevertheless.");
            }

            // try to parse body
            final Element bodyElement;
            try {
                bodyElement = DOMUtils.stringToDOM(body);
            } catch (Exception e) {
                throw new RuntimeException("Unable to parse the response body as xml. This " + method.getStatusCode() + " error will be considered as a failure.", e);
            }

            // Guess which fault it is
            QName bodyName = new QName(bodyElement.getNamespaceURI(), bodyElement.getNodeName());
            Fault faultDef = WsdlUtils.inferFault(opDef, bodyName);

            if (faultDef == null) {
                throw new RuntimeException("Unknown Fault Type [" + bodyName + "] This " + method.getStatusCode() + " error will be considered as a failure.");
            } else if (!WsdlUtils.isOdeFault(opBinding.getBindingFault(faultDef.getName()))) {
                // is this fault bound with ODE extension?
                throw new RuntimeException("Fault [" + bodyName + "] is not bound with " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "fault") + ". This " + method.getStatusCode() + " error will be considered as a failure.");
            } else {
                // a fault has only one part
                Part partDef = (Part) faultDef.getMessage().getParts().values().iterator().next();

                QName faultName = new QName(definition.getTargetNamespace(), faultDef.getName());
                QName faultType = faultDef.getMessage().getQName();

                // create the ODE Message now that we know the fault
                org.apache.ode.bpel.iapi.Message response = odeMex.createMessage(faultType);

                // build the element to be sent back
                Element partElement = createPartElement(partDef, bodyElement);
                response.setPart(partDef.getName(), partElement);

                // extract and set headers
                extractHttpResponseHeaders(response, method, opDef);
                return new Object[]{faultName, response};
            }
        }
    }

}

