KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > latka > http > RequestImpl


1 /*
2  * Copyright 1999-2002,2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.commons.latka.http;
18 // java imports
19
import java.net.URL JavaDoc;
20 import java.io.ByteArrayInputStream JavaDoc;
21 import java.io.InputStream JavaDoc;
22 import java.io.IOException JavaDoc;
23 import java.util.List JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 // latka imports
26
import org.apache.commons.httpclient.HostConfiguration;
27 import org.apache.commons.httpclient.UsernamePasswordCredentials;
28 import org.apache.commons.httpclient.HttpClient;
29 import org.apache.commons.httpclient.HttpException;
30 import org.apache.commons.httpclient.HttpMethod;
31 import org.apache.commons.httpclient.HttpState;
32 import org.apache.commons.httpclient.HttpMethodBase;
33 import org.apache.commons.httpclient.methods.PostMethod;
34 // log4j imports
35
import org.apache.log4j.Category;
36
37 /**
38  * An implementation of a Latka Request interface based on the Jakarta Commons
39  * HttpClient package.
40  *
41  * @todo pass proxy host and port to httpclient
42  * @author <a HREF="mailto:dsale@us.britannica.com">Doug Sale</a>
43  * @author <a HREF="mailto:mdelagra@us.britannica.com">Morgan Delagrange</a>
44  * @author dIon Gillard
45  * @version $Id: RequestImpl.java 155424 2005-02-26 13:09:29Z dirkv $
46  * @see Request
47  */

48 public class RequestImpl implements Request {
49     
50     /** Standard HTTP Port */
51     public static final int HTTP_PORT = 80;
52     
53     /** Standard HTTPS Port */
54     public static final int HTTPS_PORT = 443;
55     /** host the request is being made on */
56     protected String JavaDoc _host = null;
57     /** port the request is being made on */
58     protected int _port = -1;
59     /** http method being used to make the request */
60     protected int _method = -1;
61     /** http session the request is part of */
62     protected SessionImpl _session = null;
63     /** credentials for the request */
64     protected Credentials _credentials = null;
65     /** http method implementation */
66     protected HttpMethod _httpMethod = null;
67     /** URL being requested */
68     protected URL JavaDoc _targetURL = null;
69     /** query string portion of the URL */
70     protected String JavaDoc _query = null;
71     /** time taken for the request in milliseconds */
72     protected long _requestTiming = -1;
73     /** name given to the request */
74     protected String JavaDoc _label = null;
75     /** headers sent with this request */
76     protected RequestHeaders _requestHeaders = new RequestHeadersImpl();
77     /** parameters sent with this request */
78     protected Parameters _parameters = new ParametersImpl();
79     /** manually constructed post body */
80     protected String JavaDoc _requestBody = null;
81     /** whether or not redirect responses should be followed as part of the
82         request processing*/

83     protected boolean _followRedirects = true;
84     /** object used to perform the http requests */
85     protected HttpClient _httpClient = new HttpClient();
86     /** proxy used to perform the requests */
87     private Proxy _proxy = null;
88     /** log4j category used when logging messages */
89     protected static final Category _log =
90         Category.getInstance(RequestImpl.class);
91
92     /**
93      * HTTP Version 1.0
94      */

95     private static final String JavaDoc HTTP_10 = "1.0";
96     /**
97      * HTTP Version 1.1
98      */

99     private static final String JavaDoc HTTP_11 = "1.1";
100
101     protected String JavaDoc _httpVersion = HTTP_11;
102
103     protected List JavaDoc _visitedURLs = new LinkedList JavaDoc();
104
105     /**
106      * Create a request for the specified URL, process using the supplied method
107      * and use the supplied state and session for persistent data
108      * @param url the URL to send the request to
109      * @param httpMethod the http method to use in sending the request, as
110      * defined in {@link Request}
111      * @param state shared information across requests
112      * @param session state shared across servers and requests
113      */

114     protected RequestImpl(URL JavaDoc url, int httpMethod, HttpState state,
115         SessionImpl session) {
116         this(null, url, httpMethod, state, session, true);
117     }
118     
119     /**
120      * Create a RequestImpl
121      *
122      * @param label a name for the request
123      * @param url the url that this request embodies
124      * @param httpMethod the method by which this request should be executed
125      * @param state shared information across requests
126      * @param session the session that the request should be executed in
127      * @param followRedirects whether http redirect responses should be honoured
128      */

129     protected RequestImpl(String JavaDoc label, URL JavaDoc url, int httpMethod,
130         HttpState state, SessionImpl session, boolean followRedirects) {
131             
132         _followRedirects = followRedirects;
133         _method = httpMethod;
134         _httpClient.setState(state);
135         
136         _label = label;
137         _query = url.getQuery();
138         
139         _session = session;
140         _targetURL = url;
141         _httpMethod = MethodFactory.getInstance(httpMethod, url);
142         if (_query != null) {
143             _httpMethod.setQueryString(_query);
144         }
145         _httpMethod.setFollowRedirects(followRedirects);
146     }
147     
148     /**
149      * Returns the object implementing the HttpMethod
150      * (get, post, etc.) for this request.
151      *
152      * @return the underlying HttpMethod object representing the request/
153      * response pair.
154      */

155     protected HttpMethod getHttpMethod() {
156         return _httpMethod;
157     }
158     
159     /**
160      * Defined in the implemented interface
161      * @return the headers used for this request
162      * @see Request#getHeaders()
163      */

164     public RequestHeaders getHeaders() {
165         return _requestHeaders;
166     }
167     
168     /**
169      * Defined in the implemented interface
170      * @param requestHeaders new value for the headers property
171      * @see Request#setHeaders(RequestHeaders)
172      */

173     public void setHeaders(RequestHeaders requestHeaders) {
174         _requestHeaders = requestHeaders;
175     }
176     
177     /**
178      * Defined in the implemented interface
179      * @return the parameters property
180      * @see Request#getParameters()
181      */

182     public Parameters getParameters() {
183         return _parameters;
184     }
185
186     /**
187      * Defined in the implemented interface
188      * @see Request#setRequestBody(String)
189      */

190     public void setRequestBody(String JavaDoc body) {
191         _requestBody = body;
192     }
193     
194     /**
195      * Defined in the implemented interface
196      * @param parameters new value for parameters property
197      * @see Request#setParameters(Parameters)
198      */

199     public void setParameters(Parameters parameters) {
200         _parameters = parameters;
201     }
202     
203     /**
204      * Defined in the implemented interface
205      * @param credentials username and password to use
206      * @see Request#setCredentials(Credentials)
207      */

208     public void setCredentials(Credentials credentials) {
209         // null implies that this credential is the default (vs. specifying a
210
// realm)
211
UsernamePasswordCredentials creds = new UsernamePasswordCredentials(
212             credentials.getUserName(), credentials.getPassword());
213         _session._state.setCredentials(null, creds);
214         _credentials = credentials;
215     }
216
217     public Credentials getCredentials() {
218         return _credentials;
219     }
220     
221     /**
222      * Execute the request - perform the http interaction.
223      * Since HttpClient doesn't follow off-server
224      * redirects, execute() may have to construct further
225      * requests that call this method.
226      *
227      * @return a {@link Response} detailing the html etc
228      * @exception IOException
229      * when there are problems reading and writing
230      * @see Request#execute()
231      */

232     protected Response executeRequestPerHost() throws IOException JavaDoc {
233         
234         // set the request headers in HTTPClient
235
List JavaDoc headers = _requestHeaders.getHeaders();
236         for (int i = 0; i < headers.size(); ++i) {
237             String JavaDoc[] header = (String JavaDoc[]) headers.get(i);
238             _httpMethod.addRequestHeader(header[0], header[1]);
239         }
240         
241         if (_requestBody != null) {
242             InputStream JavaDoc is = new ByteArrayInputStream JavaDoc(
243                 _requestBody.getBytes("ISO-8859-1"));
244             ((PostMethod) _httpMethod).setRequestBody(is);
245         } else {
246             List JavaDoc parameters = _parameters.getParameters();
247             for (int i = 0; i < parameters.size(); ++i) {
248                 String JavaDoc[] parameter = (String JavaDoc[]) parameters.get(i);
249                 addHttpClientParameter(parameter[0], parameter[1]);
250             }
251         }
252         
253         // for timing
254
long startDate = System.currentTimeMillis();
255         
256         Response response = null;
257         try {
258             // open the connection
259
openConnection();
260             
261             _log.debug("executing request");
262             
263             _httpClient.executeMethod(_httpMethod);
264             
265             _log.debug("request executed");
266             
267             response = new ResponseImpl(this);
268
269             // Cache the response body to allow it to be accessed
270
// after the http connection is closed.
271
String JavaDoc sideEffectOnly = response.getResource();
272             
273             // set the referer
274
// note: If followRedirects
275
// is enabled, HTTPClient may return a path
276
// that is different from the initial request.
277
// HTTPClient will not follow redirects to another
278
// host, port, or protocol; in that event, it will always
279
// return a 301 or 302.
280
_session.setReferer(new URL JavaDoc(_targetURL.getProtocol(), _host, _port,
281                 _httpMethod.getPath()));
282             
283         } catch (HttpException e) {
284             throw new IOException JavaDoc(e.toString());
285         } catch (IOException JavaDoc e) {
286             // rethrow it after closing the connection
287
throw e;
288         } finally {
289             try {
290                 closeConnection();
291                 // FIXME: Shouldn't use Exception here.
292
} catch (Exception JavaDoc e) {
293                 e.printStackTrace();
294             }
295         }
296         
297         
298         _requestTiming = System.currentTimeMillis() - startDate;
299         
300         if (_log.isInfoEnabled()) {
301             _log.info("response obtained (response logging disabled because "
302                 + "some responses are binary)");
303         }
304         
305         return response;
306     }
307     
308     /**
309      * Executes the request. In the event of a 301 or 302,
310      * this method may need to create a new Request,
311      * due to an idiosyncracy of
312      * HttpClient. In that case, the Response.getRequest()
313      * method will return the actual Request that was executed.
314      */

315     public Response execute() throws IOException JavaDoc {
316         Response response = executeRequestPerHost();
317
318         if (followRedirects() == false) {
319             return response;
320         }
321
322         Request lastRequest = this;
323         // execute the request until either we get a non-redirect response, or
324
// we visit a URL we have already visited
325
while (response.getStatusCode() == 301 || response.getStatusCode() == 302) {
326             // follow the redirect
327
URL JavaDoc url = new URL JavaDoc(response.getHeader("location"));
328
329             if (_visitedURLs.contains(url.toString())) {
330                 return response;
331             }
332
333             Request request = _session.createRequest(lastRequest.getLabel(), url,
334                 lastRequest.getMethod(), lastRequest.getVersion(), true, getProxy());
335             request.setParameters(lastRequest.getParameters());
336             request.setHeaders(lastRequest.getHeaders());
337             Credentials credentials = lastRequest.getCredentials();
338             if (credentials != null) {
339                 request.setCredentials(credentials);
340             }
341             response = request.execute();
342             _visitedURLs.add(url.toString());
343             lastRequest = request;
344         }
345
346         return response;
347     }
348
349     /**
350      * Get the URL used for the request
351      * @return the {@link URL} of the request
352      * @see Request#getURL
353      */

354     public URL JavaDoc getURL() {
355         return _targetURL;
356     }
357     
358     /**
359      * Get the label used for the request
360      * @return the label used to create the request
361      * @see Request#getLabel
362      */

363     public String JavaDoc getLabel() {
364         return _label;
365     }
366     
367     /**
368      * Add a parameter (name and value) to the request
369      * @param name the name of the parameter to be added
370      * @param value the value of the parameter to be added
371      * @see Request#addParameter(String,String)
372      */

373     public void addParameter(String JavaDoc name, String JavaDoc value) {
374         _parameters.addParameter(name, value);
375     }
376     
377     /**
378      * Associate a parameter with this request.
379      *
380      * @param name the lvalue of the parameter - must not be null
381      * @param value the rvalue of the parameter - must not be null
382      */

383     protected void addHttpClientParameter(String JavaDoc name, String JavaDoc value) {
384         if (name == null) {
385             throw new NullPointerException JavaDoc("name parameter is null");
386         }
387         
388         if (value == null) {
389             throw new NullPointerException JavaDoc("value parameter is null");
390         }
391         _log.info("adding parameter, name: " + name + ", value: " + value);
392         
393         if (_httpMethod instanceof PostMethod) {
394             // addParameter adds to POST Entity, not URL
395
((PostMethod) _httpMethod).addParameter(name, value);
396         } else {
397             StringBuffer JavaDoc query = new StringBuffer JavaDoc();
398
399             // setParameter adds to URL as query string
400
if (_query == null || _query.equals("")) {
401                 query.append(name);
402                 query.append("=");
403                 query.append(value);
404             } else {
405                 query.append(_query);
406                 query.append("&");
407                 query.append(name);
408                 query.append("=");
409                 query.append(value);
410             }
411             _query = query.toString();
412             ((HttpMethod) _httpMethod).setQueryString(_query);
413         }
414     }
415     
416     /**
417      * Set a header in the request
418      *
419      * @param headerName name of any HTTP request header
420      * @param headerValue value of that header
421      */

422     public void addHeader(String JavaDoc headerName, String JavaDoc headerValue) {
423         _requestHeaders.addHeader(headerName, headerValue);
424     }
425     
426     /**
427      * Retrieve the session associated with this request.
428      *
429      * @return a <code>Session</code> object
430      */

431     public Session getSession() {
432         return _session;
433     }
434     
435     /**
436      * @return the time it took to execute this request in milliseconds
437      * or -1 if the request has not yet been executed
438      */

439     public int getRequestTiming() {
440         return (int) _requestTiming;
441     }
442     
443     /**
444      * opens an HTTP connection. This method is called
445      * before executing the method.
446      *
447      * @exception IOException
448      * if the server could not be contacted
449      */

450     protected void openConnection() throws IOException JavaDoc {
451         _log.debug("Opening connection");
452         
453         URL JavaDoc url = getURL();
454         String JavaDoc protocol = url.getProtocol();
455         String JavaDoc host = url.getHost();
456         int port = url.getPort();
457         
458         // explicitly set port if not in url,
459
// just for storing away and comparison
460
if (port == -1) {
461             if (protocol.equals("http")) {
462                 port = HTTP_PORT;
463             } else if (protocol.equals("https")) {
464                 port = HTTPS_PORT;
465             } else {
466                 throw new IllegalArgumentException JavaDoc("Unsupported Protocol");
467             }
468         }
469         
470         // save session values
471
_host = host;
472         _port = port;
473         
474         HostConfiguration hostConfiguration = _httpClient.getHostConfiguration();
475         hostConfiguration.setHost(host, port, protocol);
476         if (getProxy() != null) {
477             hostConfiguration.setProxy(getProxy().getHost(), getProxy().getPort());
478         }
479         
480         _log.debug("connection open");
481     }
482     
483     /**
484      * Closes the http connection associated with the request
485      * @throws IOException if there are problems closing the connection
486      */

487     protected void closeConnection() throws IOException JavaDoc {
488         _log.debug("closing connection");
489         _httpMethod.releaseConnection();
490         _log.debug("connection closed");
491     }
492     
493     /**
494      * Defined in the interface
495      * @return whether the request will honour http redirect status codes
496      * @see Request#followRedirects()
497      */

498     public boolean followRedirects() {
499         return _followRedirects;
500     }
501     
502     /**
503      * Defined in the interface
504      * @return the http method being used for the request, as defined in the
505      * interface
506      * @see Request#getMethod
507      */

508     public int getMethod() {
509         return _method;
510     }
511     
512     /** Getter for property proxy.
513      * @return Value of property proxy.
514      */

515     public Proxy getProxy() {
516         return _proxy;
517     }
518     
519     /** Setter for property proxy.
520      * @param proxy New value of property proxy.
521      */

522     public void setProxy(Proxy proxy) {
523         _proxy = proxy;
524     }
525     
526     /**
527      * Sets the HTTP version for this request. If
528      * the version provided is not 1.0 or 1.1, then
529      * 1.1 will be used.
530      *
531      * @param version HTTP version
532      */

533     public void setVersion(String JavaDoc version) {
534         ((HttpMethodBase) _httpMethod).setHttp11(!HTTP_10.equals(version));
535         _httpVersion = version;
536     }
537
538     /**
539      * Get the HTTP version to use in this request.
540      *
541      * @return HTTP version for the request
542      */

543     public String JavaDoc getVersion() {
544         return _httpVersion;
545     }
546 }
547
Popular Tags