001: /*
002: * ========================================================================
003: *
004: * Copyright 2001-2004 The Apache Software Foundation.
005: *
006: * Licensed under the Apache License, Version 2.0 (the "License");
007: * you may not use this file except in compliance with the License.
008: * You may obtain a copy of the License at
009: *
010: * http://www.apache.org/licenses/LICENSE-2.0
011: *
012: * Unless required by applicable law or agreed to in writing, software
013: * distributed under the License is distributed on an "AS IS" BASIS,
014: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: * See the License for the specific language governing permissions and
016: * limitations under the License.
017: *
018: * ========================================================================
019: */
020: package org.apache.cactus.internal.client.connector.http;
021:
022: import java.net.HttpURLConnection;
023:
024: import org.apache.cactus.WebRequest;
025: import org.apache.cactus.internal.HttpServiceDefinition;
026: import org.apache.cactus.internal.RequestDirectives;
027: import org.apache.cactus.internal.ServiceEnumeration;
028: import org.apache.cactus.internal.WebRequestImpl;
029: import org.apache.cactus.internal.WebTestResult;
030: import org.apache.cactus.internal.client.AssertionFailedErrorWrapper;
031: import org.apache.cactus.internal.client.ParsingException;
032: import org.apache.cactus.internal.client.ServletExceptionWrapper;
033: import org.apache.cactus.internal.client.WebTestResultParser;
034: import org.apache.cactus.internal.configuration.WebConfiguration;
035: import org.apache.cactus.internal.util.IoUtil;
036: import org.apache.cactus.util.ChainedRuntimeException;
037:
038: /**
039: * Performs the steps necessary to run a test. It involves
040: * opening a first HTTP connection to a server redirector, reading the output
041: * stream and then opening a second HTTP connection to retrieve the test
042: * result.
043: *
044: * @version $Id: DefaultHttpClient.java 238991 2004-05-22 11:34:50Z vmassol $
045: */
046: public class DefaultHttpClient {
047: /**
048: * Cactus configuration.
049: */
050: protected WebConfiguration configuration;
051:
052: /**
053: * Initialize the Http client.
054: *
055: * @param theConfiguration the Cactus configuration
056: */
057: public DefaultHttpClient(WebConfiguration theConfiguration) {
058: this .configuration = theConfiguration;
059: }
060:
061: /**
062: * Calls the test method indirectly by calling the Redirector servlet and
063: * then open a second HTTP connection to retrieve the test results.
064: *
065: * @param theRequest the request containing all data to pass to the
066: * redirector servlet.
067: *
068: * @return the <code>HttpURLConnection</code> that contains the HTTP
069: * response when the test was called.
070: *
071: * @exception Throwable if an error occured in the test method or in the
072: * redirector servlet.
073: */
074: public HttpURLConnection doTest(WebRequest theRequest)
075: throws Throwable {
076: // Open the first connection to the redirector to execute the test on
077: // the server side
078: HttpURLConnection connection = callRunTest(theRequest);
079:
080: // Open the second connection to get the test results
081: WebTestResult result = null;
082:
083: try {
084: result = callGetResult(theRequest);
085: } catch (ParsingException e) {
086: String url = this .configuration
087: .getRedirectorURL(theRequest);
088: throw new ChainedRuntimeException("Failed to get the test "
089: + "results at [" + url + "]", e);
090: }
091:
092: // Check if the returned result object returned contains an error or
093: // not. If yes, we need to raise an exception so that the JUnit
094: // framework can catch it
095: if (result.hasException()) {
096: // Wrap the exception message and stack trace into a fake
097: // exception class with overloaded <code>printStackTrace()</code>
098: // methods so that when JUnit calls this method it will print the
099: // stack trace that was set on the server side.
100: // If the error was an AssertionFailedError or ComparisonFailure
101: // then we use an instance of AssertionFailedErrorWrapper (so that
102: // JUnit recognize it is an AssertionFailedError exception and
103: // print it differently in it's runner console). Otherwise we use
104: // an instance of ServletExceptionWrapper.
105:
106: // Note: We have to test the exceptions by string name as the JUnit
107: // AssertionFailedError class is unfortunately not serializable...
108:
109: if ((result.getExceptionClassName()
110: .equals("junit.framework.AssertionFailedError"))
111: || (result.getExceptionClassName()
112: .equals("junit.framework.ComparisonFailure"))) {
113: throw new AssertionFailedErrorWrapper(result
114: .getExceptionMessage(), result
115: .getExceptionClassName(), result
116: .getExceptionStackTrace());
117: } else {
118: throw new ServletExceptionWrapper(result
119: .getExceptionMessage(), result
120: .getExceptionClassName(), result
121: .getExceptionStackTrace());
122: }
123: }
124:
125: return connection;
126: }
127:
128: /**
129: * Execute the test by calling the redirector.
130: *
131: * @param theRequest the request containing all data to pass to the
132: * redirector servlet.
133: * @return the <code>HttpURLConnection</code> that contains the HTTP
134: * response when the test was called.
135: *
136: * @exception Throwable if an error occured in the test method or in the
137: * redirector servlet.
138: */
139: private HttpURLConnection callRunTest(WebRequest theRequest)
140: throws Throwable {
141: // Specify the service to call on the redirector side
142: theRequest.addParameter(
143: HttpServiceDefinition.SERVICE_NAME_PARAM,
144: ServiceEnumeration.CALL_TEST_SERVICE.toString(),
145: WebRequest.GET_METHOD);
146:
147: // Open the first connection to the redirector to execute the test on
148: // the server side
149: HttpClientConnectionHelper helper = new HttpClientConnectionHelper(
150: this .configuration.getRedirectorURL(theRequest));
151:
152: HttpURLConnection connection = helper.connect(theRequest,
153: this .configuration);
154:
155: // Wrap the connection to ensure that all servlet output is read
156: // before we ask for results
157: connection = new AutoReadHttpURLConnection(connection);
158:
159: // Trigger the transfer of data
160: connection.getInputStream();
161:
162: return connection;
163: }
164:
165: /**
166: * Get the test result from the redirector.
167: *
168: * @param theOriginalRequest the request that was used to run the test
169: * @return the result that was returned by the redirector.
170: *
171: * @exception Throwable if an error occured in the test method or in the
172: * redirector servlet.
173: */
174: private WebTestResult callGetResult(WebRequest theOriginalRequest)
175: throws Throwable {
176: WebRequest resultsRequest = new WebRequestImpl(
177: this .configuration);
178: RequestDirectives directives = new RequestDirectives(
179: resultsRequest);
180: directives.setService(ServiceEnumeration.GET_RESULTS_SERVICE);
181:
182: // Use the same redirector as was used by the original request
183: resultsRequest.setRedirectorName(theOriginalRequest
184: .getRedirectorName());
185:
186: // Add authentication details
187: if (theOriginalRequest.getAuthentication() != null) {
188: resultsRequest.setAuthentication(theOriginalRequest
189: .getAuthentication());
190: }
191:
192: // Open the second connection to get the test results
193: HttpClientConnectionHelper helper = new HttpClientConnectionHelper(
194: this .configuration.getRedirectorURL(resultsRequest));
195:
196: HttpURLConnection resultConnection = helper.connect(
197: resultsRequest, this .configuration);
198:
199: if (resultConnection.getResponseCode() != 200) {
200: throw new ParsingException("Not a valid response ["
201: + resultConnection.getResponseCode() + " "
202: + resultConnection.getResponseMessage() + "]");
203: }
204:
205: // Read the test result
206: WebTestResultParser parser = new WebTestResultParser();
207: return parser.parse(IoUtil.getText(resultConnection
208: .getInputStream(), "UTF-8"));
209: }
210: }
|