1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpclient/trunk/module-client/src/main/java/org/apache/http/impl/conn/AbstractClientConnAdapter.java $
3 * $Revision: 672969 $
4 * $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
5 *
6 * ====================================================================
7 *
8 *  Licensed to the Apache Software Foundation (ASF) under one or more
9 *  contributor license agreements.  See the NOTICE file distributed with
10 *  this work for additional information regarding copyright ownership.
11 *  The ASF licenses this file to You under the Apache License, Version 2.0
12 *  (the "License"); you may not use this file except in compliance with
13 *  the License.  You may obtain a copy of the License at
14 *
15 *      http://www.apache.org/licenses/LICENSE-2.0
16 *
17 *  Unless required by applicable law or agreed to in writing, software
18 *  distributed under the License is distributed on an "AS IS" BASIS,
19 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20 *  See the License for the specific language governing permissions and
21 *  limitations under the License.
22 * ====================================================================
23 *
24 * This software consists of voluntary contributions made by many
25 * individuals on behalf of the Apache Software Foundation.  For more
26 * information on the Apache Software Foundation, please see
27 * <http://www.apache.org/>.
28 *
29 */
30
31package org.apache.http.impl.conn;
32
33
34import java.io.IOException;
35import java.io.InterruptedIOException;
36import java.net.InetAddress;
37import java.net.Socket;
38import java.util.concurrent.TimeUnit;
39
40import javax.net.ssl.SSLSocket;
41import javax.net.ssl.SSLSession;
42
43import org.apache.http.HttpException;
44import org.apache.http.HttpRequest;
45import org.apache.http.HttpEntityEnclosingRequest;
46import org.apache.http.HttpResponse;
47import org.apache.http.HttpConnectionMetrics;
48import org.apache.http.conn.OperatedClientConnection;
49import org.apache.http.conn.ManagedClientConnection;
50import org.apache.http.conn.ClientConnectionManager;
51
52
53/**
54 * Abstract adapter from {@link OperatedClientConnection operated} to
55 * {@link ManagedClientConnection managed} client connections.
56 * Read and write methods are delegated to the wrapped connection.
57 * Operations affecting the connection state have to be implemented
58 * by derived classes. Operations for querying the connection state
59 * are delegated to the wrapped connection if there is one, or
60 * return a default value if there is none.
61 * <br/>
62 * This adapter tracks the checkpoints for reusable communication states,
63 * as indicated by {@link #markReusable markReusable} and queried by
64 * {@link #isMarkedReusable isMarkedReusable}.
65 * All send and receive operations will automatically clear the mark.
66 * <br/>
67 * Connection release calls are delegated to the connection manager,
68 * if there is one. {@link #abortConnection abortConnection} will
69 * clear the reusability mark first. The connection manager is
70 * expected to tolerate multiple calls to the release method.
71 *
72 * @author <a href="mailto:rolandw at apache.org">Roland Weber</a>
73 *
74 *
75 * <!-- empty lines to avoid svn diff problems -->
76 * @version   $Revision: 672969 $ $Date: 2008-06-30 18:09:50 -0700 (Mon, 30 Jun 2008) $
77 *
78 * @since 4.0
79 *
80 * @deprecated Please use {@link java.net.URL#openConnection} instead.
81 *     Please visit <a href="http://android-developers.blogspot.com/2011/09/androids-http-clients.html">this webpage</a>
82 *     for further details.
83 */
84@Deprecated
85public abstract class AbstractClientConnAdapter
86    implements ManagedClientConnection {
87
88    /** Thread that requested this connection. */
89    private final Thread executionThread;
90
91    /**
92     * The connection manager, if any.
93     * This attribute MUST NOT be final, so the adapter can be detached
94     * from the connection manager without keeping a hard reference there.
95     */
96    private volatile ClientConnectionManager connManager;
97
98    /** The wrapped connection. */
99    private volatile OperatedClientConnection wrappedConnection;
100
101    /** The reusability marker. */
102    private volatile boolean markedReusable;
103
104    /** True if the connection has been aborted. */
105    private volatile boolean aborted;
106
107    /** The duration this is valid for while idle (in ms). */
108    private volatile long duration;
109
110    /**
111     * Creates a new connection adapter.
112     * The adapter is initially <i>not</i>
113     * {@link #isMarkedReusable marked} as reusable.
114     *
115     * @param mgr       the connection manager, or <code>null</code>
116     * @param conn      the connection to wrap, or <code>null</code>
117     */
118    protected AbstractClientConnAdapter(ClientConnectionManager mgr,
119                                        OperatedClientConnection conn) {
120        super();
121        executionThread = Thread.currentThread();
122        connManager = mgr;
123        wrappedConnection = conn;
124        markedReusable = false;
125        aborted = false;
126        duration = Long.MAX_VALUE;
127    } // <constructor>
128
129
130    /**
131     * Detaches this adapter from the wrapped connection.
132     * This adapter becomes useless.
133     */
134    protected void detach() {
135        wrappedConnection = null;
136        connManager = null; // base class attribute
137        duration = Long.MAX_VALUE;
138    }
139
140    protected OperatedClientConnection getWrappedConnection() {
141        return wrappedConnection;
142    }
143
144    protected ClientConnectionManager getManager() {
145        return connManager;
146    }
147
148    /**
149     * Asserts that the connection has not been aborted.
150     *
151     * @throws InterruptedIOException   if the connection has been aborted
152     */
153    protected final void assertNotAborted() throws InterruptedIOException {
154        if (aborted) {
155            throw new InterruptedIOException("Connection has been shut down.");
156        }
157    }
158
159    /**
160     * Asserts that there is a wrapped connection to delegate to.
161     *
162     * @throws IllegalStateException    if there is no wrapped connection
163     *                                  or connection has been aborted
164     */
165    protected final void assertValid(
166            final OperatedClientConnection wrappedConn) {
167        if (wrappedConn == null) {
168            throw new IllegalStateException("No wrapped connection.");
169        }
170    }
171
172    // non-javadoc, see interface HttpConnection
173    public boolean isOpen() {
174        OperatedClientConnection conn = getWrappedConnection();
175        if (conn == null)
176            return false;
177
178        return conn.isOpen();
179    }
180
181
182    // non-javadoc, see interface HttpConnection
183    public boolean isStale() {
184        if (aborted)
185            return true;
186        OperatedClientConnection conn = getWrappedConnection();
187        if (conn == null)
188            return true;
189
190        return conn.isStale();
191    }
192
193
194    // non-javadoc, see interface HttpConnection
195    public void setSocketTimeout(int timeout) {
196        OperatedClientConnection conn = getWrappedConnection();
197        assertValid(conn);
198        conn.setSocketTimeout(timeout);
199    }
200
201
202    // non-javadoc, see interface HttpConnection
203    public int getSocketTimeout() {
204        OperatedClientConnection conn = getWrappedConnection();
205        assertValid(conn);
206        return conn.getSocketTimeout();
207    }
208
209
210    // non-javadoc, see interface HttpConnection
211    public HttpConnectionMetrics getMetrics() {
212        OperatedClientConnection conn = getWrappedConnection();
213        assertValid(conn);
214        return conn.getMetrics();
215    }
216
217
218    // non-javadoc, see interface HttpClientConnection
219    public void flush()
220        throws IOException {
221
222        assertNotAborted();
223        OperatedClientConnection conn = getWrappedConnection();
224        assertValid(conn);
225
226        conn.flush();
227    }
228
229
230    // non-javadoc, see interface HttpClientConnection
231    public boolean isResponseAvailable(int timeout)
232        throws IOException {
233
234        assertNotAborted();
235        OperatedClientConnection conn = getWrappedConnection();
236        assertValid(conn);
237
238        return conn.isResponseAvailable(timeout);
239    }
240
241
242    // non-javadoc, see interface HttpClientConnection
243    public void receiveResponseEntity(HttpResponse response)
244        throws HttpException, IOException {
245
246        assertNotAborted();
247        OperatedClientConnection conn = getWrappedConnection();
248        assertValid(conn);
249
250        unmarkReusable();
251        conn.receiveResponseEntity(response);
252    }
253
254
255    // non-javadoc, see interface HttpClientConnection
256    public HttpResponse receiveResponseHeader()
257        throws HttpException, IOException {
258
259        assertNotAborted();
260        OperatedClientConnection conn = getWrappedConnection();
261        assertValid(conn);
262
263        unmarkReusable();
264        return conn.receiveResponseHeader();
265    }
266
267
268    // non-javadoc, see interface HttpClientConnection
269    public void sendRequestEntity(HttpEntityEnclosingRequest request)
270        throws HttpException, IOException {
271
272        assertNotAborted();
273        OperatedClientConnection conn = getWrappedConnection();
274        assertValid(conn);
275
276        unmarkReusable();
277        conn.sendRequestEntity(request);
278    }
279
280
281    // non-javadoc, see interface HttpClientConnection
282    public void sendRequestHeader(HttpRequest request)
283        throws HttpException, IOException {
284
285        assertNotAborted();
286        OperatedClientConnection conn = getWrappedConnection();
287        assertValid(conn);
288
289        unmarkReusable();
290        conn.sendRequestHeader(request);
291    }
292
293
294    // non-javadoc, see interface HttpInetConnection
295    public InetAddress getLocalAddress() {
296        OperatedClientConnection conn = getWrappedConnection();
297        assertValid(conn);
298        return conn.getLocalAddress();
299    }
300
301    // non-javadoc, see interface HttpInetConnection
302    public int getLocalPort() {
303        OperatedClientConnection conn = getWrappedConnection();
304        assertValid(conn);
305        return conn.getLocalPort();
306    }
307
308
309    // non-javadoc, see interface HttpInetConnection
310    public InetAddress getRemoteAddress() {
311        OperatedClientConnection conn = getWrappedConnection();
312        assertValid(conn);
313        return conn.getRemoteAddress();
314    }
315
316    // non-javadoc, see interface HttpInetConnection
317    public int getRemotePort() {
318        OperatedClientConnection conn = getWrappedConnection();
319        assertValid(conn);
320        return conn.getRemotePort();
321    }
322
323    // non-javadoc, see interface ManagedClientConnection
324    public boolean isSecure() {
325        OperatedClientConnection conn = getWrappedConnection();
326        assertValid(conn);
327        return conn.isSecure();
328    }
329
330    // non-javadoc, see interface ManagedClientConnection
331    public SSLSession getSSLSession() {
332        OperatedClientConnection conn = getWrappedConnection();
333        assertValid(conn);
334        if (!isOpen())
335            return null;
336
337        SSLSession result = null;
338        Socket    sock    = conn.getSocket();
339        if (sock instanceof SSLSocket) {
340            result = ((SSLSocket)sock).getSession();
341        }
342        return result;
343    }
344
345    // non-javadoc, see interface ManagedClientConnection
346    public void markReusable() {
347        markedReusable = true;
348    }
349
350    // non-javadoc, see interface ManagedClientConnection
351    public void unmarkReusable() {
352        markedReusable = false;
353    }
354
355    // non-javadoc, see interface ManagedClientConnection
356    public boolean isMarkedReusable() {
357        return markedReusable;
358    }
359
360    public void setIdleDuration(long duration, TimeUnit unit) {
361        if(duration > 0) {
362            this.duration = unit.toMillis(duration);
363        } else {
364            this.duration = -1;
365        }
366    }
367
368    // non-javadoc, see interface ConnectionReleaseTrigger
369    public void releaseConnection() {
370        if (connManager != null) {
371            connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS);
372        }
373    }
374
375    // non-javadoc, see interface ConnectionReleaseTrigger
376    public void abortConnection() {
377        if (aborted) {
378            return;
379        }
380        aborted = true;
381        unmarkReusable();
382        try {
383            shutdown();
384        } catch (IOException ignore) {
385        }
386        // Usually #abortConnection() is expected to be called from
387        // a helper thread in order to unblock the main execution thread
388        // blocked in an I/O operation. It may be unsafe to call
389        // #releaseConnection() from the helper thread, so we have to rely
390        // on an IOException thrown by the closed socket on the main thread
391        // to trigger the release of the connection back to the
392        // connection manager.
393        //
394        // However, if this method is called from the main execution thread
395        // it should be safe to release the connection immediately. Besides,
396        // this also helps ensure the connection gets released back to the
397        // manager if #abortConnection() is called from the main execution
398        // thread while there is no blocking I/O operation.
399        if (executionThread.equals(Thread.currentThread())) {
400            releaseConnection();
401        }
402    }
403
404} // class AbstractClientConnAdapter
405