1   /*
2    * Copyright 2006 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.ws.transport.http;
18  
19  import java.io.IOException;
20  import java.io.OutputStream;
21  import java.net.URI;
22  import java.net.URISyntaxException;
23  import java.util.zip.GZIPOutputStream;
24  import javax.servlet.Servlet;
25  import javax.servlet.ServletException;
26  import javax.servlet.http.HttpServlet;
27  import javax.servlet.http.HttpServletRequest;
28  import javax.servlet.http.HttpServletResponse;
29  import javax.xml.soap.MessageFactory;
30  import javax.xml.soap.MimeHeaders;
31  import javax.xml.soap.SOAPConstants;
32  import javax.xml.soap.SOAPException;
33  import javax.xml.soap.SOAPMessage;
34  import javax.xml.transform.Transformer;
35  import javax.xml.transform.TransformerException;
36  import javax.xml.transform.TransformerFactory;
37  import javax.xml.transform.dom.DOMResult;
38  
39  import org.custommonkey.xmlunit.XMLTestCase;
40  import org.custommonkey.xmlunit.XMLUnit;
41  import org.mortbay.jetty.Server;
42  import org.mortbay.jetty.servlet.Context;
43  import org.mortbay.jetty.servlet.ServletHolder;
44  
45  import org.springframework.util.FileCopyUtils;
46  import org.springframework.ws.WebServiceMessage;
47  import org.springframework.ws.WebServiceMessageFactory;
48  import org.springframework.ws.soap.saaj.SaajSoapMessage;
49  import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;
50  import org.springframework.ws.transport.FaultAwareWebServiceConnection;
51  import org.springframework.ws.transport.WebServiceConnection;
52  import org.springframework.xml.transform.StringResult;
53  import org.springframework.xml.transform.StringSource;
54  import org.springframework.beans.factory.InitializingBean;
55  
56  public abstract class AbstractHttpWebServiceMessageSenderIntegrationTestCase extends XMLTestCase {
57  
58      private Server jettyServer;
59  
60      private static final String REQUEST_HEADER_NAME = "RequestHeader";
61  
62      private static final String REQUEST_HEADER_VALUE = "RequestHeaderValue";
63  
64      private static final String RESPONSE_HEADER_NAME = "ResponseHeader";
65  
66      private static final String RESPONSE_HEADER_VALUE = "ResponseHeaderValue";
67  
68      private static final String REQUEST = "<Request xmlns='http://springframework.org/spring-ws/' />";
69  
70      private static final String SOAP_REQUEST =
71              "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'><SOAP-ENV:Header/><SOAP-ENV:Body>" +
72                      REQUEST + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
73  
74      private static final String RESPONSE = "<Response  xmlns='http://springframework.org/spring-ws/' />";
75  
76      private static final String SOAP_RESPONSE =
77              "<SOAP-ENV:Envelope xmlns:SOAP-ENV='http://schemas.xmlsoap.org/soap/envelope/'><SOAP-ENV:Header/><SOAP-ENV:Body>" +
78                      RESPONSE + "</SOAP-ENV:Body></SOAP-ENV:Envelope>";
79  
80      private AbstractHttpWebServiceMessageSender messageSender;
81  
82      private Context jettyContext;
83  
84      private MessageFactory saajMessageFactory;
85  
86      private TransformerFactory transformerFactory;
87  
88      private WebServiceMessageFactory messageFactory;
89  
90      private URI connectionUri;
91  
92      protected final void setUp() throws Exception {
93          connectionUri = new URI("http://localhost:8888/");
94          jettyServer = new Server(8888);
95          jettyContext = new Context(jettyServer, "/");
96          messageSender = createMessageSender();
97          if (messageSender instanceof InitializingBean) {
98              ((InitializingBean) messageSender).afterPropertiesSet();
99          }
100         XMLUnit.setIgnoreWhitespace(true);
101         saajMessageFactory = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
102         messageFactory = new SaajSoapMessageFactory(saajMessageFactory);
103         transformerFactory = TransformerFactory.newInstance();
104     }
105 
106     protected abstract AbstractHttpWebServiceMessageSender createMessageSender();
107 
108     protected final void tearDown() throws Exception {
109         if (jettyServer.isRunning()) {
110             jettyServer.stop();
111         }
112     }
113 
114     public void testSupports() throws URISyntaxException {
115         assertTrue("Message sender does not support HTTP url", messageSender.supports(connectionUri));
116     }
117 
118     public void testSendAndReceiveResponse() throws Exception {
119         MyServlet servlet = new MyServlet();
120         servlet.setResponse(true);
121         validateResponse(servlet);
122     }
123 
124     public void testSendAndReceiveNoResponse() throws Exception {
125         validateNonResponse(new MyServlet());
126     }
127 
128     public void testSendAndReceiveNoResponseAccepted() throws Exception {
129         MyServlet servlet = new MyServlet();
130         servlet.setResponseStatus(HttpServletResponse.SC_ACCEPTED);
131         validateNonResponse(servlet);
132     }
133 
134     public void testSendAndReceiveCompressed() throws Exception {
135         MyServlet servlet = new MyServlet();
136         servlet.setResponse(true);
137         servlet.setGzip(true);
138         validateResponse(servlet);
139     }
140 
141     public void testSendAndReceiveInvalidContentSize() throws Exception {
142         MyServlet servlet = new MyServlet();
143         servlet.setResponse(true);
144         servlet.setContentLength(-1);
145         validateResponse(servlet);
146     }
147 
148     public void testSendAndReceiveCompressedInvalidContentSize() throws Exception {
149         MyServlet servlet = new MyServlet();
150         servlet.setResponse(true);
151         servlet.setGzip(true);
152         servlet.setContentLength(-1);
153         validateResponse(servlet);
154     }
155 
156     public void testSendAndReceiveFault() throws Exception {
157         MyServlet servlet = new MyServlet();
158         servlet.setResponseStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
159         servlet.setResponse(true);
160         jettyContext.addServlet(new ServletHolder(servlet), "/");
161         jettyServer.start();
162         FaultAwareWebServiceConnection connection =
163                 (FaultAwareWebServiceConnection) messageSender.createConnection(connectionUri);
164         SOAPMessage request = createRequest();
165         try {
166             connection.send(new SaajSoapMessage(request));
167             connection.receive(messageFactory);
168             assertTrue("Response has no fault", connection.hasFault());
169         }
170         finally {
171             connection.close();
172         }
173     }
174 
175     public void testReuseClosedConnection() throws Exception {
176 
177     }
178 
179     private void validateResponse(Servlet servlet) throws Exception {
180         jettyContext.addServlet(new ServletHolder(servlet), "/");
181         jettyServer.start();
182         FaultAwareWebServiceConnection connection =
183                 (FaultAwareWebServiceConnection) messageSender.createConnection(connectionUri);
184         SOAPMessage request = createRequest();
185         try {
186             connection.send(new SaajSoapMessage(request));
187             SaajSoapMessage response = (SaajSoapMessage) connection.receive(messageFactory);
188             assertNotNull("No response", response);
189             assertFalse("Response has fault", connection.hasFault());
190             SOAPMessage saajResponse = response.getSaajMessage();
191             String[] headerValues = saajResponse.getMimeHeaders().getHeader(RESPONSE_HEADER_NAME);
192             assertNotNull("Response has no header", headerValues);
193             assertEquals("Response has invalid header", 1, headerValues.length);
194             assertEquals("Response has invalid header values", RESPONSE_HEADER_VALUE, headerValues[0]);
195             StringResult result = new StringResult();
196             Transformer transformer = transformerFactory.newTransformer();
197             transformer.transform(response.getPayloadSource(), result);
198             assertXMLEqual("Invalid response", RESPONSE, result.toString());
199         }
200         finally {
201             connection.close();
202         }
203     }
204 
205     private void validateNonResponse(Servlet servlet) throws Exception {
206         jettyContext.addServlet(new ServletHolder(servlet), "/");
207         jettyServer.start();
208 
209         WebServiceConnection connection = messageSender.createConnection(connectionUri);
210         SOAPMessage request = createRequest();
211         try {
212             connection.send(new SaajSoapMessage(request));
213             WebServiceMessage response = connection.receive(messageFactory);
214             assertNull("Response", response);
215         }
216         finally {
217             connection.close();
218         }
219     }
220 
221     private SOAPMessage createRequest() throws TransformerException, SOAPException {
222         SOAPMessage request = saajMessageFactory.createMessage();
223         MimeHeaders mimeHeaders = request.getMimeHeaders();
224         mimeHeaders.addHeader(REQUEST_HEADER_NAME, REQUEST_HEADER_VALUE);
225         Transformer transformer = transformerFactory.newTransformer();
226         transformer.transform(new StringSource(REQUEST), new DOMResult(request.getSOAPBody()));
227         return request;
228     }
229 
230     private class MyServlet extends HttpServlet {
231 
232         private int responseStatus = HttpServletResponse.SC_OK;
233 
234         private Integer contentLength;
235 
236         private boolean response;
237 
238         private boolean gzip;
239 
240         public void setResponseStatus(int responseStatus) {
241             this.responseStatus = responseStatus;
242         }
243 
244         public void setContentLength(int contentLength) {
245             this.contentLength = new Integer(contentLength);
246         }
247 
248         public void setResponse(boolean response) {
249             this.response = response;
250         }
251 
252         public void setGzip(boolean gzip) {
253             this.gzip = gzip;
254         }
255 
256         protected void doPost(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse)
257                 throws ServletException, IOException {
258             try {
259                 assertEquals("Invalid header value received on server side", REQUEST_HEADER_VALUE,
260                         httpServletRequest.getHeader(REQUEST_HEADER_NAME));
261                 String receivedRequest =
262                         new String(FileCopyUtils.copyToByteArray(httpServletRequest.getInputStream()), "UTF-8");
263                 assertXMLEqual("Invalid request received", SOAP_REQUEST, receivedRequest);
264                 if (gzip) {
265                     assertEquals("Invalid Accept-Encoding header value received on server side", "gzip",
266                             httpServletRequest.getHeader("Accept-Encoding"));
267                 }
268 
269                 httpServletResponse.setStatus(responseStatus);
270                 if (response) {
271                     httpServletResponse.setContentType("text/xml");
272                     if (contentLength != null) {
273                         httpServletResponse.setContentLength(contentLength.intValue());
274                     }
275                     if (gzip) {
276                         httpServletResponse.addHeader("Content-Encoding", "gzip");
277                     }
278                     httpServletResponse.setHeader(RESPONSE_HEADER_NAME, RESPONSE_HEADER_VALUE);
279                     OutputStream os;
280                     if (gzip) {
281                         os = new GZIPOutputStream(httpServletResponse.getOutputStream());
282                     }
283                     else {
284                         os = httpServletResponse.getOutputStream();
285                     }
286                     FileCopyUtils.copy(SOAP_RESPONSE.getBytes("UTF-8"), os);
287                 }
288             }
289             catch (Exception ex) {
290                 throw new ServletException(ex);
291             }
292         }
293     }
294 
295 }