001/*
002 * Copyright 2002-2018 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.aop.target;
018
019import org.apache.commons.pool2.ObjectPool;
020import org.apache.commons.pool2.PooledObject;
021import org.apache.commons.pool2.PooledObjectFactory;
022import org.apache.commons.pool2.impl.DefaultPooledObject;
023import org.apache.commons.pool2.impl.GenericObjectPool;
024import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
025
026import org.springframework.lang.Nullable;
027import org.springframework.util.Assert;
028
029/**
030 * {@link org.springframework.aop.TargetSource} implementation that holds
031 * objects in a configurable Apache Commons2 Pool.
032 *
033 * <p>By default, an instance of {@code GenericObjectPool} is created.
034 * Subclasses may change the type of {@code ObjectPool} used by
035 * overriding the {@code createObjectPool()} method.
036 *
037 * <p>Provides many configuration properties mirroring those of the Commons Pool
038 * {@code GenericObjectPool} class; these properties are passed to the
039 * {@code GenericObjectPool} during construction. If creating a subclass of this
040 * class to change the {@code ObjectPool} implementation type, pass in the values
041 * of configuration properties that are relevant to your chosen implementation.
042 *
043 * <p>The {@code testOnBorrow}, {@code testOnReturn} and {@code testWhileIdle}
044 * properties are explicitly not mirrored because the implementation of
045 * {@code PoolableObjectFactory} used by this class does not implement
046 * meaningful validation. All exposed Commons Pool properties use the
047 * corresponding Commons Pool defaults.
048 *
049 * <p>Compatible with Apache Commons Pool 2.4, as of Spring 4.2.
050 *
051 * @author Rod Johnson
052 * @author Rob Harrop
053 * @author Juergen Hoeller
054 * @author Stephane Nicoll
055 * @author Kazuki Shimizu
056 * @since 4.2
057 * @see GenericObjectPool
058 * @see #createObjectPool()
059 * @see #setMaxSize
060 * @see #setMaxIdle
061 * @see #setMinIdle
062 * @see #setMaxWait
063 * @see #setTimeBetweenEvictionRunsMillis
064 * @see #setMinEvictableIdleTimeMillis
065 */
066@SuppressWarnings({"rawtypes", "unchecked", "serial"})
067public class CommonsPool2TargetSource extends AbstractPoolingTargetSource implements PooledObjectFactory<Object> {
068
069        private int maxIdle = GenericObjectPoolConfig.DEFAULT_MAX_IDLE;
070
071        private int minIdle = GenericObjectPoolConfig.DEFAULT_MIN_IDLE;
072
073        private long maxWait = GenericObjectPoolConfig.DEFAULT_MAX_WAIT_MILLIS;
074
075        private long timeBetweenEvictionRunsMillis = GenericObjectPoolConfig.DEFAULT_TIME_BETWEEN_EVICTION_RUNS_MILLIS;
076
077        private long minEvictableIdleTimeMillis = GenericObjectPoolConfig.DEFAULT_MIN_EVICTABLE_IDLE_TIME_MILLIS;
078
079        private boolean blockWhenExhausted = GenericObjectPoolConfig.DEFAULT_BLOCK_WHEN_EXHAUSTED;
080
081        /**
082         * The Apache Commons {@code ObjectPool} used to pool target objects.
083         */
084        @Nullable
085        private ObjectPool pool;
086
087
088        /**
089         * Create a CommonsPoolTargetSource with default settings.
090         * Default maximum size of the pool is 8.
091         * @see #setMaxSize
092         * @see GenericObjectPoolConfig#setMaxTotal
093         */
094        public CommonsPool2TargetSource() {
095                setMaxSize(GenericObjectPoolConfig.DEFAULT_MAX_TOTAL);
096        }
097
098
099        /**
100         * Set the maximum number of idle objects in the pool.
101         * Default is 8.
102         * @see GenericObjectPool#setMaxIdle
103         */
104        public void setMaxIdle(int maxIdle) {
105                this.maxIdle = maxIdle;
106        }
107
108        /**
109         * Return the maximum number of idle objects in the pool.
110         */
111        public int getMaxIdle() {
112                return this.maxIdle;
113        }
114
115        /**
116         * Set the minimum number of idle objects in the pool.
117         * Default is 0.
118         * @see GenericObjectPool#setMinIdle
119         */
120        public void setMinIdle(int minIdle) {
121                this.minIdle = minIdle;
122        }
123
124        /**
125         * Return the minimum number of idle objects in the pool.
126         */
127        public int getMinIdle() {
128                return this.minIdle;
129        }
130
131        /**
132         * Set the maximum waiting time for fetching an object from the pool.
133         * Default is -1, waiting forever.
134         * @see GenericObjectPool#setMaxWaitMillis
135         */
136        public void setMaxWait(long maxWait) {
137                this.maxWait = maxWait;
138        }
139
140        /**
141         * Return the maximum waiting time for fetching an object from the pool.
142         */
143        public long getMaxWait() {
144                return this.maxWait;
145        }
146
147        /**
148         * Set the time between eviction runs that check idle objects whether
149         * they have been idle for too long or have become invalid.
150         * Default is -1, not performing any eviction.
151         * @see GenericObjectPool#setTimeBetweenEvictionRunsMillis
152         */
153        public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
154                this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
155        }
156
157        /**
158         * Return the time between eviction runs that check idle objects.
159         */
160        public long getTimeBetweenEvictionRunsMillis() {
161                return this.timeBetweenEvictionRunsMillis;
162        }
163
164        /**
165         * Set the minimum time that an idle object can sit in the pool before
166         * it becomes subject to eviction. Default is 1800000 (30 minutes).
167         * <p>Note that eviction runs need to be performed to take this
168         * setting into effect.
169         * @see #setTimeBetweenEvictionRunsMillis
170         * @see GenericObjectPool#setMinEvictableIdleTimeMillis
171         */
172        public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
173                this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
174        }
175
176        /**
177         * Return the minimum time that an idle object can sit in the pool.
178         */
179        public long getMinEvictableIdleTimeMillis() {
180                return this.minEvictableIdleTimeMillis;
181        }
182
183        /**
184         * Set whether the call should bock when the pool is exhausted.
185         */
186        public void setBlockWhenExhausted(boolean blockWhenExhausted) {
187                this.blockWhenExhausted = blockWhenExhausted;
188        }
189
190        /**
191         * Specify if the call should block when the pool is exhausted.
192         */
193        public boolean isBlockWhenExhausted() {
194                return this.blockWhenExhausted;
195        }
196
197
198        /**
199         * Creates and holds an ObjectPool instance.
200         * @see #createObjectPool()
201         */
202        @Override
203        protected final void createPool() {
204                logger.debug("Creating Commons object pool");
205                this.pool = createObjectPool();
206        }
207
208        /**
209         * Subclasses can override this if they want to return a specific Commons pool.
210         * They should apply any configuration properties to the pool here.
211         * <p>Default is a GenericObjectPool instance with the given pool size.
212         * @return an empty Commons {@code ObjectPool}.
213         * @see GenericObjectPool
214         * @see #setMaxSize
215         */
216        protected ObjectPool createObjectPool() {
217                GenericObjectPoolConfig config = new GenericObjectPoolConfig();
218                config.setMaxTotal(getMaxSize());
219                config.setMaxIdle(getMaxIdle());
220                config.setMinIdle(getMinIdle());
221                config.setMaxWaitMillis(getMaxWait());
222                config.setTimeBetweenEvictionRunsMillis(getTimeBetweenEvictionRunsMillis());
223                config.setMinEvictableIdleTimeMillis(getMinEvictableIdleTimeMillis());
224                config.setBlockWhenExhausted(isBlockWhenExhausted());
225                return new GenericObjectPool(this, config);
226        }
227
228
229        /**
230         * Borrows an object from the {@code ObjectPool}.
231         */
232        @Override
233        public Object getTarget() throws Exception {
234                Assert.state(this.pool != null, "No Commons ObjectPool available");
235                return this.pool.borrowObject();
236        }
237
238        /**
239         * Returns the specified object to the underlying {@code ObjectPool}.
240         */
241        @Override
242        public void releaseTarget(Object target) throws Exception {
243                if (this.pool != null) {
244                        this.pool.returnObject(target);
245                }
246        }
247
248        @Override
249        public int getActiveCount() throws UnsupportedOperationException {
250                return (this.pool != null ? this.pool.getNumActive() : 0);
251        }
252
253        @Override
254        public int getIdleCount() throws UnsupportedOperationException {
255                return (this.pool != null ? this.pool.getNumIdle() : 0);
256        }
257
258
259        /**
260         * Closes the underlying {@code ObjectPool} when destroying this object.
261         */
262        @Override
263        public void destroy() throws Exception {
264                if (this.pool != null) {
265                        logger.debug("Closing Commons ObjectPool");
266                        this.pool.close();
267                }
268        }
269
270
271        //----------------------------------------------------------------------------
272        // Implementation of org.apache.commons.pool2.PooledObjectFactory interface
273        //----------------------------------------------------------------------------
274
275        @Override
276        public PooledObject<Object> makeObject() throws Exception {
277                return new DefaultPooledObject<>(newPrototypeInstance());
278        }
279
280        @Override
281        public void destroyObject(PooledObject<Object> p) throws Exception {
282                destroyPrototypeInstance(p.getObject());
283        }
284
285        @Override
286        public boolean validateObject(PooledObject<Object> p) {
287                return true;
288        }
289
290        @Override
291        public void activateObject(PooledObject<Object> p) throws Exception {
292        }
293
294        @Override
295        public void passivateObject(PooledObject<Object> p) throws Exception {
296        }
297
298}