| Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||
| SoftReferenceObjectPool |
|
| 3.769230769230769;3.769 |
| 1 | /* | |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one or more | |
| 3 | * contributor license agreements. See the NOTICE file distributed with | |
| 4 | * this work for additional information regarding copyright ownership. | |
| 5 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |
| 6 | * (the "License"); you may not use this file except in compliance with | |
| 7 | * the License. You may obtain a copy of the License at | |
| 8 | * | |
| 9 | * http://www.apache.org/licenses/LICENSE-2.0 | |
| 10 | * | |
| 11 | * Unless required by applicable law or agreed to in writing, software | |
| 12 | * distributed under the License is distributed on an "AS IS" BASIS, | |
| 13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| 14 | * See the License for the specific language governing permissions and | |
| 15 | * limitations under the License. | |
| 16 | */ | |
| 17 | ||
| 18 | package org.apache.commons.pool.impl; | |
| 19 | ||
| 20 | import java.lang.ref.SoftReference; | |
| 21 | import java.lang.ref.ReferenceQueue; | |
| 22 | import java.lang.ref.Reference; | |
| 23 | import java.util.ArrayList; | |
| 24 | import java.util.Iterator; | |
| 25 | import java.util.List; | |
| 26 | import java.util.NoSuchElementException; | |
| 27 | ||
| 28 | import org.apache.commons.pool.BaseObjectPool; | |
| 29 | import org.apache.commons.pool.ObjectPool; | |
| 30 | import org.apache.commons.pool.PoolableObjectFactory; | |
| 31 | import org.apache.commons.pool.PoolUtils; | |
| 32 | ||
| 33 | /** | |
| 34 | * A {@link java.lang.ref.SoftReference SoftReference} based | |
| 35 | * {@link ObjectPool}. | |
| 36 | * | |
| 37 | * @author Rodney Waldhoff | |
| 38 | * @author Sandy McArthur | |
| 39 | * @version $Revision: 777748 $ $Date: 2009-05-22 20:00:44 -0400 (Fri, 22 May 2009) $ | |
| 40 | * @since Pool 1.0 | |
| 41 | */ | |
| 42 | public class SoftReferenceObjectPool extends BaseObjectPool implements ObjectPool { | |
| 43 | /** | |
| 44 | * Create a <code>SoftReferenceObjectPool</code> without a factory. | |
| 45 | * {@link #setFactory(PoolableObjectFactory) setFactory} should be called | |
| 46 | * before any attempts to use the pool are made. | |
| 47 | * Generally speaking you should prefer the {@link #SoftReferenceObjectPool(PoolableObjectFactory)} constructor. | |
| 48 | * | |
| 49 | * @see #SoftReferenceObjectPool(PoolableObjectFactory) | |
| 50 | */ | |
| 51 | 0 | public SoftReferenceObjectPool() { |
| 52 | 0 | _pool = new ArrayList(); |
| 53 | 0 | _factory = null; |
| 54 | 0 | } |
| 55 | ||
| 56 | /** | |
| 57 | * Create a <code>SoftReferenceObjectPool</code> with the specified factory. | |
| 58 | * | |
| 59 | * @param factory object factory to use. | |
| 60 | */ | |
| 61 | 0 | public SoftReferenceObjectPool(PoolableObjectFactory factory) { |
| 62 | 0 | _pool = new ArrayList(); |
| 63 | 0 | _factory = factory; |
| 64 | 0 | } |
| 65 | ||
| 66 | /** | |
| 67 | * Create a <code>SoftReferenceObjectPool</code> with the specified factory and initial idle object count. | |
| 68 | * | |
| 69 | * @param factory object factory to use. | |
| 70 | * @param initSize initial size to attempt to prefill the pool. | |
| 71 | * @throws Exception when there is a problem prefilling the pool. | |
| 72 | * @throws IllegalArgumentException when <code>factory</code> is <code>null</code>. | |
| 73 | * @deprecated because this is a SoftReference pool, prefilled idle obejects may be garbage collected before they are used. | |
| 74 | * To be removed in Pool 3.0. | |
| 75 | */ | |
| 76 | 0 | public SoftReferenceObjectPool(PoolableObjectFactory factory, int initSize) throws Exception, IllegalArgumentException { |
| 77 | 0 | if (factory == null) { |
| 78 | 0 | throw new IllegalArgumentException("factory required to prefill the pool."); |
| 79 | } | |
| 80 | 0 | _pool = new ArrayList(initSize); |
| 81 | 0 | _factory = factory; |
| 82 | 0 | PoolUtils.prefill(this, initSize); |
| 83 | 0 | } |
| 84 | ||
| 85 | public synchronized Object borrowObject() throws Exception { | |
| 86 | 0 | assertOpen(); |
| 87 | 0 | Object obj = null; |
| 88 | 0 | boolean newlyCreated = false; |
| 89 | 0 | while(null == obj) { |
| 90 | 0 | if(_pool.isEmpty()) { |
| 91 | 0 | if(null == _factory) { |
| 92 | 0 | throw new NoSuchElementException(); |
| 93 | } else { | |
| 94 | 0 | newlyCreated = true; |
| 95 | 0 | obj = _factory.makeObject(); |
| 96 | } | |
| 97 | } else { | |
| 98 | 0 | SoftReference ref = (SoftReference)(_pool.remove(_pool.size() - 1)); |
| 99 | 0 | obj = ref.get(); |
| 100 | 0 | ref.clear(); // prevent this ref from being enqueued with refQueue. |
| 101 | } | |
| 102 | 0 | if (null != _factory && null != obj) { |
| 103 | try { | |
| 104 | 0 | _factory.activateObject(obj); |
| 105 | 0 | if (!_factory.validateObject(obj)) { |
| 106 | 0 | throw new Exception("ValidateObject failed"); |
| 107 | } | |
| 108 | 0 | } catch (Throwable t) { |
| 109 | try { | |
| 110 | 0 | _factory.destroyObject(obj); |
| 111 | 0 | } catch (Throwable t2) { |
| 112 | // swallowed | |
| 113 | } finally { | |
| 114 | 0 | obj = null; |
| 115 | 0 | } |
| 116 | 0 | if (newlyCreated) { |
| 117 | 0 | throw new NoSuchElementException( |
| 118 | "Could not create a validated object, cause: " + | |
| 119 | t.getMessage()); | |
| 120 | } | |
| 121 | 0 | } |
| 122 | } | |
| 123 | } | |
| 124 | 0 | _numActive++; |
| 125 | 0 | return obj; |
| 126 | } | |
| 127 | ||
| 128 | public synchronized void returnObject(Object obj) throws Exception { | |
| 129 | 0 | boolean success = !isClosed(); |
| 130 | 0 | if (_factory != null) { |
| 131 | 0 | if(!_factory.validateObject(obj)) { |
| 132 | 0 | success = false; |
| 133 | } else { | |
| 134 | try { | |
| 135 | 0 | _factory.passivateObject(obj); |
| 136 | 0 | } catch(Exception e) { |
| 137 | 0 | success = false; |
| 138 | 0 | } |
| 139 | } | |
| 140 | } | |
| 141 | ||
| 142 | 0 | boolean shouldDestroy = !success; |
| 143 | 0 | _numActive--; |
| 144 | 0 | if(success) { |
| 145 | 0 | _pool.add(new SoftReference(obj, refQueue)); |
| 146 | } | |
| 147 | 0 | notifyAll(); // _numActive has changed |
| 148 | ||
| 149 | 0 | if (shouldDestroy && _factory != null) { |
| 150 | try { | |
| 151 | 0 | _factory.destroyObject(obj); |
| 152 | 0 | } catch(Exception e) { |
| 153 | // ignored | |
| 154 | 0 | } |
| 155 | } | |
| 156 | 0 | } |
| 157 | ||
| 158 | public synchronized void invalidateObject(Object obj) throws Exception { | |
| 159 | 0 | _numActive--; |
| 160 | 0 | if (_factory != null) { |
| 161 | 0 | _factory.destroyObject(obj); |
| 162 | } | |
| 163 | 0 | notifyAll(); // _numActive has changed |
| 164 | 0 | } |
| 165 | ||
| 166 | /** | |
| 167 | * Create an object, and place it into the pool. | |
| 168 | * addObject() is useful for "pre-loading" a pool with idle objects. | |
| 169 | */ | |
| 170 | public synchronized void addObject() throws Exception { | |
| 171 | 0 | assertOpen(); |
| 172 | 0 | if (_factory == null) { |
| 173 | 0 | throw new IllegalStateException("Cannot add objects without a factory."); |
| 174 | } | |
| 175 | 0 | Object obj = _factory.makeObject(); |
| 176 | ||
| 177 | 0 | boolean success = true; |
| 178 | 0 | if(!_factory.validateObject(obj)) { |
| 179 | 0 | success = false; |
| 180 | } else { | |
| 181 | 0 | _factory.passivateObject(obj); |
| 182 | } | |
| 183 | ||
| 184 | 0 | boolean shouldDestroy = !success; |
| 185 | 0 | if(success) { |
| 186 | 0 | _pool.add(new SoftReference(obj, refQueue)); |
| 187 | 0 | notifyAll(); // _numActive has changed |
| 188 | } | |
| 189 | ||
| 190 | 0 | if(shouldDestroy) { |
| 191 | try { | |
| 192 | 0 | _factory.destroyObject(obj); |
| 193 | 0 | } catch(Exception e) { |
| 194 | // ignored | |
| 195 | 0 | } |
| 196 | } | |
| 197 | 0 | } |
| 198 | ||
| 199 | /** Returns an approximation not less than the of the number of idle instances in the pool. */ | |
| 200 | public synchronized int getNumIdle() { | |
| 201 | 0 | pruneClearedReferences(); |
| 202 | 0 | return _pool.size(); |
| 203 | } | |
| 204 | ||
| 205 | /** | |
| 206 | * Return the number of instances currently borrowed from this pool. | |
| 207 | * | |
| 208 | * @return the number of instances currently borrowed from this pool | |
| 209 | */ | |
| 210 | public synchronized int getNumActive() { | |
| 211 | 0 | return _numActive; |
| 212 | } | |
| 213 | ||
| 214 | /** | |
| 215 | * Clears any objects sitting idle in the pool. | |
| 216 | */ | |
| 217 | public synchronized void clear() { | |
| 218 | 0 | if(null != _factory) { |
| 219 | 0 | Iterator iter = _pool.iterator(); |
| 220 | 0 | while(iter.hasNext()) { |
| 221 | try { | |
| 222 | 0 | Object obj = ((SoftReference)iter.next()).get(); |
| 223 | 0 | if(null != obj) { |
| 224 | 0 | _factory.destroyObject(obj); |
| 225 | } | |
| 226 | 0 | } catch(Exception e) { |
| 227 | // ignore error, keep destroying the rest | |
| 228 | 0 | } |
| 229 | } | |
| 230 | } | |
| 231 | 0 | _pool.clear(); |
| 232 | 0 | pruneClearedReferences(); |
| 233 | 0 | } |
| 234 | ||
| 235 | public void close() throws Exception { | |
| 236 | 0 | super.close(); |
| 237 | 0 | clear(); |
| 238 | 0 | } |
| 239 | ||
| 240 | /** | |
| 241 | * Sets the {@link PoolableObjectFactory factory} this pool uses | |
| 242 | * to create new instances. Trying to change | |
| 243 | * the <code>factory</code> while there are borrowed objects will | |
| 244 | * throw an {@link IllegalStateException}. | |
| 245 | * | |
| 246 | * @param factory the {@link PoolableObjectFactory} used to create new instances. | |
| 247 | * @throws IllegalStateException when the factory cannot be set at this time | |
| 248 | */ | |
| 249 | public synchronized void setFactory(PoolableObjectFactory factory) throws IllegalStateException { | |
| 250 | 0 | assertOpen(); |
| 251 | 0 | if(0 < getNumActive()) { |
| 252 | 0 | throw new IllegalStateException("Objects are already active"); |
| 253 | } else { | |
| 254 | 0 | clear(); |
| 255 | 0 | _factory = factory; |
| 256 | } | |
| 257 | 0 | } |
| 258 | ||
| 259 | /** | |
| 260 | * If any idle objects were garbage collected, remove their | |
| 261 | * {@link Reference} wrappers from the idle object pool. | |
| 262 | */ | |
| 263 | private void pruneClearedReferences() { | |
| 264 | Reference ref; | |
| 265 | 0 | while ((ref = refQueue.poll()) != null) { |
| 266 | try { | |
| 267 | 0 | _pool.remove(ref); |
| 268 | 0 | } catch (UnsupportedOperationException uoe) { |
| 269 | // ignored | |
| 270 | 0 | } |
| 271 | } | |
| 272 | 0 | } |
| 273 | ||
| 274 | /** My pool. */ | |
| 275 | 0 | private List _pool = null; |
| 276 | ||
| 277 | /** My {@link PoolableObjectFactory}. */ | |
| 278 | 0 | private PoolableObjectFactory _factory = null; |
| 279 | ||
| 280 | /** | |
| 281 | * Queue of broken references that might be able to be removed from <code>_pool</code>. | |
| 282 | * This is used to help {@link #getNumIdle()} be more accurate with minimial | |
| 283 | * performance overhead. | |
| 284 | */ | |
| 285 | 0 | private final ReferenceQueue refQueue = new ReferenceQueue(); |
| 286 | ||
| 287 | /** Number of active objects. */ | |
| 288 | 0 | private int _numActive = 0; |
| 289 | } |