View Javadoc

1   /*
2    * Copyright 2007-2012 the original author or authors.
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.springbyexample.httpclient;
18  
19  import java.util.ArrayList;
20  import java.util.List;
21  import java.util.Map;
22  
23  import org.apache.commons.httpclient.HttpClient;
24  import org.apache.commons.httpclient.HttpConnectionManager;
25  import org.apache.commons.httpclient.HttpMethod;
26  import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
27  import org.apache.commons.httpclient.NameValuePair;
28  import org.apache.commons.httpclient.UsernamePasswordCredentials;
29  import org.apache.commons.httpclient.auth.AuthScope;
30  import org.apache.commons.httpclient.methods.GetMethod;
31  import org.apache.commons.httpclient.methods.PostMethod;
32  import org.springbyexample.httpclient.auth.Credentials;
33  import org.springbyexample.httpclient.auth.NTCredentials;
34  import org.springframework.beans.factory.DisposableBean;
35  import org.springframework.beans.factory.InitializingBean;
36  import org.springframework.util.Assert;
37  
38  /**
39   * Base <code>HttpClient</code> template class.
40   * 
41   * @author David Winterfeldt
42   */
43  public abstract class AbstractHttpClientTemplate<T> implements InitializingBean, DisposableBean {
44  
45      protected HttpClient client = null;
46      protected HttpConnectionManager connectionManager = null;
47      protected String defaultUri = null;
48      protected boolean authenticationPreemptive = false;
49      protected List<Credentials> lCredentials = new ArrayList<Credentials>();
50  
51      /**
52       * Constructor.
53       */
54      public AbstractHttpClientTemplate() {}
55  
56      /**
57       * Constructor.
58       * 
59       * @param   defaultUri      Default uri.
60       */
61      public AbstractHttpClientTemplate(String defaultUri) {
62          this(defaultUri, false);
63      }
64  
65      /**
66       * Constructor.
67       * 
68       * @param   defaultUri      Default uri.
69       * @param   init            Whether or not to initialize the bean 
70       *                          (typically for programatic use).
71       */
72      public AbstractHttpClientTemplate(String defaultUri, boolean init) {
73          this.defaultUri = defaultUri;
74          
75          if (init) {
76              try {
77                  afterPropertiesSet();
78              } catch(Exception e) {
79                  throw new HttpAccessException(e.getMessage(), e);
80              }
81          }
82      }
83      
84      /**
85       * Gets http client.
86       */
87      public HttpClient getClient() {
88          return client;
89      }
90  
91      /**
92       * Sets http client.
93       */
94      public void setClient(HttpClient client) {
95          this.client = client;
96      }
97  
98      /**
99       * Gets connection manager.
100      */
101     public HttpConnectionManager getConnectionManager() {
102         return connectionManager;
103     }
104 
105     /**
106      * Sets connection manager.
107      */
108     public void setConnectionManager(HttpConnectionManager connectionManager) {
109         this.connectionManager = connectionManager;
110     }
111 
112     /**
113      * Gets default uri.
114      */
115     public String getDefaultUri() {
116         return defaultUri;
117     }
118 
119     /**
120      * Sets default uri.
121      */
122     public void setDefaultUri(String defaultUri) {
123         this.defaultUri = defaultUri;
124     }
125 
126     /**
127      * Whether or not authentication is preemptive.
128      * If <code>true</code>, authentication credentials 
129      * will be sent before a challenge is issued 
130      * for an authentication scope with credentials.
131      * Defaults to <code>false</code>.
132      */
133     public boolean isAuthenticationPreemptive() {
134         return authenticationPreemptive;
135     }
136 
137     /**
138      * Sets whether or not authentication is preemptive.
139      * If <code>true</code>, authentication credentials 
140      * will be sent before a challenge is issued 
141      * for an authentication scope with credentials.
142      * Defaults to <code>false</code>.
143      */
144     public void setAuthenticationPreemptive(boolean authenticationPreemptive) {
145         this.authenticationPreemptive = authenticationPreemptive;
146     }
147 
148     /**
149      * Gets HTTP authorization credentials.
150      */
151     public List<Credentials> getCredentials() {
152         return lCredentials;
153     }
154 
155     /**
156      * Sets HTTP authorization credentials.
157      */
158     public void setCredentials(List<Credentials> credentials) {
159         this.lCredentials = credentials;
160     }
161     
162     /**
163      * Implementation of <code>InitializingBean</code> 
164      * that initializes the <code>HttpClient</code> if it is <code>null</code> 
165      * and also sets the connection manager to <code>MultiThreadedHttpConnectionManager</code> 
166      * if it is <code>null</code> while initializing the <code>HttpClient</code>.
167      */
168     public void afterPropertiesSet() throws Exception {
169         // make sure credentials are properly set
170         for (Credentials credentials : lCredentials) {
171             Assert.notNull(credentials.getAuthScopeHost());
172             Assert.isTrue(credentials.getAuthScopePort() > 0);
173             Assert.notNull(credentials.getUserName());
174             Assert.notNull(credentials.getPassword());
175             
176             if (credentials instanceof NTCredentials) {
177                 Assert.notNull(((NTCredentials)credentials).getHost());
178                 Assert.notNull(((NTCredentials)credentials).getDomain());
179             }
180         }
181         
182         if (client == null) {
183             if (connectionManager == null) {
184                 connectionManager = new MultiThreadedHttpConnectionManager();
185             }
186 
187             client = new HttpClient(connectionManager);
188         }
189 
190         client.getParams().setAuthenticationPreemptive(authenticationPreemptive);
191         
192         for (Credentials credentials : lCredentials) {
193             AuthScope authScope = new AuthScope(credentials.getAuthScopeHost(), 
194                                                 credentials.getAuthScopePort(), 
195                                                 AuthScope.ANY_REALM);
196             
197             org.apache.commons.httpclient.Credentials httpCredentials = null;
198             
199             if (credentials instanceof NTCredentials) {
200                 httpCredentials = new org.apache.commons.httpclient.NTCredentials(
201                         credentials.getUserName(), 
202                         credentials.getPassword(),
203                         ((NTCredentials)credentials).getHost(),
204                         ((NTCredentials)credentials).getDomain());     
205             } else {
206                 httpCredentials = new UsernamePasswordCredentials(credentials.getUserName(), 
207                                                                   credentials.getPassword());
208             }
209             
210             client.getState().setCredentials(authScope, httpCredentials);
211         }
212     }
213 
214     /**
215      * Implementation of <code>DisposableBean</code> that 
216      * shuts down the connection manager if it is an instance of 
217      * <code>MultiThreadedHttpConnectionManager</code>.
218      */
219     public void destroy() throws Exception {
220         if (client.getHttpConnectionManager() instanceof MultiThreadedHttpConnectionManager) {
221             ((MultiThreadedHttpConnectionManager)client.getHttpConnectionManager()).shutdown();
222         }
223     }
224 
225     /**
226      * Execute get method.
227      */
228     public void executeGetMethod() {
229         executeGetMethod(defaultUri, null, null);
230     }
231     
232     /**
233      * Execute get method.
234      * 
235      * @param   callback        Callback with HTTP method's response.
236      */
237     public void executeGetMethod(ResponseCallback<?> callback) {
238         executeGetMethod(defaultUri, null, callback);
239     }
240 
241     /**
242      * Execute get method.
243      * 
244      * @param   hParams         Parameters for the HTTP get.
245      */
246     public void executeGetMethod(Map<String, String> hParams) {
247         executeGetMethod(defaultUri, hParams, null);
248     }
249     
250     /**
251      * Execute get method.
252      * 
253      * @param   hParams         Parameters for the HTTP get.
254      * @param   callback        Callback with HTTP method's response.
255      */
256     public void executeGetMethod(Map<String, String> hParams, ResponseCallback<?> callback) {
257         executeGetMethod(defaultUri, hParams, callback);
258     }
259     
260     /**
261      * Execute get method.
262      * 
263      * @param   uri             URI to use when processing this HTTP request instead 
264      *                          of using the default URI.
265      * @param   hParams         Parameters for the HTTP get.
266      */
267     public void executeGetMethod(String uri, Map<String, String> hParams) {
268         executeGetMethod(uri, hParams, null);
269     }
270     
271     /**
272      * Execute get method.
273      * 
274      * @param   uri             URI to use when processing this HTTP request instead 
275      *                          of using the default URI.
276      * @param   hParams         Parameters for the HTTP get.
277      * @param   callback        Callback with HTTP method's response.
278      */
279     public void executeGetMethod(String uri, Map<String, String> hParams, ResponseCallback<?> callback) {
280         GetMethod get = new GetMethod(uri);
281 
282         processHttpMethodParams(get, hParams);
283         
284         processHttpMethod(get, callback);
285     }
286 
287     /**
288      * Execute post method.
289      */
290     public void executePostMethod() {
291         executePostMethod(defaultUri, null, null, null);
292     }
293 
294     /**
295      * Execute post method.
296      * 
297      * @param   callback        Callback with HTTP method's response.
298      */
299     public void executePostMethod(ResponseCallback<?> callback) {
300         executePostMethod(defaultUri, null, null, callback);
301     }
302 
303     /**
304      * Execute post method.
305      * 
306      * @param   hParams         Parameters for the HTTP post.
307      */
308     public void executePostMethod(Map<String, String> hParams) {
309         executePostMethod(defaultUri, null, hParams, null);
310     }
311     
312     /**
313      * Execute post method.
314      * 
315      * @param   hParams         Parameters for the HTTP post.
316      * @param   callback        Callback with HTTP method's response.
317      */
318     public void executePostMethod(Map<String, String> hParams, ResponseCallback<?> callback) {
319         executePostMethod(defaultUri, null, hParams, callback);
320     }
321 
322     /**
323      * Execute post method.
324      * 
325      * @param   uri             URI to use when processing this HTTP request instead 
326      *                          of using the default URI.
327      * @param   requestPayload  Request data to post.
328      * @param   hParams         Parameters for the HTTP post.
329 
330      */
331     public void executePostMethod(String uri,
332                                   T requestPayload, Map<String, String> hParams) {
333         executePostMethod(uri, requestPayload, hParams, null);
334     }
335     
336     /**
337      * Execute post method.
338      * 
339      * @param   uri             URI to use when processing this HTTP request instead 
340      *                          of using the default URI.
341      * @param   requestPayload  Request data to post.
342      * @param   hParams         Parameters for the HTTP post.
343      * @param   callback        Callback with HTTP method's response.
344 
345      */
346     public abstract void executePostMethod(String uri,
347                                            T requestPayload, Map<String, String> hParams,
348                                            ResponseCallback<?> callback);
349     
350     /**
351      * Processes <code>HttpMethod</code> by executing the method, 
352      * validating the response, and calling the callback.
353      * 
354      * @param   httpMethod      <code>HttpMethod</code> to process.
355      * @param   callback        Callback with HTTP method's response.
356      */
357     protected abstract void processHttpMethod(HttpMethod httpMethod, ResponseCallback<?> callback);
358 
359     /**
360      * Processes <code>HttpMethod</code> parameters.
361      * 
362      * @param   httpMethod      <code>HttpMethod</code> to process.
363      * @param   hParams         Parameters for the HTTP get.
364      */
365     protected void processHttpMethodParams(HttpMethod httpMethod, Map<String, String> hParams) {
366         if (hParams != null) {
367             List<NameValuePair> lParams = new ArrayList<NameValuePair>();
368             
369             for (Object key : hParams.keySet()) {
370                 Object value = hParams.get(key);
371                 
372                 lParams.add(new NameValuePair(key.toString(), value.toString()));
373             }
374 
375             if (httpMethod instanceof GetMethod) {
376                 ((GetMethod)httpMethod).setQueryString(lParams.toArray(new NameValuePair[] {}));
377             } else if (httpMethod instanceof PostMethod) {
378                 ((PostMethod)httpMethod).setRequestBody(lParams.toArray(new NameValuePair[] {}));
379             }
380         }
381     }
382 
383     /**
384      * Validate response.
385      * 
386      * @param   httpMethod      <code>HttpMethod</code> to validate.
387      */
388     protected void validateResponse(HttpMethod httpMethod) {
389         if (httpMethod.getStatusCode() >= 300) {
390             throw new HttpAccessException(
391                     "Did not receive successful HTTP response: status code = " + 
392                     httpMethod.getStatusCode() + 
393                     ", status message = [" + httpMethod.getStatusText() + "]", httpMethod.getStatusCode());
394         }
395     }
396     
397 }