1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.ws.client.core;
18
19 import java.io.IOException;
20 import java.util.Enumeration;
21 import java.util.Iterator;
22 import java.util.StringTokenizer;
23 import javax.activation.CommandMap;
24 import javax.activation.DataHandler;
25 import javax.activation.MailcapCommandMap;
26 import javax.mail.util.ByteArrayDataSource;
27 import javax.servlet.ServletConfig;
28 import javax.servlet.ServletException;
29 import javax.servlet.http.HttpServlet;
30 import javax.servlet.http.HttpServletRequest;
31 import javax.servlet.http.HttpServletResponse;
32 import javax.xml.namespace.QName;
33 import javax.xml.parsers.DocumentBuilder;
34 import javax.xml.parsers.DocumentBuilderFactory;
35 import javax.xml.soap.MessageFactory;
36 import javax.xml.soap.MimeHeader;
37 import javax.xml.soap.MimeHeaders;
38 import javax.xml.soap.SOAPBody;
39 import javax.xml.soap.SOAPException;
40 import javax.xml.soap.SOAPMessage;
41 import javax.xml.transform.Result;
42 import javax.xml.transform.Source;
43 import javax.xml.transform.Transformer;
44 import javax.xml.transform.TransformerConfigurationException;
45 import javax.xml.transform.TransformerException;
46 import javax.xml.transform.TransformerFactory;
47 import javax.xml.transform.dom.DOMSource;
48 import javax.xml.transform.stream.StreamResult;
49
50 import junit.extensions.TestSetup;
51 import junit.framework.Test;
52 import junit.framework.TestSuite;
53 import org.custommonkey.xmlunit.XMLTestCase;
54 import org.mortbay.jetty.Server;
55 import org.mortbay.jetty.servlet.Context;
56 import org.mortbay.jetty.servlet.ServletHolder;
57 import org.w3c.dom.Document;
58 import org.xml.sax.SAXException;
59
60 import org.springframework.oxm.Marshaller;
61 import org.springframework.oxm.Unmarshaller;
62 import org.springframework.oxm.XmlMappingException;
63 import org.springframework.util.StringUtils;
64 import org.springframework.ws.WebServiceMessage;
65 import org.springframework.ws.client.WebServiceTransportException;
66 import org.springframework.ws.pox.dom.DomPoxMessageFactory;
67 import org.springframework.ws.soap.SoapMessage;
68 import org.springframework.ws.soap.SoapMessageFactory;
69 import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;
70 import org.springframework.ws.soap.client.SoapFaultClientException;
71 import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
72 import org.springframework.ws.transport.http.CommonsHttpMessageSender;
73 import org.springframework.xml.transform.StringResult;
74 import org.springframework.xml.transform.StringSource;
75
76 public class WebServiceTemplateIntegrationTest extends XMLTestCase {
77
78 private WebServiceTemplate template;
79
80 private static Server jettyServer;
81
82 private String messagePayload = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
83
84 public static Test suite() {
85 return new ServerTestSetup(new TestSuite(WebServiceTemplateIntegrationTest.class));
86 }
87
88 public void testSaaj() throws Exception {
89 doSoap(new SaajSoapMessageFactory(MessageFactory.newInstance()));
90 }
91
92 public void testAxiom() throws Exception {
93 doSoap(new AxiomSoapMessageFactory());
94 }
95
96 public void testAxiomNonCaching() throws Exception {
97 AxiomSoapMessageFactory axiomFactory = new AxiomSoapMessageFactory();
98 axiomFactory.setPayloadCaching(false);
99 doSoap(axiomFactory);
100 }
101
102 public void testPox() throws Exception {
103 template = new WebServiceTemplate(new DomPoxMessageFactory());
104 template.setMessageSender(new CommonsHttpMessageSender());
105 String content = "<root xmlns='http://springframework.org/spring-ws'><child/></root>";
106 StringResult result = new StringResult();
107 template.sendSourceAndReceiveToResult("http://localhost:8888/pox", new StringSource(content), result);
108 assertXMLEqual(content, result.toString());
109 try {
110 template.sendSourceAndReceiveToResult("http://localhost:8888/errors/notfound", new StringSource(content),
111 new StringResult());
112 fail("WebServiceTransportException expected");
113 }
114 catch (WebServiceTransportException ex) {
115
116 }
117 try {
118 template.sendSourceAndReceiveToResult("http://localhost:8888/errors/server", new StringSource(content),
119 result);
120 fail("WebServiceTransportException expected");
121 }
122 catch (WebServiceTransportException ex) {
123
124 }
125 }
126
127 private void doSoap(SoapMessageFactory messageFactory) throws Exception {
128 template = new WebServiceTemplate(messageFactory);
129 template.setMessageSender(new CommonsHttpMessageSender());
130 sendSourceAndReceiveToResult();
131 sendSourceAndReceiveToResultNoResponse();
132 marshalSendAndReceiveResponse();
133 marshalSendAndReceiveNoResponse();
134 notFound();
135 fault();
136 faultNonCompliant();
137 attachment();
138 }
139
140 private void sendSourceAndReceiveToResult() throws SAXException, IOException {
141 StringResult result = new StringResult();
142 boolean b = template.sendSourceAndReceiveToResult("http://localhost:8888/soap/echo",
143 new StringSource(messagePayload), result);
144 assertTrue("Invalid result", b);
145 assertXMLEqual(messagePayload, result.toString());
146 }
147
148 private void sendSourceAndReceiveToResultNoResponse() {
149 boolean b = template.sendSourceAndReceiveToResult("http://localhost:8888/soap/noResponse",
150 new StringSource(messagePayload), new StringResult());
151 assertFalse("Invalid result", b);
152 }
153
154 private void marshalSendAndReceiveResponse() throws TransformerConfigurationException {
155 final Transformer transformer = TransformerFactory.newInstance().newTransformer();
156 final Object requestObject = new Object();
157 Marshaller marshaller = new Marshaller() {
158
159 public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
160 assertEquals("Invalid object", graph, requestObject);
161 try {
162 transformer.transform(new StringSource(messagePayload), result);
163 }
164 catch (TransformerException e) {
165 fail(e.getMessage());
166 }
167 }
168
169 public boolean supports(Class clazz) {
170 assertEquals("Invalid class", Object.class, clazz);
171 return true;
172 }
173 };
174 final Object responseObject = new Object();
175 Unmarshaller unmarshaller = new Unmarshaller() {
176
177 public Object unmarshal(Source source) throws XmlMappingException, IOException {
178 return responseObject;
179 }
180
181 public boolean supports(Class clazz) {
182 assertEquals("Invalid class", Object.class, clazz);
183 return true;
184 }
185 };
186 template.setMarshaller(marshaller);
187 template.setUnmarshaller(unmarshaller);
188 Object result = template.marshalSendAndReceive("http://localhost:8888/soap/echo", requestObject);
189 assertEquals("Invalid response object", responseObject, result);
190 }
191
192 private void marshalSendAndReceiveNoResponse() throws TransformerConfigurationException {
193 final Transformer transformer = TransformerFactory.newInstance().newTransformer();
194 final Object requestObject = new Object();
195 Marshaller marshaller = new Marshaller() {
196
197 public void marshal(Object graph, Result result) throws XmlMappingException, IOException {
198 assertEquals("Invalid object", graph, requestObject);
199 try {
200 transformer.transform(new StringSource(messagePayload), result);
201 }
202 catch (TransformerException e) {
203 fail(e.getMessage());
204 }
205 }
206
207 public boolean supports(Class clazz) {
208 assertEquals("Invalid class", Object.class, clazz);
209 return true;
210 }
211 };
212 template.setMarshaller(marshaller);
213 Object result = template.marshalSendAndReceive("http://localhost:8888/soap/noResponse", requestObject);
214 assertNull("Invalid response object", result);
215 }
216
217 private void notFound() {
218 try {
219 template.sendSourceAndReceiveToResult("http://localhost:8888/errors/notfound",
220 new StringSource(messagePayload), new StringResult());
221 fail("WebServiceTransportException expected");
222 }
223 catch (WebServiceTransportException ex) {
224
225 }
226 }
227
228 private void fault() {
229 Result result = new StringResult();
230 try {
231 template.sendSourceAndReceiveToResult("http://localhost:8888/soap/fault", new StringSource(messagePayload),
232 result);
233 fail("SoapFaultClientException expected");
234 }
235 catch (SoapFaultClientException ex) {
236
237 }
238 }
239
240 private void faultNonCompliant() {
241 Result result = new StringResult();
242 template.setCheckConnectionForFault(false);
243 template.setCheckConnectionForError(false);
244 try {
245 template.sendSourceAndReceiveToResult("http://localhost:8888/soap/badRequestFault",
246 new StringSource(messagePayload), result);
247 fail("SoapFaultClientException expected");
248 }
249 catch (SoapFaultClientException ex) {
250
251 }
252 }
253
254 private void attachment() {
255 template.sendSourceAndReceiveToResult("http://localhost:8888/soap/attachment", new StringSource(messagePayload),
256 new WebServiceMessageCallback() {
257
258 public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
259 SoapMessage soapMessage = (SoapMessage) message;
260 final String attachmentContent = "content";
261 soapMessage.addAttachment("attachment-1",
262 new DataHandler(new ByteArrayDataSource(attachmentContent, "text/plain")));
263 }
264 }, new StringResult());
265 }
266
267
268 private static class ErrorServlet extends HttpServlet {
269
270 private int sc;
271
272 private ErrorServlet(int sc) {
273 this.sc = sc;
274 }
275
276 protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
277 resp.sendError(sc);
278 }
279 }
280
281
282 private static class PoxServlet extends HttpServlet {
283
284 private DocumentBuilderFactory documentBuilderFactory;
285
286 private TransformerFactory transformerFactory;
287
288 public void init(ServletConfig servletConfig) throws ServletException {
289 super.init(servletConfig);
290 documentBuilderFactory = DocumentBuilderFactory.newInstance();
291 documentBuilderFactory.setNamespaceAware(true);
292 transformerFactory = TransformerFactory.newInstance();
293 }
294
295 public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
296 try {
297 DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
298 Document message = documentBuilder.parse(req.getInputStream());
299 Transformer transformer = transformerFactory.newTransformer();
300 transformer.transform(new DOMSource(message), new StreamResult(resp.getOutputStream()));
301 }
302 catch (Exception ex) {
303 throw new ServletException("POX POST failed" + ex.getMessage());
304 }
305 }
306 }
307
308
309 private abstract static class AbstractSoapServlet extends HttpServlet {
310
311 protected MessageFactory messageFactory = null;
312
313 private int sc = -1;
314
315 public void setSc(int sc) {
316 this.sc = sc;
317 }
318
319 public void init(ServletConfig servletConfig) throws ServletException {
320 super.init(servletConfig);
321 try {
322 messageFactory = MessageFactory.newInstance();
323 }
324 catch (SOAPException ex) {
325 throw new ServletException("Unable to create message factory" + ex.getMessage());
326 }
327 }
328
329 public void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
330 try {
331 MimeHeaders headers = getHeaders(req);
332 SOAPMessage request = messageFactory.createMessage(headers, req.getInputStream());
333 SOAPMessage reply = onMessage(request);
334 if (sc != -1) {
335 resp.setStatus(sc);
336 }
337 if (reply != null) {
338 if (reply.saveRequired()) {
339 reply.saveChanges();
340 }
341 if (sc == -1) {
342 resp.setStatus(!reply.getSOAPBody().hasFault() ? HttpServletResponse.SC_OK :
343 HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
344 }
345 putHeaders(reply.getMimeHeaders(), resp);
346 reply.writeTo(resp.getOutputStream());
347 }
348 else if (sc == -1) {
349 resp.setStatus(HttpServletResponse.SC_ACCEPTED);
350 }
351 }
352 catch (Exception ex) {
353 throw new ServletException("SAAJ POST failed " + ex.getMessage(), ex);
354 }
355 }
356
357 private MimeHeaders getHeaders(HttpServletRequest httpServletRequest) {
358 Enumeration enumeration = httpServletRequest.getHeaderNames();
359 MimeHeaders headers = new MimeHeaders();
360 while (enumeration.hasMoreElements()) {
361 String headerName = (String) enumeration.nextElement();
362 String headerValue = httpServletRequest.getHeader(headerName);
363 StringTokenizer values = new StringTokenizer(headerValue, ",");
364 while (values.hasMoreTokens()) {
365 headers.addHeader(headerName, values.nextToken().trim());
366 }
367 }
368 return headers;
369 }
370
371 private void putHeaders(MimeHeaders headers, HttpServletResponse res) {
372 Iterator it = headers.getAllHeaders();
373 while (it.hasNext()) {
374 MimeHeader header = (MimeHeader) it.next();
375 String[] values = headers.getHeader(header.getName());
376 res.setHeader(header.getName(), StringUtils.arrayToCommaDelimitedString(values));
377 }
378 }
379
380 protected abstract SOAPMessage onMessage(SOAPMessage message) throws SOAPException;
381 }
382
383 private static class EchoSoapServlet extends AbstractSoapServlet {
384
385 protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
386 return message;
387 }
388 }
389
390 private static class NoResponseSoapServlet extends AbstractSoapServlet {
391
392 protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
393 return null;
394 }
395 }
396
397 private static class SoapFaultServlet extends AbstractSoapServlet {
398
399 protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
400 SOAPMessage response = messageFactory.createMessage();
401 SOAPBody body = response.getSOAPBody();
402 body.addFault(new QName("http://schemas.xmlsoap.org/soap/envelope/", "Server"), "Server fault");
403 return response;
404 }
405 }
406
407 private static class AttachmentsServlet extends AbstractSoapServlet {
408
409 protected SOAPMessage onMessage(SOAPMessage message) throws SOAPException {
410 assertEquals("No attachments found", 1, message.countAttachments());
411 return null;
412 }
413 }
414
415
416 private static class ServerTestSetup extends TestSetup {
417
418 private ServerTestSetup(Test test) {
419 super(test);
420 }
421
422 protected void setUp() throws Exception {
423 removeXmlDataContentHandler();
424
425 jettyServer = new Server(8888);
426 Context jettyContext = new Context(jettyServer, "/");
427 jettyContext.addServlet(new ServletHolder(new EchoSoapServlet()), "/soap/echo");
428 jettyContext.addServlet(new ServletHolder(new SoapFaultServlet()), "/soap/fault");
429 SoapFaultServlet badRequestFault = new SoapFaultServlet();
430 badRequestFault.setSc(400);
431 jettyContext.addServlet(new ServletHolder(badRequestFault), "/soap/badRequestFault");
432 jettyContext.addServlet(new ServletHolder(new NoResponseSoapServlet()), "/soap/noResponse");
433 jettyContext.addServlet(new ServletHolder(new AttachmentsServlet()), "/soap/attachment");
434 jettyContext.addServlet(new ServletHolder(new PoxServlet()), "/pox");
435 jettyContext.addServlet(new ServletHolder(new ErrorServlet(404)), "/errors/notfound");
436 jettyContext.addServlet(new ServletHolder(new ErrorServlet(500)), "/errors/server");
437 jettyServer.start();
438 }
439
440
441
442
443
444 private void removeXmlDataContentHandler() throws SOAPException {
445 MessageFactory messageFactory = MessageFactory.newInstance();
446 SOAPMessage message = messageFactory.createMessage();
447 message.createAttachmentPart();
448 CommandMap.setDefaultCommandMap(new MailcapCommandMap());
449 }
450
451 protected void tearDown() throws Exception {
452 jettyServer.stop();
453 }
454 }
455
456 }