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));
}
}
}