1b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/*
2b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Copyright 2008 Sean Sullivan
3b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
4b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Licensed under the Apache License, Version 2.0 (the "License");
5b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * you may not use this file except in compliance with the License.
6b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * You may obtain a copy of the License at
7b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
8b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *     http://www.apache.org/licenses/LICENSE-2.0
9b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
10b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Unless required by applicable law or agreed to in writing, software
11b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * distributed under the License is distributed on an "AS IS" BASIS,
12b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * See the License for the specific language governing permissions and
14b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * limitations under the License.
15b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */
16b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
17b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpackage net.oauth.client.httpclient4;
18b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
19b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.IOException;
20b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.io.InputStream;
21b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.net.URL;
22b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport java.util.Map;
23b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.client.ExcerptInputStream;
24b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpMessage;
25b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport net.oauth.http.HttpResponseMessage;
26b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.HttpResponse;
27b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.HttpClient;
28b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpDelete;
29b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
30b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpGet;
31b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpPost;
32b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpPut;
33b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.methods.HttpRequestBase;
34b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.client.params.ClientPNames;
35b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.conn.ClientConnectionManager;
36b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.entity.InputStreamEntity;
37b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.impl.client.DefaultHttpClient;
38b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
39b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienimport org.apache.http.params.HttpParams;
40b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
41b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien/**
42b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * Utility methods for an OAuth client based on the <a
43b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * href="http://hc.apache.org">Apache HttpClient</a>.
44b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien *
45b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @author Sean Sullivan
46b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien * @hide
47b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien */
48b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembienpublic class HttpClient4 implements net.oauth.http.HttpClient {
49b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
50b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    public HttpClient4() {
51b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        this(SHARED_CLIENT);
52b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
53b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
54b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    public HttpClient4(HttpClientPool clientPool) {
55b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        this.clientPool = clientPool;
56b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
57b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
58b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private final HttpClientPool clientPool;
59b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
60b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    public HttpResponseMessage execute(HttpMessage request) throws IOException {
61b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final String method = request.method;
62b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final String url = request.url.toExternalForm();
63b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final InputStream body = request.getBody();
64b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final boolean isDelete = DELETE.equalsIgnoreCase(method);
65b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final boolean isPost = POST.equalsIgnoreCase(method);
66b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        final boolean isPut = PUT.equalsIgnoreCase(method);
67b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        byte[] excerpt = null;
68b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        HttpRequestBase httpRequest;
69b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        if (isPost || isPut) {
70b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            HttpEntityEnclosingRequestBase entityEnclosingMethod =
71b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                isPost ? new HttpPost(url) : new HttpPut(url);
72b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            if (body != null) {
73b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                ExcerptInputStream e = new ExcerptInputStream(body);
74b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                excerpt = e.getExcerpt();
75b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                String length = request.removeHeaders(HttpMessage.CONTENT_LENGTH);
76b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                entityEnclosingMethod.setEntity(new InputStreamEntity(e,
77b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        (length == null) ? -1 : Long.parseLong(length)));
78b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            }
79b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            httpRequest = entityEnclosingMethod;
80b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } else if (isDelete) {
81b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            httpRequest = new HttpDelete(url);
82b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        } else {
83b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            httpRequest = new HttpGet(url);
84b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
85b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        for (Map.Entry<String, String> header : request.headers) {
86b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            httpRequest.addHeader(header.getKey(), header.getValue());
87b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
88b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        HttpClient client = clientPool.getHttpClient(new URL(httpRequest.getURI().toString()));
89b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
90b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        HttpResponse httpResponse = client.execute(httpRequest);
91b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        return new HttpMethodResponse(httpRequest, httpResponse, excerpt, request.getContentCharset());
92b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
93b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
94b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private static final HttpClientPool SHARED_CLIENT = new SingleClient();
95b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
96b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    /**
97b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     * A pool that simply shares a single HttpClient. An HttpClient owns a pool
98b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     * of TCP connections. So, callers that share an HttpClient will share
99b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     * connections. Sharing improves performance (by avoiding the overhead of
100b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     * creating connections) and uses fewer resources in the client and its
101b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     * servers.
102b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien     */
103b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    private static class SingleClient implements HttpClientPool
104b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    {
105b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        SingleClient()
106b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        {
107b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            HttpClient client = new DefaultHttpClient();
108b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            ClientConnectionManager mgr = client.getConnectionManager();
109b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            if (!(mgr instanceof ThreadSafeClientConnManager)) {
110b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                HttpParams params = client.getParams();
111b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
112b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien                        mgr.getSchemeRegistry()), params);
113b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            }
114b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            this.client = client;
115b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
116b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
117b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        private final HttpClient client;
118b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
119b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        public HttpClient getHttpClient(URL server)
120b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        {
121b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien            return client;
122b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien        }
123b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien    }
124b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien
125b852fcf48a8909164d7f323dd02a35d2a8056a61Nico Sallembien}
126