1 10 package org.picocontainer.gems.adapters; 11 12 import java.io.ByteArrayOutputStream ; 13 import java.io.IOException ; 14 import java.io.NotSerializableException ; 15 import java.io.ObjectInputStream ; 16 import java.io.ObjectOutputStream ; 17 import java.io.Serializable ; 18 import java.util.ArrayList ; 19 import java.util.Iterator ; 20 import java.util.List ; 21 22 import org.picocontainer.ComponentAdapter; 23 import org.picocontainer.LifecycleManager; 24 import org.picocontainer.PicoContainer; 25 import org.picocontainer.defaults.DecoratingComponentAdapter; 26 import org.picocontainer.defaults.LifecycleStrategy; 27 28 import com.thoughtworks.proxy.ProxyFactory; 29 import com.thoughtworks.proxy.factory.StandardProxyFactory; 30 import com.thoughtworks.proxy.kit.NoOperationResetter; 31 import com.thoughtworks.proxy.kit.Resetter; 32 import com.thoughtworks.proxy.toys.nullobject.Null; 33 import com.thoughtworks.proxy.toys.pool.Pool; 34 35 36 72 public class PoolingComponentAdapter extends DecoratingComponentAdapter implements LifecycleManager { 73 74 private static final long serialVersionUID = 1L; 75 76 82 public static interface Context { 83 90 int getMaxSize(); 91 92 100 int getMaxWaitInMilliseconds(); 101 102 109 boolean autostartGC(); 110 111 117 ProxyFactory getProxyFactory(); 118 119 125 Resetter getResetter(); 126 127 138 int getSerializationMode(); 139 } 140 141 147 public static class DefaultContext implements Context { 148 149 152 public int getMaxSize() { 153 return DEFAULT_MAX_SIZE; 154 } 155 156 159 public int getMaxWaitInMilliseconds() { 160 return FAIL_ON_WAIT; 161 } 162 163 166 public boolean autostartGC() { 167 return false; 168 } 169 170 173 public ProxyFactory getProxyFactory() { 174 return new StandardProxyFactory(); 175 } 176 177 180 public Resetter getResetter() { 181 return DEFAULT_RESETTER; 182 } 183 184 187 public int getSerializationMode() { 188 return Pool.SERIALIZATION_STANDARD; 189 } 190 191 } 192 193 197 public static final int UNLIMITED_SIZE = Integer.MAX_VALUE; 198 201 public static final int DEFAULT_MAX_SIZE = 8; 202 206 public static final int BLOCK_ON_WAIT = 0; 207 210 public static final int FAIL_ON_WAIT = -1; 211 214 public static final Resetter DEFAULT_RESETTER = new NoOperationResetter(); 215 216 private int maxPoolSize; 217 private int waitMilliSeconds; 218 private Pool pool; 219 private int serializationMode; 220 private boolean autostartGC; 221 private boolean started; 222 private boolean disposed; 223 private boolean delegateHasLifecylce; 224 private transient List components; 225 226 232 public PoolingComponentAdapter(ComponentAdapter delegate) { 233 this(delegate, new DefaultContext()); 234 } 235 236 248 public PoolingComponentAdapter(ComponentAdapter delegate, Context context) { 249 super(delegate); 250 this.maxPoolSize = context.getMaxSize(); 251 this.waitMilliSeconds = context.getMaxWaitInMilliseconds(); 252 this.autostartGC = context.autostartGC(); 253 this.serializationMode = context.getSerializationMode(); 254 if (maxPoolSize <= 0) { 255 throw new IllegalArgumentException ("Invalid maximum pool size"); 256 } 257 started = false; 258 disposed = false; 259 delegateHasLifecylce = delegate instanceof LifecycleStrategy 260 && ((LifecycleStrategy)delegate) 261 .hasLifecycle(delegate.getComponentImplementation()); 262 components = new ArrayList (); 263 264 final Class type = delegate.getComponentKey() instanceof Class ? (Class )delegate 265 .getComponentKey() : delegate.getComponentImplementation(); 266 final Resetter resetter = context.getResetter(); 267 this.pool = new Pool(type, delegateHasLifecylce ? new LifecycleResetter( 268 this, resetter) : resetter, context.getProxyFactory(), serializationMode); 269 } 270 271 276 protected PoolingComponentAdapter() { 277 super((ComponentAdapter)Null.object(ComponentAdapter.class)); 279 } 280 281 293 public Object getComponentInstance(PicoContainer container) { 294 if (delegateHasLifecylce) { 295 if (disposed) throw new IllegalStateException ("Already disposed"); 296 } 297 Object componentInstance = null; 298 long now = System.currentTimeMillis(); 299 boolean gc = autostartGC; 300 while (true) { 301 synchronized (pool) { 302 componentInstance = pool.get(); 303 if (componentInstance != null) { 304 break; 305 } 306 if (maxPoolSize > pool.size()) { 307 final Object component = super.getComponentInstance(container); 308 if (delegateHasLifecylce) { 309 components.add(component); 310 if (started) { 311 start(component); 312 } 313 } 314 pool.add(component); 315 } else if (!gc) { 316 long after = System.currentTimeMillis(); 317 if (waitMilliSeconds < 0) { 318 throw new PoolException("Pool exhausted"); 319 } 320 if (waitMilliSeconds > 0 && after - now > waitMilliSeconds) { 321 throw new PoolException("Time out wating for returning object into pool"); 322 } 323 try { 324 pool.wait(waitMilliSeconds); } catch (InterruptedException e) { 327 Thread.currentThread().interrupt(); 329 throw new PoolException( 330 "Interrupted waiting for returning object into the pool", e); 331 } 332 } else { 333 System.gc(); 334 gc = false; 335 } 336 } 337 } 338 return componentInstance; 339 } 340 341 348 public int size() { 349 return pool.size(); 350 } 351 352 static class LifecycleResetter implements Resetter, Serializable { 353 private static final long serialVersionUID = 1L; 354 private Resetter delegate; 355 private PoolingComponentAdapter adapter; 356 357 LifecycleResetter(final PoolingComponentAdapter adapter, final Resetter delegate) { 358 this.adapter = adapter; 359 this.delegate = delegate; 360 } 361 362 public boolean reset(Object object) { 363 final boolean result = delegate.reset(object); 364 if (!result || adapter.disposed) { 365 if (adapter.started) { 366 adapter.stop(object); 367 } 368 adapter.components.remove(object); 369 if (!adapter.disposed) { 370 adapter.dispose(object); 371 } 372 } 373 return result && !adapter.disposed; 374 } 375 376 } 377 378 385 public void start(final PicoContainer container) { 386 if (delegateHasLifecylce) { 387 if (started) throw new IllegalStateException ("Already started"); 388 if (disposed) throw new IllegalStateException ("Already disposed"); 389 for (final Iterator iter = components.iterator(); iter.hasNext();) { 390 start(iter.next()); 391 } 392 started = true; 393 if (pool.size() == 0) { 394 getComponentInstance(container); 395 } 396 } 397 } 398 399 405 public void stop(final PicoContainer container) { 406 if (delegateHasLifecylce) { 407 if (!started) throw new IllegalStateException ("Not started yet"); 408 if (disposed) throw new IllegalStateException ("Already disposed"); 409 for (final Iterator iter = components.iterator(); iter.hasNext();) { 410 stop(iter.next()); 411 } 412 started = false; 413 } 414 } 415 416 423 public void dispose(final PicoContainer container) { 424 if (delegateHasLifecylce) { 425 if (started) throw new IllegalStateException ("Not stopped yet"); 426 if (disposed) throw new IllegalStateException ("Already disposed"); 427 disposed = true; 428 for (final Iterator iter = components.iterator(); iter.hasNext();) { 429 dispose(iter.next()); 430 } 431 } 433 } 434 435 private synchronized void writeObject(final ObjectOutputStream out) throws IOException { 436 out.defaultWriteObject(); 437 int mode = serializationMode; 438 if (mode == Pool.SERIALIZATION_FORCE && components.size() > 0) { 439 try { 440 final ByteArrayOutputStream buffer = new ByteArrayOutputStream (); 441 final ObjectOutputStream testStream = new ObjectOutputStream (buffer); 442 testStream.writeObject(components); testStream.close(); 444 } catch (final NotSerializableException e) { 445 mode = Pool.SERIALIZATION_NONE; 446 } 447 } 448 if (mode == Pool.SERIALIZATION_STANDARD) { 449 out.writeObject(components); 450 } else { 451 out.writeObject(new ArrayList ()); 452 } 453 } 454 455 private void readObject(final ObjectInputStream in) throws IOException , ClassNotFoundException { 456 in.defaultReadObject(); 457 components = (List )in.readObject(); 458 } 459 } 460 | Popular Tags |