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 31 package org.apache.http.impl.conn; 32 33 34 import java.io.IOException; 35 import java.io.InterruptedIOException; 36 import java.net.InetAddress; 37 import java.net.Socket; 38 import java.util.concurrent.TimeUnit; 39 40 import javax.net.ssl.SSLSocket; 41 import javax.net.ssl.SSLSession; 42 43 import org.apache.http.HttpException; 44 import org.apache.http.HttpRequest; 45 import org.apache.http.HttpEntityEnclosingRequest; 46 import org.apache.http.HttpResponse; 47 import org.apache.http.HttpConnectionMetrics; 48 import org.apache.http.conn.OperatedClientConnection; 49 import org.apache.http.conn.ManagedClientConnection; 50 import 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 85 public 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 */ AbstractClientConnAdapter(ClientConnectionManager mgr, OperatedClientConnection conn)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 */ detach()134 protected void detach() { 135 wrappedConnection = null; 136 connManager = null; // base class attribute 137 duration = Long.MAX_VALUE; 138 } 139 getWrappedConnection()140 protected OperatedClientConnection getWrappedConnection() { 141 return wrappedConnection; 142 } 143 getManager()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 */ assertNotAborted()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 */ assertValid( final OperatedClientConnection wrappedConn)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 isOpen()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 isStale()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 setSocketTimeout(int timeout)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 getSocketTimeout()203 public int getSocketTimeout() { 204 OperatedClientConnection conn = getWrappedConnection(); 205 assertValid(conn); 206 return conn.getSocketTimeout(); 207 } 208 209 210 // non-javadoc, see interface HttpConnection getMetrics()211 public HttpConnectionMetrics getMetrics() { 212 OperatedClientConnection conn = getWrappedConnection(); 213 assertValid(conn); 214 return conn.getMetrics(); 215 } 216 217 218 // non-javadoc, see interface HttpClientConnection flush()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 isResponseAvailable(int timeout)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 receiveResponseEntity(HttpResponse response)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 receiveResponseHeader()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 sendRequestEntity(HttpEntityEnclosingRequest request)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 sendRequestHeader(HttpRequest request)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 getLocalAddress()295 public InetAddress getLocalAddress() { 296 OperatedClientConnection conn = getWrappedConnection(); 297 assertValid(conn); 298 return conn.getLocalAddress(); 299 } 300 301 // non-javadoc, see interface HttpInetConnection getLocalPort()302 public int getLocalPort() { 303 OperatedClientConnection conn = getWrappedConnection(); 304 assertValid(conn); 305 return conn.getLocalPort(); 306 } 307 308 309 // non-javadoc, see interface HttpInetConnection getRemoteAddress()310 public InetAddress getRemoteAddress() { 311 OperatedClientConnection conn = getWrappedConnection(); 312 assertValid(conn); 313 return conn.getRemoteAddress(); 314 } 315 316 // non-javadoc, see interface HttpInetConnection getRemotePort()317 public int getRemotePort() { 318 OperatedClientConnection conn = getWrappedConnection(); 319 assertValid(conn); 320 return conn.getRemotePort(); 321 } 322 323 // non-javadoc, see interface ManagedClientConnection isSecure()324 public boolean isSecure() { 325 OperatedClientConnection conn = getWrappedConnection(); 326 assertValid(conn); 327 return conn.isSecure(); 328 } 329 330 // non-javadoc, see interface ManagedClientConnection getSSLSession()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 markReusable()346 public void markReusable() { 347 markedReusable = true; 348 } 349 350 // non-javadoc, see interface ManagedClientConnection unmarkReusable()351 public void unmarkReusable() { 352 markedReusable = false; 353 } 354 355 // non-javadoc, see interface ManagedClientConnection isMarkedReusable()356 public boolean isMarkedReusable() { 357 return markedReusable; 358 } 359 setIdleDuration(long duration, TimeUnit unit)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 releaseConnection()369 public void releaseConnection() { 370 if (connManager != null) { 371 connManager.releaseConnection(this, duration, TimeUnit.MILLISECONDS); 372 } 373 } 374 375 // non-javadoc, see interface ConnectionReleaseTrigger abortConnection()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