/* */ package org.jboss.resource.connectionmanager;
/* */
/* */ import EDU.oswego.cs.dl.util.concurrent.FIFOSemaphore;
/* */ import EDU.oswego.cs.dl.util.concurrent.SynchronizedBoolean;
/* */ import java.util.ArrayList;
/* */ import java.util.Collections;
/* */ import java.util.HashSet;
/* */ import java.util.Iterator;
/* */ import java.util.Set;
/* */ import javax.resource.ResourceException;
/* */ import javax.resource.spi.ConnectionRequestInfo;
/* */ import javax.resource.spi.ManagedConnection;
/* */ import javax.resource.spi.ManagedConnectionFactory;
/* */ import javax.resource.spi.ValidatingManagedConnectionFactory;
/* */ import javax.security.auth.Subject;
/* */ import org.jboss.logging.Logger;
/* */ import org.jboss.resource.JBossResourceException;
/* */ import org.jboss.util.UnreachableStatementException;
/* */
/* */ public class InternalManagedConnectionPool
/* */ implements IdleConnectionRemovalSupport
/* */ {
/* */ private final ManagedConnectionFactory mcf;
/* */ private final ConnectionListenerFactory clf;
/* */ private final Subject defaultSubject;
/* */ private final ConnectionRequestInfo defaultCri;
/* */ private final PoolParams poolParams;
/* */ private int maxSize;
/* */ private ArrayList cls;
/* */ private final FIFOSemaphore permits;
/* */ private final Logger log;
/* */ private final boolean trace;
/* 88 */ private final Counter connectionCounter = new Counter(null);
/* */
/* 91 */ private final HashSet checkedOut = new HashSet();
/* */
/* 94 */ private boolean started = false;
/* */
/* 97 */ private SynchronizedBoolean shutdown = new SynchronizedBoolean(false);
/* */
/* 100 */ private volatile int maxUsedConnections = 0;
/* */
/* */ protected InternalManagedConnectionPool(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject, ConnectionRequestInfo cri, PoolParams poolParams, Logger log)
/* */ {
/* 114 */ this.mcf = mcf;
/* 115 */ this.clf = clf;
/* 116 */ this.defaultSubject = subject;
/* 117 */ this.defaultCri = cri;
/* 118 */ this.poolParams = poolParams;
/* 119 */ this.maxSize = poolParams.maxSize;
/* 120 */ this.log = log;
/* 121 */ this.trace = log.isTraceEnabled();
/* 122 */ this.cls = new ArrayList(this.maxSize);
/* 123 */ this.permits = new FIFOSemaphore(this.maxSize);
/* */
/* 125 */ if (poolParams.prefill)
/* */ {
/* 127 */ PoolFiller.fillPool(this);
/* */ }
/* */ }
/* */
/* */ protected void initialize()
/* */ {
/* 137 */ if (this.poolParams.idleTimeout != 0L) {
/* 138 */ IdleRemover.registerPool(this, this.poolParams.idleTimeout);
/* */ }
/* 140 */ if (this.poolParams.backgroundValidation)
/* */ {
/* 143 */ this.log.debug("Registering for background validation at interval " + this.poolParams.backgroundInterval);
/* 144 */ ConnectionValidator.registerPool(this, this.poolParams.backgroundInterval);
/* */ }
/* */ }
/* */
/* */ public long getAvailableConnections()
/* */ {
/* 151 */ return this.permits.permits();
/* */ }
/* */
/* */ public int getMaxConnectionsInUseCount()
/* */ {
/* 156 */ return this.maxUsedConnections;
/* */ }
/* */
/* */ public int getConnectionInUseCount()
/* */ {
/* 161 */ return this.checkedOut.size();
/* */ }
/* */ public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException {
/* 171 */ subject = subject == null ? this.defaultSubject : subject;
/* 172 */ cri = cri == null ? this.defaultCri : cri;
/* 173 */ long startWait = System.currentTimeMillis();
/* */ long end;
/* */ try { this.connectionCounter.updateBlockTime(System.currentTimeMillis() - startWait);
/* */
/* 178 */ if (this.permits.attempt(this.poolParams.blockingTimeout))
/* */ {
/* 181 */ ConnectionListener cl = null;
/* */ do
/* */ {
/* 184 */ synchronized (this.cls)
/* */ {
/* 186 */ if (this.shutdown.get())
/* */ {
/* 188 */ this.permits.release();
/* 189 */ throw new ResourceException("The pool has been shutdown");
/* */ }
/* */
/* 192 */ if (this.cls.size() > 0)
/* */ {
/* 194 */ cl = (ConnectionListener)this.cls.remove(this.cls.size() - 1);
/* 195 */ this.checkedOut.add(cl);
/* 196 */ int size = (int)(this.maxSize - this.permits.permits());
/* 197 */ if (size > this.maxUsedConnections)
/* 198 */ this.maxUsedConnections = size;
/* */ }
/* */ }
/* 201 */ if (cl == null) {
/* */ continue;
/* */ }
/* */ try
/* */ {
/* 206 */ Object matchedMC = this.mcf.matchManagedConnections(Collections.singleton(cl.getManagedConnection()), subject, cri);
/* */
/* 208 */ if (matchedMC != null)
/* */ {
/* 210 */ if (this.trace)
/* 211 */ this.log.trace("supplying ManagedConnection from pool: " + cl);
/* 212 */ cl.grantPermit(true);
/* 213 */ return cl;
/* */ }
/* */
/* 221 */ this.log.warn("Destroying connection that could not be successfully matched: " + cl);
/* 222 */ synchronized (this.cls)
/* */ {
/* 224 */ this.checkedOut.remove(cl);
/* */ }
/* 226 */ doDestroy(cl);
/* 227 */ cl = null;
/* */ }
/* */ catch (Throwable t)
/* */ {
/* 231 */ this.log.warn("Throwable while trying to match ManagedConnection, destroying connection: " + cl, t);
/* 232 */ synchronized (this.cls)
/* */ {
/* 234 */ this.checkedOut.remove(cl);
/* */ }
/* 236 */ doDestroy(cl);
/* 237 */ cl = null;
/* */ }
/* */
/* 240 */ if (!this.poolParams.useFastFail)
/* */ continue;
/* 242 */ this.log.trace("Fast failing for connection attempt. No more attempts will be made to acquire connection from pool and a new connection will be created immeadiately");
/* 243 */ break;
/* */ }
/* */
/* 248 */ while (this.cls.size() > 0);
/* */ try
/* */ {
/* 254 */ cl = createConnectionEventListener(subject, cri);
/* 255 */ synchronized (this.cls)
/* */ {
/* 257 */ this.checkedOut.add(cl);
/* 258 */ int size = (int)(this.maxSize - this.permits.permits());
/* 259 */ if (size > this.maxUsedConnections) {
/* 260 */ this.maxUsedConnections = size;
/* */ }
/* */
/* */ }
/* */
/* 265 */ if (!this.started)
/* */ {
/* 267 */ this.started = true;
/* 268 */ if (this.poolParams.minSize > 0)
/* 269 */ PoolFiller.fillPool(this);
/* */ }
/* 271 */ if (this.trace)
/* 272 */ this.log.trace("supplying new ManagedConnection: " + cl);
/* 273 */ cl.grantPermit(true);
/* 274 */ return cl;
/* */ }
/* */ catch (Throwable t)
/* */ {
/* 278 */ this.log.warn("Throwable while attempting to get a new connection: " + cl, t);
/* */
/* 280 */ synchronized (this.cls)
/* */ {
/* 282 */ this.checkedOut.remove(cl);
/* */ }
/* 284 */ this.permits.release();
/* 285 */ JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying to create a connection: " + cl, t);
/* 286 */ throw new UnreachableStatementException();
/* */ }
/* */
/* */ }
/* */
/* 292 */ throw new ResourceException("No ManagedConnections available within configured blocking timeout ( " + this.poolParams.blockingTimeout + " [ms] )");
/* */ }
/* */ catch (InterruptedException ie)
/* */ {
/* 299 */ end = System.currentTimeMillis() - startWait;
/* 300 */ }throw new ResourceException("Interrupted while requesting permit! Waited " + end + " ms");
/* */ }
/* */
/* */ public void returnConnection(ConnectionListener cl, boolean kill)
/* */ {
/* 306 */ synchronized (this.cls)
/* */ {
/* 308 */ if (cl.getState() == 2)
/* */ {
/* 310 */ if (this.trace)
/* 311 */ this.log.trace("ManagedConnection is being returned after it was destroyed" + cl);
/* 312 */ if (cl.hasPermit())
/* */ {
/* 315 */ cl.grantPermit(false);
/* 316 */ this.permits.release();
/* */ }
/* */
/* 319 */ return;
/* */ }
/* */ }
/* */
/* 323 */ if (this.trace)
/* 324 */ this.log.trace("putting ManagedConnection back into pool kill=" + kill + " cl=" + cl);
/* */ try
/* */ {
/* 327 */ cl.getManagedConnection().cleanup();
/* */ }
/* */ catch (ResourceException re)
/* */ {
/* 331 */ this.log.warn("ResourceException cleaning up ManagedConnection: " + cl, re);
/* 332 */ kill = true;
/* */ }
/* */
/* 335 */ synchronized (this.cls)
/* */ {
/* 338 */ if ((cl.getState() == 1) || (cl.getState() == 2))
/* 339 */ kill = true;
/* 340 */ this.checkedOut.remove(cl);
/* */
/* 343 */ if ((!kill) && (this.cls.size() >= this.poolParams.maxSize))
/* */ {
/* 345 */ this.log.warn("Destroying returned connection, maximum pool size exceeded " + cl);
/* 346 */ kill = true;
/* */ }
/* */
/* 350 */ if (kill)
/* */ {
/* 357 */ this.cls.remove(cl);
/* */ }
/* */ else
/* */ {
/* 362 */ cl.used();
/* 363 */ if (!this.cls.contains(cl)) {
/* 364 */ this.cls.add(cl);
/* */ }
/* */ }
/* 367 */ if (cl.hasPermit())
/* */ {
/* 370 */ cl.grantPermit(false);
/* 371 */ this.permits.release();
/* */ }
/* */ }
/* */
/* 375 */ if (kill)
/* */ {
/* 377 */ if (this.trace)
/* 378 */ this.log.trace("Destroying returned connection " + cl);
/* 379 */ doDestroy(cl);
/* */ }
/* */ }
/* */
/* */ public void flush()
/* */ {
/* 386 */ ArrayList destroy = null;
/* 387 */ synchronized (this.cls)
/* */ {
/* 389 */ if (this.trace) {
/* 390 */ this.log.trace("Flushing pool checkedOut=" + this.checkedOut + " inPool=" + this.cls);
/* */ }
/* */
/* 393 */ for (Iterator i = this.checkedOut.iterator(); i.hasNext(); )
/* */ {
/* 395 */ ConnectionListener cl = (ConnectionListener)i.next();
/* 396 */ if (this.trace)
/* 397 */ this.log.trace("Flush marking checked out connection for destruction " + cl);
/* 398 */ cl.setState(1);
/* */ }
/* */
/* 401 */ while (this.cls.size() > 0)
/* */ {
/* 403 */ ConnectionListener cl = (ConnectionListener)this.cls.remove(0);
/* 404 */ if (destroy == null)
/* 405 */ destroy = new ArrayList();
/* 406 */ destroy.add(cl);
/* */ }
/* */
/* */ }
/* */
/* 411 */ if (destroy != null)
/* */ {
/* 413 */ for (int i = 0; i < destroy.size(); i++)
/* */ {
/* 415 */ ConnectionListener cl = (ConnectionListener)destroy.get(i);
/* 416 */ if (this.trace)
/* 417 */ this.log.trace("Destroying flushed connection " + cl);
/* 418 */ doDestroy(cl);
/* */ }
/* */
/* 422 */ if ((!this.shutdown.get()) && (this.poolParams.minSize > 0))
/* 423 */ PoolFiller.fillPool(this);
/* */ }
/* */ }
/* */
/* */ public void removeIdleConnections()
/* */ {
/* 429 */ ArrayList destroy = null;
/* 430 */ long timeout = System.currentTimeMillis() - this.poolParams.idleTimeout;
/* */ while (true)
/* */ {
/* 433 */ synchronized (this.cls)
/* */ {
/* 437 */ if (this.cls.size() == 0)
/* */ {
/* */ break;
/* */ }
/* 441 */ ConnectionListener cl = (ConnectionListener)this.cls.get(0);
/* 442 */ if ((!cl.isTimedOut(timeout)) || (!shouldRemove()))
/* */ continue;
/* 444 */ this.connectionCounter.incTimedOut();
/* */
/* 446 */ this.cls.remove(0);
/* 447 */ if (destroy == null)
/* 448 */ destroy = new ArrayList();
/* 449 */ destroy.add(cl); continue;
/* */
/* 454 */ break;
/* */ }
/* */
/* */ }
/* */
/* 460 */ if (destroy != null)
/* */ {
/* 462 */ for (int i = 0; i < destroy.size(); i++)
/* */ {
/* 464 */ ConnectionListener cl = (ConnectionListener)destroy.get(i);
/* 465 */ if (this.trace)
/* 466 */ this.log.trace("Destroying timedout connection " + cl);
/* 467 */ doDestroy(cl);
/* */ }
/* */
/* 471 */ if ((!this.shutdown.get()) && (this.poolParams.minSize > 0))
/* 472 */ PoolFiller.fillPool(this);
/* */ }
/* */ }
/* */
/* */ public void shutdownWithoutClear()
/* */ {
/* 482 */ IdleRemover.unregisterPool(this);
/* 483 */ IdleRemover.waitForBackgroundThread();
/* 484 */ ConnectionValidator.unRegisterPool(this);
/* 485 */ ConnectionValidator.waitForBackgroundThread();
/* */
/* 487 */ fillToMin();
/* 488 */ this.shutdown.set(true);
/* */ }
/* */
/* */ public void shutdown()
/* */ {
/* 493 */ this.shutdown.set(true);
/* 494 */ IdleRemover.unregisterPool(this);
/* 495 */ ConnectionValidator.unRegisterPool(this);
/* 496 */ flush();
/* */ }
/* */
/* */ public void fillToMin()
/* */ {
/* */ while (true)
/* */ try
/* */ {
/* 507 */ if (!this.permits.attempt(this.poolParams.blockingTimeout))
/* */ continue;
/* */ try
/* */ {
/* 511 */ if (this.shutdown.get()) {
/* */ return;
/* */ }
/* 515 */ if (getMinSize() - this.connectionCounter.getGuaranteedCount() <= 0) {
/* */ return;
/* */ }
/* */ try
/* */ {
/* 521 */ ConnectionListener cl = createConnectionEventListener(this.defaultSubject, this.defaultCri);
/* 522 */ synchronized (this.cls)
/* */ {
/* 524 */ if (this.trace)
/* 525 */ this.log.trace("Filling pool cl=" + cl);
/* 526 */ this.cls.add(cl);
/* */ }
/* */ }
/* */ catch (ResourceException re)
/* */ {
/* 531 */ this.log.warn("Unable to fill pool ", re);
/* */
/* 537 */ this.permits.release(); return;
/* */ } } finally { this.permits.release();
/* */ }
/* */
/* 544 */ continue;
/* */ }
/* */ catch (InterruptedException ignored)
/* */ {
/* 543 */ this.log.trace("Interrupted while requesting permit in fillToMin");
/* */ }
/* */ }
/* */
/* */ public int getConnectionCount()
/* */ {
/* 550 */ return this.connectionCounter.getCount();
/* */ }
/* */
/* */ public long getTotalBlockTime()
/* */ {
/* 555 */ return this.connectionCounter.getTotalBlockTime();
/* */ }
/* */
/* */ public int getTimedOut()
/* */ {
/* 561 */ return this.connectionCounter.getTimedOut();
/* */ }
/* */
/* */ public long getAverageBlockTime()
/* */ {
/* 566 */ return this.connectionCounter.getTotalBlockTime() / getConnectionCreatedCount();
/* */ }
/* */
/* */ public int getConnectionCreatedCount()
/* */ {
/* 571 */ return this.connectionCounter.getCreatedCount();
/* */ }
/* */
/* */ public int getConnectionDestroyedCount()
/* */ {
/* 576 */ return this.connectionCounter.getDestroyedCount();
/* */ }
/* */
/* */ private ConnectionListener createConnectionEventListener(Subject subject, ConnectionRequestInfo cri)
/* */ throws ResourceException
/* */ {
/* 590 */ ManagedConnection mc = this.mcf.createManagedConnection(subject, cri);
/* 591 */ this.connectionCounter.inc();
/* */ try
/* */ {
/* 594 */ return this.clf.createConnectionListener(mc, this);
/* */ }
/* */ catch (ResourceException re)
/* */ {
/* 598 */ this.connectionCounter.dec();
/* 599 */ mc.destroy();
/* 600 */ }throw re;
/* */ }
/* */
/* */ private void doDestroy(ConnectionListener cl)
/* */ {
/* 611 */ if (cl.getState() == 2)
/* */ {
/* 613 */ this.log.trace("ManagedConnection is already destroyed " + cl);
/* 614 */ return;
/* */ }
/* */
/* 617 */ this.connectionCounter.dec();
/* 618 */ cl.setState(2);
/* */ try
/* */ {
/* 621 */ cl.getManagedConnection().destroy();
/* */ }
/* */ catch (Throwable t)
/* */ {
/* 625 */ this.log.warn("Exception destroying ManagedConnection " + cl, t);
/* */ }
/* */ }
/* */
/* */ private boolean shouldRemove()
/* */ {
/* 632 */ boolean remove = true;
/* */
/* 634 */ if (this.poolParams.stictMin)
/* */ {
/* 636 */ remove = this.cls.size() > this.poolParams.minSize;
/* */
/* 638 */ this.log.trace("StrictMin is active. Current connection will be removed is " + remove);
/* */ }
/* */
/* 642 */ return remove;
/* */ }
/* */
/* */ public void validateConnections()
/* */ throws Exception
/* */ {
/* 649 */ if (this.trace) {
/* 650 */ this.log.trace("Attempting to validate connections for pool " + this);
/* */ }
/* 652 */ if (this.permits.attempt(this.poolParams.blockingTimeout))
/* */ {
/* 655 */ boolean destroyed = false;
/* */ try
/* */ {
/* */ while (true)
/* */ {
/* 663 */ ConnectionListener cl = null;
/* */
/* 665 */ synchronized (this.cls)
/* */ {
/* 667 */ if (this.cls.size() == 0)
/* */ {
/* */ break;
/* */ }
/* */
/* 674 */ cl = removeForFrequencyCheck();
/* */ }
/* */
/* 678 */ if (cl == null)
/* */ {
/* */ break;
/* */ }
/* */
/* */ try
/* */ {
/* 687 */ Set candidateSet = Collections.singleton(cl.getManagedConnection());
/* */
/* 689 */ if ((this.mcf instanceof ValidatingManagedConnectionFactory))
/* */ {
/* 691 */ ValidatingManagedConnectionFactory vcf = (ValidatingManagedConnectionFactory)this.mcf;
/* 692 */ candidateSet = vcf.getInvalidConnections(candidateSet);
/* */
/* 694 */ if ((candidateSet != null) && (candidateSet.size() > 0))
/* */ {
/* 697 */ if (cl.getState() != 1)
/* */ {
/* 699 */ doDestroy(cl);
/* 700 */ destroyed = true;
/* */ }
/* */
/* */ }
/* */
/* */ }
/* */ else
/* */ {
/* 708 */ this.log.warn("warning: background validation was specified with a non compliant ManagedConnectionFactory interface.");
/* */ }
/* */
/* */ }
/* */ finally
/* */ {
/* 714 */ if (!destroyed)
/* */ {
/* 716 */ synchronized (this.cls)
/* */ {
/* 718 */ returnForFrequencyCheck(cl);
/* */ }
/* */
/* */ }
/* */
/* */ }
/* */
/* */ }
/* */
/* */ }
/* */ finally
/* */ {
/* 730 */ this.permits.release();
/* */
/* 732 */ if ((destroyed) && (!this.shutdown.get()) && (this.poolParams.minSize > 0))
/* */ {
/* 734 */ PoolFiller.fillPool(this);
/* */ }
/* */ }
/* */ }
/* */ }
/* */
/* */ private ConnectionListener removeForFrequencyCheck()
/* */ {
/* 745 */ this.log.debug("Checking for connection within frequency");
/* */
/* 747 */ ConnectionListener cl = null;
/* */
/* 749 */ for (Iterator iter = this.cls.iterator(); iter.hasNext(); )
/* */ {
/* 752 */ cl = (ConnectionListener)iter.next();
/* 753 */ long lastCheck = cl.getLastValidatedTime();
/* */
/* 755 */ if (System.currentTimeMillis() - lastCheck >= this.poolParams.backgroundInterval)
/* */ {
/* 757 */ this.cls.remove(cl);
/* 758 */ break;
/* */ }
/* */
/* 763 */ cl = null;
/* */ }
/* */
/* 768 */ return cl;
/* */ }
/* */
/* */ private void returnForFrequencyCheck(ConnectionListener cl)
/* */ {
/* 774 */ this.log.debug("Returning for connection within frequency");
/* */
/* 776 */ cl.setLastValidatedTime(System.currentTimeMillis());
/* 777 */ this.cls.add(cl);
/* */ }
/* */
/* */ private int getMinSize()
/* */ {
/* 787 */ if (this.poolParams.minSize > this.maxSize) {
/* 788 */ return this.maxSize;
/* */ }
/* 790 */ return this.poolParams.minSize;
/* */ }
/* */
/* */ private static class Counter {
/* 820 */ private int created = 0;
/* */
/* 822 */ private int destroyed = 0;
/* */ private long totalBlockTime;
/* */ private int timedOut;
/* */
/* */ synchronized int getGuaranteedCount() {
/* 830 */ return this.created - this.destroyed;
/* */ }
/* */
/* */ int getCount()
/* */ {
/* 835 */ return this.created - this.destroyed;
/* */ }
/* */
/* */ int getCreatedCount()
/* */ {
/* 840 */ return this.created;
/* */ }
/* */
/* */ int getDestroyedCount()
/* */ {
/* 845 */ return this.destroyed;
/* */ }
/* */
/* */ synchronized void inc()
/* */ {
/* 850 */ this.created += 1;
/* */ }
/* */
/* */ synchronized void dec()
/* */ {
/* 855 */ this.destroyed += 1;
/* */ }
/* */
/* */ synchronized void updateBlockTime(long latest)
/* */ {
/* 860 */ this.totalBlockTime += latest;
/* */ }
/* */
/* */ long getTotalBlockTime()
/* */ {
/* 866 */ return this.totalBlockTime;
/* */ }
/* */
/* */ int getTimedOut()
/* */ {
/* 872 */ return this.timedOut;
/* */ }
/* */
/* */ synchronized void incTimedOut()
/* */ {
/* 878 */ this.timedOut += 1;
/* */ }
/* */ }
/* */
/* */ public static class PoolParams
/* */ {
/* 795 */ public int minSize = 0;
/* */
/* 797 */ public int maxSize = 10;
/* */
/* 799 */ public int blockingTimeout = 30000;
/* */
/* 801 */ public long idleTimeout = 1800000L;
/* */ public boolean backgroundValidation;
/* 805 */ public long backgroundInterval = 600000L;
/* */ public boolean prefill;
/* */ public boolean stictMin;
/* */ public boolean useFastFail;
/* */ }
/* */ }
/* Location: /home/mnovotny/projects/EMBEDDED_JBOSS_BETA3_COMMUNITY/embedded/output/lib/embedded-jboss/lib/jboss-embedded-all.jar
* Qualified Name: org.jboss.resource.connectionmanager.InternalManagedConnectionPool
* JD-Core Version: 0.6.0
*/