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 */ 027package org.apache.http.pool; 028 029import java.util.HashSet; 030import java.util.Iterator; 031import java.util.LinkedList; 032import java.util.Set; 033import java.util.concurrent.Future; 034 035import org.apache.http.util.Args; 036import org.apache.http.util.Asserts; 037 038abstract class RouteSpecificPool<T, C, E extends PoolEntry<T, C>> { 039 040 private final T route; 041 private final Set<E> leased; 042 private final LinkedList<E> available; 043 private final LinkedList<Future<E>> pending; 044 045 RouteSpecificPool(final T route) { 046 super(); 047 this.route = route; 048 this.leased = new HashSet<E>(); 049 this.available = new LinkedList<E>(); 050 this.pending = new LinkedList<Future<E>>(); 051 } 052 053 protected abstract E createEntry(C conn); 054 055 public final T getRoute() { 056 return route; 057 } 058 059 public int getLeasedCount() { 060 return this.leased.size(); 061 } 062 063 public int getPendingCount() { 064 return this.pending.size(); 065 } 066 067 public int getAvailableCount() { 068 return this.available.size(); 069 } 070 071 public int getAllocatedCount() { 072 return this.available.size() + this.leased.size(); 073 } 074 075 public E getFree(final Object state) { 076 if (!this.available.isEmpty()) { 077 if (state != null) { 078 final Iterator<E> it = this.available.iterator(); 079 while (it.hasNext()) { 080 final E entry = it.next(); 081 if (state.equals(entry.getState())) { 082 it.remove(); 083 this.leased.add(entry); 084 return entry; 085 } 086 } 087 } 088 final Iterator<E> it = this.available.iterator(); 089 while (it.hasNext()) { 090 final E entry = it.next(); 091 if (entry.getState() == null) { 092 it.remove(); 093 this.leased.add(entry); 094 return entry; 095 } 096 } 097 } 098 return null; 099 } 100 101 public E getLastUsed() { 102 if (!this.available.isEmpty()) { 103 return this.available.getLast(); 104 } else { 105 return null; 106 } 107 } 108 109 public boolean remove(final E entry) { 110 Args.notNull(entry, "Pool entry"); 111 if (!this.available.remove(entry)) { 112 if (!this.leased.remove(entry)) { 113 return false; 114 } 115 } 116 return true; 117 } 118 119 public void free(final E entry, final boolean reusable) { 120 Args.notNull(entry, "Pool entry"); 121 final boolean found = this.leased.remove(entry); 122 Asserts.check(found, "Entry %s has not been leased from this pool", entry); 123 if (reusable) { 124 this.available.addFirst(entry); 125 } 126 } 127 128 public E add(final C conn) { 129 final E entry = createEntry(conn); 130 this.leased.add(entry); 131 return entry; 132 } 133 134 public void queue(final Future<E> future) { 135 if (future == null) { 136 return; 137 } 138 this.pending.add(future); 139 } 140 141 public Future<E> nextPending() { 142 return this.pending.poll(); 143 } 144 145 public void unqueue(final Future<E> future) { 146 if (future == null) { 147 return; 148 } 149 150 this.pending.remove(future); 151 } 152 153 public void shutdown() { 154 for (final Future<E> future: this.pending) { 155 future.cancel(true); 156 } 157 this.pending.clear(); 158 for (final E entry: this.available) { 159 entry.close(); 160 } 161 this.available.clear(); 162 for (final E entry: this.leased) { 163 entry.close(); 164 } 165 this.leased.clear(); 166 } 167 168 @Override 169 public String toString() { 170 final StringBuilder buffer = new StringBuilder(); 171 buffer.append("[route: "); 172 buffer.append(this.route); 173 buffer.append("][leased: "); 174 buffer.append(this.leased.size()); 175 buffer.append("][available: "); 176 buffer.append(this.available.size()); 177 buffer.append("][pending: "); 178 buffer.append(this.pending.size()); 179 buffer.append("]"); 180 return buffer.toString(); 181 } 182 183}