Author: midon
Date: Mon Jul 14 11:42:40 2008
New Revision: 676683

URL: http://svn.apache.org/viewvc?rev=676683&view=rev
Log:
ODE-333: better support for xml and text content types

Modified:
    
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
    
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpHelper.java
    
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java
    
ode/branches/APACHE_ODE_1.X/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpHelperTest.java

Modified: 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
URL: 
http://svn.apache.org/viewvc/ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java?rev=676683&r1=676682&r2=676683&view=diff
==============================================================================
--- 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
 (original)
+++ 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpExternalService.java
 Mon Jul 14 11:42:40 2008
@@ -23,6 +23,7 @@
 import org.apache.commons.httpclient.HttpMethod;
 import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
 import org.apache.commons.httpclient.URIException;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.params.HttpParams;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -43,8 +44,8 @@
 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.Document;
 
 import javax.wsdl.Binding;
 import javax.wsdl.BindingOperation;
@@ -81,11 +82,11 @@
     protected QName serviceName;
     protected String portName;
     protected WSAEndpoint endpointReference;
-    
+
     protected HttpMethodConverter httpMethodConverter;
 
     protected Binding portBinding;
-    
+
     public HttpExternalService(ProcessConf pconf, QName serviceName, String 
portName, ExecutorService executorService, Scheduler scheduler, BpelServer 
server) {
         this.portName = portName;
         this.serviceName = serviceName;
@@ -183,7 +184,7 @@
                 odeMex.replyOneWayOk();
             }
         } catch (UnsupportedEncodingException e) {
-            String errmsg = "The HTTP encoding returned isn't supported " + 
odeMex;
+            String errmsg = "The returned HTTP encoding isn't supported " + 
odeMex;
             log.error(errmsg, e);
             odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, 
errmsg, null);
         } catch (URIException e) {
@@ -222,24 +223,13 @@
                 // as a result the connection might be closed before the body 
processing (see the finally clause below).
                 byte[] responseBody = method.getResponseBody();
                 // ... and process the response
-                if (log.isDebugEnabled())log.debug("Received response for MEX 
" + mexId);
+                if (log.isDebugEnabled()) log.debug("Received response for MEX 
" + mexId);
                 processResponse(statusCode);
             } catch (final IOException e) {
-                // ODE MEX needs to be invoked in a TX.
-                try {
-                    scheduler.execIsolatedTransaction(new Callable<Void>() {
-                        public Void call() throws Exception {
-                            PartnerRoleMessageExchange odeMex = 
(PartnerRoleMessageExchange) server.getEngine().getMessageExchange(mexId);      
                      
-                            String errmsg = "Unable to execute http request : 
" + e.getMessage();
-                            log.error(errmsg, e);
-                            
odeMex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, 
errmsg, null);
-                            return null;
-                        }
-                    });
-                } catch (Exception e1) {
-                    String errmsg = "Error executing reply transaction; reply 
will be lost.";
-                    log.error(errmsg, e);
-                }
+                PartnerRoleMessageExchange odeMex = 
(PartnerRoleMessageExchange) server.getEngine().getMessageExchange(mexId);
+                String errmsg = "Unable to execute HTTP request : " + 
e.getMessage();
+                log.error(errmsg, e);
+                
odeMex.replyWithFailure(MessageExchange.FailureType.COMMUNICATION_ERROR, 
errmsg, null);
             } finally {
                 method.releaseConnection();
             }
@@ -251,13 +241,14 @@
             try {
                 // log the URI since the engine may have moved on while this 
One Way request was executing
                 if (statusCode >= 400) {
-                        log.error("OneWay HTTP Request failed, Status-Line: " 
+ method.getStatusLine()+ " for "+ method.getURI());
+                    log.error("OneWay HTTP Request failed, Status-Line: " + 
method.getStatusLine() + " for " + method.getURI());
                 } else {
                     if (log.isDebugEnabled())
-                        log.debug("OneWay HTTP Request, Status-Line: " + 
method.getStatusLine()+ " for "+ method.getURI());
+                        log.debug("OneWay HTTP Request, Status-Line: " + 
method.getStatusLine() + " for " + method.getURI());
                 }
             } catch (URIException e) {
-                if (log.isDebugEnabled()) log.debug(e);
+                String errmsg = "Exception occured while processing the HTTP 
response of a one-way request: " + e.getMessage();
+                log.error(errmsg, e);
             }
         }
     }
@@ -289,14 +280,16 @@
                     }
                 });
             } catch (Exception e) {
-                String errmsg = "Error executing reply transaction; reply will 
be lost.";
+                String errmsg = "Exception occured while processing the HTTP 
response of a two-way request: " + e.getMessage();
                 log.error(errmsg, e);
+                PartnerRoleMessageExchange odeMex = 
(PartnerRoleMessageExchange) server.getEngine().getMessageExchange(mexId);
+                
odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
             }
         }
 
         private void unmanagedStatus() throws IOException {
             PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
-            String errmsg = "Unmanaged Status Code! Status-Line: " + 
method.getStatusLine()+ " for "+ method.getURI();
+            String errmsg = "Unmanaged Status Code! Status-Line: " + 
method.getStatusLine() + " for " + method.getURI();
             log.error(errmsg);
             odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpHelper.prepareDetailsElement(method));
         }
@@ -307,12 +300,26 @@
          * @throws IOException
          */
         private void _5xx_serverError() throws IOException {
-            String errmsg = "Status-Line: " + method.getStatusLine()+ " for "+ 
method.getURI();
-            if(log.isWarnEnabled()) log.warn(errmsg);
+            String errmsg;
+            if (log.isWarnEnabled()) {
+                errmsg = "Status-Line: " + method.getStatusLine() + " for " + 
method.getURI();
+                log.warn(errmsg);
+            }
             PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
             Operation opDef = odeMex.getOperation();
             BindingOperation opBinding = 
portBinding.getBindingOperation(opDef.getName(), opDef.getInput().getName(), 
opDef.getOutput().getName());
-            String body = method.getResponseBodyAsString();
+
+            final String body;
+            try {
+                body = method.getResponseBodyAsString();
+            } catch (IOException e) {
+                errmsg = "Unable to get the request body : " + e.getMessage();
+                log.error(errmsg, e);
+                
odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, 
HttpHelper.prepareDetailsElement(method));
+                return;
+            }
+            Header h = method.getResponseHeader("Content-Type");
+            String receivedType = h != null ? h.getValue() : null;
             if (opDef.getFaults().isEmpty()) {
                 errmsg = "Operation [" + opDef.getName() + "] has no fault. 
This 500 error will be considered as a failure.";
                 log.error(errmsg);
@@ -325,129 +332,178 @@
                 errmsg = "No body in the response. This 500 error will be 
considered as a failure.";
                 log.error(errmsg);
                 odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
+            } else if (receivedType != null && 
!HttpHelper.isXml(receivedType)) {
+                errmsg = "Response Content-Type [" + receivedType + "] does 
not describe XML entities. Faults must be XML. This 500 error will be 
considered as a failure.";
+                log.error(errmsg);
+                odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
             } else {
-                try {
-                    Element bodyEl = DOMUtils.stringToDOM(body);
-                    QName bodyName = new QName(bodyEl.getNamespaceURI(), 
bodyEl.getNodeName());
-                    Fault faultDef = WsdlUtils.inferFault(opDef, bodyName);
-
-                    if (faultDef == null) {
-                        errmsg = "Unknown Fault Type [" + bodyName + "] This 
500 error will be considered as a failure.";
-                        log.error(errmsg);
-                        
odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpHelper.prepareDetailsElement(method));
-                    } else if 
(!WsdlUtils.isOdeFault(opBinding.getBindingFault(faultDef.getName()))) {
-                        // is this fault bound with ODE extension?
-                        errmsg = "Fault [" + bodyName + "] is not bound with " 
+ new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "fault") + ". This 500 error will 
be considered as a failure.";
-                        log.error(errmsg);
-                        
odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpHelper.prepareDetailsElement(method));
-                    } else {
-                        // a fault must have only one part
-                        Part partDef = (Part) 
faultDef.getMessage().getParts().values().iterator().next();
 
-                        // 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 faultName = new QName(targetNamespace, 
faultDef.getName());
-                        QName faultType = faultDef.getMessage().getQName();
-                        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!
-                        if (log.isWarnEnabled())
-                            log.warn("Fault response: faultName=" + faultName 
+ " faultType=" + faultType + "\n" + DOMUtils.domToString(odeMsgEl));
-                        odeMex.replyWithFault(faultName, response);
-                    }
+                if (receivedType == null) {
+                    if (log.isWarnEnabled())
+                        log.warn("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) {
                     errmsg = "Unable to parse the response body as xml. This 
500 error will be considered as a failure.";
                     log.error(errmsg, e);
-                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method, false));
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
+                    return;
                 }
-            }
 
+                // Guess which fault it is
+                QName bodyName = new QName(bodyElement.getNamespaceURI(), 
bodyElement.getNodeName());
+                Fault faultDef = WsdlUtils.inferFault(opDef, bodyName);
+
+                if (faultDef == null) {
+                    errmsg = "Unknown Fault Type [" + bodyName + "] This 500 
error will be considered as a failure.";
+                    log.error(errmsg);
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
+                } else if 
(!WsdlUtils.isOdeFault(opBinding.getBindingFault(faultDef.getName()))) {
+                    // is this fault bound with ODE extension?
+                    errmsg = "Fault [" + bodyName + "] is not bound with " + 
new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "fault") + ". This 500 error will 
be considered as a failure.";
+                    log.error(errmsg);
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
+                } else {
+                    // a fault has only one part
+                    Part partDef = (Part) 
faultDef.getMessage().getParts().values().iterator().next();
+
+                    QName faultName = new QName(targetNamespace, 
faultDef.getName());
+                    QName faultType = faultDef.getMessage().getQName();
+
+                    // create the ODE Message now that we know the fault
+                    Message response = odeMex.createMessage(faultType);
+
+                    // build the element to be sent back
+                    Element partElement = 
httpMethodConverter.createPartElement(partDef, bodyElement);
+                    response.setPart(partDef.getName(), partElement);
+
+                    // extract and set headers
+                    httpMethodConverter.extractHttpResponseHeaders(response, 
method, faultDef.getMessage(), opBinding.getBindingOutput());
+
+                    // finally send the fault. We did it!
+                    if (log.isWarnEnabled())
+                        log.warn("Fault response: faultName=" + faultName + " 
faultType=" + faultType + "\n" + DOMUtils.domToString(response.getMessage()));
+                    odeMex.replyWithFault(faultName, response);
+                }
+
+            }
         }
 
         private void _4xx_badRequest() throws IOException {
-           PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
-            String errmsg = "HTTP Status-Line: " + method.getStatusLine()+ " 
for "+ method.getURI();
+            PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
+            String errmsg = "HTTP Status-Line: " + method.getStatusLine() + " 
for " + method.getURI();
             log.error(errmsg);
             odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpClientHelper.prepareDetailsElement(method));
         }
 
         private void _3xx_redirection() throws IOException {
             PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
-            String errmsg = "Redirections disabled! HTTP Status-Line: " + 
method.getStatusLine()+ " for "+ method.getURI();
+            String errmsg = "Redirections disabled! HTTP Status-Line: " + 
method.getStatusLine() + " for " + method.getURI();
             log.error(errmsg);
             odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpClientHelper.prepareDetailsElement(method));
         }
 
         private void _2xx_success() throws IOException {
             PartnerRoleMessageExchange odeMex = (PartnerRoleMessageExchange) 
server.getEngine().getMessageExchange(mexId);
-            if (log.isDebugEnabled()) log.debug("HTTP Status-Line: " + 
method.getStatusLine()+ " for "+ method.getURI());
+            if (log.isDebugEnabled())
+                log.debug("HTTP Status-Line: " + method.getStatusLine() + " 
for " + method.getURI());
             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");
+            javax.wsdl.Message outputMessage = 
odeMex.getOperation().getOutput().getMessage();
+
+            // this is the message to populate and send to ODE
+            Message odeResponse = 
odeMex.createMessage(outputMessage.getQName());
+
+            /* process headers */
+            httpMethodConverter.extractHttpResponseHeaders(odeResponse, 
method, outputMessage, opBinding.getBindingOutput());
 
+            /* 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());
+            boolean xmlExpected = outputContent != null && 
HttpHelper.isXml(outputContent.getType());
+            boolean isBodyExpected = outputContent != null;
+            boolean isBodyMandatory = isBodyExpected && xmlExpected;
+            final String body;
             try {
-                final String body = method.getResponseBodyAsString();
-                if (isBodyMandatory && StringUtils.isEmpty(body)) {
+                body = method.getResponseBodyAsString();
+            } catch (IOException e) {
+                String errmsg = "Unable to get the request body : " + 
e.getMessage();
+                log.error(errmsg, e);
+                
odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, 
HttpHelper.prepareDetailsElement(method));
+                return;
+            }
+
+            final boolean emptyBody = StringUtils.isEmpty(body);
+            if (emptyBody) {
+                if (isBodyMandatory) {
                     String errmsg = "Response body is mandatory but missing! 
Msg Id=" + odeMex.getMessageExchangeId();
                     log.error(errmsg);
-                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, null);
-                } else {
-                    javax.wsdl.Message outputMessage = 
odeMex.getOperation().getOutput().getMessage();
-                    Message odeResponse = 
odeMex.createMessage(outputMessage.getQName());
+                    odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
+                    return;
+                }
+            } else {
+                if (isBodyExpected) {
+                    Part partDef = 
outputMessage.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 && 
HttpHelper.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);
+                        }
 
-                    // handle the body if any
-                    if (StringUtils.isNotEmpty(body)) {
-                        // only text/xml is supported in the response body
+                        // parse the body and create the message part
                         try {
                             Element bodyElement = DOMUtils.stringToDOM(body);
-                            Part part = 
outputMessage.getPart(outputContent.getPart());
-                            Element partElement = 
httpMethodConverter.createPartElement(part, bodyElement);
-                            odeResponse.setPart(part.getName(), partElement);
+                            partElement = 
httpMethodConverter.createPartElement(partDef, bodyElement);
                         } 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);
+                            
odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, 
HttpHelper.prepareDetailsElement(method));
                             return;
                         }
+                    } else {
+                        // if not xml, process it as text
+                        partElement = 
httpMethodConverter.createPartElement(partDef, body);
                     }
 
-                    // handle headers
-                    
httpMethodConverter.extractHttpResponseHeaders(odeResponse, method, 
outputMessage, opBinding.getBindingOutput());
-
-                    try {
+                    // set the part
+                    odeResponse.setPart(partDef.getName(), partElement);
 
-                        if (log.isInfoEnabled())
-                            log.info("Response: " + (odeResponse.getMessage() 
!= null ? DOMUtils.domToString(odeResponse.getMessage()) : "empty"));
-                        odeMex.reply(odeResponse);
-                    } catch (Exception ex) {
-                        String errmsg = "Unable to process response: " + 
ex.getMessage();
-                        log.error(errmsg, ex);
-                        
odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, errmsg, 
HttpHelper.prepareDetailsElement(method));
-                    }
+                } 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);
                 }
-            } catch (IOException e) {
-                String errmsg = "Unable to get the request body : " + 
e.getMessage();
-                log.error(errmsg, e);
-                
odeMex.replyWithFailure(MessageExchange.FailureType.FORMAT_ERROR, errmsg, null);
-                return;
+            }
+
+            // finally send the message
+            try {
+                if (log.isInfoEnabled())
+                    log.info("Response: " + (odeResponse.getMessage() != null 
? DOMUtils.domToString(odeResponse.getMessage()) : "empty"));
+                odeMex.reply(odeResponse);
+            } catch (Exception ex) {
+                String errmsg = "Unable to process response: " + 
ex.getMessage();
+                log.error(errmsg, ex);
+                odeMex.replyWithFailure(MessageExchange.FailureType.OTHER, 
errmsg, HttpHelper.prepareDetailsElement(method));
             }
         }
     }
 }
-

Modified: 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpHelper.java
URL: 
http://svn.apache.org/viewvc/ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpHelper.java?rev=676683&r1=676682&r2=676683&view=diff
==============================================================================
--- 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpHelper.java
 (original)
+++ 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpHelper.java
 Mon Jul 14 11:42:40 2008
@@ -27,6 +27,7 @@
 import org.apache.commons.httpclient.URIException;
 import org.apache.commons.httpclient.StatusLine;
 import org.apache.commons.httpclient.HttpException;
+import org.apache.commons.httpclient.Header;
 import org.apache.commons.httpclient.params.HttpParams;
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -117,43 +118,42 @@
      * @return
      * @throws IOException
      */
-    public static Element prepareDetailsElement(HttpMethod method) throws 
IOException {
-        return prepareDetailsElement(method, true);
-    }
+    public static Element prepareDetailsElement(HttpMethod method) {
+        Header h = method.getResponseHeader("Content-Type");
+        String receivedType = h != null ? h.getValue() : null;
+        boolean bodyIsXml = receivedType != null && 
HttpHelper.isXml(receivedType);
+
 
-    /**
-     * @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 static 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 String body = method.getResponseBodyAsString();
-        if (StringUtils.isNotEmpty(body)) {
-            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.stringToDOM(body);
-                    bodyEl.appendChild(doc.importNode(parsedBodyEl, true));
-                } 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;
+        try {
+            final String body = method.getResponseBodyAsString();
+            if (StringUtils.isNotEmpty(body)) {
+                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.stringToDOM(body);
+                        bodyEl.appendChild(doc.importNode(parsedBodyEl, true));
+                    } 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;
+                    }
+                }
+                if (!bodyIsXml || exceptionDuringParsing) {
+                    bodyEl.setTextContent(body);
                 }
             }
-            if (!bodyIsXml || exceptionDuringParsing) {
-                bodyEl.setTextContent(method.getResponseBodyAsString());
-            }
+        } catch (IOException e) {
+            if (log.isWarnEnabled()) log.warn("Exception while loading 
response body", e);
         }
         return detailsEl;
     }
@@ -161,14 +161,13 @@
     private static final Pattern NON_LWS_PATTERN = 
Pattern.compile("\r\n([^\\s])");
 
     /**
-     *
      * This method ensures that a header value containing CRLF does not mess 
up the HTTP request.
      * Actually CRLF is the end-of-line marker for headers.
      * <p/>
      * To do so, all CRLF followed by a non-whitespace character are replaced 
by CRLF HT.
      * <p/>
      * This is possible because the
-     *  <a 
href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2";>Section 
2.2</a> of HTTP standard (RFC2626) states that:
+     * <a 
href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2.2";>Section 
2.2</a> of HTTP standard (RFC2626) states that:
      * <p/>
      * <quote>
      * HTTP/1.1 header field values can be folded onto multiple lines if the
@@ -180,8 +179,9 @@
      * LWS            = [CRLF] 1*( SP | HT )
      * <p/>
      * </quote>
-     *<p/>
+     * <p/>
      * FYI, HttpClient 3.x.x does not check this.
+     *
      * @param header
      * @return the string properly ready to be used as an HTTP header 
field-content
      */
@@ -195,4 +195,17 @@
         m.appendTail(sb);
         return sb.toString();
     }
+
+    public static final String XML_MIME_TYPE_REGEX = 
"(text/xml)|(application/xml)|((.*)\\+xml)";
+    private static final String TEXT_MIME_TYPE_REGEX = "text/(?!xml$).*";
+    private static final Pattern XML_MIME_TYPE_PATTERN = 
Pattern.compile(XML_MIME_TYPE_REGEX);
+    private static final Pattern TEXT_MIME_TYPE_PATTERN = 
Pattern.compile(TEXT_MIME_TYPE_REGEX);
+
+    public static boolean isXml(String contentType) {
+        return XML_MIME_TYPE_PATTERN.matcher(contentType).matches();
+    }
+
+    public static boolean isText(String contentType) {
+        return TEXT_MIME_TYPE_PATTERN.matcher(contentType).matches();
+    }
 }

Modified: 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java
URL: 
http://svn.apache.org/viewvc/ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java?rev=676683&r1=676682&r2=676683&view=diff
==============================================================================
--- 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java
 (original)
+++ 
ode/branches/APACHE_ODE_1.X/axis2/src/main/java/org/apache/ode/axis2/httpbinding/HttpMethodConverter.java
 Mon Jul 14 11:42:40 2008
@@ -65,7 +65,6 @@
 
 public class HttpMethodConverter {
 
-    private static final String CONTENT_TYPE_TEXT_XML = "text/xml";
     private static final Log log = 
LogFactory.getLog(HttpMethodConverter.class);
 
     protected static final Messages msgs = 
Messages.getMessages(Messages.class);
@@ -114,7 +113,7 @@
         BindingInput bindingInput = opBinding.getBindingInput();
         HTTPOperation httpOperation = (HTTPOperation) 
WsdlUtils.getOperationExtension(opBinding);
         MIMEContent content = 
WsdlUtils.getMimeContent(bindingInput.getExtensibilityElements());
-        String contentType = content == null ? "" : content.getType();
+        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);
 
@@ -172,24 +171,30 @@
             }
 
             // 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, 
method.getParams().getContentCharset());
-            } else if (contentType.endsWith(CONTENT_TYPE_TEXT_XML)) {
+                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 the part has an element name, we must take the first 
element
-                if (part.getElementName() != null) {
-                    String xmlString = 
DOMUtils.domToString(DOMUtils.getFirstChildElement(partValue));
-                    requestEntity = new 
ByteArrayRequestEntity(xmlString.getBytes(), contentType);
-                } else {
-                    String errMsg = "Types are not supported with 'text/xml'. 
Parts must use elements.";
+
+                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 (HttpHelper.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);
                 }
-            } 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
@@ -207,19 +212,37 @@
         method.setPath(completeUri); // assumes that the path is properly 
encoded (URL safe).
         method.setQueryString(queryPath);
 
-        // headers
-        setHttpRequestHeaders(method, partValues, headers, 
opBinding.getOperation().getInput().getMessage(), opBinding.getBindingInput());
+        // set headers
+        setHttpRequestHeaders(method, partValues, headers, opBinding);
         return method;
     }
 
     /**
-     * Go through the list of [EMAIL PROTECTED] [EMAIL PROTECTED] :header} 
elements included in the input binding. For each of them, set the HTTP Request 
Header with the static value defined by the attribute [EMAIL PROTECTED] [EMAIL 
PROTECTED] :value},
+     * Go through the list of message headers and set them if empty.
+     * <p/>
+     * Then go through the list of [EMAIL PROTECTED] [EMAIL PROTECTED] 
:header} elements included in the input binding.
+     * For each of them, set the HTTP Request Header with the static value 
defined by the attribute [EMAIL PROTECTED] [EMAIL PROTECTED] :value},
      * or the part value mentionned in the attribute [EMAIL PROTECTED] [EMAIL 
PROTECTED] :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, Map<String, Element> 
partValues, Map<String, Node> headers, Message inputMessage, BindingInput 
bindingInput) {
+    public void setHttpRequestHeaders(HttpMethod method, Map<String, Element> 
partValues, Map<String, Node> headers, BindingOperation opBinding) {
+        BindingInput inputBinding = opBinding.getBindingInput();
+        Message inputMessage = 
opBinding.getOperation().getInput().getMessage();
+
+        // 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(bindingInput.getExtensibilityElements());
+        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");
@@ -254,16 +277,10 @@
             method.setRequestHeader(headerName, 
HttpHelper.replaceCRLFwithLWS(headerValue));
         }
 
-        // 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();
-            // set the request header but do not override any part value
-            if (method.getRequestHeader(headerName) == null) {
-                String headerValue = DOMUtils.domToString(headerNode);
-                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());
         }
 
     }
@@ -343,8 +360,10 @@
     /**
      * Process the HTTP Response Headers.
      * <p/>
-     * First go through the list of [EMAIL PROTECTED] [EMAIL PROTECTED] 
:header} elements included in the output binding. For each of them, set the 
header value as the value of the message part.
-     * <br/>Then add all HTTP headers as header part in the message. The name 
of the header would be the part name.
+     * First go through the list of [EMAIL PROTECTED] [EMAIL PROTECTED] 
: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.
      *
      * @param odeMessage
      * @param method
@@ -363,7 +382,14 @@
 
             Part part = messageDef.getPart(partName);
             if (StringUtils.isNotEmpty(partName)) {
-                odeMessage.setPart(partName, createPartElement(part, 
method.getResponseHeader(headerName).getValue()));
+                Header responseHeader = method.getResponseHeader(headerName);
+                if (responseHeader != null) {
+                    odeMessage.setPart(partName, createPartElement(part, 
responseHeader.getValue()));
+                } else {
+                    String errMsg = "Part [" + partName + "] is bound to 
header [" + headerName + "], but this header is not set in the HTTP response.";
+                    if (log.isErrorEnabled()) log.error(errMsg);
+                    throw new RuntimeException(errMsg);
+                }
             } else {
                 String errMsg = "Invalid binding: missing required attribute! 
Part name: " + new QName(Namespaces.ODE_HTTP_EXTENSION_NS, "part");
                 if (log.isErrorEnabled()) log.error(errMsg);

Modified: 
ode/branches/APACHE_ODE_1.X/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpHelperTest.java
URL: 
http://svn.apache.org/viewvc/ode/branches/APACHE_ODE_1.X/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpHelperTest.java?rev=676683&r1=676682&r2=676683&view=diff
==============================================================================
--- 
ode/branches/APACHE_ODE_1.X/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpHelperTest.java
 (original)
+++ 
ode/branches/APACHE_ODE_1.X/axis2/src/test/java/org/apache/ode/axis2/httpbinding/HttpHelperTest.java
 Mon Jul 14 11:42:40 2008
@@ -20,6 +20,8 @@
 package org.apache.ode.axis2.httpbinding;
 
 import junit.framework.TestCase;
+import org.apache.ode.utils.DOMUtils;
+import org.w3c.dom.Document;
 
 /**
  *
@@ -49,26 +51,26 @@
     public void testIsXml() {
 
         for (String s : IS_XML) {
-            assertTrue(HttpHelper.isXml(s));
+            assertTrue(s+" is an xml type", HttpHelper.isXml(s));
         }
         for (String s : IS_TEXT) {
-            assertFalse(HttpHelper.isXml(s));
+            assertFalse(s+" is not an xml type", HttpHelper.isXml(s));
         }
         for (String s : IS_IMAGE) {
-            assertFalse(HttpHelper.isXml(s));
+            assertFalse(s+" is not an xml type", HttpHelper.isXml(s));
         }
 
     }
 
     public void testIsText() {
         for (String s : IS_TEXT) {
-            assertTrue("", HttpHelper.isText(s));
+            assertTrue(s+" is a text type", HttpHelper.isText(s));
         }
         for (String s : IS_XML) {
-            assertFalse(HttpHelper.isText(s));
+            assertFalse(s+" is not a text type", HttpHelper.isText(s));
         }
         for (String s : IS_IMAGE) {
-            assertFalse(HttpHelper.isXml(s));
+            assertFalse(s+" is not a text type", HttpHelper.isXml(s));
         }
     }
 }


Reply via email to