You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ode.apache.org by mi...@apache.org on 2008/06/25 20:41:27 UTC

svn commit: r671630 [1/2] - in /ode/trunk: axis2/src/main/java/org/apache/ode/axis2/httpbinding/ axis2/src/main/java/org/apache/ode/axis2/soapbinding/ axis2/src/main/java/org/apache/ode/axis2/util/ axis2/src/test/java/org/apache/ode/axis2/httpbinding/ ...

Author: midon
Date: Wed Jun 25 11:41:26 2008
New Revision: 671630

URL: http://svn.apache.org/viewvc?rev=671630&view=rev
Log:
Merge branch 'tr_rest-connector' into trunk

Conflicts:

	axis2/src/test/resources/http-binding-extensions.wsdl
	axis2/src/test/resources/http-binding-validator.wsdl

Added:
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java
      - copied, changed from r671620, ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java
    ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpMethodConverterTest.java
      - copied, changed from r671620, ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpClientHelperTest.java
Removed:
    ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpClientHelperTest.java
Modified:
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapExternalService.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapMessageConverter.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java
    ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java
    ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlEncodedTransformerTest.java
    ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlReplacementTransformerTest.java
    ode/trunk/axis2/src/test/resources/http-binding-extensions.wsdl
    ode/trunk/axis2/src/test/resources/http-binding-validator.wsdl
    ode/trunk/bpel-api/src/main/java/org/apache/ode/bpel/iapi/Message.java
    ode/trunk/bpel-runtime/src/main/java/org/apache/ode/bpel/engine/MessageImpl.java
    ode/trunk/utils/src/main/java/org/apache/ode/utils/wsdl/Messages.java
    ode/trunk/utils/src/main/java/org/apache/ode/utils/wsdl/WsdlUtils.java
    ode/trunk/utils/src/test/java/org/apache/ode/utils/wsdl/WsdlUtilsTest.java

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpBindingValidator.java Wed Jun 25 11:41:26 2008
@@ -26,8 +26,8 @@
 import javax.wsdl.BindingInput;
 import javax.wsdl.BindingOperation;
 import javax.wsdl.BindingOutput;
-import javax.wsdl.extensions.http.HTTPBinding;
 import javax.wsdl.extensions.http.HTTPOperation;
+import javax.wsdl.extensions.mime.MIMEContent;
 import java.util.Map;
 import java.util.Set;
 import java.util.Iterator;
@@ -76,8 +76,8 @@
 
 
         BindingOutput output = bindingOperation.getBindingOutput();
-        String outputContentType = WsdlUtils.getMimeContentType(output.getExtensibilityElements());
-        if (!outputContentType.endsWith("text/xml")) {
+        MIMEContent outputContent = WsdlUtils.getMimeContent(output.getExtensibilityElements());
+        if (outputContent!=null && !outputContent.getType().endsWith("text/xml")) {
             throw new IllegalArgumentException(httpMsgs.msgUnsupportedContentType(binding, bindingOperation));
         }
 
@@ -87,7 +87,6 @@
         }
 
         BindingInput input = bindingOperation.getBindingInput();
-        String inputContentType = WsdlUtils.getMimeContentType(input.getExtensibilityElements());
 
         // multipartRelated not supported
         if (WsdlUtils.useMimeMultipartRelated(input)) {
@@ -95,7 +94,9 @@
         }
 
         // only 2 content-types supported
-        if (inputContentType != null) {
+        MIMEContent inputContent= WsdlUtils.getMimeContent(input.getExtensibilityElements());
+        if (inputContent != null) {
+            String inputContentType = inputContent.getType();
             if (!inputContentType.endsWith("text/xml") && !PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(inputContentType)) {
                 throw new IllegalArgumentException(httpMsgs.msgUnsupportedContentType(binding, bindingOperation));
             }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java Wed Jun 25 11:41:26 2008
@@ -25,6 +25,8 @@
 import org.apache.commons.httpclient.HttpState;
 import org.apache.commons.httpclient.URI;
 import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.StatusLine;
+import org.apache.commons.httpclient.HttpException;
 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
 import org.apache.commons.httpclient.methods.DeleteMethod;
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
@@ -36,6 +38,7 @@
 import org.apache.commons.httpclient.params.HttpParams;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.lang.StringUtils;
 import org.apache.ode.axis2.Properties;
 import org.apache.ode.axis2.util.URLEncodedTransformer;
 import org.apache.ode.axis2.util.UrlReplacementTransformer;
@@ -45,6 +48,7 @@
 import org.apache.ode.utils.wsdl.WsdlUtils;
 import org.apache.ode.il.epr.MutableEndpoint;
 import org.w3c.dom.Element;
+import org.w3c.dom.Document;
 
 import javax.wsdl.Binding;
 import javax.wsdl.BindingInput;
@@ -53,24 +57,19 @@
 import javax.wsdl.Operation;
 import javax.wsdl.Part;
 import javax.wsdl.extensions.http.HTTPOperation;
+import javax.wsdl.extensions.mime.MIMEContent;
 import javax.xml.namespace.QName;
 import java.io.UnsupportedEncodingException;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
 public class HttpClientHelper {
 
-    private static final String CONTENT_TYPE_TEXT_XML = "text/xml";
     private static final Log log = LogFactory.getLog(HttpClientHelper.class);
 
-    protected static final org.apache.ode.utils.wsdl.Messages msgs = Messages.getMessages(Messages.class);
-    protected Binding binding;
-
-    public HttpClientHelper(Binding binding) {
-        this.binding = binding;
-    }
-
     public void configure(HostConfiguration hostConfig, HttpState state, URI targetURI, HttpParams params) throws URIException {
         if (log.isDebugEnabled()) log.debug("Configuring http client...");
         // proxy configuration
@@ -84,142 +83,101 @@
 
     }
 
-    public HttpMethod buildHttpMethod(PartnerRoleMessageExchange odeMex, HttpParams params) 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();
-
-        // base url
-        String url = ((MutableEndpoint) odeMex.getEndpointReference()).getUrl();
-
-        // 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, url, params);
-        return method;
-    }
-
-    protected Map<String, Element> extractPartElements(Message msgDef, Element message) {
-        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;
+    /**
+     * Parse and convert a HTTP status line into an aml element.
+     *
+     * @param statusLine
+     * @return
+     * @throws HttpException
+     * @see #statusLineToElement(org.w3c.dom.Document, org.apache.commons.httpclient.StatusLine)
+     */
+    public Element statusLineToElement(String statusLine) throws HttpException {
+        return statusLineToElement(new StatusLine(statusLine));
+    }
+
+    public Element statusLineToElement(StatusLine statusLine) {
+        return statusLineToElement(DOMUtils.newDocument(), statusLine);
     }
 
     /**
-     * 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)
+     * Convert a <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html#sec6.1">HTTP status line</a> into an xml element like this:
+     * <p/>
+     * < Status-line>
+     * < HTTP-Version>HTTP/1.1< /HTTP-Version>
+     * < Status-Code>200< /Status-Code>
+     * < Reason-Phrase>Success - The action was successfully received, understood, and accepted< /Reason-Phrase>
+     * < /Status-line></br>
+     *
+     * @param statusLine - the {@link org.apache.commons.httpclient.StatusLine} instance to be converted
+     * @param doc        - the document to use to create new nodes
+     * @return an Element
      */
-    protected HttpMethod prepareHttpMethod(BindingOperation bindingOperation, String verb, Map<String, Element> partValues,
-                                           final String rootUri, HttpParams params) throws UnsupportedEncodingException {
-        if (log.isDebugEnabled()) log.debug("Preparing http request...");
-        // convenience variables...
-        BindingInput bindingInput = bindingOperation.getBindingInput();
-        HTTPOperation httpOperation = (HTTPOperation) WsdlUtils.getOperationExtension(bindingOperation);
-        String contentType = WsdlUtils.getMimeContentType(bindingInput.getExtensibilityElements());
-        boolean useUrlEncoded = WsdlUtils.useUrlEncoded(bindingInput) || PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(contentType);
-        boolean useUrlReplacement = WsdlUtils.useUrlReplacement(bindingInput);
-
-        final UrlReplacementTransformer replacementTransformer = new UrlReplacementTransformer(partValues.keySet());
-        final URLEncodedTransformer encodedTransformer = new URLEncodedTransformer();
-
-        // 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 = null;
-        String encodedParams = null;
-
-
-        if (useUrlReplacement) {
-            // insert part values in the url
-            relativeUri = replacementTransformer.transform(relativeUri, partValues);
-        } else if (useUrlEncoded) {
-            // encode part values
-            encodedParams = encodedTransformer.transform(partValues);
-        }
+    public Element statusLineToElement(Document doc, StatusLine statusLine) {
+        Element statusLineEl = doc.createElementNS(null, "Status-Line");
+        Element versionEl = doc.createElementNS(null, "HTTP-Version");
+        Element codeEl = doc.createElementNS(null, "Status-Code");
+        Element reasonEl = doc.createElementNS(null, "Reason-Phrase");
+
+        // wiring
+        doc.appendChild(statusLineEl);
+        statusLineEl.appendChild(versionEl);
+        statusLineEl.appendChild(codeEl);
+        statusLineEl.appendChild(reasonEl);
+
+        // values
+        versionEl.setTextContent(statusLine.getHttpVersion());
+        codeEl.setTextContent(String.valueOf(statusLine.getStatusCode()));
+        reasonEl.setTextContent(statusLine.getReasonPhrase());
 
-        // 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();
-            }
-            if (useUrlEncoded) {
-                queryPath = encodedParams;
-            }
+        return statusLineEl;
+    }
 
-            // 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();
-            }
+    /**
+     * Build a "details" element that looks like this:
+     *
+     * @param method
+     * @return
+     * @throws IOException
+     */
+    public Element prepareDetailsElement(HttpMethod method) throws IOException {
+        return prepareDetailsElement(method, true);
+    }
 
-            // some body-building...
-            if (useUrlEncoded) {
-                requestEntity = new StringRequestEntity(encodedParams, PostMethod.FORM_URL_ENCODED_CONTENT_TYPE, method.getParams().getContentCharset());
-            } else if (contentType.endsWith(CONTENT_TYPE_TEXT_XML)) {
-                // assumption is made that there is a single part
-                // validation steps in the constructor must warranty that
-                Part part = (Part) bindingOperation.getOperation().getInput().getMessage().getParts().values().iterator().next();
-                Element partValue = partValues.get(part.getName());
-                // if the part has an element name, we must take the first element
-                if (part.getElementName() != null) {
-                    partValue = DOMUtils.getFirstChildElement(partValue);
+    /**
+     *
+     * @param method
+     * @param bodyIsXml if true the body will be parsed as xml else the body will be inserted as string
+     * @return
+     * @throws IOException
+     */
+    public Element prepareDetailsElement(HttpMethod method, boolean bodyIsXml) throws IOException {
+        Document doc = DOMUtils.newDocument();
+        Element detailsEl = doc.createElementNS(null, "details");
+        Element statusLineEl = statusLineToElement(doc, method.getStatusLine());
+        detailsEl.appendChild(statusLineEl);
+
+        // set the body if any
+        final InputStream bodyAsStream = method.getResponseBodyAsStream();
+        if (bodyAsStream != null) {
+            Element bodyEl = doc.createElementNS(null, "responseBody");
+            detailsEl.appendChild(bodyEl);
+            // first, try to parse the body as xml
+            // if it fails, put it as string in the body element
+            boolean exceptionDuringParsing = false;
+            if (bodyIsXml) {
+                try {
+                    Element parsedBodyEl = DOMUtils.parse(bodyAsStream).getDocumentElement();
+                    bodyEl.appendChild(parsedBodyEl);
+                } catch (Exception e) {
+                    String errmsg = "Unable to parse the response body as xml. Body will be inserted as string.";
+                    if (log.isDebugEnabled()) log.debug(errmsg, e);
+                    exceptionDuringParsing = true;
                 }
-                String xmlString = DOMUtils.domToString(partValue);
-                requestEntity = new ByteArrayRequestEntity(xmlString.getBytes(), contentType);
-            } else {
-                // should not happen because of HttpBindingValidator, but never say never
-                throw new IllegalArgumentException("Unsupported content-type!");
             }
-
-            // 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);
+            if (!bodyIsXml || exceptionDuringParsing) {
+                bodyEl.setTextContent(method.getResponseBodyAsString());
+            }
         }
-
-        // link params together
-        method.getParams().setDefaults(params);
-
-        String completeUri = rootUri + (rootUri.endsWith("/") || relativeUri.startsWith("/") ? "" : "/") + relativeUri;
-        method.setPath(completeUri); // assumes that the path is properly encoded (URL safe).
-        method.setQueryString(queryPath);
-        return method;
+        return detailsEl;
     }
 }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java Wed Jun 25 11:41:26 2008
@@ -29,36 +29,36 @@
 import org.apache.ode.axis2.ExternalService;
 import org.apache.ode.axis2.ODEService;
 import org.apache.ode.axis2.Properties;
-import org.apache.ode.il.epr.EndpointFactory;
-import org.apache.ode.il.epr.WSAEndpoint;
 import org.apache.ode.bpel.iapi.BpelServer;
 import org.apache.ode.bpel.iapi.EndpointReference;
+import org.apache.ode.bpel.iapi.Message;
 import org.apache.ode.bpel.iapi.MessageExchange;
 import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
-import org.apache.ode.bpel.iapi.Scheduler;
 import org.apache.ode.bpel.iapi.ProcessConf;
+import org.apache.ode.il.epr.EndpointFactory;
+import org.apache.ode.il.epr.WSAEndpoint;
 import org.apache.ode.utils.DOMUtils;
 import org.apache.ode.utils.Namespaces;
 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 javax.wsdl.Binding;
+import javax.wsdl.BindingOperation;
 import javax.wsdl.Definition;
+import javax.wsdl.Fault;
 import javax.wsdl.Operation;
 import javax.wsdl.Part;
 import javax.wsdl.Port;
 import javax.wsdl.Service;
+import javax.wsdl.extensions.mime.MIMEContent;
 import javax.xml.namespace.QName;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.util.Map;
-import java.util.HashMap;
 import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
 
 
 /**
@@ -73,27 +73,32 @@
 
     protected BpelServer server;
     protected ProcessConf pconf;
+    private String targetNamespace;
     protected QName serviceName;
     protected String portName;
 
-    protected HttpClientHelper clientHelper;    
+    protected HttpClientHelper helper;
+    protected HttpMethodConverter httpMethodConverter;
     protected WSAEndpoint endpointReference;
 
+    protected Binding portBinding;
+
     public HttpExternalService(ProcessConf pconf, QName serviceName, String portName, BpelServer server) {
         this.portName = portName;
         this.serviceName = serviceName;
         this.server = server;
+        this.pconf = pconf;
 
-	this.pconf= pconf;
-	Definition definition = pconf.getDefinitionForService(serviceName);
+        Definition definition = pconf.getDefinitionForService(serviceName);
+        targetNamespace = definition.getTargetNamespace();
         Service serviceDef = definition.getService(serviceName);
         if (serviceDef == null)
             throw new IllegalArgumentException(msgs.msgServiceDefinitionNotFound(serviceName));
         Port port = serviceDef.getPort(portName);
         if (port == null)
             throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName));
-        Binding binding = port.getBinding();
-        if (binding == null)
+        portBinding = port.getBinding();
+        if (portBinding == null)
             throw new IllegalArgumentException(msgs.msgBindingNotFound(portName));
 
         // validate the http binding
@@ -101,7 +106,7 @@
             throw new IllegalArgumentException(msgs.msgNoHTTPBindingForPort(portName));
         }
         // throws an IllegalArgumentException if not valid
-        new HttpBindingValidator(binding).validate();
+        new HttpBindingValidator(portBinding).validate();
 
         // initial endpoint reference
         Element eprElmt = ODEService.genEPRfromWSDL(definition, serviceName, portName);
@@ -109,7 +114,8 @@
             throw new IllegalArgumentException(msgs.msgPortDefinitionNotFound(serviceName, portName));
         endpointReference = EndpointFactory.convertToWSA(ODEService.createServiceRef(eprElmt));
 
-        clientHelper = new HttpClientHelper(binding);
+        httpMethodConverter = new HttpMethodConverter(portBinding);
+        helper = new HttpClientHelper();
         connections = new MultiThreadedHttpConnectionManager();
     }
 
@@ -137,27 +143,28 @@
             final HttpParams params = Properties.HttpClient.translate(properties);
 
             // build the http method
-            final HttpMethod method = clientHelper.buildHttpMethod(odeMex, params);
+            final HttpMethod method = httpMethodConverter.createHttpRequest(odeMex, params);
 
             // create a client
             HttpClient client = new HttpClient(connections);
-            // don't forget to wire params so that IL properties are passed around
+            // don't forget to wire params so that EPR properties are passed around
             client.getParams().setDefaults(params);
 
-            clientHelper.configure(client.getHostConfiguration(),client.getState(), method.getURI(),params);
+            // configure the client (proxy, security, etc)
+            helper.configure(client.getHostConfiguration(), client.getState(), method.getURI(), params);
 
             // this callable encapsulates the http method execution and the process of the response 
             final Callable executionCallable;
 
             // execute it
-            boolean isTwoWay = odeMex.getMessageExchangePattern() == org.apache.ode.bpel.iapi.MessageExchange.MessageExchangePattern.REQUEST_RESPONSE;
+            boolean isTwoWay = odeMex.getMessageExchangePattern() == MessageExchange.MessageExchangePattern.REQUEST_RESPONSE;
             if (isTwoWay) {
                 // two way
-                executionCallable = new HttpExternalService.TwoWayCallable(client, method, odeMex, odeMex.getOperation());
+                executionCallable = new HttpExternalService.TwoWayCallable(client, method, odeMex);
                 executionCallable.call();
             } else {
                 // one way, just execute and forget
-                executionCallable = new HttpExternalService.OneWayCallable(client, method, odeMex, odeMex.getOperation());
+                executionCallable = new HttpExternalService.OneWayCallable(client, method, odeMex);
                 executionCallable.call();
                 odeMex.replyOneWayOk();
             }
@@ -181,13 +188,11 @@
     private class OneWayCallable implements Callable<Void> {
         HttpMethod method;
         PartnerRoleMessageExchange odeMex;
-        Operation operation;
-	HttpClient client;
+        HttpClient client;
 
-        public OneWayCallable(HttpClient client, HttpMethod method, PartnerRoleMessageExchange odeMex, Operation operation) {
+        public OneWayCallable(HttpClient client, HttpMethod method, PartnerRoleMessageExchange odeMex) {
             this.method = method;
             this.odeMex = odeMex;
-            this.operation = operation;
             this.client = client;
         }
 
@@ -202,7 +207,7 @@
                 if (log.isDebugEnabled())
                     log.debug("Executing http request : " + method.getName() + " " + method.getURI());
                 final int statusCode = client.executeMethod(method);
-                // invoke getResponseBody to force the loading of the body 
+                // invoke getResponseBody to force the loading of the body
                 // Actually the processResponse may happen in a separate thread and
                 // as a result the connection might be closed before the body processing (see the finally clause below).
                 byte[] responseBody = method.getResponseBody();
@@ -229,31 +234,34 @@
             try {
                 // log the URI since the engine may have moved on while this One Way request was executing
                 if (statusCode >= 400) {
-                    if (log.isWarnEnabled()) log.warn("OneWay http request ["+method.getURI()+"] failed with status: " + method.getStatusLine());
+                    if (log.isWarnEnabled())
+                        log.warn("OneWay http request [" + method.getURI() + "] failed with status: " + method.getStatusLine());
                 } else {
-                    if (log.isDebugEnabled()) log.debug("OneWay http request ["+method.getURI()+"] status: " + method.getStatusLine());
+                    if (log.isDebugEnabled())
+                        log.debug("OneWay http request [" + method.getURI() + "] status: " + method.getStatusLine());
                 }
             } catch (URIException e) {
-                if(log.isDebugEnabled()) log.debug(e);
+                if (log.isDebugEnabled()) log.debug(e);
             }
         }
     }
 
     private class TwoWayCallable extends OneWayCallable {
-        public TwoWayCallable(HttpClient client, HttpMethod method, PartnerRoleMessageExchange odeMex, Operation operation) {
-            super(client, method, odeMex, operation);
+
+        public TwoWayCallable(HttpClient client, HttpMethod method, PartnerRoleMessageExchange odeMex) {
+            super(client, method, odeMex);
         }
 
         public void processResponse(final int statusCode) {
             try {
                 if (statusCode >= 200 && statusCode < 300) {
-                    success();
+                    _2xx_success();
                 } else if (statusCode >= 300 && statusCode < 400) {
-                    redirection();
+                    _3xx_redirection();
                 } else if (statusCode >= 400 && statusCode < 500) {
-                    badRequest();
+                    _4xx_badRequest();
                 } else if (statusCode >= 500 && statusCode < 600) {
-                    serverError();
+                    _5xx_serverError();
                 } else {
                     unmanagedStatus();
                 }
@@ -263,80 +271,137 @@
             }
         }
 
-        private void unmanagedStatus() {
+        private void unmanagedStatus() throws IOException {
             String errmsg = "Unmanaged Status Code! " + method.getStatusLine();
             log.error(errmsg);
-            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
         }
 
-        private void serverError() {
-            QName type = new QName(Namespaces.ODE_EXTENSION_NS, "HttpRemoteServerFault");
-
-            Document odeMsg = DOMUtils.newDocument();
-            Element odeMsgEl = odeMsg.createElementNS(null, "message");
-            Element statusEl = odeMsg.createElementNS(null, "statusLine");
-            statusEl.setTextContent(String.valueOf(method.getStatusLine()));
+        /**
+         * For 500s if a fault is defined in the WSDL and the response body contains the corresponding xml doc, then reply with a fault ; else reply with failure.
+         *
+         * @throws IOException
+         */
+        private void _5xx_serverError() throws IOException {
+            String errmsg = "Internal Server Error! " + method.getStatusLine();
+            log.error(errmsg);
 
-            odeMsg.appendChild(odeMsgEl);
-            odeMsgEl.appendChild(statusEl);
-            org.apache.ode.bpel.iapi.Message response = odeMex.createMessage(type);
-            response.setMessage(odeMsgEl);
+            Operation opDef = odeMex.getOperation();
+            BindingOperation opBinding = portBinding.getBindingOperation(opDef.getName(), opDef.getInput().getName(), opDef.getOutput().getName());
+            if (opDef.getFaults().isEmpty()) {
+                errmsg = "Operation has no fault. This 500 error will be considered as a failure.";
+                if (log.isDebugEnabled()) log.debug(errmsg);
+                odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
+            } else if (opBinding.getBindingFaults().isEmpty()) {
+                errmsg = "No fault binding. This 500 error will be considered as a failure.";
+                if (log.isDebugEnabled()) log.debug(errmsg);
+                odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
+            } else if (method.getResponseBodyAsStream() == null) {
+                errmsg = "No body in the response. This 500 error will be considered as a failure.";
+                if (log.isDebugEnabled()) log.debug(errmsg);
+                odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
+            } else {
+                final InputStream bodyAsStream = method.getResponseBodyAsStream();
+                try {
+                    Element bodyEl = DOMUtils.parse(bodyAsStream).getDocumentElement();
+                    QName bodyName = new QName(bodyEl.getNamespaceURI(), bodyEl.getNodeName());
+                    Fault faultDef = WsdlUtils.inferFault(opDef, bodyName);
+
+                    // is this fault bound with ODE extension?
+                    if (!WsdlUtils.isOdeFault(opBinding.getBindingFault(faultDef.getName()))) {
+                        errmsg = "Fault " + bodyName + " is not bound with " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "fault") + ". This 500 error will be considered as a failure.";
+                        if (log.isDebugEnabled()) log.debug(errmsg);
+                        odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
+                    } else {
+                        Part partDef = (Part) faultDef.getMessage().getParts().values().iterator().next();
 
-            log.error("Http Server Error! " + method.getStatusLine());
-            odeMex.replyWithFault(type, response);
+                        // build the element to be sent back
+                        Document odeMsg = DOMUtils.newDocument();
+                        Element odeMsgEl = odeMsg.createElementNS(null, "message");
+                        Element partEl = odeMsgEl.getOwnerDocument().createElementNS(null, partDef.getName());
+                        odeMsgEl.appendChild(partEl);
+                        // import the response body
+                        partEl.appendChild(odeMsgEl.getOwnerDocument().importNode(bodyEl, true));
+
+                        QName faultType = new QName(targetNamespace, faultDef.getName());
+                        Message response = odeMex.createMessage(faultType);
+                        response.setMessage(odeMsgEl);
+
+                        // extract and set headers
+                        httpMethodConverter.extractHttpResponseHeaders(response, method, faultDef.getMessage(), opBinding.getBindingOutput());
+                        // finally send the fault. We did it!
+                        odeMex.replyWithFault(faultType, response);
+                    }
+                } catch (Exception e) {
+                    errmsg = "Unable to parse the response body as xml. This 500 error will be considered as a failure.";
+                    if (log.isDebugEnabled()) log.debug(errmsg, e);
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method, false));
+                }
+            }
         }
 
-        private void badRequest() {
+        private void _4xx_badRequest() throws IOException {
             String errmsg = "Bad Request! " + method.getStatusLine();
             log.error(errmsg);
-            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
         }
 
-        private void redirection() {
-            String errmsg = "Redirections are not supported! " + method.getStatusLine();
+        private void _3xx_redirection() throws IOException {
+            String errmsg = "Redirections disabled! " + method.getStatusLine();
             log.error(errmsg);
-            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
+            odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
         }
 
-        private void success() {
+        private void _2xx_success() {
             if (log.isDebugEnabled()) log.debug("Http Status Line=" + method.getStatusLine());
             if (log.isDebugEnabled()) log.debug("Received response for MEX " + odeMex);
+
+            Operation opDef = odeMex.getOperation();
+            BindingOperation opBinding = portBinding.getBindingOperation(opDef.getName(), opDef.getInput().getName(), opDef.getOutput().getName());
+
+            // assumption is made that a response may have at most one body. HttpBindingValidator checks this.
+            MIMEContent outputContent = WsdlUtils.getMimeContent(opBinding.getBindingOutput().getExtensibilityElements());
+            boolean isBodyMandatory = outputContent != null && !outputContent.getType().endsWith("text/xml");
+
             try {
                 final InputStream bodyAsStream = method.getResponseBodyAsStream();
-                if (bodyAsStream == null) {
-                    String errmsg = "Request body of a Two-way message may be empty! Msg Id=" + odeMex.getMessageExchangeId();
+                if (isBodyMandatory && bodyAsStream == null) {
+                    String errmsg = "Response body is mandatory but missing! Msg Id=" + odeMex.getMessageExchangeId();
                     log.error(errmsg);
                     odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, null);
-                    return;
                 } else {
-                    // only text/xml is supported in the response body
-                    // parse the body
-                    Element bodyElement;
-                    try {
-                        bodyElement = DOMUtils.parse(bodyAsStream).getDocumentElement();
-                    } catch (Exception e) {
-                        String errmsg = "Unable to parse the request body : " + e.getMessage();
-                        log.error(errmsg, e);
-                        odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
-                        return;
-                    }
-                    try {
-                        org.apache.ode.bpel.iapi.Message odeResponse = odeMex.createMessage(odeMex.getOperation().getOutput().getMessage().getQName());
-
-                        // we expect a single part per output message
-                        // see org.apache.ode.axis2.httpbinding.HttpBindingValidator call in constructor
-                        Part part = (Part) operation.getOutput().getMessage().getParts().values().iterator().next();
+                    javax.wsdl.Message outputMessage = odeMex.getOperation().getOutput().getMessage();
+                    Message odeResponse = odeMex.createMessage(outputMessage.getQName());
 
-                        Element partElement = processBodyElement(part, bodyElement);
-                        odeResponse.setPart(part.getName(), partElement);
+                    // handle the body if any
+                    if (bodyAsStream != null) {
+                        // only text/xml is supported in the response body
+                        try {
+                            Element bodyElement = DOMUtils.parse(bodyAsStream).getDocumentElement();
+                            // we expect a single part per output message
+                            // see org.apache.ode.axis2.httpbinding.HttpBindingValidator call in constructor
+                            Part part = (Part) outputMessage.getParts().values().iterator().next();
+                            Element partElement = httpMethodConverter.createPartElement(part, bodyElement);
+                            odeResponse.setPart(part.getName(), partElement);
+                        } catch (Exception e) {
+                            String errmsg = "Unable to parse the response body: " + e.getMessage();
+                            log.error(errmsg, e);
+                            odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
+                            return;
+                        }
+                    }
 
+                    // handle headers
+                    httpMethodConverter.extractHttpResponseHeaders(odeResponse, method, outputMessage, opBinding.getBindingOutput());
+                    
+                    try {
                         if (log.isInfoEnabled())
                             log.info("Response:\n" + DOMUtils.domToString(odeResponse.getMessage()));
                         odeMex.reply(odeResponse);
                     } catch (Exception ex) {
                         String errmsg = "Unable to process response: " + ex.getMessage();
                         log.error(errmsg, ex);
-                        odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, bodyElement);
+                        odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, helper.prepareDetailsElement(method));
                     }
                 }
             } catch (IOException e) {
@@ -345,48 +410,6 @@
                 odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
             }
         }
-
-        /**
-         * Create the element to be inserted into org.apache.ode.bpel.iapi.Message.
-         * 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 bodyElement
-         * @return the element to insert "as is" to ODE message
-         */
-        private Element processBodyElement(Part part, Element bodyElement) {
-            Document doc = DOMUtils.newDocument();
-            Element partElement = doc.createElementNS(null, part.getName());
-            if (part.getElementName() != null) {
-                partElement.appendChild(doc.importNode(bodyElement, true));
-            } else {
-                if (DOMUtils.isEmptyElement(bodyElement)) {
-                    // Append an empty text node.
-                    // Warning! setting an empty string with setTextContent has not effect. See javadoc.
-                    partElement.appendChild(doc.createTextNode(""));
-                } else {
-                    String textContent = DOMUtils.getTextContent(bodyElement);
-                    if (textContent != null) {
-                        // this is a simple type
-                        partElement.setTextContent(textContent);
-                    } else {
-                        // this is a complex type, import every child
-                        // !!! Attributes are ignored
-                        for (int m = 0; m < bodyElement.getChildNodes().getLength(); m++) {
-                            Node child = bodyElement.getChildNodes().item(m);
-                            partElement.appendChild(doc.importNode(child, true));
-                        }
-                    }
-                }
-
-            }
-            return partElement;
-        }
     }
 
 }
-

Copied: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java (from r671620, ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java)
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java?p2=ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java&p1=ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java&r1=671620&r2=671630&rev=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpClientHelper.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java Wed Jun 25 11:41:26 2008
@@ -19,12 +19,9 @@
 
 package org.apache.ode.axis2.httpbinding;
 
-import org.apache.axis2.transport.http.HttpTransportProperties;
-import org.apache.commons.httpclient.HostConfiguration;
+import org.apache.axis2.AxisFault;
 import org.apache.commons.httpclient.HttpMethod;
-import org.apache.commons.httpclient.HttpState;
-import org.apache.commons.httpclient.URI;
-import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.methods.ByteArrayRequestEntity;
 import org.apache.commons.httpclient.methods.DeleteMethod;
 import org.apache.commons.httpclient.methods.EntityEnclosingMethod;
@@ -36,15 +33,22 @@
 import org.apache.commons.httpclient.params.HttpParams;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
+import org.apache.commons.lang.StringUtils;
 import org.apache.ode.axis2.Properties;
+import org.apache.ode.axis2.OdeFault;
 import org.apache.ode.axis2.util.URLEncodedTransformer;
 import org.apache.ode.axis2.util.UrlReplacementTransformer;
 import org.apache.ode.bpel.iapi.PartnerRoleMessageExchange;
 import org.apache.ode.utils.DOMUtils;
+import org.apache.ode.utils.Namespaces;
 import org.apache.ode.utils.wsdl.Messages;
 import org.apache.ode.utils.wsdl.WsdlUtils;
 import org.apache.ode.il.epr.MutableEndpoint;
+import org.apache.ode.il.OMUtils;
+import org.apache.axiom.om.OMElement;
 import org.w3c.dom.Element;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
 
 import javax.wsdl.Binding;
 import javax.wsdl.BindingInput;
@@ -52,39 +56,33 @@
 import javax.wsdl.Message;
 import javax.wsdl.Operation;
 import javax.wsdl.Part;
+import javax.wsdl.BindingOutput;
 import javax.wsdl.extensions.http.HTTPOperation;
+import javax.wsdl.extensions.mime.MIMEContent;
+import javax.wsdl.extensions.soap.SOAPHeader;
+import javax.wsdl.extensions.ExtensibilityElement;
+import javax.wsdl.extensions.UnknownExtensibilityElement;
 import javax.xml.namespace.QName;
 import java.io.UnsupportedEncodingException;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.Collection;
+import java.util.List;
 
-public class HttpClientHelper {
+public class HttpMethodConverter {
 
     private static final String CONTENT_TYPE_TEXT_XML = "text/xml";
     private static final Log log = LogFactory.getLog(HttpClientHelper.class);
 
-    protected static final org.apache.ode.utils.wsdl.Messages msgs = Messages.getMessages(Messages.class);
+    protected static final Messages msgs = Messages.getMessages(Messages.class);
     protected Binding binding;
 
-    public HttpClientHelper(Binding binding) {
+    public HttpMethodConverter(Binding binding) {
         this.binding = binding;
     }
 
-    public void configure(HostConfiguration hostConfig, HttpState state, URI targetURI, HttpParams params) throws URIException {
-        if (log.isDebugEnabled()) log.debug("Configuring http client...");
-        // proxy configuration
-        if (ProxyConf.isProxyEnabled(params, targetURI.getHost())) {
-            if (log.isDebugEnabled()) log.debug("ProxyConf");
-            ProxyConf.configure(hostConfig, state, (HttpTransportProperties.ProxyProperties) params.getParameter(Properties.PROP_HTTP_PROXY_PREFIX));
-        }
-
-        // security
-        // ...
-
-    }
-
-    public HttpMethod buildHttpMethod(PartnerRoleMessageExchange odeMex, HttpParams params) throws UnsupportedEncodingException {
+    public HttpMethod createHttpRequest(PartnerRoleMessageExchange odeMex, HttpParams params) throws UnsupportedEncodingException {
         Operation operation = odeMex.getOperation();
         BindingOperation bindingOperation = binding.getBindingOperation(operation.getName(), operation.getInput().getName(), operation.getOutput().getName());
 
@@ -107,17 +105,6 @@
         return method;
     }
 
-    protected Map<String, Element> extractPartElements(Message msgDef, Element message) {
-        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 and initialize the http method.
@@ -132,28 +119,33 @@
         // convenience variables...
         BindingInput bindingInput = bindingOperation.getBindingInput();
         HTTPOperation httpOperation = (HTTPOperation) WsdlUtils.getOperationExtension(bindingOperation);
-        String contentType = WsdlUtils.getMimeContentType(bindingInput.getExtensibilityElements());
+        MIMEContent content = WsdlUtils.getMimeContent(bindingInput.getExtensibilityElements());
+        String contentType = content == null ? "" : content.getType();
         boolean useUrlEncoded = WsdlUtils.useUrlEncoded(bindingInput) || PostMethod.FORM_URL_ENCODED_CONTENT_TYPE.equalsIgnoreCase(contentType);
         boolean useUrlReplacement = WsdlUtils.useUrlReplacement(bindingInput);
 
-        final UrlReplacementTransformer replacementTransformer = new UrlReplacementTransformer(partValues.keySet());
-        final URLEncodedTransformer encodedTransformer = new URLEncodedTransformer();
-
         // 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 = 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
-            relativeUri = replacementTransformer.transform(relativeUri, partValues);
+            completeUri = new UrlReplacementTransformer().transform(completeUri, partValues);
         } else if (useUrlEncoded) {
             // encode part values
-            encodedParams = encodedTransformer.transform(partValues);
+            encodedParams = new URLEncodedTransformer().transform(partValues);
         }
 
         // http-client api is not really neat
@@ -189,9 +181,8 @@
             if (useUrlEncoded) {
                 requestEntity = new StringRequestEntity(encodedParams, PostMethod.FORM_URL_ENCODED_CONTENT_TYPE, method.getParams().getContentCharset());
             } else if (contentType.endsWith(CONTENT_TYPE_TEXT_XML)) {
-                // assumption is made that there is a single part
-                // validation steps in the constructor must warranty that
-                Part part = (Part) bindingOperation.getOperation().getInput().getMessage().getParts().values().iterator().next();
+                // get the part to be put in the body
+                Part part = bindingOperation.getOperation().getInput().getMessage().getPart(content.getPart());
                 Element partValue = partValues.get(part.getName());
                 // if the part has an element name, we must take the first element
                 if (part.getElementName() != null) {
@@ -216,10 +207,128 @@
 
         // link params together
         method.getParams().setDefaults(params);
-
-        String completeUri = rootUri + (rootUri.endsWith("/") || relativeUri.startsWith("/") ? "" : "/") + relativeUri;
         method.setPath(completeUri); // assumes that the path is properly encoded (URL safe).
         method.setQueryString(queryPath);
         return method;
     }
+
+
+    protected Map<String, Element> extractPartElements(Message msgDef, Element message) {
+        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 {
+                String textContent = DOMUtils.getTextContent(receivedElement);
+                if (textContent != null) {
+                    // this is a simple type
+                    partElement.setTextContent(textContent);
+                } else {
+                    // this is a complex type, import every child
+                    // !!! 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 Namespaces.ODE_HTTP_EXTENSION_NS:header elements included in the output binding. For each of them, set the header value as the value of the message part.
+     * <b/>Then add all HTTP headers as header part in the message. The name of the header would be the part name.
+     * @param odeMessage
+     * @param method
+     * @param messageDef
+     * @param bindingOutput
+     */
+    public void extractHttpResponseHeaders(org.apache.ode.bpel.iapi.Message odeMessage, HttpMethod method, Message messageDef, BindingOutput bindingOutput) {
+        Collection<UnknownExtensibilityElement> headerBindings = WsdlUtils.getHttpHeaders(bindingOutput.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)) {
+                odeMessage.setPart(partName, createPartElement(part, method.getRequestHeader(headerName).getValue()));
+            } else {
+                if(log.isErrorEnabled()) {
+                    String errMsg = "Invalid binding: missing required attribute! Part name: "+new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "part");
+                    log.error(errMsg);
+                    throw new RuntimeException(errMsg);
+                }
+            }
+        }
+
+        // also add all HTTP headers into the messade as header parts
+        Header[] reqHeaders = method.getResponseHeaders();
+        for (int i = 0; i < reqHeaders.length; i++) {
+            Header h = reqHeaders[i];
+            odeMessage.setHeaderPart(h.getName(), h.getValue());
+        }
+    }
+
+
 }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapExternalService.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapExternalService.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapExternalService.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapExternalService.java Wed Jun 25 11:41:26 2008
@@ -277,12 +277,8 @@
                 if (faultType != null) {
                     if (__log.isWarnEnabled())
                         __log.warn("Fault response: faultType=" + faultType + "\n" + DOMUtils.domToString(odeMsgEl));
-                    QName nonNullFT = new QName(Namespaces.ODE_EXTENSION_NS, "unknownFault");
-                    Fault f = odeMex.getOperation().getFault(faultType.getLocalPart());
-                    if (f != null && f.getMessage().getQName() != null) nonNullFT = f.getMessage().getQName();
-                    else __log.debug("Fault " + faultType + " isn't referenced in the service definition, unknown fault.");
-
-                    Message response = odeMex.createMessage(nonNullFT);
+                    
+                    Message response = odeMex.createMessage(faultType);
                     response.setMessage(odeMsgEl);
 
                     odeMex.replyWithFault(faultType, response);

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapMessageConverter.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapMessageConverter.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapMessageConverter.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/soapbinding/SoapMessageConverter.java Wed Jun 25 11:41:26 2008
@@ -425,10 +425,7 @@
 
         if (headerEl == null) return;
 
-        Element msgElmt = odeMessage.getMessage();
-        Element destPart = msgElmt.getOwnerDocument().createElementNS(null, p.getName());
-        msgElmt.appendChild(destPart);
-        destPart.appendChild(msgElmt.getOwnerDocument().importNode(OMUtils.toDOM(headerEl), true));
+        odeMessage.setHeaderPart(p.getName(), OMUtils.toDOM(headerEl));
     }
 
     private String findHeaderPartName(List<SOAPHeader> headerDefs, QName elmtName) {
@@ -518,29 +515,13 @@
         return new QName(_def.getTargetNamespace(), fdef.getName());
     }
 
-    @SuppressWarnings("unchecked")
     private Fault inferFault(Operation operation, SOAPFault flt) {
         if (flt.getDetail() == null)
             return null;
 
         // The detail is a dummy <detail> node containing the interesting fault element
         QName elName = flt.getDetail().getFirstElement().getQName();
-        for (Fault f : (Collection<Fault>)operation.getFaults().values()) {
-            if (f.getMessage() == null)
-                continue;  // should have checked in ctor
-
-            Collection<Part> parts = f.getMessage().getParts().values();
-            if (parts.isEmpty())
-                continue;  // should check this in ctor
-            Part p = parts.iterator().next();
-            if (p.getElementName() == null)
-                continue;  // should check this is ctor
-
-            if (p.getElementName().equals(elName))
-                return f;
-        }
-
-        return null;
+        return WsdlUtils.inferFault(operation, elName);
     }
 
 }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/URLEncodedTransformer.java Wed Jun 25 11:41:26 2008
@@ -21,6 +21,8 @@
 
 import org.apache.commons.httpclient.NameValuePair;
 import org.apache.commons.httpclient.util.EncodingUtil;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
 import org.apache.ode.utils.DOMUtils;
 import org.apache.ode.axis2.httpbinding.Messages;
 import org.w3c.dom.Element;
@@ -28,28 +30,37 @@
 import javax.wsdl.Part;
 import java.util.Iterator;
 import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
 
 /**
  * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
  */
 public class URLEncodedTransformer {
 
-    private static final Messages msgs = Messages.getMessages(Messages.class);
 
+    private static final Log log = LogFactory.getLog(URLEncodedTransformer.class);
+
+    /**
+     * @param values - a map<String, Element>, the key is a part name (without curly braces), the value the replacement value for the part name. If the value is not a simple type, it will be skipped.
+     * @return the encoded params
+     */
     public String transform(Map<String, Element> values) {
         if (values.isEmpty()) return null;
-        NameValuePair[] pairs = new NameValuePair[values.size()];
-        int i = 0;
+        List<NameValuePair> l = new ArrayList<NameValuePair>(values.size());
         for (Map.Entry<String, Element> e : values.entrySet()) {
+            String partName = e.getKey();
             Element node = e.getValue();
             String nodeContent = DOMUtils.isEmptyElement(node) ? "" : DOMUtils.getTextContent(node);
             if (nodeContent == null) {
-                throw new IllegalArgumentException(msgs.msgSimpleTypeExpected(e.getKey()));
+                // if it is not a simple type, skip it
+                if (log.isDebugEnabled())
+                    log.debug("Part " + partName + " skipped because associated element is not of a simple type.");
+                continue;
             }
-            NameValuePair p = new NameValuePair(e.getKey(), nodeContent);
-            pairs[i++] = p;
+            l.add(new NameValuePair(e.getKey(), nodeContent));
         }
-        return EncodingUtil.formUrlEncode(pairs, "UTF-8");
+        return EncodingUtil.formUrlEncode(l.toArray(new NameValuePair[0]), "UTF-8");
     }
 
 }

Modified: ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java (original)
+++ ode/trunk/axis2/src/main/java/org/apache/ode/axis2/util/UrlReplacementTransformer.java Wed Jun 25 11:41:26 2008
@@ -19,24 +19,20 @@
 
 package org.apache.ode.axis2.util;
 
-import org.apache.commons.collections.CollectionUtils;
 import org.apache.commons.httpclient.util.URIUtil;
 import org.apache.commons.httpclient.URIException;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
 import org.apache.ode.utils.DOMUtils;
-import org.apache.ode.utils.wsdl.Messages;
 import org.w3c.dom.Element;
 
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 /**
  * This encoder applies urlReplacement as defined by the <a href='http://www.w3.org/TR/wsdl#_http:urlReplacement'>WSDL specification</a>.
+ * <br/>Surrounding characters for parts may be parentheses '()' or braces '{}'. Pattern with parentheses is look up first, if found then it's replaced with the part value, else the pattern with braces is look up. 
  * <p/><strong>Escaping Considerations</strong>
  * <br/>Replacement and default values are escaped. All characters except unreserved (as defined by <a href="http://tools.ietf.org/html/rfc2396#appendix-A">rfc2396</a>) are escaped.
  * <br/> unreserved    = alphanum | mark
@@ -51,33 +47,18 @@
 
     private static final Log log = LogFactory.getLog(UrlReplacementTransformer.class);
 
-    private static final org.apache.ode.utils.wsdl.Messages msgs = Messages.getMessages(Messages.class);
     private static final org.apache.ode.axis2.httpbinding.Messages httpMsgs = org.apache.ode.axis2.httpbinding.Messages.getMessages(org.apache.ode.axis2.httpbinding.Messages.class);
 
-    protected Set<String> partNames;
-
     public UrlReplacementTransformer() {
-        partNames = new HashSet<String>();
-    }
-
-    public UrlReplacementTransformer(Set<String> partNames) {
-        this.partNames = partNames;
     }
 
     /**
      * @param baseUri - the base uri template containing part names enclosed within single curly braces
-     * @param values  - a map<String, Object>, the key is a part name (without curly braces), the value the replacement value for the part name.
+     * @param values  - a map<String, Element>, the key is a part name (without curly braces), the value the replacement value for the part name. If the value is not a simple type, it will be skipped.
      * @return the encoded uri
-     * @throws java.lang.IllegalArgumentException
-     *          if a part (key) is missing in the map, if a replacement value is null in the map, if a part pattern is not found in the uri template, if a part pattern is found more than once
+     * @throws java.lang.IllegalArgumentException if a replacement value is null in the map or if a part pattern is found more than once
      */
     public String transform(String baseUri, Map<String, Element> values) {
-        // each part must be given a replacement value
-        if (values.keySet().size() != partNames.size() || !values.keySet().containsAll(partNames)) {
-            Collection<String> disjunction = CollectionUtils.disjunction(partNames, values.keySet());
-            throw new IllegalArgumentException(msgs.msgMissingReplacementValuesFor(disjunction));
-        }
-
         // the list containing the final split result
         List<String> result = new ArrayList<String>();
 
@@ -87,16 +68,16 @@
         // replace each part exactly once
         for (Map.Entry<String, Element> e : values.entrySet()) {
 
-            String partPattern;
+            String partName = e.getKey();
             String replacementValue;
             {
-                String partName = e.getKey();
-                partPattern = "\\(" + partName + "\\)";
                 Element value = e.getValue();
-                if (value == null) {
-                    throw new IllegalArgumentException(httpMsgs.msgSimpleTypeExpected(partName));
-                }
                 replacementValue = DOMUtils.isEmptyElement(value) ? "" : DOMUtils.getTextContent(value);
+                if (replacementValue == null) {
+                    // if it is not a simple type, skip it
+                    if(log.isDebugEnabled()) log.debug("Part "+partName+" skipped because associated element is not of a simple type.");
+                    continue;
+                }
             }
 
             try {
@@ -105,7 +86,14 @@
                 // this exception is never thrown by the code of httpclient
                 if (log.isWarnEnabled()) log.warn(urie.getMessage(), urie);
             }
-            replace(result, partPattern, replacementValue);
+
+            // first, search for parentheses 
+            String partPattern = "\\(" + partName + "\\)";
+            if(!replace(result, partPattern, replacementValue)){
+                // if parentheses not found, try braces
+                partPattern = "\\{" + partName + "\\}";
+                replace(result, partPattern, replacementValue);
+            }
         }
 
         // join all the array elements to form the final url
@@ -114,23 +102,14 @@
         return sb.toString();
     }
 
-    private void replace(List<String> result, String partPattern, String replacementValue) {
+    private boolean replace(List<String> result, String partPattern, String replacementValue) {
         // !!!  i=i+2      replacement values will be skipped,
         // so replaced values do not trigger additional matches
         for (int i = 0; i < result.size(); i = i + 2) {
             String segment = result.get(i);
             // use a negative limit, so empty strings are not discarded
             String[] matches = segment.split(partPattern, -1);
-            if (matches.length == 1) {
-                if (i == result.size() - 1) {
-                    // last segment, no more string to test
-                    throw new IllegalArgumentException(httpMsgs.msgInvalidURIPattern());
-                } else {
-                    continue;
-                }
-            } else if (matches.length > 2) {
-                throw new IllegalArgumentException(httpMsgs.msgInvalidURIPattern());
-            } else {
+            if (matches.length == 2) {
                 // if exactly one match...
 
                 // remove the matching segment
@@ -142,8 +121,9 @@
 
                 // pattern found and replaced, we're done for this pattern
                 // move on to the next part
-                break;
+                return true;
             }
         }
+        return false;
     }
 }

Copied: ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpMethodConverterTest.java (from r671620, ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpClientHelperTest.java)
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpMethodConverterTest.java?p2=ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpMethodConverterTest.java&p1=ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpClientHelperTest.java&r1=671620&r2=671630&rev=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpClientHelperTest.java (original)
+++ ode/trunk/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpMethodConverterTest.java Wed Jun 25 11:41:26 2008
@@ -49,15 +49,15 @@
 /**
  * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
  */
-public class HttpClientHelperTest extends TestCase {
+public class HttpMethodConverterTest extends TestCase {
 
     protected Definition definition;
 
-    protected HttpClientHelper deliciousBuilder;
+    protected HttpMethodConverter deliciousBuilder;
     protected Binding deliciousBinding;
     protected Port deliciousPort;
 
-    protected HttpClientHelper dummyBuilder;
+    protected HttpMethodConverter dummyBuilder;
     protected Port dummyPort;
     protected Binding dummyBinding;
 
@@ -72,12 +72,12 @@
         Service deliciousService = definition.getService(new QName("http://ode/bpel/unit-test.wsdl", "DeliciousService"));
         deliciousPort = deliciousService.getPort("TagHttpPort");
         deliciousBinding = deliciousPort.getBinding();
-        deliciousBuilder = new HttpClientHelper(deliciousBinding);
+        deliciousBuilder = new HttpMethodConverter(deliciousBinding);
 
         Service dummyService = definition.getService(new QName("http://ode/bpel/unit-test.wsdl", "DummyService"));
         dummyPort = dummyService.getPort("DummyServiceHttpport");
         dummyBinding = dummyPort.getBinding();
-        dummyBuilder = new HttpClientHelper(dummyBinding);
+        dummyBuilder = new HttpMethodConverter(dummyBinding);
 
     }
 
@@ -98,7 +98,7 @@
         odeMex.op = deliciousBinding.getBindingOperation("getTag", null, null).getOperation();
         odeMex.req = new MockMessage(msgEl);
         odeMex.epr = new MockEPR(uri);
-        HttpMethod httpMethod = deliciousBuilder.buildHttpMethod(odeMex, new DefaultHttpParams());
+        HttpMethod httpMethod = deliciousBuilder.createHttpRequest(odeMex, new DefaultHttpParams());
 
 
         assertTrue("GET".equalsIgnoreCase(httpMethod.getName()));
@@ -119,7 +119,7 @@
         odeMex.req = new MockMessage(msgEl);
         odeMex.epr = new MockEPR(uri);
         try {
-            HttpMethod httpMethod = deliciousBuilder.buildHttpMethod(odeMex, new DefaultHttpParams());
+            HttpMethod httpMethod = deliciousBuilder.createHttpRequest(odeMex, new DefaultHttpParams());
             fail("IllegalArgumentException expected because message element is empty.");
         } catch (IllegalArgumentException e) {
             // expected behavior
@@ -145,7 +145,7 @@
         odeMex.op = dummyBinding.getBindingOperation("hello", null, null).getOperation();
         odeMex.req = new MockMessage(msgEl);
         odeMex.epr = new MockEPR(uri);
-        HttpMethod httpMethod = dummyBuilder.buildHttpMethod(odeMex, new DefaultHttpParams());
+        HttpMethod httpMethod = dummyBuilder.createHttpRequest(odeMex, new DefaultHttpParams());
         assertTrue("POST".equalsIgnoreCase(httpMethod.getName()));
         assertEquals("Generated URI does not match", expectedUri, httpMethod.getURI().toString());
 
@@ -224,6 +224,10 @@
 
         }
 
+        public void setHeaderPart(String name, String content) {
+
+        }
+
         public void setMessage(Element msg) {
 
         }

Modified: ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlEncodedTransformerTest.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlEncodedTransformerTest.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlEncodedTransformerTest.java (original)
+++ ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlEncodedTransformerTest.java Wed Jun 25 11:41:26 2008
@@ -31,10 +31,10 @@
  * @author <a href="mailto:midon@intalio.com">Alexis Midon</a>
  */
 public class UrlEncodedTransformerTest extends TestCase {
-    protected URLEncodedTransformer transformer= new URLEncodedTransformer();
+    protected URLEncodedTransformer transformer = new URLEncodedTransformer();
 
 
-    public void testSimple(){
+    public void testSimple() {
         Document doc = DOMUtils.newDocument();
         Map<String, Element> m = new HashMap<String, Element>();
         Element element = doc.createElement("part1");
@@ -52,7 +52,7 @@
         assertTrue(res.contains("part1=42+3.14159"));
         assertTrue(res.contains("part2=hello+word+%40%23%24%25+%26*"));
         assertTrue(res.contains("emptyPart="));
-        assertTrue(res.split("&").length==m.size());
+        assertTrue(res.split("&").length == m.size());
     }
 
 
@@ -63,12 +63,6 @@
         Map<String, Element> m = new HashMap<String, Element>();
         m.put("part1", element);
 
-        try {
-            transformer.transform(m);
-            fail("IllegalArgumentException expected because a complex type is passed.");
-        } catch (IllegalArgumentException e) {
-            // expected behavior
-        }
-
+        assertEquals("Result should empty because the only part is associated to a complex type", "", transformer.transform(m));
     }
 }

Modified: ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlReplacementTransformerTest.java
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlReplacementTransformerTest.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlReplacementTransformerTest.java (original)
+++ ode/trunk/axis2/src/test/java/org/apache/ode/axis2/util/UrlReplacementTransformerTest.java Wed Jun 25 11:41:26 2008
@@ -33,22 +33,48 @@
  */
 public class UrlReplacementTransformerTest extends TestCase {
 
-    //<http:operation location="o1/A(part1)B(part2)/(part3)"/>
-    private String baseUrl = "o1/A(part1)B(part2)/(part3)";
 
-    public void testRegularCases() {
+    public void testWithParentheses() {
         String[][] a = new String[][]{
-                new String[]{"with alphabetical chars", baseUrl, "o1/AtutuBtiti/toto", "part1", "tutu", "part2", "titi", "part3", "toto"}
+                new String[]{"with alphabetical chars", "o1/A(part1)B(part2)/(part3)", "o1/AtutuBtiti/toto", "part1", "tutu", "part2", "titi", "part3", "toto"}
                 , new String[]{"parts are ends", "(part1)B(part2)/(part3)", "3B14/159", "part1", "3", "part2", "14", "part3", "159"}
                 , new String[]{"a single part", "(part1)", "314159", "part1", "314159"}
                 , new String[]{"parts surrounded with ()", "o1/A((part1))B((part2))/((part3))", "o1/A(3)B(14)/(159)", "part1", "3", "part2", "14", "part3", "159"}
-                , new String[]{"with numeric chars", baseUrl, "o1/A3B14/159%20and%20an%20epsilon", "part1", "3", "part2", "14", "part3", "159 and an epsilon"}
-                , new String[]{"with empty values", baseUrl, "o1/AB/", "part1", "", "part2", "", "part3", ""}
-                , new String[]{"with special chars", baseUrl, "o1/AWhatB%2410%2C000/~!%40%23%24%25%5E%26*()_%2B%3D-%60%5B%5D%7B%7D%7C%5C.", "part1", "What", "part2", "$10,000", "part3", "~!@#$%^&*()_+=-`[]{}|\\."}
-                , new String[]{"with values containing key names", baseUrl, "o1/Avalue_of_part1_is_(part2)_and_should_not_be_replacedBsame_for_part2(part3)/foo", "part1", "value_of_part1_is_(part2)_and_should_not_be_replaced", "part2", "same_for_part2(part3)", "part3", "foo"}
+                , new String[]{"with numeric chars", "o1/A(part1)B(part2)/(part3)", "o1/A3B14/159%20and%20an%20epsilon", "part1", "3", "part2", "14", "part3", "159 and an epsilon"}
+                , new String[]{"with empty values", "o1/A(part1)B(part2)/(part3)", "o1/AB/", "part1", "", "part2", "", "part3", ""}
+                , new String[]{"with special chars", "o1/A(part1)B(part2)/(part3)", "o1/AWhatB%2410%2C000/~!%40%23%24%25%5E%26*()_%2B%3D-%60%5B%5D%7B%7D%7C%5C.", "part1", "What", "part2", "$10,000", "part3", "~!@#$%^&*()_+=-`[]{}|\\."}
+                , new String[]{"with values containing key names", "o1/A(part1)B(part2)/(part3)", "o1/Avalue_of_part1_is_(part2)_and_should_not_be_replacedBsame_for_part2(part3)/foo", "part1", "value_of_part1_is_(part2)_and_should_not_be_replaced", "part2", "same_for_part2(part3)", "part3", "foo"}
         };
 
         Document doc = DOMUtils.newDocument();
+        UrlReplacementTransformer encoder = new UrlReplacementTransformer();
+        for (String[] data : a) {
+            // convert into map
+            Map<String, Element> parts = new HashMap<String, Element>();
+            for (int k = 3; k < data.length; k = k + 2) {
+                Element element = doc.createElement(data[k]);
+                element.setTextContent(data[k + 1]);
+                parts.put(data[k], element);
+            }
+            assertEquals(data[0], data[2], encoder.transform(data[1], parts));
+        }
+    }
+
+
+    public void testWithBraces() {
+        String[][] a = new String[][]{
+                new String[]{"with alphabetical chars", "o1/A{part1}B{part2}/{part3}", "o1/AtutuBtiti/toto", "part1", "tutu", "part2", "titi", "part3", "toto"}
+                , new String[]{"parts are ends", "{part1}B{part2}/{part3}", "3B14/159", "part1", "3", "part2", "14", "part3", "159"}
+                , new String[]{"a single part", "{part1}", "314159", "part1", "314159"}
+                , new String[]{"parts surrounded with {}", "o1/A{{part1}}B{{part2}}/{{part3}}", "o1/A{3}B{14}/{159}", "part1", "3", "part2", "14", "part3", "159"}
+                , new String[]{"with numeric chars", "o1/A{part1}B{part2}/{part3}", "o1/A3B14/159%20and%20an%20epsilon", "part1", "3", "part2", "14", "part3", "159 and an epsilon"}
+                , new String[]{"with empty values", "o1/A{part1}B{part2}/{part3}", "o1/AB/", "part1", "", "part2", "", "part3", ""}
+                , new String[]{"with special chars", "o1/A{part1}B{part2}/{part3}", "o1/AWhatB%2410%2C000/~!%40%23%24%25%5E%26*()_%2B%3D-%60%5B%5D%7B%7D%7C%5C.", "part1", "What", "part2", "$10,000", "part3", "~!@#$%^&*()_+=-`[]{}|\\."}
+                , new String[]{"with values containing key names", "o1/A{part1}B{part2}/{part3}", "o1/Avalue_of_part1_is_%7Bpart2%7D_and_should_not_be_replacedBsame_for_part2%7Bpart3%7D/foo", "part1", "value_of_part1_is_{part2}_and_should_not_be_replaced", "part2", "same_for_part2{part3}", "part3", "foo"}
+        };
+
+        Document doc = DOMUtils.newDocument();
+        UrlReplacementTransformer encoder = new UrlReplacementTransformer();
         for (String[] data : a) {
             // convert into map
             Map<String, Element> parts = new HashMap<String, Element>();
@@ -57,24 +83,35 @@
                 element.setTextContent(data[k + 1]);
                 parts.put(data[k], element);
             }
-            UrlReplacementTransformer encoder = new UrlReplacementTransformer(parts.keySet());
             assertEquals(data[0], data[2], encoder.transform(data[1], parts));
         }
 
     }
 
-    public void testMissingPartPatterns() {
-        try {
-            Map<String, Element> map = new HashMap<String, Element>();
-            map.put("part1", null);
-            UrlReplacementTransformer encoder = new UrlReplacementTransformer(map.keySet());
-            encoder.transform("", map);
-            fail("Exception expected! Missing Part Patterns in URI");
-        } catch (IllegalArgumentException e) {
-            // expected behavior
+    public void testWithMixnMatch() {
+        String[][] a = new String[][]{
+                new String[]{"with alphabetical chars", "o1/A(part1)B{part2}/{part3}", "o1/AtutuBtiti/toto", "part1", "tutu", "part2", "titi", "part3", "toto"}
+                , new String[]{"parts are ends", "{part1}B{part2}/(part3)", "3B14/159", "part1", "3", "part2", "14", "part3", "159"}
+                , new String[]{"a single part", "{part1}", "314159", "part1", "314159"}
+                , new String[]{"with empty values", "o1/A{part1}B(part2)/{part3}", "o1/AB/", "part1", "", "part2", "", "part3", ""}
+        };
+
+        Document doc = DOMUtils.newDocument();
+        UrlReplacementTransformer encoder = new UrlReplacementTransformer();
+        for (String[] data : a) {
+            // convert into map
+            Map<String, Element> parts = new HashMap<String, Element>();
+            for (int k = 3; k < data.length; k = k + 2) {
+                Element element = doc.createElement(data[k]);
+                element.setTextContent(data[k + 1]);
+                parts.put(data[k], element);
+            }
+            assertEquals(data[0], data[2], encoder.transform(data[1], parts));
         }
+
     }
 
+
     public void testComplexType() {
         Document doc = DOMUtils.newDocument();
         Element element = doc.createElement("part1");
@@ -82,13 +119,9 @@
         Map<String, Element> m = new HashMap<String, Element>();
         m.put("part1", element);
 
-        UrlReplacementTransformer encoder = new UrlReplacementTransformer(m.keySet());
-        try {
-            encoder.transform("(part1)", m);
-            fail("IllegalArgumentException expected because a complex type is passed.");
-        } catch (IllegalArgumentException e) {
-            // expected behavior
-        }
+        UrlReplacementTransformer encoder = new UrlReplacementTransformer();
+        assertEquals("Result should be equal to template because the only part is associated to a complex type", "(part1)", encoder.transform("(part1)", m));
+
     }
 
 }

Modified: ode/trunk/axis2/src/test/resources/http-binding-extensions.wsdl
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/test/resources/http-binding-extensions.wsdl?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/test/resources/http-binding-extensions.wsdl (original)
+++ ode/trunk/axis2/src/test/resources/http-binding-extensions.wsdl Wed Jun 25 11:41:26 2008
@@ -120,10 +120,14 @@
             <wsdl:input>
                 <http:urlReplacement/>
                 <mime:content type="text/xml" part="article"/>
-                <!-- fault binding -->
-                <odex:fault name="UpdateFailed"/>
             </wsdl:input>
             <wsdl:output/>
+            <!-- fault binding -->
+            <wsdl:fault name="UpdateFailed">
+                <!-- name attribute is optional -->
+                <!--<odex:fault name="UpdateFailed"/>-->
+                <odex:fault/>
+            </wsdl:fault>
         </wsdl:operation>
         <wsdl:operation name="doPOST">
             <http:operation location=""/>

Modified: ode/trunk/axis2/src/test/resources/http-binding-validator.wsdl
URL: http://svn.apache.org/viewvc/ode/trunk/axis2/src/test/resources/http-binding-validator.wsdl?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/axis2/src/test/resources/http-binding-validator.wsdl (original)
+++ ode/trunk/axis2/src/test/resources/http-binding-validator.wsdl Wed Jun 25 11:41:26 2008
@@ -382,7 +382,8 @@
     </wsdl:binding>
     <wsdl:binding name="DummyServiceHttpBinding_get+urlReplacement+missing_part" type="ns1:DummyServicePortType">
         <wsdl:documentation>
-            shouldPass # WSLD spec requires that all message parts must be in the url pattern when urlReplacement is used. However ODE relaxes this.
+            shouldPass # WSLD spec requires that all message parts must be in the url pattern when urlReplacement is used.
+            However ODE relaxes this.
         </wsdl:documentation>
         <http:binding verb="GET"/>
         <wsdl:operation name="hello">
@@ -410,6 +411,21 @@
             </wsdl:output>
         </wsdl:operation>
     </wsdl:binding>
+    <wsdl:binding name="DummyServiceHttpBinding_get+urlReplacement+empty_pattern" type="ns1:DummyServicePortType">
+        <wsdl:documentation>
+            shouldPass # Operation-location may be empty. REST connector will not fill it for instance.
+        </wsdl:documentation>
+        <http:binding verb="GET"/>
+        <wsdl:operation name="hello">
+            <http:operation location=""/>
+            <wsdl:input>
+                <http:urlReplacement/>
+            </wsdl:input>
+            <wsdl:output>
+                <mime:content type="text/xml" part="hello"/>
+            </wsdl:output>
+        </wsdl:operation>
+    </wsdl:binding>
 
     <!-- ###################################### -->
     <!-- Verb at the operation level -->

Modified: ode/trunk/bpel-api/src/main/java/org/apache/ode/bpel/iapi/Message.java
URL: http://svn.apache.org/viewvc/ode/trunk/bpel-api/src/main/java/org/apache/ode/bpel/iapi/Message.java?rev=671630&r1=671629&r2=671630&view=diff
==============================================================================
--- ode/trunk/bpel-api/src/main/java/org/apache/ode/bpel/iapi/Message.java (original)
+++ ode/trunk/bpel-api/src/main/java/org/apache/ode/bpel/iapi/Message.java Wed Jun 25 11:41:26 2008
@@ -69,6 +69,13 @@
     void setHeaderPart(String name, Element content);
 
     /**
+     * Set a header part value
+     * @param name header part name
+     * @param content header part text content
+     */
+    void setHeaderPart(String name, String content);
+
+    /**
      * Gets all header parts in the message.
      * @return
      */