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