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.HashMap;
41 import java.util.List;
44 import org.collectionspace.services.common.api.Tools;
47 * @author Laramie Crocker
49 public class XmlReplayTransport {
51 private static String BOUNDARY = "34d97c83-0d61-4958-80ab-6bf8d362290f";
52 private static String DD = "--";
53 private static String CRLF = "\r\n";
55 public static ServiceResult doGET(String urlString, String authForTest, String fromTestID) throws Exception {
56 ServiceResult pr = new ServiceResult();
57 pr.fromTestID = fromTestID;
59 //HACK for speed testing.
61 //pr.overrideGotExpectedResult();
62 //if (true) return pr;
64 HttpClient client = new HttpClient();
65 GetMethod getMethod = new GetMethod(urlString);
66 getMethod.addRequestHeader("Accept", "multipart/mixed");
67 getMethod.addRequestHeader("Accept", "application/xml");
68 getMethod.setRequestHeader("Authorization", "Basic " + authForTest); //"dGVzdDp0ZXN0");
69 getMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
71 int statusCode1 = client.executeMethod(getMethod);
72 pr.responseCode = statusCode1;
73 pr.result = getMethod.getResponseBodyAsString();
74 pr.responseMessage = getMethod.getStatusText();
75 Header[] headers = getMethod.getResponseHeaders();
76 pr.responseHeaders = Arrays.copyOf(headers, headers.length);
77 Header hdr = getMethod.getResponseHeader("CONTENT-TYPE");
79 String hdrStr = hdr.toExternalForm();
80 pr.boundary = PayloadLogger.parseBoundary(hdrStr);
82 pr.contentLength = getMethod.getResponseContentLength();
83 getMethod.releaseConnection();
84 } catch (Throwable t){
85 //System.err.println("ERROR getting content from response: "+t);
86 pr.error = t.toString();
91 public static ServiceResult doDELETE(String urlString, String authForTest, String testID, String fromTestID) throws Exception {
92 ServiceResult pr = new ServiceResult();
93 pr.failureReason = "";
95 pr.fullURL = urlString;
96 pr.fromTestID = fromTestID;
97 if (Tools.isEmpty(urlString)){
98 pr.error = "url was empty. Check the result for fromTestID: "+fromTestID+". currentTest: "+testID;
101 HttpClient client = new HttpClient();
102 DeleteMethod deleteMethod = new DeleteMethod(urlString);
103 deleteMethod.setRequestHeader("Accept", "multipart/mixed");
104 deleteMethod.addRequestHeader("Accept", "application/xml");
105 deleteMethod.setRequestHeader("Authorization", "Basic " + authForTest);
106 deleteMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
110 statusCode1 = client.executeMethod(deleteMethod);
111 pr.responseCode = statusCode1;
112 //System.out.println("statusCode: "+statusCode1+" statusLine ==>" + deleteMethod.getStatusLine());
113 pr.responseMessage = deleteMethod.getStatusText();
114 res = deleteMethod.getResponseBodyAsString();
115 deleteMethod.releaseConnection();
116 } catch (Throwable t){
117 pr.error = t.toString();
120 pr.responseCode = statusCode1;
124 public static ServiceResult doLIST(String urlString, String listQueryParams, String authForTest, String fromTestID) throws Exception {
125 //String u = Tools.glue(urlString, "/", "items/");
126 if (Tools.notEmpty(listQueryParams)){
127 urlString = Tools.glue(urlString, "?", listQueryParams);
129 return doGET(urlString, authForTest, fromTestID);
132 public static final String MULTIPART_MIXED = "multipart/mixed";
133 public static final String APPLICATION_XML = "application/xml";
135 /** Use this overload for multipart messages. */
137 public static ServiceResult doPOST_PUTFromXML_Multipart(List<String> filesList,
138 List<String> partsList,
139 List<Map<String,String>> varsList,
140 String protoHostPort,
143 XmlReplayEval evalStruct,
147 if ( filesList==null||filesList.size()==0
148 ||partsList==null||partsList.size()==0
149 ||(partsList.size() != filesList.size())){
150 throw new Exception("filesList and partsList must not be empty and must have the same number of items each.");
152 String content = DD + BOUNDARY;
153 Map<String, String> contentRaw = new HashMap<String, String>();
154 for (int i=0; i<partsList.size(); i++){
155 String fileName = filesList.get(i);
156 String commonPartName = partsList.get(i);
157 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
158 String xmlString = new String(b);
160 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, varsList.get(i), evalStruct.jexl, evalStruct.jc);
161 contentRaw.put(commonPartName, xmlString);
162 content = content + CRLF + "label: "+commonPartName + CRLF
163 + "Content-Type: application/xml" + CRLF
168 content = content + DD;
169 String urlString = protoHostPort+uri;
170 return doPOST_PUT(urlString, content, contentRaw, BOUNDARY, method, MULTIPART_MIXED, authForTest, fromTestID); //method is POST or PUT.
174 /** Use this overload for NON-multipart messages, that is, regular POSTs. */
175 public static ServiceResult doPOST_PUTFromXML(String fileName,
176 Map<String,String> vars,
177 String protoHostPort,
181 XmlReplayEval evalStruct,
185 byte[] b = FileUtils.readFileToByteArray(new File(fileName));
186 String xmlString = new String(b);
187 String contentRaw = xmlString;
188 xmlString = evalStruct.eval(xmlString, evalStruct.serviceResultsMap, vars, evalStruct.jexl, evalStruct.jc);
189 String urlString = protoHostPort+uri;
190 return doPOST_PUT(urlString, xmlString, contentRaw, BOUNDARY, method, contentType, authForTest, fromTestID); //method is POST or PUT.
193 //HACK for speed testing in doPOST_PUT.
194 // Result: XmlReplay takes 9ms to process one test
195 // right up to the point of actually firing an HTTP request.
196 // or ~ 120 records per second.
198 //result.overrideGotExpectedResult();
199 //if (true) return result;
202 public static ServiceResult doPOST_PUT(String urlString,
209 String fromTestID) throws Exception {
210 ServiceResult result = new ServiceResult();
211 result.method = method;
212 String deleteURL = "";
213 String location = "";
215 URL url = new URL(urlString);
216 HttpURLConnection conn;
217 conn = (HttpURLConnection) url.openConnection();
219 if (MULTIPART_MIXED.equalsIgnoreCase(contentType)){
220 conn.setRequestProperty("Accept", "multipart/mixed");
221 conn.setRequestProperty("content-type", "multipart/mixed; boundary=" + boundary);
223 conn.setRequestProperty("Accept", "application/xml");
224 conn.setRequestProperty("content-type", contentType);
226 conn.setRequestProperty("Authorization", "Basic " + authForTest); //TODO: remove test user : hard-coded as "dGVzdDp0ZXN0"
227 conn.setRequestProperty("Connection", "close");
228 conn.setRequestProperty("X-XmlReplay-fromTestID", fromTestID);
229 conn.setDoOutput(true);
230 conn.setDoInput(true);
231 conn.setRequestMethod(method); // "POST" or "PUT"
232 OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
237 result.requestPayload = content;
238 result.requestPayloadsRaw = contentRaw;
239 result.responseCode = conn.getResponseCode();
240 //System.out.println("responseCode: "+result.responseCode);
241 if (400 <= result.responseCode && result.responseCode <= 499){
244 readStream(conn, result);
245 } catch (Throwable t){
246 //System.err.println("ERROR getting content from response: "+t);
247 result.error = t.toString();
251 Map<String, List<String>> headers = conn.getHeaderFields();
252 List<String> locations = headers.get("Location");
253 if (locations != null){
254 String locationZero = locations.get(0);
255 if (locationZero != null){
256 String[] segments = locationZero.split("/");
257 location = segments[segments.length - 1];
258 deleteURL = Tools.glue(urlString, "/", location);
261 result.location = location;
262 result.deleteURL = deleteURL;
263 result.CSID = location;
264 } catch (Throwable t2){
265 result.error = "ERROR in XmlReplayTransport: "+t2;
270 public static ServiceResult doPOST_PUT_PostMethod(String urlString, String content, Map<String,String> contentRaw,
271 String boundary, String method, String contentType,
272 String authForTest, String fromTestID) throws Exception {
273 ServiceResult result = new ServiceResult();
274 result.method = method;
275 String deleteURL = "";
276 String location = "";
278 HttpClient client = new HttpClient();
279 PostMethod postMethod = new PostMethod(urlString);
280 postMethod.setRequestHeader("Accept", "multipart/mixed");
281 postMethod.addRequestHeader("Accept", "application/xml");
282 postMethod.setRequestHeader("Authorization", "Basic " + authForTest);
283 postMethod.setRequestHeader("X-XmlReplay-fromTestID", fromTestID);
284 //this method takes an array of params. Not sure what they expect us to do with a raw post:
285 // postMethod.setRequestBody();
289 statusCode1 = client.executeMethod(postMethod);
290 result.responseCode = statusCode1;
291 //System.out.println("statusCode: "+statusCode1+" statusLine ==>" + postMethod.getStatusLine());
292 result.responseMessage = postMethod.getStatusText();
293 res = postMethod.getResponseBodyAsString();
294 Header[] headers = postMethod.getResponseHeaders("Location");
295 if (headers.length>0) {
296 System.out.println("headers[0]: "+headers[0]);
297 String locationZero = headers[0].getValue();
298 if (locationZero != null){
299 String[] segments = locationZero.split("/");
300 location = segments[segments.length - 1];
301 deleteURL = Tools.glue(urlString, "/", location);
304 postMethod.releaseConnection();
305 } catch (Throwable t){
306 result.error = t.toString();
309 result.location = location;
310 result.deleteURL = deleteURL;
311 result.CSID = location;
312 } catch (Throwable t2){
313 result.error = "ERROR in XmlReplayTransport: "+t2;
318 private static void readStream(HttpURLConnection conn, ServiceResult result) throws Throwable {
319 BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
322 StringBuffer sb = new StringBuffer();
323 while ((line = rd.readLine()) != null) {
324 sb.append(line).append("\r\n");
326 String msg = sb.toString();
328 result.boundary = PayloadLogger.parseBoundary(conn.getHeaderField("CONTENT-TYPE"));