2 * This document is a part of the source code and related artifacts
\r
3 * for CollectionSpace, an open source collections management system
\r
4 * for museums and related institutions:
\r
6 * http://www.collectionspace.org
\r
7 * http://wiki.collectionspace.org
\r
9 * Copyright (c) 2009 Regents of the University of California
\r
11 * Licensed under the Educational Community License (ECL), Version 2.0.
\r
12 * You may not use this file except in compliance with this License.
\r
14 * You may obtain a copy of the ECL 2.0 License at
\r
15 * https://source.collectionspace.org/collection-space/LICENSE.txt
\r
17 * Unless required by applicable law or agreed to in writing, software
\r
18 * distributed under the License is distributed on an "AS IS" BASIS,
\r
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
20 * See the License for the specific language governing permissions and
\r
21 * limitations under the License.
\r
24 package org.collectionspace.services.IntegrationTests.xmlreplay;
\r
26 import org.apache.commons.httpclient.Header;
\r
27 import org.apache.commons.httpclient.HttpClient;
\r
28 import org.apache.commons.httpclient.methods.DeleteMethod;
\r
29 import org.apache.commons.httpclient.methods.GetMethod;
\r
30 import org.apache.commons.httpclient.methods.PostMethod;
\r
31 import org.apache.commons.io.FileUtils;
\r
33 import java.io.BufferedReader;
\r
34 import java.io.File;
\r
35 import java.io.InputStreamReader;
\r
36 import java.io.OutputStreamWriter;
\r
37 import java.net.HttpURLConnection;
\r
38 import java.net.URL;
\r
39 import java.util.Arrays;
\r
40 import java.util.HashMap;
\r
41 import java.util.List;
\r
42 import java.util.Map;
\r
44 import org.collectionspace.services.common.api.Tools;
\r
47 * @author Laramie Crocker
\r
49 public class XmlReplayTransport {
\r
51 private static String BOUNDARY = "34d97c83-0d61-4958-80ab-6bf8d362290f";
\r
52 private static String DD = "--";
\r
53 private static String CRLF = "\r\n";
\r
55 public static ServiceResult doGET(String urlString, String authForTest, String fromTestID) throws Exception {
\r
56 ServiceResult pr = new ServiceResult();
\r
57 pr.fromTestID = fromTestID;
\r
59 //HACK for speed testing.
\r
61 //pr.overrideGotExpectedResult();
\r
62 //if (true) return pr;
\r
64 HttpClient client = new HttpClient();
\r
65 GetMethod getMethod = new GetMethod(urlString);
\r
66 getMethod.addRequestHeader("Accept", "multipart/mixed");
\r
67 getMethod.addRequestHeader("Accept", "application/xml");
\r
68 getMethod.setRequestHeader("Authorization", "Basic " + authForTest); //"dGVzdDp0ZXN0");
\r
69 getMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
\r
71 int statusCode1 = client.executeMethod(getMethod);
\r
72 pr.responseCode = statusCode1;
\r
73 pr.result = getMethod.getResponseBodyAsString();
\r
74 pr.responseMessage = getMethod.getStatusText();
\r
75 Header[] headers = getMethod.getResponseHeaders();
\r
76 pr.responseHeaders = Arrays.copyOf(headers, headers.length);
\r
77 Header hdr = getMethod.getResponseHeader("CONTENT-TYPE");
\r
79 String hdrStr = hdr.toExternalForm();
\r
80 pr.boundary = PayloadLogger.parseBoundary(hdrStr);
\r
82 pr.contentLength = getMethod.getResponseContentLength();
\r
83 getMethod.releaseConnection();
\r
84 } catch (Throwable t){
\r
85 //System.err.println("ERROR getting content from response: "+t);
\r
86 pr.error = t.toString();
\r
93 public static ServiceResult doDELETE(String urlString, String authForTest, String testID, String fromTestID) throws Exception {
\r
94 ServiceResult pr = new ServiceResult();
\r
95 pr.method = "DELETE";
\r
96 pr.fullURL = urlString;
\r
97 pr.fromTestID = fromTestID;
\r
98 if (Tools.isEmpty(urlString)){
\r
99 pr.error = "url was empty. Check the result for fromTestID: "+fromTestID+". currentTest: "+testID;
\r
102 HttpClient client = new HttpClient();
\r
103 DeleteMethod deleteMethod = new DeleteMethod(urlString);
\r
104 deleteMethod.setRequestHeader("Accept", "multipart/mixed");
\r
105 deleteMethod.addRequestHeader("Accept", "application/xml");
\r
106 deleteMethod.setRequestHeader("Authorization", "Basic " + authForTest);
\r
107 deleteMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
\r
108 int statusCode1 = 0;
\r
111 statusCode1 = client.executeMethod(deleteMethod);
\r
112 pr.responseCode = statusCode1;
\r
113 //System.out.println("statusCode: "+statusCode1+" statusLine ==>" + deleteMethod.getStatusLine());
\r
114 pr.responseMessage = deleteMethod.getStatusText();
\r
115 res = deleteMethod.getResponseBodyAsString();
\r
116 deleteMethod.releaseConnection();
\r
117 } catch (Throwable t){
\r
118 pr.error = t.toString();
\r
121 pr.responseCode = statusCode1;
\r
125 public static ServiceResult doLIST(String urlString, String listQueryParams, String authForTest, String fromTestID) throws Exception {
\r
126 //String u = Tools.glue(urlString, "/", "items/");
\r
127 if (Tools.notEmpty(listQueryParams)){
\r
128 urlString = Tools.glue(urlString, "?", listQueryParams);
\r
130 return doGET(urlString, authForTest, fromTestID);
\r
133 public static final String MULTIPART_MIXED = "multipart/mixed";
\r
134 public static final String APPLICATION_XML = "application/xml";
\r
136 /** Use this overload for multipart messages. */
\r
137 public static ServiceResult doPOST_PUTFromXML_Multipart(List<String> filesList,
\r
138 List<String> partsList,
\r
139 List<Map<String,String>> varsList,
\r
140 String protoHostPort,
\r
143 XmlReplayEval evalStruct,
\r
144 String authForTest,
\r
147 if ( filesList==null||filesList.size()==0
\r
148 ||partsList==null||partsList.size()==0
\r
149 ||(partsList.size() != filesList.size())){
\r
150 throw new Exception("filesList and partsList must not be empty and must have the same number of items each.");
\r
152 String content = DD + BOUNDARY;
\r
153 Map<String, String> contentRaw = new HashMap<String, String>();
\r
154 for (int i=0; i<partsList.size(); i++){
\r
155 String fileName = filesList.get(i);
\r
156 String commonPartName = partsList.get(i);
\r
157 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
\r
158 String xmlString = new String(b);
\r
160 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, varsList.get(i), evalStruct.jexl, evalStruct.jc);
\r
161 contentRaw.put(commonPartName, xmlString);
\r
162 content = content + CRLF + "label: "+commonPartName + CRLF
\r
163 + "Content-Type: application/xml" + CRLF
\r
168 content = content + DD;
\r
169 String urlString = protoHostPort+uri;
\r
170 return doPOST_PUT(urlString, content, contentRaw, BOUNDARY, method, MULTIPART_MIXED, authForTest, fromTestID); //method is POST or PUT.
\r
173 public static ServiceResult doPOST_PUTFromXML_POX(List<String> filesList,
\r
174 List<String> partsList,
\r
175 List<Map<String,String>> varsList,
\r
176 String protoHostPort,
\r
179 XmlReplayEval evalStruct,
\r
180 String authForTest,
\r
183 if ( filesList==null||filesList.size()==0
\r
184 ||partsList==null||partsList.size()==0
\r
185 ||(partsList.size() != filesList.size())){
\r
186 throw new Exception("filesList and partsList must not be empty and must have the same number of items each.");
\r
188 //NO: Patrick sez all test files should be complete XML now: StringBuffer content = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n");
\r
189 StringBuffer content = new StringBuffer();
\r
190 //content.append(CRLF).append("<document name=\"objectexit\">").append(CRLF);
\r
191 Map<String, String> contentRaw = new HashMap<String, String>();
\r
192 for (int i=0; i<partsList.size(); i++){
\r
193 String fileName = filesList.get(i);
\r
194 String commonPartName = partsList.get(i);
\r
195 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
\r
196 String xmlString = new String(b);
\r
198 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, varsList.get(i), evalStruct.jexl, evalStruct.jc);
\r
199 contentRaw.put(commonPartName, xmlString);
\r
201 content.append(xmlString).append(CRLF);
\r
203 //content.append("</document>");
\r
204 String urlString = protoHostPort+uri;
\r
205 String POX_BOUNDARY = "";//empty for POX.
\r
206 return doPOST_PUT(urlString, content.toString(), contentRaw, POX_BOUNDARY, method,APPLICATION_XML, authForTest, fromTestID); //method is POST or PUT.
\r
210 /** Use this overload for NON-multipart messages, that is, regular POSTs. */
\r
211 public static ServiceResult doPOST_PUTFromXML(String fileName,
\r
212 Map<String,String> vars,
\r
213 String protoHostPort,
\r
216 String contentType,
\r
217 XmlReplayEval evalStruct,
\r
218 String authForTest,
\r
221 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
\r
222 String xmlString = new String(b);
\r
223 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, vars, evalStruct.jexl, evalStruct.jc);
\r
224 String urlString = protoHostPort+uri;
\r
225 Map<String, String> contentRaw = new HashMap<String, String>();
\r
226 contentRaw.put("default", xmlString);
\r
227 return doPOST_PUT(urlString, xmlString, contentRaw, BOUNDARY, method, contentType, authForTest, fromTestID); //method is POST or PUT.
\r
230 //HACK for speed testing in doPOST_PUT.
\r
231 // Result: XmlReplay takes 9ms to process one test
\r
232 // right up to the point of actually firing an HTTP request.
\r
233 // or ~ 120 records per second.
\r
234 //result.CSID = "2";
\r
235 //result.overrideGotExpectedResult();
\r
236 //if (true) return result;
\r
239 public static ServiceResult doPOST_PUT(String urlString, String content, Map<String,String> contentRaw,
\r
240 String boundary, String method, String contentType,
\r
241 String authForTest, String fromTestID) throws Exception {
\r
242 ServiceResult result = new ServiceResult();
\r
243 result.method = method;
\r
244 String deleteURL = "";
\r
245 String location = "";
\r
247 URL url = new URL(urlString);
\r
248 HttpURLConnection conn;
\r
249 conn = (HttpURLConnection) url.openConnection();
\r
251 if (MULTIPART_MIXED.equalsIgnoreCase(contentType)){
\r
252 conn.setRequestProperty("Accept", "multipart/mixed");
\r
253 conn.setRequestProperty("content-type", "multipart/mixed; boundary=" + boundary);
\r
255 conn.setRequestProperty("Accept", "application/xml");
\r
256 conn.setRequestProperty("content-type", contentType);
\r
258 conn.setRequestProperty("Authorization", "Basic " + authForTest); //TODO: remove test user : hard-coded as "dGVzdDp0ZXN0"
\r
259 conn.setRequestProperty("Connection", "close");
\r
260 conn.setRequestProperty("X-XmlReplay-fromTestID", fromTestID);
\r
261 conn.setDoOutput(true);
\r
262 conn.setDoInput(true);
\r
263 conn.setRequestMethod(method); // "POST" or "PUT"
\r
264 OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
\r
269 result.requestPayload = content;
\r
270 result.requestPayloadsRaw = contentRaw;
\r
271 result.responseCode = conn.getResponseCode();
\r
272 //System.out.println("responseCode: "+result.responseCode);
\r
273 if (400 <= result.responseCode && result.responseCode <= 499){
\r
276 readStream(conn, result);
\r
277 } catch (Throwable t){
\r
278 //System.err.println("ERROR getting content from response: "+t);
\r
279 result.error = t.toString();
\r
283 Map<String, List<String>> headers = conn.getHeaderFields();
\r
284 List<String> locations = headers.get("Location");
\r
285 if (locations != null){
\r
286 String locationZero = locations.get(0);
\r
287 if (locationZero != null){
\r
288 String[] segments = locationZero.split("/");
\r
289 location = segments[segments.length - 1];
\r
290 deleteURL = Tools.glue(urlString, "/", location);
\r
293 result.location = location;
\r
294 result.deleteURL = deleteURL;
\r
295 result.CSID = location;
\r
296 } catch (Throwable t2){
\r
297 result.error = "ERROR in XmlReplayTransport: "+t2;
\r
303 public static ServiceResult doPOST_PUT_PostMethod(String urlString, String content, Map<String,String> contentRaw,
\r
304 String boundary, String method, String contentType,
\r
305 String authForTest, String fromTestID) throws Exception {
\r
306 ServiceResult result = new ServiceResult();
\r
307 result.method = method;
\r
308 String deleteURL = "";
\r
309 String location = "";
\r
311 HttpClient client = new HttpClient();
\r
312 PostMethod postMethod = new PostMethod(urlString);
\r
313 postMethod.setRequestHeader("Accept", "multipart/mixed");
\r
314 postMethod.addRequestHeader("Accept", "application/xml");
\r
315 postMethod.setRequestHeader("Authorization", "Basic " + authForTest);
\r
316 postMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
\r
317 //this method takes an array of params. Not sure what they expect us to do with a raw post:
\r
318 // postMethod.setRequestBody();
\r
319 int statusCode1 = 0;
\r
322 statusCode1 = client.executeMethod(postMethod);
\r
323 result.responseCode = statusCode1;
\r
324 //System.out.println("statusCode: "+statusCode1+" statusLine ==>" + postMethod.getStatusLine());
\r
325 result.responseMessage = postMethod.getStatusText();
\r
326 res = postMethod.getResponseBodyAsString();
\r
327 Header[] headers = postMethod.getResponseHeaders("Location");
\r
328 if (headers.length>0) {
\r
329 System.out.println("headers[0]: "+headers[0]);
\r
330 String locationZero = headers[0].getValue();
\r
331 if (locationZero != null){
\r
332 String[] segments = locationZero.split("/");
\r
333 location = segments[segments.length - 1];
\r
334 deleteURL = Tools.glue(urlString, "/", location);
\r
337 postMethod.releaseConnection();
\r
338 } catch (Throwable t){
\r
339 result.error = t.toString();
\r
341 result.result = res;
\r
342 result.location = location;
\r
343 result.deleteURL = deleteURL;
\r
344 result.CSID = location;
\r
345 } catch (Throwable t2){
\r
346 result.error = "ERROR in XmlReplayTransport: "+t2;
\r
351 private static void readStream(HttpURLConnection conn, ServiceResult result) throws Throwable {
\r
352 BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
\r
355 StringBuffer sb = new StringBuffer();
\r
356 while ((line = rd.readLine()) != null) {
\r
357 sb.append(line).append("\r\n");
\r
359 String msg = sb.toString();
\r
360 result.result = msg;
\r
361 result.boundary = PayloadLogger.parseBoundary(conn.getHeaderField("CONTENT-TYPE"));
\r