001/* 002 * ==================================================================== 003 * Licensed to the Apache Software Foundation (ASF) under one 004 * or more contributor license agreements. See the NOTICE file 005 * distributed with this work for additional information 006 * regarding copyright ownership. The ASF licenses this file 007 * to you under the Apache License, Version 2.0 (the 008 * "License"); you may not use this file except in compliance 009 * with the License. You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, 014 * software distributed under the License is distributed on an 015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 016 * KIND, either express or implied. See the License for the 017 * specific language governing permissions and limitations 018 * under the License. 019 * ==================================================================== 020 * 021 * This software consists of voluntary contributions made by many 022 * individuals on behalf of the Apache Software Foundation. For more 023 * information on the Apache Software Foundation, please see 024 * <http://www.apache.org/>. 025 * 026 */ 027 028package org.apache.http.impl.execchain; 029 030import java.io.Closeable; 031import java.io.IOException; 032import java.util.concurrent.TimeUnit; 033import java.util.concurrent.atomic.AtomicBoolean; 034 035import org.apache.commons.logging.Log; 036import org.apache.http.HttpClientConnection; 037import org.apache.http.annotation.Contract; 038import org.apache.http.annotation.ThreadingBehavior; 039import org.apache.http.concurrent.Cancellable; 040import org.apache.http.conn.ConnectionReleaseTrigger; 041import org.apache.http.conn.HttpClientConnectionManager; 042 043/** 044 * Internal connection holder. 045 * 046 * @since 4.3 047 */ 048@Contract(threading = ThreadingBehavior.SAFE) 049class ConnectionHolder implements ConnectionReleaseTrigger, Cancellable, Closeable { 050 051 private final Log log; 052 053 private final HttpClientConnectionManager manager; 054 private final HttpClientConnection managedConn; 055 private final AtomicBoolean released; 056 private volatile boolean reusable; 057 private volatile Object state; 058 private volatile long validDuration; 059 private volatile TimeUnit tunit; 060 061 public ConnectionHolder( 062 final Log log, 063 final HttpClientConnectionManager manager, 064 final HttpClientConnection managedConn) { 065 super(); 066 this.log = log; 067 this.manager = manager; 068 this.managedConn = managedConn; 069 this.released = new AtomicBoolean(false); 070 } 071 072 public boolean isReusable() { 073 return this.reusable; 074 } 075 076 public void markReusable() { 077 this.reusable = true; 078 } 079 080 public void markNonReusable() { 081 this.reusable = false; 082 } 083 084 public void setState(final Object state) { 085 this.state = state; 086 } 087 088 public void setValidFor(final long duration, final TimeUnit tunit) { 089 synchronized (this.managedConn) { 090 this.validDuration = duration; 091 this.tunit = tunit; 092 } 093 } 094 095 private void releaseConnection(final boolean reusable) { 096 if (this.released.compareAndSet(false, true)) { 097 synchronized (this.managedConn) { 098 if (reusable) { 099 this.manager.releaseConnection(this.managedConn, 100 this.state, this.validDuration, this.tunit); 101 } else { 102 try { 103 this.managedConn.close(); 104 log.debug("Connection discarded"); 105 } catch (final IOException ex) { 106 if (this.log.isDebugEnabled()) { 107 this.log.debug(ex.getMessage(), ex); 108 } 109 } finally { 110 this.manager.releaseConnection( 111 this.managedConn, null, 0, TimeUnit.MILLISECONDS); 112 } 113 } 114 } 115 } 116 } 117 118 @Override 119 public void releaseConnection() { 120 releaseConnection(this.reusable); 121 } 122 123 @Override 124 public void abortConnection() { 125 if (this.released.compareAndSet(false, true)) { 126 synchronized (this.managedConn) { 127 try { 128 this.managedConn.shutdown(); 129 log.debug("Connection discarded"); 130 } catch (final IOException ex) { 131 if (this.log.isDebugEnabled()) { 132 this.log.debug(ex.getMessage(), ex); 133 } 134 } finally { 135 this.manager.releaseConnection( 136 this.managedConn, null, 0, TimeUnit.MILLISECONDS); 137 } 138 } 139 } 140 } 141 142 @Override 143 public boolean cancel() { 144 final boolean alreadyReleased = this.released.get(); 145 log.debug("Cancelling request execution"); 146 abortConnection(); 147 return !alreadyReleased; 148 } 149 150 public boolean isReleased() { 151 return this.released.get(); 152 } 153 154 @Override 155 public void close() throws IOException { 156 releaseConnection(false); 157 } 158 159}