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}