View Javadoc

1   /*
2    * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/HttpClient.java,v 1.95 2004/05/13 04:03:25 mbecke Exp $
3    * $Revision: 1.95 $
4    * $Date: 2004/05/13 04:03:25 $
5    *
6    * ====================================================================
7    *
8    *  Copyright 1999-2004 The Apache Software Foundation
9    *
10   *  Licensed under the Apache License, Version 2.0 (the "License");
11   *  you may not use this file except in compliance with the License.
12   *  You may obtain a copy of the License at
13   *
14   *      http://www.apache.org/licenses/LICENSE-2.0
15   *
16   *  Unless required by applicable law or agreed to in writing, software
17   *  distributed under the License is distributed on an "AS IS" BASIS,
18   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19   *  See the License for the specific language governing permissions and
20   *  limitations under the License.
21   * ====================================================================
22   *
23   * This software consists of voluntary contributions made by many
24   * individuals on behalf of the Apache Software Foundation.  For more
25   * information on the Apache Software Foundation, please see
26   * <http://www.apache.org/>.
27   *
28   */
29  
30  package org.apache.commons.httpclient;
31  
32  import java.io.IOException;
33  import java.security.Provider;
34  import java.security.Security;
35  
36  import org.apache.commons.httpclient.params.HttpClientParams;
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  
40  /***
41   * <p>
42   * An HTTP "user-agent", containing an {@link HttpState HTTP state} and
43   * one or more {@link HttpConnection HTTP connections}, to which
44   * {@link HttpMethod HTTP methods} can be applied.
45   * </p>
46   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
47   * @author <a href="mailto:rwaldhoff@apache.org">Rodney Waldhoff</a>
48   * @author Sean C. Sullivan
49   * @author <a href="mailto:dion@apache.org">dIon Gillard</a>
50   * @author Ortwin Gl?ck
51   * @author <a href="mailto:becke@u.washington.edu">Michael Becke</a>
52   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
53   * @author Sam Maloney
54   * @author Laura Werner
55   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
56   * 
57   * @version $Revision: 1.95 $ $Date: 2004/05/13 04:03:25 $
58   */
59  public class HttpClient {
60  
61  
62      // -------------------------------------------------------------- Constants
63  
64      /*** Log object for this class. */
65      private static final Log LOG = LogFactory.getLog(HttpClient.class);
66  
67      static {
68          
69          if (LOG.isDebugEnabled()) {
70              try {
71                  LOG.debug("Java version: " + System.getProperty("java.version"));
72                  LOG.debug("Java vendor: " + System.getProperty("java.vendor"));
73                  LOG.debug("Java class path: " + System.getProperty("java.class.path"));
74                  LOG.debug("Operating system name: " + System.getProperty("os.name"));
75                  LOG.debug("Operating system architecture: " + System.getProperty("os.arch"));
76                  LOG.debug("Operating system version: " + System.getProperty("os.version"));
77  
78                  Provider[] providers = Security.getProviders();
79                  for (int i = 0; i < providers.length; i++) {
80                      Provider provider = providers[i];
81                      LOG.debug(provider.getName() + " " + provider.getVersion()
82                         + ": " + provider.getInfo());   
83                  }
84              } catch (SecurityException ignore) {
85              }
86          }
87      }
88      // ----------------------------------------------------------- Constructors
89  
90      /***
91       * Creates an instance of HttpClient using default {@link HttpClientParams parameter set}.
92       * 
93       * @see HttpClientParams
94       */
95      public HttpClient() {
96          this(new HttpClientParams());
97      }
98  
99      /***
100      * Creates an instance of HttpClient using the given 
101      * {@link HttpClientParams parameter set}.
102      * 
103      * @param params The {@link HttpClientParams parameters} to use.
104      * 
105      * @see HttpClientParams
106      * 
107      * @since 3.0
108      */
109     public HttpClient(HttpClientParams params) {
110         super();
111         if (params == null) {
112             throw new IllegalArgumentException("Params may not be null");  
113         }
114         this.params = params;
115         this.httpConnectionManager = null;
116         Class clazz = params.getConnectionManagerClass();
117         if (clazz != null) {
118             try {
119                 this.httpConnectionManager = (HttpConnectionManager) clazz.newInstance();
120             } catch (Exception e) {
121                 LOG.warn("Error instantiating connection manager class, defaulting to"
122                     + " SimpleHttpConnectionManager", 
123                     e);
124             }
125         }
126         if (this.httpConnectionManager == null) {
127             this.httpConnectionManager = new SimpleHttpConnectionManager();
128         }
129         if (this.httpConnectionManager != null) {
130             this.httpConnectionManager.getParams().setDefaults(this.params);
131         }
132     }
133 
134     /***
135      * Creates an instance of HttpClient with a user specified 
136      * {@link HttpClientParams parameter set} and 
137      * {@link HttpConnectionManager HTTP connection manager}.
138      * 
139      * @param params The {@link HttpClientParams parameters} to use.
140      * @param httpConnectionManager The {@link HttpConnectionManager connection manager}
141      * to use.
142      * 
143      * @since 3.0
144      */
145     public HttpClient(HttpClientParams params, HttpConnectionManager httpConnectionManager) {
146         super();
147         if (httpConnectionManager == null) {
148             throw new IllegalArgumentException("httpConnectionManager cannot be null");  
149         }
150         if (params == null) {
151             throw new IllegalArgumentException("Params may not be null");  
152         }
153         this.params = params; 
154         this.httpConnectionManager = httpConnectionManager;
155         if (this.httpConnectionManager != null) {
156             this.httpConnectionManager.getParams().setDefaults(this.params);
157         }
158     }
159     
160     /***
161      * Creates an instance of HttpClient with a user specified 
162      * {@link HttpConnectionManager HTTP connection manager}.
163      * 
164      * @param httpConnectionManager The {@link HttpConnectionManager connection manager}
165      * to use.
166      * 
167      * @since 2.0
168      */
169     public HttpClient(HttpConnectionManager httpConnectionManager) {
170         this(new HttpClientParams(), httpConnectionManager);
171     }
172     
173     // ----------------------------------------------------- Instance Variables
174 
175     /*** 
176      * The {@link HttpConnectionManager connection manager} being used to manage
177      * connections for this HttpClient
178      */
179     private HttpConnectionManager httpConnectionManager;
180 
181     /***
182      * The {@link HttpState HTTP state} associated with this HttpClient.
183      */
184     private HttpState state = new HttpState();
185     
186     /***
187      * The {@link HttpClientParams collection of parameters} associated with this HttpClient.
188      */
189     private HttpClientParams params = null; 
190 
191     /*** 
192      * The {@link HostConfiguration host configuration} associated with
193      * the HttpClient
194      */
195     private HostConfiguration hostConfiguration = new HostConfiguration();
196     
197     // ------------------------------------------------------------- Properties
198 
199     /***
200      * Returns {@link HttpState HTTP state} associated with the HttpClient.
201      *
202      * @see #setState(HttpState)
203      * @return the shared client state
204      */
205     public synchronized HttpState getState() {
206         return state;
207     }
208 
209     /***
210      * Assigns {@link HttpState HTTP state} for the HttpClient.
211      *
212      * @see #getState()
213      * @param state the new {@link HttpState HTTP state} for the client
214      */
215     public synchronized void setState(HttpState state) {
216         this.state = state;
217     }
218 
219     /***
220      * Defines how strictly the method follows the HTTP protocol specification  
221      * (see RFC 2616 and other relevant RFCs). 
222      * 
223      * In the strict mode the method precisely
224      * implements the requirements of the specification, whereas in non-strict mode 
225      * it attempts to mimic the exact behaviour of commonly used HTTP agents, 
226      * which many HTTP servers expect.
227      * 
228      * @param strictMode <tt>true</tt> for strict mode, <tt>false</tt> otherwise
229      *
230      * @see #isStrictMode()
231      *
232      * @deprecated Use {@link HttpClientParams#setParameter(String, Object)}
233      * to exercise a more granular control over HTTP protocol strictness.
234      */
235     public synchronized void setStrictMode(boolean strictMode) {
236         if (strictMode) {
237             this.params.makeStrict();
238         } else {
239             this.params.makeLenient();
240         }
241     }
242 
243     /***
244      * Returns the value of the strict mode flag.
245      * 
246      * @return <tt>true</tt> if strict mode is enabled, <tt>false</tt> otherwise
247      *
248      * @see #setStrictMode(boolean)
249      *
250      * @deprecated Use 
251      * {@link org.apache.commons.httpclient.params.HttpClientParams#getParameter(String)} 
252      * to exercise a more granular control over HTTP protocol strictness.
253      */
254     public synchronized boolean isStrictMode() {
255         return false;
256     }
257 
258     /***
259      * Sets the socket timeout (<tt>SO_TIMEOUT</tt>) in milliseconds which is the 
260      * timeout for waiting for data. A timeout value of zero is interpreted as an 
261      * infinite timeout.
262      *
263      * @param newTimeoutInMilliseconds Timeout in milliseconds
264      * 
265      * @deprecated Use 
266      * {@link org.apache.commons.httpclient.params.HttpConnectionManagerParams#setSoTimeout(int)},
267      * {@link HttpConnectionManager#getParams()}.
268      *
269      */
270     public synchronized void setTimeout(int newTimeoutInMilliseconds) {
271         this.httpConnectionManager.getParams().setSoTimeout(newTimeoutInMilliseconds);
272     }
273 
274     /***
275      * Sets the timeout in milliseconds used when retrieving an 
276      * {@link HttpConnection HTTP connection} from the
277      * {@link HttpConnectionManager HTTP connection manager}.
278      * 
279      * @param timeout the timeout in milliseconds
280      * 
281      * @see HttpConnectionManager#getConnection(HostConfiguration, long)
282      * 
283      * @deprecated Use 
284      * {@link org.apache.commons.httpclient.params.HttpClientParams#setConnectionManagerTimeout(long)},
285      * {@link HttpClient#getParams()}
286      */
287     public synchronized void setHttpConnectionFactoryTimeout(long timeout) {
288         this.params.setConnectionManagerTimeout(timeout);
289     }
290 
291     /***
292      * Sets the timeout until a connection is etablished. A value of zero 
293      * means the timeout is not used. The default value is zero.
294      * 
295      * @see HttpConnection#setConnectionTimeout(int)
296      * @param newTimeoutInMilliseconds Timeout in milliseconds.
297      * 
298      * @deprecated Use 
299      * {@link org.apache.commons.httpclient.params.HttpConnectionManagerParams#setConnectionTimeout(int)},
300      * {@link HttpConnectionManager#getParams()}.
301      */
302     public synchronized void setConnectionTimeout(int newTimeoutInMilliseconds) {
303        this.httpConnectionManager.getParams().setConnectionTimeout(newTimeoutInMilliseconds);
304     }
305 
306     // --------------------------------------------------------- Public Methods
307 
308    /***
309      * Executes the given {@link HttpMethod HTTP method}.
310      *
311      * @param method the {@link HttpMethod HTTP method} to execute.
312      * @return the method's response code
313      *
314      * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
315      *                     can be recovered from.      
316      * @throws HttpException  If a protocol exception occurs. Usually protocol exceptions 
317      *                    cannot be recovered from.
318      */
319     public int executeMethod(HttpMethod method)
320         throws IOException, HttpException  {
321             
322         LOG.trace("enter HttpClient.executeMethod(HttpMethod)");
323         // execute this method and use its host configuration, if it has one
324         return executeMethod(
325             method.getHostConfiguration() != null 
326             ? method.getHostConfiguration()
327             : getHostConfiguration(), 
328             method,
329             null
330         );
331         
332     }
333 
334     /***
335     * Executes the given {@link HttpMethod HTTP method} using custom 
336     * {@link HostConfiguration host configuration}.
337     *
338     * @param hostConfiguration The {@link HostConfiguration host configuration} to use.
339     * @param method the {@link HttpMethod HTTP method} to execute.
340     * @return the method's response code
341     *
342     * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
343     *                     can be recovered from.
344     * @throws HttpException  If a protocol exception occurs. Usually protocol exceptions 
345     *                    cannot be recovered from.
346     * @since 2.0
347     */
348     public int executeMethod(HostConfiguration hostConfiguration, HttpMethod method)
349         throws IOException, HttpException {
350     
351         LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod)");
352     
353         return executeMethod(hostConfiguration, method, null); 
354     }
355     
356 
357     
358     /***
359      * Executes the given {@link HttpMethod HTTP method} using the given custom 
360      * {@link HostConfiguration host configuration} with the given custom 
361      * {@link HttpState HTTP state}.
362      *
363      * @param hostConfiguration The {@link HostConfiguration host configuration} to use.
364      * @param method the {@link HttpMethod HTTP method} to execute.
365      * @param state the {@link HttpState HTTP state} to use when executing the method.
366      * If <code>null</code>, the state returned by {@link #getState} will be used instead.
367      *
368      * @return the method's response code
369      *
370      * @throws IOException If an I/O (transport) error occurs. Some transport exceptions
371      *                     can be recovered from.
372      * @throws HttpException  If a protocol exception occurs. Usually protocol exceptions 
373      *                    cannot be recovered from.
374      * @since 2.0
375      */
376     public int executeMethod(HostConfiguration hostConfiguration, 
377         HttpMethod method, HttpState state)
378         throws IOException, HttpException  {
379             
380         LOG.trace("enter HttpClient.executeMethod(HostConfiguration,HttpMethod,HttpState)");
381 
382         if (method == null) {
383             throw new IllegalArgumentException("HttpMethod parameter may not be null");
384         }
385 
386         if (hostConfiguration == null) {
387             hostConfiguration = (
388                 method.getHostConfiguration() != null 
389                 ? method.getHostConfiguration()
390                 : getHostConfiguration()
391             );
392         }
393 
394         HostConfiguration defaultHostConfiguration = null;
395         synchronized (this) {
396             defaultHostConfiguration = getHostConfiguration();
397         }
398         HostConfiguration methodConfiguration = new HostConfiguration(hostConfiguration);
399         if (hostConfiguration != defaultHostConfiguration) {
400             // we may need to apply some defaults
401             if (!methodConfiguration.isHostSet()) {
402                 methodConfiguration.setHost(
403                     defaultHostConfiguration.getHost(),
404                     defaultHostConfiguration.getVirtualHost(),
405                     defaultHostConfiguration.getPort(),
406                     defaultHostConfiguration.getProtocol()
407                 );
408             }
409             if (!methodConfiguration.isProxySet() 
410                 && defaultHostConfiguration.isProxySet()) {
411                     
412                 methodConfiguration.setProxy(
413                     defaultHostConfiguration.getProxyHost(),
414                     defaultHostConfiguration.getProxyPort() 
415                 );   
416             }
417             if (methodConfiguration.getLocalAddress() == null
418                 && defaultHostConfiguration.getLocalAddress() != null) {
419                     
420                 methodConfiguration.setLocalAddress(defaultHostConfiguration.getLocalAddress());
421             }
422         }
423         
424         /* access all synchronized data in a single block, this will keeps us
425          * from accessing data asynchronously as well having to regain the lock
426          * for each item.
427          */
428         HttpMethodDirector methodDirector = null;
429         synchronized (this) {
430             methodDirector = new HttpMethodDirector(
431                 this.httpConnectionManager,
432                 methodConfiguration,
433                 this.params,
434                 (state == null ? getState() : state));
435             defaultHostConfiguration = getHostConfiguration();
436         }
437         methodDirector.executeMethod(method);
438         return method.getStatusCode();
439     }
440 
441     /***
442       * Returns the default host. 
443       *
444       * @return The default host.
445       * 
446       * @deprecated use #getHostConfiguration()
447       */
448      public String getHost() {
449          return hostConfiguration.getHost();
450      }
451 
452      /***
453       * Returns the default port.
454       *
455       * @return The default port.
456       * 
457       * @deprecated use #getHostConfiguration()
458       */
459      public int getPort() {
460          return hostConfiguration.getPort();
461      }
462      
463     /***
464      * Returns the {@link HostConfiguration host configuration} associated with the 
465      * HttpClient.
466      * 
467      * @return {@link HostConfiguration host configuration}
468      * 
469      * @since 2.0
470      */
471     public synchronized HostConfiguration getHostConfiguration() {
472         return hostConfiguration;
473     }
474 
475     /***
476      * Assigns the {@link HostConfiguration host configuration} to use with the
477      * HttpClient.
478      * 
479      * @param hostConfiguration The {@link HostConfiguration host configuration} to set
480      * 
481      * @since 2.0
482      */
483     public synchronized void setHostConfiguration(HostConfiguration hostConfiguration) {
484         this.hostConfiguration = hostConfiguration;
485     }
486 
487     /***
488      * Returns the {@link HttpConnectionManager HTTP connection manager} associated 
489      * with the HttpClient.
490      * 
491      * @return {@link HttpConnectionManager HTTP connection manager}
492      * 
493      * @since 2.0
494      */
495     public synchronized HttpConnectionManager getHttpConnectionManager() {
496         return httpConnectionManager;
497     }
498 
499     /***
500      * Assigns the {@link HttpConnectionManager HTTP connection manager} to use with
501      * the HttpClient.
502      * 
503      * @param httpConnectionManager The {@link HttpConnectionManager HTTP connection manager}
504      *  to set
505      * 
506      * @since 2.0
507      */
508     public synchronized void setHttpConnectionManager(
509         HttpConnectionManager httpConnectionManager
510     ) {
511         this.httpConnectionManager = httpConnectionManager;
512         if (this.httpConnectionManager != null) {
513             this.httpConnectionManager.getParams().setDefaults(this.params);
514         }
515     }
516 
517     /***
518      * Returns {@link HttpClientParams HTTP protocol parameters} associated with this HttpClient.
519      * 
520      * @since 3.0
521      * 
522      * @see HttpClientParams
523      */
524     public HttpClientParams getParams() {
525         return this.params;
526     }
527 
528     /***
529      * Assigns {@link HttpClientParams HTTP protocol parameters} for this HttpClient.
530      * 
531      * @since 3.0
532      * 
533      * @see HttpClientParams
534      */
535     public void setParams(final HttpClientParams params) {
536         if (params == null) {
537             throw new IllegalArgumentException("Parameters may not be null");
538         }
539         this.params = params;
540     }
541 
542 }