1/*
2 * Copyright 2008 Sean Sullivan
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
17package net.oauth.client.httpclient4;
18
19import java.io.IOException;
20import java.io.InputStream;
21import java.net.URL;
22import java.util.Map;
23import net.oauth.client.ExcerptInputStream;
24import net.oauth.http.HttpMessage;
25import net.oauth.http.HttpResponseMessage;
26import org.apache.http.HttpResponse;
27import org.apache.http.client.HttpClient;
28import org.apache.http.client.methods.HttpDelete;
29import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
30import org.apache.http.client.methods.HttpGet;
31import org.apache.http.client.methods.HttpPost;
32import org.apache.http.client.methods.HttpPut;
33import org.apache.http.client.methods.HttpRequestBase;
34import org.apache.http.client.params.ClientPNames;
35import org.apache.http.conn.ClientConnectionManager;
36import org.apache.http.entity.InputStreamEntity;
37import org.apache.http.impl.client.DefaultHttpClient;
38import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
39import org.apache.http.params.HttpParams;
40
41/**
42 * Utility methods for an OAuth client based on the <a
43 * href="http://hc.apache.org">Apache HttpClient</a>.
44 *
45 * @author Sean Sullivan
46 * @hide
47 */
48public class HttpClient4 implements net.oauth.http.HttpClient {
49
50    public HttpClient4() {
51        this(SHARED_CLIENT);
52    }
53
54    public HttpClient4(HttpClientPool clientPool) {
55        this.clientPool = clientPool;
56    }
57
58    private final HttpClientPool clientPool;
59
60    public HttpResponseMessage execute(HttpMessage request) throws IOException {
61        final String method = request.method;
62        final String url = request.url.toExternalForm();
63        final InputStream body = request.getBody();
64        final boolean isDelete = DELETE.equalsIgnoreCase(method);
65        final boolean isPost = POST.equalsIgnoreCase(method);
66        final boolean isPut = PUT.equalsIgnoreCase(method);
67        byte[] excerpt = null;
68        HttpRequestBase httpRequest;
69        if (isPost || isPut) {
70            HttpEntityEnclosingRequestBase entityEnclosingMethod =
71                isPost ? new HttpPost(url) : new HttpPut(url);
72            if (body != null) {
73                ExcerptInputStream e = new ExcerptInputStream(body);
74                excerpt = e.getExcerpt();
75                String length = request.removeHeaders(HttpMessage.CONTENT_LENGTH);
76                entityEnclosingMethod.setEntity(new InputStreamEntity(e,
77                        (length == null) ? -1 : Long.parseLong(length)));
78            }
79            httpRequest = entityEnclosingMethod;
80        } else if (isDelete) {
81            httpRequest = new HttpDelete(url);
82        } else {
83            httpRequest = new HttpGet(url);
84        }
85        for (Map.Entry<String, String> header : request.headers) {
86            httpRequest.addHeader(header.getKey(), header.getValue());
87        }
88        HttpClient client = clientPool.getHttpClient(new URL(httpRequest.getURI().toString()));
89        client.getParams().setBooleanParameter(ClientPNames.HANDLE_REDIRECTS, false);
90        HttpResponse httpResponse = client.execute(httpRequest);
91        return new HttpMethodResponse(httpRequest, httpResponse, excerpt, request.getContentCharset());
92    }
93
94    private static final HttpClientPool SHARED_CLIENT = new SingleClient();
95
96    /**
97     * A pool that simply shares a single HttpClient. An HttpClient owns a pool
98     * of TCP connections. So, callers that share an HttpClient will share
99     * connections. Sharing improves performance (by avoiding the overhead of
100     * creating connections) and uses fewer resources in the client and its
101     * servers.
102     */
103    private static class SingleClient implements HttpClientPool
104    {
105        SingleClient()
106        {
107            HttpClient client = new DefaultHttpClient();
108            ClientConnectionManager mgr = client.getConnectionManager();
109            if (!(mgr instanceof ThreadSafeClientConnManager)) {
110                HttpParams params = client.getParams();
111                client = new DefaultHttpClient(new ThreadSafeClientConnManager(params,
112                        mgr.getSchemeRegistry()), params);
113            }
114            this.client = client;
115        }
116
117        private final HttpClient client;
118
119        public HttpClient getHttpClient(URL server)
120        {
121            return client;
122        }
123    }
124
125}
126