001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017package org.apache.commons.pool2;
018
019import java.io.Closeable;
020import java.util.Collection;
021import java.util.Iterator;
022import java.util.NoSuchElementException;
023
024/**
025 * A "keyed" pooling interface.
026 * <p>
027 * A keyed pool maintains a pool of instances for each key value.
028 * </p>
029 * <p>
030 * Example of use:
031 * </p>
032 * <pre style="border:solid thin; padding: 1ex;"
033 * > Object obj = <code style="color:#00C">null</code>;
034 * Object key = <code style="color:#C00">"Key"</code>;
035 *
036 * <code style="color:#00C">try</code> {
037 *     obj = pool.borrowObject(key);
038 *     <code style="color:#0C0">//...use the object...</code>
039 * } <code style="color:#00C">catch</code> (Exception e) {
040 *     <code style="color:#0C0">// invalidate the object</code>
041 *     pool.invalidateObject(key, obj);
042 *     <code style="color:#0C0">// do not return the object to the pool twice</code>
043 *     obj = <code style="color:#00C">null</code>;
044 * } <code style="color:#00C">finally</code> {
045 *     <code style="color:#0C0">// make sure the object is returned to the pool</code>
046 *     <code style="color:#00C">if</code> (<code style="color:#00C">null</code> != obj) {
047 *         pool.returnObject(key, obj);
048 *     }
049 * }</pre>
050 * <p>
051 * {@link KeyedObjectPool} implementations <i>may</i> choose to store at most
052 * one instance per key value, or may choose to maintain a pool of instances
053 * for each key (essentially creating a {@link java.util.Map Map} of
054 * {@link ObjectPool pools}).
055 * </p>
056 * <p>
057 * See {@link org.apache.commons.pool2.impl.GenericKeyedObjectPool
058 * GenericKeyedObjectPool} for an implementation.
059 * </p>
060 *
061 * @param <K> The type of keys maintained by this pool.
062 * @param <V> Type of element pooled in this pool.
063 *
064 * @see KeyedPooledObjectFactory
065 * @see ObjectPool
066 * @see org.apache.commons.pool2.impl.GenericKeyedObjectPool GenericKeyedObjectPool
067 *
068 * @since 2.0
069 */
070public interface KeyedObjectPool<K, V> extends Closeable {
071
072    /**
073     * Creates an object using the {@link KeyedPooledObjectFactory factory} or
074     * other implementation dependent mechanism, passivate it, and then place it
075     * in the idle object pool. {@code addObject} is useful for
076     * "pre-loading" a pool with idle objects (Optional operation).
077     *
078     * @param key the key a new instance should be added to
079     *
080     * @throws Exception
081     *              when {@link KeyedPooledObjectFactory#makeObject} fails.
082     * @throws IllegalStateException
083     *              after {@link #close} has been called on this pool.
084     * @throws UnsupportedOperationException
085     *              when this pool cannot add new idle objects.
086     */
087    void addObject(K key) throws Exception, IllegalStateException,
088            UnsupportedOperationException;
089
090    /**
091     * Calls {@link KeyedObjectPool#addObject(Object)} with each
092     * key in {@code keys} for {@code count} number of times. This has
093     * the same effect as calling {@link #addObjects(Object, int)}
094     * for each key in the {@code keys} collection.
095     *
096     * @param keys
097     *            {@link Collection} of keys to add objects for.
098     * @param count
099     *            the number of idle objects to add for each {@code key}.
100     * @throws Exception
101     *             when {@link KeyedObjectPool#addObject(Object)} fails.
102     * @throws IllegalArgumentException
103     *             when {@code keyedPool}, {@code keys}, or any value
104     *             in {@code keys} is {@code null}.
105     * @see #addObjects(Object, int)
106     */
107    default void addObjects(final Collection<K> keys, final int count) throws Exception, IllegalArgumentException {
108        if (keys == null) {
109            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEYS);
110        }
111        final Iterator<K> iter = keys.iterator();
112        while (iter.hasNext()) {
113            addObjects(iter.next(), count);
114        }
115    }
116
117    /**
118     * Calls {@link KeyedObjectPool#addObject(Object)}
119     * {@code key} {@code count} number of times.
120     *
121     * @param key
122     *            the key to add objects for.
123     * @param count
124     *            the number of idle objects to add for {@code key}.
125     * @throws Exception
126     *             when {@link KeyedObjectPool#addObject(Object)} fails.
127     * @throws IllegalArgumentException
128     *             when {@code key} is {@code null}.
129     * @since 2.8.0
130     */
131    default void addObjects(final K key, final int count) throws Exception, IllegalArgumentException {
132        if (key == null) {
133            throw new IllegalArgumentException(PoolUtils.MSG_NULL_KEY);
134        }
135        for (int i = 0; i < count; i++) {
136            addObject(key);
137        }
138    }
139
140    /**
141     * Borrows an instance from this pool for the specified {@code key}.
142     * <p>
143     * Instances returned from this method will have been either newly created
144     * with {@link KeyedPooledObjectFactory#makeObject makeObject} or will be
145     * a previously idle object and have been activated with
146     * {@link KeyedPooledObjectFactory#activateObject activateObject} and then
147     * (optionally) validated with
148     * {@link KeyedPooledObjectFactory#validateObject validateObject}.
149     * </p>
150     * <p>
151     * By contract, clients <strong>must</strong> return the borrowed object
152     * using {@link #returnObject returnObject},
153     * {@link #invalidateObject invalidateObject}, or a related method as
154     * defined in an implementation or sub-interface, using a {@code key}
155     * that is {@link Object#equals equivalent} to the one used to borrow the
156     * instance in the first place.
157     * </p>
158     * <p>
159     * The behavior of this method when the pool has been exhausted is not
160     * strictly specified (although it may be specified by implementations).
161     * </p>
162     *
163     * @param key the key used to obtain the object
164     *
165     * @return an instance from this pool.
166     *
167     * @throws IllegalStateException
168     *              after {@link #close close} has been called on this pool
169     * @throws Exception
170     *              when {@link KeyedPooledObjectFactory#makeObject
171     *              makeObject} throws an exception
172     * @throws NoSuchElementException
173     *              when the pool is exhausted and cannot or will not return
174     *              another instance
175     */
176    V borrowObject(K key) throws Exception, NoSuchElementException, IllegalStateException;
177
178    /**
179     * Clears the pool, removing all pooled instances (optional operation).
180     *
181     * @throws UnsupportedOperationException when this implementation doesn't
182     *                                       support the operation
183     *
184     * @throws Exception if the pool cannot be cleared
185     */
186    void clear() throws Exception, UnsupportedOperationException;
187
188    /**
189     * Clears the specified pool, removing all pooled instances corresponding to
190     * the given {@code key} (optional operation).
191     *
192     * @param key the key to clear
193     *
194     * @throws UnsupportedOperationException when this implementation doesn't
195     *                                       support the operation
196     *
197     * @throws Exception if the key cannot be cleared
198     */
199    void clear(K key) throws Exception, UnsupportedOperationException;
200
201    /**
202     * Closes this pool, and free any resources associated with it.
203     * <p>
204     * Calling {@link #addObject addObject} or
205     * {@link #borrowObject borrowObject} after invoking this method on a pool
206     * will cause them to throw an {@link IllegalStateException}.
207     * </p>
208     * <p>
209     * Implementations should silently fail if not all resources can be freed.
210     * </p>
211     */
212    @Override
213    void close();
214
215    /**
216     * Gets the total number of instances currently borrowed from this pool but
217     * not yet returned. Returns a negative value if this information is not
218     * available.
219     * @return the total number of instances currently borrowed from this pool but
220     * not yet returned.
221     */
222    int getNumActive();
223
224    /**
225     * Gets the number of instances currently borrowed from but not yet
226     * returned to the pool corresponding to the given {@code key}.
227     * Returns a negative value if this information is not available.
228     *
229     * @param key the key to query
230     * @return the number of instances currently borrowed from but not yet
231     * returned to the pool corresponding to the given {@code key}.
232     */
233    int getNumActive(K key);
234
235    /**
236     * Gets the total number of instances currently idle in this pool.
237     * Returns a negative value if this information is not available.
238     * @return the total number of instances currently idle in this pool.
239     */
240    int getNumIdle();
241
242    /**
243     * Gets the number of instances corresponding to the given
244     * {@code key} currently idle in this pool. Returns a negative value if
245     * this information is not available.
246     *
247     * @param key the key to query
248     * @return the number of instances corresponding to the given
249     * {@code key} currently idle in this pool.
250     */
251    int getNumIdle(K key);
252
253    /**
254     * Invalidates an object from the pool.
255     * <p>
256     * By contract, {@code obj} <strong>must</strong> have been obtained
257     * using {@link #borrowObject borrowObject} or a related method as defined
258     * in an implementation or sub-interface using a {@code key} that is
259     * equivalent to the one used to borrow the {@code Object} in the first
260     * place.
261     * </p>
262     * <p>
263     * This method should be used when an object that has been borrowed is
264     * determined (due to an exception or other problem) to be invalid.
265     * </p>
266     *
267     * @param key the key used to obtain the object
268     * @param obj a {@link #borrowObject borrowed} instance to be returned.
269     *
270     * @throws Exception if the instance cannot be invalidated
271     */
272    void invalidateObject(K key, V obj) throws Exception;
273
274    /**
275     * Invalidates an object from the pool, using the provided
276     * {@link DestroyMode}.
277     * <p>
278     * By contract, {@code obj} <strong>must</strong> have been obtained
279     * using {@link #borrowObject borrowObject} or a related method as defined
280     * in an implementation or sub-interface using a {@code key} that is
281     * equivalent to the one used to borrow the {@code Object} in the first
282     * place.
283     * </p>
284     * <p>
285     * This method should be used when an object that has been borrowed is
286     * determined (due to an exception or other problem) to be invalid.
287     * </p>
288     *
289     * @param key the key used to obtain the object
290     * @param obj a {@link #borrowObject borrowed} instance to be returned.
291     * @param destroyMode destroy activation context provided to the factory
292     *
293     * @throws Exception if the instance cannot be invalidated
294     * @since 2.9.0
295     */
296    default void invalidateObject(final K key, final V obj, final DestroyMode destroyMode) throws Exception {
297        invalidateObject(key, obj);
298    }
299
300    /**
301     * Return an instance to the pool. By contract, {@code obj}
302     * <strong>must</strong> have been obtained using
303     * {@link #borrowObject borrowObject} or a related method as defined in an
304     * implementation or sub-interface using a {@code key} that is
305     * equivalent to the one used to borrow the instance in the first place.
306     *
307     * @param key the key used to obtain the object
308     * @param obj a {@link #borrowObject borrowed} instance to be returned.
309     *
310     * @throws IllegalStateException
311     *              if an attempt is made to return an object to the pool that
312     *              is in any state other than allocated (i.e. borrowed).
313     *              Attempting to return an object more than once or attempting
314     *              to return an object that was never borrowed from the pool
315     *              will trigger this exception.
316     *
317     * @throws Exception if an instance cannot be returned to the pool
318     */
319    void returnObject(K key, V obj) throws Exception;
320}