001: /*
002: * Copyright 2005-2007 Noelios Consulting.
003: *
004: * The contents of this file are subject to the terms of the Common Development
005: * and Distribution License (the "License"). You may not use this file except in
006: * compliance with the License.
007: *
008: * You can obtain a copy of the license at
009: * http://www.opensource.org/licenses/cddl1.txt See the License for the specific
010: * language governing permissions and limitations under the License.
011: *
012: * When distributing Covered Code, include this CDDL HEADER in each file and
013: * include the License file at http://www.opensource.org/licenses/cddl1.txt If
014: * applicable, add the following below this CDDL HEADER, with the fields
015: * enclosed by brackets "[]" replaced with your own identifying information:
016: * Portions Copyright [yyyy] [name of copyright owner]
017: */
018:
019: package com.noelios.restlet.ext.httpclient;
020:
021: import java.io.IOException;
022: import java.util.logging.Level;
023:
024: import org.apache.commons.httpclient.HttpClient;
025: import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
026: import org.apache.commons.httpclient.cookie.CookiePolicy;
027: import org.restlet.Client;
028: import org.restlet.data.Protocol;
029: import org.restlet.data.Request;
030:
031: import com.noelios.restlet.http.HttpClientCall;
032:
033: /**
034: * HTTP client connector using the HttpMethodCall and Apache HTTP Client
035: * project. Note that the response must be fully read in all cases in order to
036: * surely release the underlying connection. Not doing so may cause future
037: * requests to block.
038: *
039: * @see http://jakarta.apache.org/httpcomponents/httpclient-3.x/tutorial.html
040: *
041: * Here is the list of parameters that are supported: <table>
042: * <tr>
043: * <th>Parameter name</th>
044: * <th>Value type</th>
045: * <th>Default value</th>
046: * <th>Description</th>
047: * </tr>
048: * <tr>
049: * <td>followRedirects</td>
050: * <td>boolean</td>
051: * <td>false</td>
052: * <td>If true, the protocol will automatically follow redirects. If false, the
053: * protocol will not automatically follow redirects.</td>
054: * </tr>
055: * <tr>
056: * <td>maxConnectionsPerHost</td>
057: * <td>int</td>
058: * <td>2 (uses HttpClient's default)</td>
059: * <td>The maximum number of connections that will be created for any
060: * particular host.</td>
061: * </tr>
062: * <tr>
063: * <td>maxTotalConnections</td>
064: * <td>int</td>
065: * <td>20 (uses HttpClient's default)</td>
066: * <td>The maximum number of active connections.</td>
067: * </tr>
068: * <tr>
069: * <td>connectionManagerTimeout</td>
070: * <td>int</td>
071: * <td>0</td>
072: * <td>The timeout in milliseconds used when retrieving an HTTP connection from
073: * the HTTP connection manager.</td>
074: * </tr>
075: * <tr>
076: * <td>stopIdleTimeout</td>
077: * <td>int</td>
078: * <td>1000</td>
079: * <td>The minimum idle time, in milliseconds, for connections to be closed
080: * when stopping the connector.</td>
081: * </tr>
082: * <tr>
083: * <td>readTimeout</td>
084: * <td>int</td>
085: * <td>0</td>
086: * <td>Sets the read timeout to a specified timeout, in milliseconds. A timeout
087: * of zero is interpreted as an infinite timeout.</td>
088: * </tr>
089: * </table>
090: *
091: * @see <a
092: * href="http://java.sun.com/j2se/1.5.0/docs/guide/net/index.html">Networking
093: * Features</a>
094: * @author Jerome Louvel (contact@noelios.com)
095: */
096: public class HttpClientHelper extends
097: com.noelios.restlet.http.HttpClientHelper {
098: private HttpClient httpClient;
099:
100: /**
101: * Constructor.
102: *
103: * @param client
104: * The client to help.
105: */
106: public HttpClientHelper(Client client) {
107: super (client);
108: this .httpClient = null;
109: getProtocols().add(Protocol.HTTP);
110: getProtocols().add(Protocol.HTTPS);
111: }
112:
113: public HttpClient getHttpClient() {
114: return this .httpClient;
115: }
116:
117: @Override
118: public void start() throws Exception {
119: super .start();
120:
121: // Create the multi-threaded connection manager and configure it
122: MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
123: connectionManager.getParams().setDefaultMaxConnectionsPerHost(
124: getMaxConnectionsPerHost());
125: connectionManager.getParams().setMaxTotalConnections(
126: getMaxTotalConnections());
127:
128: // Create the internal client connector
129: this .httpClient = new HttpClient(connectionManager);
130: getHttpClient().getParams().setAuthenticationPreemptive(false);
131: getHttpClient().getParams().setConnectionManagerTimeout(
132: getConnectionManagerTimeout());
133: getHttpClient().getParams().setCookiePolicy(
134: CookiePolicy.IGNORE_COOKIES);
135: getHttpClient().getParams().setSoTimeout(getReadTimeout());
136: }
137:
138: @Override
139: public void stop() throws Exception {
140: getHttpClient().getHttpConnectionManager()
141: .closeIdleConnections(getStopIdleTimeout());
142: }
143:
144: /**
145: * Creates a low-level HTTP client call from a high-level uniform call.
146: *
147: * @param request
148: * The high-level request.
149: * @return A low-level HTTP client call.
150: */
151: public HttpClientCall create(Request request) {
152: HttpClientCall result = null;
153:
154: try {
155: result = new HttpMethodCall(this , request.getMethod()
156: .toString(), request.getResourceRef().toString(),
157: request.isEntityAvailable());
158: } catch (IOException ioe) {
159: getLogger().log(Level.WARNING,
160: "Unable to create the HTTP client call", ioe);
161: }
162:
163: return result;
164: }
165:
166: /**
167: * Indicates if the protocol will automatically follow redirects.
168: *
169: * @return True if the protocol will automatically follow redirects.
170: */
171: public boolean isFollowRedirects() {
172: return Boolean.parseBoolean(getParameters().getFirstValue(
173: "followRedirects", "false"));
174: }
175:
176: /**
177: * Returns the maximum number of connections that will be created for any
178: * particular host.
179: *
180: * @return The maximum number of connections that will be created for any
181: * particular host.
182: */
183: public int getMaxConnectionsPerHost() {
184: return Integer.parseInt(getParameters().getFirstValue(
185: "maxConnectionsPerHost", "2"));
186: }
187:
188: /**
189: * Returns the maximum number of active connections.
190: *
191: * @return The maximum number of active connections.
192: */
193: public int getMaxTotalConnections() {
194: return Integer.parseInt(getParameters().getFirstValue(
195: "maxTotalConnections", "20"));
196: }
197:
198: /**
199: * Returns the timeout in milliseconds used when retrieving an HTTP
200: * connection from the HTTP connection manager.
201: *
202: * @return The timeout in milliseconds used when retrieving an HTTP
203: * connection from the HTTP connection manager.
204: */
205: public int getConnectionManagerTimeout() {
206: return Integer.parseInt(getParameters().getFirstValue(
207: "connectionManagerTimeout", "0"));
208: }
209:
210: /**
211: * Returns the minimum idle time, in milliseconds, for connections to be
212: * closed when stopping the connector.
213: *
214: * @return The minimum idle time, in milliseconds, for connections to be
215: * closed when stopping the connector.
216: */
217: public int getStopIdleTimeout() {
218: return Integer.parseInt(getParameters().getFirstValue(
219: "stopIdleTimeout", "1000"));
220: }
221:
222: /**
223: * Returns the read timeout value. A timeout of zero is interpreted as an
224: * infinite timeout.
225: *
226: * @return The read timeout value.
227: */
228: public int getReadTimeout() {
229: return Integer.parseInt(getParameters().getFirstValue(
230: "readTimeout", "0"));
231: }
232:
233: }
|