2 * This document is a part of the source code and related artifacts
3 * for CollectionSpace, an open source collections management system
4 * for museums and related institutions:
6 * http://www.collectionspace.org
7 * http://wiki.collectionspace.org
9 * Copyright (c) 2009 Regents of the University of California
11 * Licensed under the Educational Community License (ECL), Version 2.0.
12 * You may not use this file except in compliance with this License.
14 * You may obtain a copy of the ECL 2.0 License at
15 * https://source.collectionspace.org/collection-space/LICENSE.txt
17 * Unless required by applicable law or agreed to in writing, software
18 * distributed under the License is distributed on an "AS IS" BASIS,
19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 * See the License for the specific language governing permissions and
21 * limitations under the License.
24 package org.collectionspace.services.IntegrationTests.xmlreplay;
26 import org.apache.commons.httpclient.Header;
27 import org.apache.commons.httpclient.HttpClient;
28 import org.apache.commons.httpclient.methods.DeleteMethod;
29 import org.apache.commons.httpclient.methods.GetMethod;
30 import org.apache.commons.httpclient.methods.PostMethod;
31 import org.apache.commons.io.FileUtils;
33 import java.io.BufferedReader;
35 import java.io.InputStreamReader;
36 import java.io.OutputStreamWriter;
37 import java.net.HttpURLConnection;
39 import java.util.Arrays;
40 import java.util.List;
43 import org.collectionspace.services.common.api.Tools;
46 * @author Laramie Crocker
48 public class XmlReplayTransport {
50 private static String BOUNDARY = "34d97c83-0d61-4958-80ab-6bf8d362290f";
51 private static String DD = "--";
52 private static String CRLF = "\r\n";
54 private static String formatAuth(String authForTest) {
55 if (authForTest.startsWith("Bearer ")) {
59 return ("Basic " + authForTest);
62 public static ServiceResult doGET(String urlString, String authForTest, String fromTestID) throws Exception {
63 ServiceResult pr = new ServiceResult();
64 pr.fromTestID = fromTestID;
66 //HACK for speed testing.
68 //pr.overrideGotExpectedResult();
69 //if (true) return pr;
71 HttpClient client = new HttpClient();
72 GetMethod getMethod = new GetMethod(urlString);
73 getMethod.addRequestHeader("Accept", "multipart/mixed");
74 getMethod.addRequestHeader("Accept", "application/xml");
75 getMethod.setRequestHeader("Authorization", formatAuth(authForTest)); //"dGVzdDp0ZXN0");
76 getMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
78 int statusCode1 = client.executeMethod(getMethod);
79 pr.responseCode = statusCode1;
80 pr.result = getMethod.getResponseBodyAsString();
81 pr.responseMessage = getMethod.getStatusText();
82 Header[] headers = getMethod.getResponseHeaders();
83 pr.responseHeaders = Arrays.copyOf(headers, headers.length);
84 Header hdr = getMethod.getResponseHeader("CONTENT-TYPE");
86 String hdrStr = hdr.toExternalForm();
87 pr.boundary = PayloadLogger.parseBoundary(hdrStr);
89 pr.contentLength = getMethod.getResponseContentLength();
90 getMethod.releaseConnection();
91 } catch (Throwable t){
92 //System.err.println("ERROR getting content from response: "+t);
93 pr.error = t.toString();
98 public static ServiceResult doDELETE(String urlString, String authForTest, String testID, String fromTestID) throws Exception {
99 ServiceResult pr = new ServiceResult();
100 pr.failureReason = "";
101 pr.method = "DELETE";
102 pr.fullURL = urlString;
103 pr.fromTestID = fromTestID;
104 if (Tools.isEmpty(urlString)){
105 pr.error = "url was empty. Check the result for fromTestID: "+fromTestID+". currentTest: "+testID;
108 HttpClient client = new HttpClient();
109 DeleteMethod deleteMethod = new DeleteMethod(urlString);
110 deleteMethod.setRequestHeader("Accept", "multipart/mixed");
111 deleteMethod.addRequestHeader("Accept", "application/xml");
112 deleteMethod.setRequestHeader("Authorization", formatAuth(authForTest));
113 if (Tools.notBlank(fromTestID)) {
114 deleteMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
119 statusCode1 = client.executeMethod(deleteMethod);
120 pr.responseCode = statusCode1;
121 //System.out.println("statusCode: "+statusCode1+" statusLine ==>" + deleteMethod.getStatusLine());
122 pr.responseMessage = deleteMethod.getStatusText();
123 res = deleteMethod.getResponseBodyAsString();
124 deleteMethod.releaseConnection();
125 } catch (Throwable t){
126 pr.error = t.toString();
129 pr.responseCode = statusCode1;
133 public static ServiceResult doLIST(String urlString, String listQueryParams, String authForTest, String fromTestID) throws Exception {
134 //String u = Tools.glue(urlString, "/", "items/");
135 if (Tools.notEmpty(listQueryParams)){
136 urlString = Tools.glue(urlString, "?", listQueryParams);
138 return doGET(urlString, authForTest, fromTestID);
141 public static final String MULTIPART_MIXED = "multipart/mixed";
142 public static final String APPLICATION_XML = "application/xml";
144 /** Use this overload for multipart messages. */
146 public static ServiceResult doPOST_PUTFromXML_Multipart(List<String> filesList,
147 List<String> partsList,
148 List<Map<String,String>> varsList,
149 String protoHostPort,
152 XmlReplayEval evalStruct,
156 if ( filesList==null||filesList.size()==0
157 ||partsList==null||partsList.size()==0
158 ||(partsList.size() != filesList.size())){
159 throw new Exception("filesList and partsList must not be empty and must have the same number of items each.");
161 String content = DD + BOUNDARY;
162 Map<String, String> contentRaw = new HashMap<String, String>();
163 for (int i=0; i<partsList.size(); i++){
164 String fileName = filesList.get(i);
165 String commonPartName = partsList.get(i);
166 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
167 String xmlString = new String(b);
169 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, varsList.get(i), evalStruct.jexl, evalStruct.jc);
170 contentRaw.put(commonPartName, xmlString);
171 content = content + CRLF + "label: "+commonPartName + CRLF
172 + "Content-Type: application/xml" + CRLF
177 content = content + DD;
178 String urlString = protoHostPort+uri;
179 return doPOST_PUT(urlString, content, contentRaw, BOUNDARY, method, MULTIPART_MIXED, authForTest, fromTestID); //method is POST or PUT.
183 /** Use this overload for NON-multipart messages, that is, regular POSTs. */
184 public static ServiceResult doPOST_PUTFromXML(
188 String protoHostPort,
192 XmlReplayEval evalStruct,
194 String fromTestID) throws Exception {
195 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
196 String xmlString = new String(b);
197 String contentRaw = xmlString;
199 // Add the test ID so we can substitute instances of "${testID}" in the
200 // payload with the test ID.
202 String testId = fromTestID.split("\\.")[1]; // Get the unqualified (without the group ID part) test name
203 vars.put("Test.ID", testId);
205 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, vars, evalStruct.jexl, evalStruct.jc);
206 String urlString = protoHostPort + uri;
208 return doPOST_PUT(urlString, xmlString, contentRaw, BOUNDARY, method, contentType, authForTest, fromTestID); // method is POST or PUT.
211 //HACK for speed testing in doPOST_PUT.
212 // Result: XmlReplay takes 9ms to process one test
213 // right up to the point of actually firing an HTTP request.
214 // or ~ 120 records per second.
216 //result.overrideGotExpectedResult();
217 //if (true) return result;
220 private static ServiceResult doPOST_PUT(
228 String fromTestID) throws Exception {
229 ServiceResult result = new ServiceResult();
230 result.method = method;
232 String deleteURL = "";
233 String location = "";
236 URL url = new URL(urlString);
237 HttpURLConnection conn;
238 conn = (HttpURLConnection) url.openConnection();
240 if (MULTIPART_MIXED.equalsIgnoreCase(contentType)){
241 conn.setRequestProperty("Accept", "multipart/mixed");
242 conn.setRequestProperty("content-type", "multipart/mixed; boundary=" + boundary);
244 conn.setRequestProperty("Accept", "application/xml");
245 conn.setRequestProperty("content-type", contentType);
247 conn.setRequestProperty("Authorization", formatAuth(authForTest)); //TODO: remove test user : hard-coded as "dGVzdDp0ZXN0"
248 conn.setRequestProperty("Connection", "close");
249 conn.setRequestProperty("X-XmlReplay-fromTestID", fromTestID);
250 conn.setDoOutput(true);
251 conn.setDoInput(true);
252 conn.setRequestMethod(method); // "POST" or "PUT"
253 OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
258 result.requestPayload = content;
259 result.requestPayloadsRaw = contentRaw;
260 result.responseCode = conn.getResponseCode();
261 //System.out.println("responseCode: "+result.responseCode);
262 if (400 <= result.responseCode && result.responseCode <= 499){
265 readStream(conn, result);
266 } catch (Throwable t){
267 //System.err.println("ERROR getting content from response: "+t);
268 result.error = t.toString();
272 Map<String, List<String>> headers = conn.getHeaderFields();
273 List<String> locations = headers.get("Location");
274 if (locations != null){
275 String locationZero = locations.get(0);
276 if (locationZero != null){
277 String[] segments = locationZero.split("/");
278 location = segments[segments.length - 1];
279 deleteURL = Tools.glue(urlString, "/", location);
282 result.location = location;
283 result.deleteURL = deleteURL;
284 result.CSID = location;
285 } catch (Throwable t2){
286 result.error = "ERROR in XmlReplayTransport: "+t2;
294 * This method is not used and is a good candidate for removal.
307 private static ServiceResult doPOST_PUT_PostMethod(
310 Map<String, String> contentRaw,
317 ServiceResult result = new ServiceResult();
318 result.method = method;
319 String deleteURL = "";
320 String location = "";
323 HttpClient client = new HttpClient();
324 PostMethod postMethod = new PostMethod(urlString);
325 postMethod.setRequestHeader("Accept", "multipart/mixed");
326 postMethod.addRequestHeader("Accept", "application/xml");
327 postMethod.setRequestHeader("Authorization", formatAuth(authForTest));
328 postMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
329 // this method takes an array of params. Not sure what they expect
330 // us to do with a raw post:
331 // postMethod.setRequestBody();
335 statusCode1 = client.executeMethod(postMethod);
336 result.responseCode = statusCode1;
337 // System.out.println("statusCode: "+statusCode1+" statusLine
338 // ==>" + postMethod.getStatusLine());
339 result.responseMessage = postMethod.getStatusText();
340 res = postMethod.getResponseBodyAsString();
341 Header[] headers = postMethod.getResponseHeaders("Location");
342 if (headers.length > 0) {
343 System.out.println("headers[0]: " + headers[0]);
344 String locationZero = headers[0].getValue();
345 if (locationZero != null) {
346 String[] segments = locationZero.split("/");
347 location = segments[segments.length - 1];
348 deleteURL = Tools.glue(urlString, "/", location);
351 postMethod.releaseConnection();
352 } catch (Throwable t) {
353 result.error = t.toString();
356 result.location = location;
357 result.deleteURL = deleteURL;
358 result.CSID = location;
359 } catch (Throwable t2) {
360 result.error = "ERROR in XmlReplayTransport: " + t2;
366 private static void readStream(HttpURLConnection conn, ServiceResult result) throws Throwable {
367 BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
370 StringBuffer sb = new StringBuffer();
371 while ((line = rd.readLine()) != null) {
372 sb.append(line).append("\r\n");
374 String msg = sb.toString();
376 result.boundary = PayloadLogger.parseBoundary(conn.getHeaderField("CONTENT-TYPE"));