2011/08/05 - Jakarta Cactus has been retired.

For more information, please explore the Attic.

View Javadoc

1   /* 
2    * ========================================================================
3    * 
4    * Licensed to the Apache Software Foundation (ASF) under one or more
5    * contributor license agreements.  See the NOTICE file distributed with
6    * this work for additional information regarding copyright ownership.
7    * The ASF licenses this file to You under the Apache License, Version 2.0
8    * (the "License"); you may not use this file except in compliance with
9    * the License.  You may obtain a copy of the License at
10   * 
11   *   http://www.apache.org/licenses/LICENSE-2.0
12   * 
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * 
19   * ========================================================================
20   */
21  package org.apache.cactus.internal.client.connector.http;
22  
23  import java.net.HttpURLConnection;
24  
25  import org.apache.cactus.WebRequest;
26  import org.apache.cactus.internal.HttpServiceDefinition;
27  import org.apache.cactus.internal.RequestDirectives;
28  import org.apache.cactus.internal.ServiceEnumeration;
29  import org.apache.cactus.internal.WebRequestImpl;
30  import org.apache.cactus.internal.WebTestResult;
31  import org.apache.cactus.internal.client.AssertionFailedErrorWrapper;
32  import org.apache.cactus.internal.client.ParsingException;
33  import org.apache.cactus.internal.client.ServletExceptionWrapper;
34  import org.apache.cactus.internal.client.WebTestResultParser;
35  import org.apache.cactus.internal.configuration.WebConfiguration;
36  import org.apache.cactus.internal.util.IoUtil;
37  import org.apache.cactus.util.ChainedRuntimeException;
38  
39  /**
40   * Performs the steps necessary to run a test. It involves
41   * opening a first HTTP connection to a server redirector, reading the output
42   * stream and then opening a second HTTP connection to retrieve the test 
43   * result.
44   *
45   * @version $Id: DefaultHttpClient.java 238991 2004-05-22 11:34:50Z vmassol $
46   */
47  public class DefaultHttpClient
48  {
49      /**
50       * Cactus configuration.
51       */
52      protected WebConfiguration configuration;
53      
54      /**
55       * Initialize the Http client.
56       * 
57       * @param theConfiguration the Cactus configuration
58       */
59      public DefaultHttpClient(WebConfiguration theConfiguration)
60      {
61          this.configuration = theConfiguration;
62      }
63  
64      /**
65       * Calls the test method indirectly by calling the Redirector servlet and
66       * then open a second HTTP connection to retrieve the test results.
67       *
68       * @param theRequest the request containing all data to pass to the
69       *        redirector servlet.
70       *
71       * @return the <code>HttpURLConnection</code> that contains the HTTP
72       *         response when the test was called.
73       *
74       * @exception Throwable if an error occured in the test method or in the
75       *            redirector servlet.
76       */
77      public HttpURLConnection doTest(WebRequest theRequest) throws Throwable
78      {
79          // Open the first connection to the redirector to execute the test on
80          // the server side
81          HttpURLConnection connection = callRunTest(theRequest);
82  
83          // Open the second connection to get the test results
84          WebTestResult result = null;
85  
86          try
87          {
88              result = callGetResult(theRequest);
89          }
90          catch (ParsingException e)
91          {
92              String url = this.configuration.getRedirectorURL(theRequest);
93              throw new ChainedRuntimeException("Failed to get the test "
94                  + "results at [" + url + "]", e);
95          }
96  
97          // Check if the returned result object returned contains an error or
98          // not. If yes, we need to raise an exception so that the JUnit
99          // framework can catch it
100         if (result.hasException())
101         {
102             // Wrap the exception message and stack trace into a fake
103             // exception class with overloaded <code>printStackTrace()</code>
104             // methods so that when JUnit calls this method it will print the
105             // stack trace that was set on the server side.
106             // If the error was an AssertionFailedError or ComparisonFailure
107             // then we use an instance of AssertionFailedErrorWrapper (so that 
108             // JUnit recognize it is an AssertionFailedError exception and 
109             // print it differently in it's runner console). Otherwise we use 
110             // an instance of ServletExceptionWrapper.
111 
112             // Note: We have to test the exceptions by string name as the JUnit
113             // AssertionFailedError class is unfortunately not serializable...
114 
115             if ((result.getExceptionClassName().equals(
116                 "junit.framework.AssertionFailedError"))
117                 || (result.getExceptionClassName().equals(
118                 "junit.framework.ComparisonFailure")))
119             {
120                 throw new AssertionFailedErrorWrapper(
121                     result.getExceptionMessage(), 
122                     result.getExceptionClassName(), 
123                     result.getExceptionStackTrace());
124             }
125             else
126             {
127                 throw new ServletExceptionWrapper(
128                     result.getExceptionMessage(), 
129                     result.getExceptionClassName(), 
130                     result.getExceptionStackTrace());
131             }
132         }
133 
134         return connection;
135     }
136 
137     /**
138      * Execute the test by calling the redirector.
139      *
140      * @param theRequest the request containing all data to pass to the
141      *        redirector servlet.
142      * @return the <code>HttpURLConnection</code> that contains the HTTP
143      *         response when the test was called.
144      *
145      * @exception Throwable if an error occured in the test method or in the
146      *            redirector servlet.
147      */
148     private HttpURLConnection callRunTest(WebRequest theRequest) 
149         throws Throwable
150     {
151         // Specify the service to call on the redirector side
152         theRequest.addParameter(HttpServiceDefinition.SERVICE_NAME_PARAM, 
153             ServiceEnumeration.CALL_TEST_SERVICE.toString(), 
154             WebRequest.GET_METHOD);
155 
156         // Open the first connection to the redirector to execute the test on
157         // the server side
158         HttpClientConnectionHelper helper = 
159             new HttpClientConnectionHelper(
160                 this.configuration.getRedirectorURL(theRequest));
161         
162         HttpURLConnection connection = 
163             helper.connect(theRequest, this.configuration); 
164 
165         // Wrap the connection to ensure that all servlet output is read
166         // before we ask for results
167         connection = new AutoReadHttpURLConnection(connection);
168 
169         // Trigger the transfer of data
170         connection.getInputStream();
171 
172         return connection;
173     }
174 
175     /**
176      * Get the test result from the redirector.
177      *
178      * @param theOriginalRequest the request that was used to run the test
179      * @return the result that was returned by the redirector.
180      *
181      * @exception Throwable if an error occured in the test method or in the
182      *            redirector servlet.
183      */
184     private WebTestResult callGetResult(WebRequest theOriginalRequest) 
185         throws Throwable
186     {
187         WebRequest resultsRequest = new WebRequestImpl(this.configuration);
188         RequestDirectives directives = new RequestDirectives(resultsRequest);
189         directives.setService(ServiceEnumeration.GET_RESULTS_SERVICE);
190 
191         // Use the same redirector as was used by the original request
192         resultsRequest.setRedirectorName(
193             theOriginalRequest.getRedirectorName());
194         
195         // Add authentication details
196         if (theOriginalRequest.getAuthentication() != null)
197         {
198             resultsRequest.setAuthentication(
199                 theOriginalRequest.getAuthentication());
200         }
201 
202         // Open the second connection to get the test results
203         HttpClientConnectionHelper helper = 
204             new HttpClientConnectionHelper(
205                 this.configuration.getRedirectorURL(resultsRequest));
206 
207         HttpURLConnection resultConnection = 
208             helper.connect(resultsRequest, this.configuration);
209 
210         if (resultConnection.getResponseCode() != 200)
211         {
212             throw new ParsingException("Not a valid response ["
213                 + resultConnection.getResponseCode() + " "
214                 + resultConnection.getResponseMessage() + "]");
215         }
216 
217         // Read the test result
218         WebTestResultParser parser = new WebTestResultParser();
219         return parser.parse(
220             IoUtil.getText(resultConnection.getInputStream(), "UTF-8"));
221     }
222 }