Correctly set HTTP status code on SOAP 1.2 fault

SOAP v1.2 specifies that for SOAP Fault's with Code of "env:Sender" the
HTTP response status code should be 400 (rather than 500 for all other
faults). This commit changes both client and server-side to reflect
this.

Issue: SWS-868
This commit is contained in:
Arjen Poutsma
2014-04-23 11:37:41 +02:00
parent d43b880637
commit ded1efd456
22 changed files with 1033 additions and 192 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,8 @@
package org.springframework.ws;
import javax.xml.namespace.QName;
/**
* Sub-interface of {@link WebServiceMessage} that can contain special Fault messages. Fault messages (such as {@link
* org.springframework.ws.soap.SoapFault} SOAP Faults) often require different processing rules.
@@ -34,6 +36,12 @@ public interface FaultAwareWebServiceMessage extends WebServiceMessage {
*/
boolean hasFault();
/**
* Returns the fault code, if any.
*/
QName getFaultCode();
/**
* Returns the fault reason message.
*

View File

@@ -16,6 +16,7 @@
package org.springframework.ws.soap;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
@@ -61,7 +62,17 @@ public abstract class AbstractSoapMessage extends AbstractMimeMessage implements
return getSoapBody().hasFault();
}
/** Returns {@code getSoapBody().getFault().getFaultStringOrReason()}. */
/** Returns {@code getSoapBody().getFault().getFaultCode()}. */
@Override
public final QName getFaultCode() {
if (hasFault()) {
return getSoapBody().getFault().getFaultCode();
} else {
return null;
}
}
/** Returns {@code getSoapBody().getFault().getFaultStringOrReason()}. */
@Override
public final String getFaultReason() {
if (hasFault()) {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2007 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
package org.springframework.ws.transport;
import java.io.IOException;
import javax.xml.namespace.QName;
import org.springframework.ws.soap.SoapFault;
@@ -47,6 +48,18 @@ public interface FaultAwareWebServiceConnection extends WebServiceConnection {
*
* @param fault {@code true} if this will send a fault; {@code false} otherwise.
* @throws IOException in case of I/O errors
* @deprecated In favor of {@link #setFaultCode(QName)}
*/
@Deprecated
void setFault(boolean fault) throws IOException;
/**
* Sets a specific fault code.
*
* <p>Typically implemented by setting an HTTP status code.
*
* @param faultCode the fault code to be set on the connection, or {@code null} for no fault.
* @throws IOException in case of I/O errors
*/
void setFaultCode(QName faultCode) throws IOException;
}

View File

@@ -21,6 +21,7 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Iterator;
import java.util.zip.GZIPInputStream;
import javax.xml.namespace.QName;
import org.springframework.util.FileCopyUtils;
import org.springframework.util.StringUtils;
@@ -119,15 +120,34 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
@Override
public final boolean hasFault() throws IOException {
return HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR == getResponseCode() && isXmlResponse();
// SOAP 1.1 specifies a 500 status code for faults
// SOAP 1.2 specifies a 400 status code for sender faults, and 500 for all other faults
switch (getResponseCode()) {
case HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR:
return isSoap11Response() || isSoap12Response();
case HttpTransportConstants.STATUS_BAD_REQUEST:
return isSoap12Response();
default:
return false;
}
}
/** Determine whether the response is a XML message. */
private boolean isXmlResponse() throws IOException {
/** Determine whether the response is a SOAP 1.1 message. */
private boolean isSoap11Response() throws IOException {
Iterator<String> iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_TYPE);
if (iterator.hasNext()) {
String contentType = iterator.next().toLowerCase();
return contentType.contains("xml");
return contentType.contains("text/xml");
}
return false;
}
/** Determine whether the response is a SOAP 1.1 message. */
private boolean isSoap12Response() throws IOException {
Iterator<String> iterator = getResponseHeaders(HttpTransportConstants.HEADER_CONTENT_TYPE);
if (iterator.hasNext()) {
String contentType = iterator.next().toLowerCase();
return contentType.contains("application/soap+xml");
}
return false;
}
@@ -136,4 +156,7 @@ public abstract class AbstractHttpSenderConnection extends AbstractSenderConnect
public final void setFault(boolean fault) {
}
@Override
public final void setFaultCode(QName faultCode) throws IOException {
}
}

View File

@@ -24,6 +24,8 @@ import java.net.URISyntaxException;
import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPConstants;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.transport.AbstractReceiverConnection;
@@ -163,4 +165,22 @@ public class HttpServletConnection extends AbstractReceiverConnection
}
statusCodeSet = true;
}
@Override
public void setFaultCode(QName faultCode) throws IOException {
if (faultCode != null) {
if (SOAPConstants.SOAP_SENDER_FAULT.equals(faultCode)) {
getHttpServletResponse()
.setStatus(HttpTransportConstants.STATUS_BAD_REQUEST);
}
else {
getHttpServletResponse()
.setStatus(HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR);
}
}
else {
getHttpServletResponse().setStatus(HttpTransportConstants.STATUS_OK);
}
statusCodeSet = true;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2007 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -44,6 +44,9 @@ public interface HttpTransportConstants extends TransportConstants {
/** The "204 No Content" status code. */
int STATUS_NO_CONTENT = 204;
/** The "400 Bad Request" status code. */
int STATUS_BAD_REQUEST = 400;
/** The "404 Not Found" status code. */
int STATUS_NOT_FOUND = 404;

View File

@@ -93,7 +93,7 @@ public abstract class WebServiceMessageReceiverObjectSupport implements Initiali
connection instanceof FaultAwareWebServiceConnection) {
FaultAwareWebServiceMessage faultResponse = (FaultAwareWebServiceMessage) response;
FaultAwareWebServiceConnection faultConnection = (FaultAwareWebServiceConnection) connection;
faultConnection.setFault(faultResponse.hasFault());
faultConnection.setFaultCode(faultResponse.getFaultCode());
}
connection.send(messageContext.getResponse());
}

View File

@@ -23,6 +23,7 @@ import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Reader;
import java.io.Writer;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
@@ -49,9 +50,11 @@ public class MockWebServiceMessage implements FaultAwareWebServiceMessage {
private boolean fault = false;
private QName faultCode;
private String faultReason;
public MockWebServiceMessage() {
public MockWebServiceMessage() {
}
public MockWebServiceMessage(Source source) throws TransformerException {
@@ -126,7 +129,16 @@ public class MockWebServiceMessage implements FaultAwareWebServiceMessage {
this.fault = fault;
}
@Override
@Override
public QName getFaultCode() {
return faultCode;
}
public void setFaultCode(QName faultCode) {
this.faultCode = faultCode;
}
@Override
public String getFaultReason() {
return faultReason;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -20,9 +20,7 @@ import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.MailcapCommandMap;
import javax.mail.util.ByteArrayDataSource;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
@@ -30,8 +28,6 @@ import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.namespace.QName;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
@@ -44,8 +40,18 @@ import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import org.junit.AfterClass;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.xml.sax.SAXException;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
@@ -53,32 +59,15 @@ import org.springframework.oxm.XmlMappingException;
import org.springframework.util.StringUtils;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.pox.dom.DomPoxMessageFactory;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
import org.springframework.ws.soap.client.SoapFaultClientException;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.ws.transport.http.CommonsHttpMessageSender;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
import org.springframework.ws.transport.support.FreePortScanner;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import static org.junit.Assert.assertEquals;
public class WebServiceTemplateIntegrationTest {
public abstract class AbstractSoap11WebServiceTemplateIntegrationTestCase {
private static Server jettyServer;
@@ -102,88 +91,29 @@ public class WebServiceTemplateIntegrationTest {
jettyContext.addServlet(new ServletHolder(badRequestFault), "/soap/badRequestFault");
jettyContext.addServlet(new ServletHolder(new NoResponseSoapServlet()), "/soap/noResponse");
jettyContext.addServlet(new ServletHolder(new AttachmentsServlet()), "/soap/attachment");
jettyContext.addServlet(new ServletHolder(new PoxServlet()), "/pox");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
}
/**
* A workaround for the faulty XmlDataContentHandler in the SAAJ RI, which cannot handle mime types such as
* "text/xml; charset=UTF-8", causing issues with Axiom. We basically reset the command map
*/
@Before
public void removeXmlDataContentHandler() throws SOAPException {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
message.createAttachmentPart();
CommandMap.setDefaultCommandMap(new MailcapCommandMap());
}
@AfterClass
public static void stopJetty() throws Exception {
if (jettyServer.isRunning()) {
jettyServer.stop();
}
}
@Test
public void testSaaj() throws Exception {
doSoap(new SaajSoapMessageFactory(MessageFactory.newInstance()));
}
@Test
public void testAxiom() throws Exception {
doSoap(new AxiomSoapMessageFactory());
}
@AfterClass
public static void stopJetty() throws Exception {
if (jettyServer.isRunning()) {
jettyServer.stop();
}
}
@Test
public void testAxiomNonCaching() throws Exception {
AxiomSoapMessageFactory axiomFactory = new AxiomSoapMessageFactory();
axiomFactory.setPayloadCaching(false);
doSoap(axiomFactory);
}
@Before
public void createWebServiceTemplate() throws Exception {
template = new WebServiceTemplate(createMessageFactory());
template.setMessageSender(new HttpComponentsMessageSender());
}
@Test
public void testPox() throws Exception {
template = new WebServiceTemplate(new DomPoxMessageFactory());
template.setMessageSender(new CommonsHttpMessageSender());
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendSourceAndReceiveToResult(baseUrl + "/pox", new StringSource(content), result);
assertXMLEqual(content, result.toString());
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/notfound", new StringSource(content),
new StringResult());
Assert.fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/server", new StringSource(content),
result);
Assert.fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
}
private void doSoap(SoapMessageFactory messageFactory) throws Exception {
template = new WebServiceTemplate(messageFactory);
template.setMessageSender(new CommonsHttpMessageSender());
sendSourceAndReceiveToResult();
sendSourceAndReceiveToResultNoResponse();
marshalSendAndReceiveResponse();
marshalSendAndReceiveNoResponse();
notFound();
fault();
faultNonCompliant();
attachment();
}
public abstract SoapMessageFactory createMessageFactory() throws Exception;
private void sendSourceAndReceiveToResult() throws SAXException, IOException {
@Test
public void sendSourceAndReceiveToResult() throws SAXException, IOException {
StringResult result = new StringResult();
boolean b = template.sendSourceAndReceiveToResult(baseUrl + "/soap/echo",
new StringSource(messagePayload), result);
@@ -191,17 +121,20 @@ public class WebServiceTemplateIntegrationTest {
assertXMLEqual(messagePayload, result.toString());
}
private void sendSourceAndReceiveToResultNoResponse() {
@Test
public void sendSourceAndReceiveToResultNoResponse() {
boolean b = template.sendSourceAndReceiveToResult(baseUrl + "/soap/noResponse",
new StringSource(messagePayload), new StringResult());
Assert.assertFalse("Invalid result", b);
}
private void marshalSendAndReceiveResponse() throws TransformerConfigurationException {
@Test
public void marshalSendAndReceiveResponse() throws TransformerConfigurationException {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
final Object requestObject = new Object();
Marshaller marshaller = new Marshaller() {
@Override
public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
Assert.assertEquals("Invalid object", graph, requestObject);
try {
@@ -212,6 +145,7 @@ public class WebServiceTemplateIntegrationTest {
}
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
@@ -220,10 +154,12 @@ public class WebServiceTemplateIntegrationTest {
final Object responseObject = new Object();
Unmarshaller unmarshaller = new Unmarshaller() {
@Override
public Object unmarshal(Source source) throws XmlMappingException, IOException {
return responseObject;
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
@@ -235,11 +171,13 @@ public class WebServiceTemplateIntegrationTest {
Assert.assertEquals("Invalid response object", responseObject, result);
}
private void marshalSendAndReceiveNoResponse() throws TransformerConfigurationException {
@Test
public void marshalSendAndReceiveNoResponse() throws TransformerConfigurationException {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
final Object requestObject = new Object();
Marshaller marshaller = new Marshaller() {
@Override
public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
Assert.assertEquals("Invalid object", graph, requestObject);
try {
@@ -250,6 +188,7 @@ public class WebServiceTemplateIntegrationTest {
}
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
@@ -260,7 +199,8 @@ public class WebServiceTemplateIntegrationTest {
Assert.assertNull("Invalid response object", result);
}
private void notFound() {
@Test
public void notFound() {
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/notfound",
new StringSource(messagePayload), new StringResult());
@@ -271,7 +211,8 @@ public class WebServiceTemplateIntegrationTest {
}
}
private void fault() {
@Test
public void fault() {
Result result = new StringResult();
try {
template.sendSourceAndReceiveToResult(baseUrl + "/soap/fault", new StringSource(messagePayload),
@@ -283,7 +224,8 @@ public class WebServiceTemplateIntegrationTest {
}
}
private void faultNonCompliant() {
@Test
public void faultNonCompliant() {
Result result = new StringResult();
template.setCheckConnectionForFault(false);
template.setCheckConnectionForError(false);
@@ -297,10 +239,12 @@ public class WebServiceTemplateIntegrationTest {
}
}
private void attachment() {
@Test
public void attachment() {
template.sendSourceAndReceiveToResult(baseUrl + "/soap/attachment", new StringSource(messagePayload),
new WebServiceMessageCallback() {
@Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
SoapMessage soapMessage = (SoapMessage) message;
final String attachmentContent = "content";
@@ -325,36 +269,7 @@ public class WebServiceTemplateIntegrationTest {
}
}
/** Simple POX Servlet. */
private static class PoxServlet extends HttpServlet {
private DocumentBuilderFactory documentBuilderFactory;
private TransformerFactory transformerFactory;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
transformerFactory = TransformerFactory.newInstance();
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document message = documentBuilder.parse(req.getInputStream());
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(message), new StreamResult(resp.getOutputStream()));
}
catch (Exception ex) {
throw new ServletException("POX POST failed" + ex.getMessage());
}
}
}
/** Abstract SOAP Servlet */
/** Abstract SOAP Servlet */
private abstract static class AbstractSoapServlet extends HttpServlet {
protected MessageFactory messageFactory = null;
@@ -386,9 +301,7 @@ public class WebServiceTemplateIntegrationTest {
resp.setStatus(sc);
}
if (reply != null) {
if (reply.saveRequired()) {
reply.saveChanges();
}
reply.saveChanges();
if (sc == -1) {
resp.setStatus(!reply.getSOAPBody().hasFault() ? HttpServletResponse.SC_OK :
HttpServletResponse.SC_INTERNAL_SERVER_ERROR);

View File

@@ -0,0 +1,408 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.StringTokenizer;
import javax.activation.CommandMap;
import javax.activation.DataHandler;
import javax.activation.MailcapCommandMap;
import javax.mail.util.ByteArrayDataSource;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeader;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPBody;
import javax.xml.soap.SOAPConstants;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import org.junit.AfterClass;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.xml.sax.SAXException;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.oxm.XmlMappingException;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.soap.SoapMessage;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.client.SoapFaultClientException;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
import org.springframework.ws.transport.support.FreePortScanner;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
public abstract class AbstractSoap12WebServiceTemplateIntegrationTestCase {
private static Server jettyServer;
private static String baseUrl;
private WebServiceTemplate template;
private String messagePayload = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
@BeforeClass
public static void startJetty() throws Exception {
int port = FreePortScanner.getFreePort();
baseUrl = "http://localhost:" + port;
jettyServer = new Server(port);
Context jettyContext = new Context(jettyServer, "/");
jettyContext.addServlet(new ServletHolder(new EchoSoapServlet()), "/soap/echo");
jettyContext.addServlet(new ServletHolder(new SoapReceiverFaultServlet()), "/soap/receiverFault");
jettyContext.addServlet(new ServletHolder(new SoapSenderFaultServlet()), "/soap/senderFault");
jettyContext.addServlet(new ServletHolder(new NoResponseSoapServlet()), "/soap/noResponse");
jettyContext.addServlet(new ServletHolder(new AttachmentsServlet()), "/soap/attachment");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
}
@AfterClass
public static void stopJetty() throws Exception {
if (jettyServer.isRunning()) {
jettyServer.stop();
}
}
/**
* A workaround for the faulty XmlDataContentHandler in the SAAJ RI, which cannot handle mime types such as
* "text/xml; charset=UTF-8", causing issues with Axiom. We basically reset the command map
*/
@Before
public void removeXmlDataContentHandler() throws SOAPException {
MessageFactory messageFactory = MessageFactory.newInstance();
SOAPMessage message = messageFactory.createMessage();
message.createAttachmentPart();
CommandMap.setDefaultCommandMap(new MailcapCommandMap());
}
@Before
public void createWebServiceTemplate() throws Exception {
template = new WebServiceTemplate(createMessageFactory());
template.setMessageSender(new HttpComponentsMessageSender());
}
public abstract SoapMessageFactory createMessageFactory() throws Exception;
@Test
public void sendSourceAndReceiveToResult() throws SAXException, IOException {
StringResult result = new StringResult();
boolean b = template.sendSourceAndReceiveToResult(baseUrl + "/soap/echo",
new StringSource(messagePayload), result);
Assert.assertTrue("Invalid result", b);
assertXMLEqual(messagePayload, result.toString());
}
@Test
public void sendSourceAndReceiveToResultNoResponse() {
boolean b = template.sendSourceAndReceiveToResult(baseUrl + "/soap/noResponse",
new StringSource(messagePayload), new StringResult());
Assert.assertFalse("Invalid result", b);
}
@Test
public void marshalSendAndReceiveResponse() throws TransformerConfigurationException {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
final Object requestObject = new Object();
Marshaller marshaller = new Marshaller() {
@Override
public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
Assert.assertEquals("Invalid object", graph, requestObject);
try {
transformer.transform(new StringSource(messagePayload), result);
}
catch (TransformerException e) {
Assert.fail(e.getMessage());
}
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
}
};
final Object responseObject = new Object();
Unmarshaller unmarshaller = new Unmarshaller() {
@Override
public Object unmarshal(Source source) throws XmlMappingException, IOException {
return responseObject;
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
}
};
template.setMarshaller(marshaller);
template.setUnmarshaller(unmarshaller);
Object result = template.marshalSendAndReceive(baseUrl + "/soap/echo", requestObject);
Assert.assertEquals("Invalid response object", responseObject, result);
}
@Test
public void marshalSendAndReceiveNoResponse() throws TransformerConfigurationException {
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
final Object requestObject = new Object();
Marshaller marshaller = new Marshaller() {
@Override
public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
Assert.assertEquals("Invalid object", graph, requestObject);
try {
transformer.transform(new StringSource(messagePayload), result);
}
catch (TransformerException e) {
Assert.fail(e.getMessage());
}
}
@Override
public boolean supports(Class<?> clazz) {
Assert.assertEquals("Invalid class", Object.class, clazz);
return true;
}
};
template.setMarshaller(marshaller);
Object result = template.marshalSendAndReceive(baseUrl + "/soap/noResponse", requestObject);
Assert.assertNull("Invalid response object", result);
}
@Test
public void notFound() {
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/notfound",
new StringSource(messagePayload), new StringResult());
Assert.fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
}
@Test
public void receiverFault() {
Result result = new StringResult();
try {
template.sendSourceAndReceiveToResult(baseUrl + "/soap/receiverFault", new StringSource(messagePayload),
result);
Assert.fail("SoapFaultClientException expected");
}
catch (SoapFaultClientException ex) {
//expected
}
}
@Test
public void senderFault() {
Result result = new StringResult();
try {
template.sendSourceAndReceiveToResult(baseUrl + "/soap/senderFault", new StringSource(messagePayload),
result);
Assert.fail("SoapFaultClientException expected");
}
catch (SoapFaultClientException ex) {
//expected
}
}
@Test
public void attachment() {
template.sendSourceAndReceiveToResult(baseUrl + "/soap/attachment", new StringSource(messagePayload),
new WebServiceMessageCallback() {
@Override
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
SoapMessage soapMessage = (SoapMessage) message;
final String attachmentContent = "content";
soapMessage.addAttachment("attachment-1",
new DataHandler(new ByteArrayDataSource(attachmentContent, "text/plain")));
}
}, new StringResult());
}
/** Servlet that returns and error message for a given status code. */
private static class ErrorServlet extends HttpServlet {
private int sc;
private ErrorServlet(int sc) {
this.sc = sc;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendError(sc);
}
}
/** Abstract SOAP Servlet */
private abstract static class AbstractSoapServlet extends HttpServlet {
protected MessageFactory messageFactory = null;
private final int sc = -1;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
try {
messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
}
catch (SOAPException ex) {
throw new ServletException("Unable to create message factory" + ex.getMessage());
}
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
MimeHeaders headers = getHeaders(req);
SOAPMessage request = messageFactory.createMessage(headers, req.getInputStream());
SOAPMessage reply = onMessage(request);
if (reply != null) {
reply.saveChanges();
SOAPBody replyBody = reply.getSOAPBody();
if (!replyBody.hasFault()) {
resp.setStatus(HttpServletResponse.SC_OK);
}
else {
if (replyBody.getFault().getFaultCodeAsQName()
.equals(SOAPConstants.SOAP_SENDER_FAULT)) {
resp.setStatus(HttpServletResponse.SC_BAD_REQUEST);
}
else {
resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
}
putHeaders(reply.getMimeHeaders(), resp);
reply.writeTo(resp.getOutputStream());
}
else {
resp.setStatus(HttpServletResponse.SC_ACCEPTED);
}
}
catch (Exception ex) {
throw new ServletException("SAAJ POST failed " + ex.getMessage(), ex);
}
}
private MimeHeaders getHeaders(HttpServletRequest httpServletRequest) {
Enumeration<?> enumeration = httpServletRequest.getHeaderNames();
MimeHeaders headers = new MimeHeaders();
while (enumeration.hasMoreElements()) {
String headerName = (String) enumeration.nextElement();
String headerValue = httpServletRequest.getHeader(headerName);
StringTokenizer values = new StringTokenizer(headerValue, ",");
while (values.hasMoreTokens()) {
headers.addHeader(headerName, values.nextToken().trim());
}
}
return headers;
}
private void putHeaders(MimeHeaders headers, HttpServletResponse res) {
Iterator<?> it = headers.getAllHeaders();
while (it.hasNext()) {
MimeHeader header = (MimeHeader) it.next();
String[] values = headers.getHeader(header.getName());
for (String value : values) {
res.addHeader(header.getName(), value);
}
}
}
protected abstract SOAPMessage onMessage(SOAPMessage message) throws SOAPException;
}
private static class EchoSoapServlet extends AbstractSoapServlet {
@Override
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
return message;
}
}
private static class NoResponseSoapServlet extends AbstractSoapServlet {
@Override
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
return null;
}
}
private static class SoapReceiverFaultServlet extends AbstractSoapServlet {
@Override
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
SOAPMessage response = messageFactory.createMessage();
SOAPBody body = response.getSOAPBody();
body.addFault(SOAPConstants.SOAP_RECEIVER_FAULT, "Receiver Fault");
return response;
}
}
private static class SoapSenderFaultServlet extends AbstractSoapServlet {
@Override
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
SOAPMessage response = messageFactory.createMessage();
SOAPBody body = response.getSOAPBody();
body.addFault(SOAPConstants.SOAP_SENDER_FAULT, "Sender Fault");
return response;
}
}
private static class AttachmentsServlet extends AbstractSoapServlet {
@Override
protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
assertEquals("No attachments found", 1, message.countAttachments());
return null;
}
}
}

View File

@@ -0,0 +1,32 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class AxiomNonStreamingSoap11WebServiceTemplateIntegrationTest
extends AbstractSoap11WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
return new AxiomSoapMessageFactory();
}
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class AxiomNonStreamingSoap12WebServiceTemplateIntegrationTest
extends AbstractSoap12WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
AxiomSoapMessageFactory messageFactory = new AxiomSoapMessageFactory();
messageFactory.setSoapVersion(SoapVersion.SOAP_12);
return messageFactory;
}
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class AxiomStreamingSoap11WebServiceTemplateIntegrationTest
extends AbstractSoap11WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
AxiomSoapMessageFactory axiomFactory = new AxiomSoapMessageFactory();
axiomFactory.setPayloadCaching(false);
return axiomFactory;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class AxiomStreamingSoap12WebServiceTemplateIntegrationTest
extends AbstractSoap12WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
AxiomSoapMessageFactory axiomFactory = new AxiomSoapMessageFactory();
axiomFactory.setSoapVersion(SoapVersion.SOAP_12);
axiomFactory.setPayloadCaching(false);
return axiomFactory;
}
}

View File

@@ -0,0 +1,145 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import org.mortbay.jetty.Server;
import org.mortbay.jetty.servlet.Context;
import org.mortbay.jetty.servlet.ServletHolder;
import org.w3c.dom.Document;
import org.springframework.ws.client.WebServiceTransportException;
import org.springframework.ws.pox.dom.DomPoxMessageFactory;
import org.springframework.ws.transport.http.HttpComponentsMessageSender;
import org.springframework.ws.transport.support.FreePortScanner;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
public class DomPoxWebServiceTemplateIntegrationTest {
private static Server jettyServer;
private static String baseUrl;
@BeforeClass
public static void startJetty() throws Exception {
int port = FreePortScanner.getFreePort();
baseUrl = "http://localhost:" + port;
jettyServer = new Server(port);
Context jettyContext = new Context(jettyServer, "/");
jettyContext.addServlet(new ServletHolder(new PoxServlet()), "/pox");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
jettyServer.start();
}
@AfterClass
public static void stopJetty() throws Exception {
if (jettyServer.isRunning()) {
jettyServer.stop();
}
}
@Test
public void domPox() throws Exception {
WebServiceTemplate template = new WebServiceTemplate(new DomPoxMessageFactory());
template.setMessageSender(new HttpComponentsMessageSender());
String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
StringResult result = new StringResult();
template.sendSourceAndReceiveToResult(baseUrl + "/pox", new StringSource(content),
result);
assertXMLEqual(content, result.toString());
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/notfound",
new StringSource(content), new StringResult());
Assert.fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
try {
template.sendSourceAndReceiveToResult(baseUrl + "/errors/server",
new StringSource(content), result);
Assert.fail("WebServiceTransportException expected");
}
catch (WebServiceTransportException ex) {
//expected
}
}
/** Servlet that returns and error message for a given status code. */
private static class ErrorServlet extends HttpServlet {
private int sc;
private ErrorServlet(int sc) {
this.sc = sc;
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.sendError(sc);
}
}
/** Simple POX Servlet. */
private static class PoxServlet extends HttpServlet {
private DocumentBuilderFactory documentBuilderFactory;
private TransformerFactory transformerFactory;
@Override
public void init(ServletConfig servletConfig) throws ServletException {
super.init(servletConfig);
documentBuilderFactory = DocumentBuilderFactory.newInstance();
documentBuilderFactory.setNamespaceAware(true);
transformerFactory = TransformerFactory.newInstance();
}
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document message = documentBuilder.parse(req.getInputStream());
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(new DOMSource(message), new StreamResult(resp.getOutputStream()));
}
catch (Exception ex) {
throw new ServletException("POX POST failed" + ex.getMessage());
}
}
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class SaajSoap11WebServiceTemplateIntegrationTest
extends AbstractSoap11WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
return new SaajSoapMessageFactory(messageFactory);
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ws.client.core;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.SOAPConstants;
import org.springframework.ws.soap.SoapMessageFactory;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
/**
* @author Arjen Poutsma
*/
public class SaajSoap12WebServiceTemplateIntegrationTest
extends AbstractSoap12WebServiceTemplateIntegrationTestCase {
@Override
public SoapMessageFactory createMessageFactory() throws Exception {
MessageFactory messageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_2_PROTOCOL);
return new SaajSoapMessageFactory(messageFactory);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,6 +21,11 @@ import java.net.URI;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;
import org.springframework.ws.MockWebServiceMessage;
@@ -37,12 +42,6 @@ import org.springframework.ws.transport.WebServiceMessageSender;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
import static org.junit.Assert.*;
public class WebServiceTemplateTest {
private WebServiceTemplate template;
@@ -60,10 +59,12 @@ public class WebServiceTemplateTest {
expect(connectionMock.getUri()).andReturn(expectedUri).anyTimes();
template.setMessageSender(new WebServiceMessageSender() {
@Override
public WebServiceConnection createConnection(URI uri) throws IOException {
return connectionMock;
}
@Override
public boolean supports(URI uri) {
assertEquals("Invalid uri", expectedUri, uri);
return true;
@@ -339,10 +340,12 @@ public class WebServiceTemplateTest {
final URI customUri = new URI("http://www.springframework.org/spring-ws/custom");
template.setMessageSender(new WebServiceMessageSender() {
@Override
public WebServiceConnection createConnection(URI uri) throws IOException {
return connectionMock;
}
@Override
public boolean supports(URI uri) {
assertEquals("Invalid uri", customUri, uri);
return true;
@@ -472,10 +475,12 @@ public class WebServiceTemplateTest {
template.setMessageSender(new WebServiceMessageSender() {
@Override
public WebServiceConnection createConnection(URI uri) throws IOException {
return connectionMock;
}
@Override
public boolean supports(URI uri) {
assertEquals("Invalid uri", providerUri, uri);
return true;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
package org.springframework.ws.transport.http;
import java.io.IOException;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPConstants;
@@ -23,19 +24,20 @@ import javax.xml.soap.SOAPMessage;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
import org.junit.Assert;
import static org.junit.Assert.assertEquals;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.soap.saaj.SaajSoapMessage;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
import org.springframework.xml.transform.StringResult;
import org.springframework.xml.transform.StringSource;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.custommonkey.xmlunit.XMLAssert.assertXMLEqual;
public class HttpServletConnectionTest {
private HttpServletConnection connection;
@@ -69,7 +71,7 @@ public class HttpServletConnectionTest {
}
@Test
public void testReceive() throws Exception {
public void receive() throws Exception {
byte[] bytes = SOAP_CONTENT.getBytes("UTF-8");
httpServletRequest.addHeader("Content-Type", "text/xml");
httpServletRequest.addHeader("Content-Length", Integer.toString(bytes.length));
@@ -84,13 +86,13 @@ public class HttpServletConnectionTest {
SOAPMessage saajMessage = message.getSaajMessage();
String[] headerValues = saajMessage.getMimeHeaders().getHeader(HEADER_NAME);
Assert.assertNotNull("Response has no header", headerValues);
Assert.assertEquals("Response has invalid header", 1, headerValues.length);
Assert.assertEquals("Response has invalid header values", HEADER_VALUE, headerValues[0]);
assertEquals("Response has invalid header", 1, headerValues.length);
assertEquals("Response has invalid header values", HEADER_VALUE, headerValues[0]);
}
@Test
public void testSend() throws Exception {
SaajSoapMessage message = (SaajSoapMessage) messageFactory.createWebServiceMessage();
public void send() throws Exception {
SaajSoapMessage message = messageFactory.createWebServiceMessage();
SOAPMessage saajMessage = message.getSaajMessage();
MimeHeaders mimeHeaders = saajMessage.getMimeHeaders();
mimeHeaders.addHeader(HEADER_NAME, HEADER_VALUE);
@@ -99,8 +101,24 @@ public class HttpServletConnectionTest {
connection.send(message);
Assert.assertEquals("Invalid header", HEADER_VALUE, httpServletResponse.getHeader(HEADER_NAME));
assertEquals("Invalid header", HEADER_VALUE,
httpServletResponse.getHeader(HEADER_NAME));
assertXMLEqual("Invalid content", SOAP_CONTENT, httpServletResponse.getContentAsString());
}
@Test
public void faultCodes() throws IOException {
connection.setFaultCode(SoapVersion.SOAP_11.getClientOrSenderFaultName());
assertEquals(500, httpServletResponse.getStatus());
connection.setFaultCode(SoapVersion.SOAP_11.getServerOrReceiverFaultName());
assertEquals(500, httpServletResponse.getStatus());
connection.setFaultCode(SoapVersion.SOAP_12.getClientOrSenderFaultName());
assertEquals(400, httpServletResponse.getStatus());
connection.setFaultCode(SoapVersion.SOAP_12.getServerOrReceiverFaultName());
assertEquals(500, httpServletResponse.getStatus());
}
}

View File

@@ -1,11 +1,11 @@
/*
* Copyright 2005-2012 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
@@ -20,6 +20,11 @@ import java.io.InputStream;
import java.io.OutputStream;
import javax.servlet.http.HttpServletResponse;
import static org.easymock.EasyMock.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.ws.FaultAwareWebServiceMessage;
@@ -27,14 +32,9 @@ import org.springframework.ws.InvalidXmlException;
import org.springframework.ws.NoEndpointFoundException;
import org.springframework.ws.WebServiceMessageFactory;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
public class WebServiceMessageReceiverHandlerAdapterTest {
private static final String REQUEST = " <SOAP-ENV:Envelope\n" +
@@ -72,6 +72,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
replayMockControls();
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
}
};
@@ -92,6 +93,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
replayMockControls();
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
}
};
@@ -112,12 +114,13 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
httpRequest.setCharacterEncoding("UTF-8");
expect(factoryMock.createWebServiceMessage(isA(InputStream.class))).andReturn(requestMock);
expect(factoryMock.createWebServiceMessage()).andReturn(responseMock);
expect(responseMock.hasFault()).andReturn(false);
expect(responseMock.getFaultCode()).andReturn(null);
responseMock.writeTo(isA(OutputStream.class));
replayMockControls();
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
messageContext.getResponse();
}
@@ -137,12 +140,13 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
httpRequest.setCharacterEncoding("UTF-8");
expect(factoryMock.createWebServiceMessage(isA(InputStream.class))).andReturn(requestMock);
expect(factoryMock.createWebServiceMessage()).andReturn(responseMock);
expect(responseMock.hasFault()).andReturn(true);
expect(responseMock.getFaultCode()).andReturn(SoapVersion.SOAP_11.getServerOrReceiverFaultName());
responseMock.writeTo(isA(OutputStream.class));
replayMockControls();
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
messageContext.getResponse();
}
@@ -167,6 +171,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
throw new NoEndpointFoundException(messageContext.getRequest());
}
@@ -191,6 +196,7 @@ public class WebServiceMessageReceiverHandlerAdapterTest {
WebServiceMessageReceiver endpoint = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
}
};

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2005-2010 the original author or authors.
* Copyright 2005-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -17,24 +17,25 @@
package org.springframework.ws.transport.support;
import java.net.URI;
import javax.xml.namespace.QName;
import static org.easymock.EasyMock.*;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.springframework.ws.MockWebServiceMessage;
import org.springframework.ws.MockWebServiceMessageFactory;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.context.MessageContext;
import org.springframework.ws.transport.WebServiceConnection;
import org.springframework.ws.soap.SoapVersion;
import org.springframework.ws.transport.FaultAwareWebServiceConnection;
import org.springframework.ws.transport.WebServiceMessageReceiver;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import static org.easymock.EasyMock.*;
public class WebServiceMessageReceiverObjectSupportTest {
private WebServiceMessageReceiverObjectSupport receiverSupport;
private WebServiceConnection connectionMock;
private FaultAwareWebServiceConnection connectionMock;
private MockWebServiceMessageFactory messageFactory;
@@ -45,14 +46,15 @@ public class WebServiceMessageReceiverObjectSupportTest {
receiverSupport = new MyReceiverSupport();
messageFactory = new MockWebServiceMessageFactory();
receiverSupport.setMessageFactory(messageFactory);
connectionMock = createStrictMock(WebServiceConnection.class);
connectionMock = createStrictMock(FaultAwareWebServiceConnection.class);
request = new MockWebServiceMessage();
}
@Test
public void testHandleConnectionResponse() throws Exception {
public void handleConnectionResponse() throws Exception {
expect(connectionMock.getUri()).andReturn(new URI("http://example.com"));
expect(connectionMock.receive(messageFactory)).andReturn(request);
connectionMock.setFaultCode(null);
connectionMock.send(isA(WebServiceMessage.class));
connectionMock.close();
@@ -60,6 +62,7 @@ public class WebServiceMessageReceiverObjectSupportTest {
WebServiceMessageReceiver receiver = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
Assert.assertNotNull("No message context", messageContext);
messageContext.getResponse();
@@ -72,7 +75,35 @@ public class WebServiceMessageReceiverObjectSupportTest {
}
@Test
public void testHandleConnectionNoResponse() throws Exception {
public void handleConnectionFaultResponse() throws Exception {
final QName faultCode = SoapVersion.SOAP_11.getClientOrSenderFaultName();
expect(connectionMock.getUri()).andReturn(new URI("http://example.com"));
expect(connectionMock.receive(messageFactory)).andReturn(request);
connectionMock.setFaultCode(faultCode);
connectionMock.send(isA(WebServiceMessage.class));
connectionMock.close();
replay(connectionMock);
WebServiceMessageReceiver receiver = new WebServiceMessageReceiver() {
@Override
public void receive(MessageContext messageContext) throws Exception {
Assert.assertNotNull("No message context", messageContext);
MockWebServiceMessage response =
(MockWebServiceMessage) messageContext.getResponse();
response.setFaultCode(faultCode);
}
};
receiverSupport.handleConnection(connectionMock, receiver);
verify(connectionMock);
}
@Test
public void handleConnectionNoResponse() throws Exception {
expect(connectionMock.getUri()).andReturn(new URI("http://example.com"));
expect(connectionMock.receive(messageFactory)).andReturn(request);
connectionMock.close();

View File

@@ -25,6 +25,8 @@ import java.net.URISyntaxException;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPConstants;
import com.sun.net.httpserver.HttpExchange;
@@ -174,4 +176,18 @@ public class HttpExchangeConnection extends AbstractReceiverConnection
}
}
@Override
public void setFaultCode(QName faultCode) throws IOException {
if (faultCode != null) {
if (SOAPConstants.SOAP_SENDER_FAULT.equals(faultCode)) {
responseStatusCode = HttpTransportConstants.STATUS_BAD_REQUEST;
}
else {
responseStatusCode = HttpTransportConstants.STATUS_INTERNAL_SERVER_ERROR;
}
}
else {
responseStatusCode = HttpTransportConstants.STATUS_OK;
}
}
}