[jboss-cvs] JBossAS SVN: r107950 - in projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager: pool and 5 other directories.
jboss-cvs-commits at lists.jboss.org
jboss-cvs-commits at lists.jboss.org
Thu Sep 2 10:59:32 EDT 2010
Author: jesper.pedersen
Date: 2010-09-02 10:59:31 -0400 (Thu, 02 Sep 2010)
New Revision: 107950
Added:
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ArrayBlockingQueueManagedConnectionPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPoolFactory.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/PoolFiller.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SecurityActions.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SemaphoreArrayListManagedConnectionPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/package.html
Removed:
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/ManagedConnectionPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/PoolFiller.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SecurityActions.java
Modified:
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SubPoolContext.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/Pool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/PoolConfiguration.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/strategy/OnePool.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/validator/ConnectionValidator.java
projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java
Log:
[JBJCA-413] ManagedConnectionPool strategies
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/AbstractConnectionListener.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -72,9 +72,6 @@
/** Track by transaction or not */
private AtomicBoolean trackByTx = new AtomicBoolean(false);
- /** Connection permit */
- private boolean permit;
-
/** Connection last use */
private long lastUse;
@@ -184,22 +181,6 @@
/**
* {@inheritDoc}
*/
- public void grantPermit(boolean value)
- {
- this.permit = value;
- }
-
- /**
- * {@inheritDoc}
- */
- public boolean hasPermit()
- {
- return this.permit;
- }
-
- /**
- * {@inheritDoc}
- */
public boolean isManagedConnectionFree()
{
return this.connectionHandles.isEmpty();
@@ -380,9 +361,29 @@
}
/**
+ * Compare
+ * @param o The other object
+ * @return 0 if equal; -1 if less than based on lastUse; otherwise 1
+ */
+ public int compareTo(Object o)
+ {
+ if (this == o)
+ return 0;
+
+ if (!(o instanceof AbstractConnectionListener))
+ throw new ClassCastException("Not correct type: " + o.getClass().getName());
+
+ final AbstractConnectionListener acl = (AbstractConnectionListener)o;
+
+ if (lastUse < acl.lastUse)
+ return -1;
+
+ return 1;
+ }
+
+ /**
* {@inheritDoc}
*/
- // For debugging
public String toString()
{
StringBuffer buffer = new StringBuffer(100);
@@ -408,7 +409,6 @@
buffer.append(" managed connection=").append(this.managedConnection);
buffer.append(" connection handles=").append(this.connectionHandles.size());
buffer.append(" lastUse=").append(lastUse);
- buffer.append(" permit=").append(permit);
buffer.append(" trackByTx=").append(trackByTx.get());
buffer.append(" pool=").append(this.pool);
buffer.append(" pool internal context=").append(this.internalManagedPoolContext);
@@ -422,10 +422,8 @@
* Add specific properties.
* @param buffer buffer instance
*/
- // For debugging
protected void toString(StringBuffer buffer)
{
}
-
}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/listener/ConnectionListener.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -36,7 +36,7 @@
* @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
* @author <a href="weston.price at jboss.com">Weston Price</a>
*/
-public interface ConnectionListener extends ConnectionEventListener
+public interface ConnectionListener extends ConnectionEventListener, Comparable
{
/**
* Retrieve the managed connection for this listener.
@@ -146,20 +146,6 @@
void setTrackByTx(boolean trackByTx);
/**
- * Whether the connection has a permit
- *
- * @return true when it has permit, false otherwise
- */
- boolean hasPermit();
-
- /**
- * Tell the connection listener whether it owns the permit.
- *
- * @param value true for owning the permit, false otherwise
- */
- void grantPermit(boolean value);
-
- /**
* Retrieve the last time this connection was validated.
*
* @return the last time the connection was validated
@@ -173,5 +159,4 @@
* milliseconds.
*/
void setLastValidatedTime(long lastValidated);
-
}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/AbstractPool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -27,6 +27,7 @@
import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
import org.jboss.jca.core.connectionmanager.pool.api.Pool;
import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
@@ -149,12 +150,11 @@
if (subPoolContext == null)
{
SubPoolContext newSubPoolContext = new SubPoolContext(getTransactionManager(), mcf, clf, subject,
- cri, poolConfiguration);
+ cri, poolConfiguration, this, log);
subPoolContext = subPools.putIfAbsent(key, newSubPoolContext);
if (subPoolContext == null)
{
subPoolContext = newSubPoolContext;
- subPoolContext.initialize();
}
}
@@ -307,7 +307,7 @@
// Make sure that IMCP is running
if (!imcp.isRunning())
- imcp.initialize();
+ imcp.reenable();
//Getting connection from pool
cl = imcp.getConnection(subject, cri);
Deleted: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/ManagedConnectionPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/ManagedConnectionPool.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/ManagedConnectionPool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -1,953 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008-2009, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.jca.core.connectionmanager.pool;
-
-import org.jboss.jca.common.JBossResourceException;
-import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
-import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
-import org.jboss.jca.core.connectionmanager.listener.ConnectionState;
-import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
-import org.jboss.jca.core.connectionmanager.pool.idle.IdleConnectionRemovalSupport;
-import org.jboss.jca.core.connectionmanager.pool.idle.IdleRemover;
-import org.jboss.jca.core.connectionmanager.pool.validator.ConnectionValidator;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import javax.resource.ResourceException;
-import javax.resource.spi.ConnectionRequestInfo;
-import javax.resource.spi.ManagedConnection;
-import javax.resource.spi.ManagedConnectionFactory;
-import javax.resource.spi.RetryableUnavailableException;
-import javax.resource.spi.ValidatingManagedConnectionFactory;
-import javax.security.auth.Subject;
-
-import org.jboss.logging.Logger;
-import org.jboss.util.UnreachableStatementException;
-
-
-/**
- * Actual internal managed connection pool.
- *
- * <p>
- * Contains and manages the {@link ConnectionListener} instances.
- * Each pool strategy can contains several {@link SubPoolContext} instance
- * that contains {@link ManagedConnectionPool} internally.
- * </p>
- *
- * <p>
- * Each internal managed connection pool instances could be
- * differentiated by a key.
- * </p>
- * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
- * @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
- * @author <a href="mailto:weston.price at jboss.com">Weston Price</a>
- * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
- * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
- * @see AbstractPool
- */
-public class ManagedConnectionPool implements IdleConnectionRemovalSupport
-{
- /** The log */
- private static Logger log = Logger.getLogger(ManagedConnectionPool.class);
-
- /** Whether trace is enabled */
- private final boolean trace = log.isTraceEnabled();
-
- /** The managed connection factory */
- private final ManagedConnectionFactory mcf;
-
- /** The connection listener factory */
- private final ConnectionListenerFactory clf;
-
- /** The subpool */
- private final SubPoolContext subPool;
-
- /** The default subject */
- private final Subject defaultSubject;
-
- /** The default connection request information */
- private final ConnectionRequestInfo defaultCri;
-
- /** The pool configuration */
- private final PoolConfiguration poolConfiguration;
-
- /** Copy of the maximum size from the pooling parameters.
- * Dynamic changes to this value are not compatible with
- * the semaphore which cannot change be dynamically changed.
- */
- private int maxSize;
-
- /** The available connection event listeners */
- private CopyOnWriteArrayList<ConnectionListener> cls = new CopyOnWriteArrayList<ConnectionListener>();
-
- /** The permits used to control who can checkout a connection */
- private final Semaphore permits;
-
- /** The checked out connections */
- private final CopyOnWriteArraySet<ConnectionListener> checkedOut = new CopyOnWriteArraySet<ConnectionListener>();
-
- /** Whether the pool has been started */
- private AtomicBoolean started = new AtomicBoolean(false);
-
- /** Whether the pool has been shutdown */
- private AtomicBoolean shutdown = new AtomicBoolean(false);
-
- /** the max connections ever checked out **/
- private volatile int maxUsedConnections = 0;
-
- /**
- * Create a new ManagedConnectionPool.
- *
- * @param mcf the managed connection factory
- * @param clf the connection listener factory
- * @param subject the subject
- * @param cri the connection request info
- * @param pc the pool configuration
- * @param spc The subpool context
- */
- public ManagedConnectionPool(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
- ConnectionRequestInfo cri, PoolConfiguration pc, SubPoolContext spc)
- {
- if (mcf == null)
- throw new IllegalArgumentException("MCF is null");
-
- if (clf == null)
- throw new IllegalArgumentException("CLF is null");
-
- if (pc == null)
- throw new IllegalArgumentException("PoolConfiguration is null");
-
- if (pc == null)
- throw new IllegalArgumentException("SubPoolContext is null");
-
- this.mcf = mcf;
- this.clf = clf;
- this.subPool = spc;
- this.defaultSubject = subject;
- this.defaultCri = cri;
- this.poolConfiguration = pc;
- this.maxSize = pc.getMaxSize();
- this.permits = new Semaphore(this.maxSize, true);
-
- if (pc.isPrefill())
- {
- PoolFiller.fillPool(this);
- }
- }
-
- /**
- * Get the subpool context
- * @return The pool
- */
- public SubPoolContext getSubPool()
- {
- return subPool;
- }
-
- /**
- * Returns a connection listener that wraps managed connection.
- * @param subject subject
- * @param cri connection request info
- * @return connection listener wrapped managed connection
- * @throws ResourceException exception
- */
- public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException
- {
- ConnectionListener connectionListener = null;
-
- if (subject == null)
- {
- subject = this.defaultSubject;
- }
-
- if (cri == null)
- {
- cri = this.defaultCri;
- }
-
- //Use in blocked time
- long startWait = System.currentTimeMillis();
-
- try
- {
- //Check connection is available, and if not waits for the blocking timeout
- if (this.permits.tryAcquire(this.poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
- {
- do
- {
- //Check shutdown
- if (this.shutdown.get())
- {
- permits.release();
- throw new RetryableUnavailableException("The pool has been shut down");
- }
-
- if (cls.size() > 0)
- {
- connectionListener = this.cls.remove(this.cls.size() - 1);
- this.checkedOut.add(connectionListener);
-
- //Max used connections, maxSize - permits.aval --> gives current used connection!
- int size = (maxSize - permits.availablePermits());
- if (size > maxUsedConnections)
- {
- maxUsedConnections = size;
- }
-
- if (connectionListener != null)
- {
- try
- {
- //Match connection
- ConnectionListener matchedConnectionListener =
- isManagedConnectionMatched(connectionListener, subject, cri);
-
- //Connection matched
- if (matchedConnectionListener != null)
- {
- connectionListener = matchedConnectionListener;
- break;
- }
-
- //Match did not succeed but no exception was thrown.
- //Either we have the matching strategy wrong or the
- //connection died while being checked. We need to
- //distinguish these cases, but for now we always
- //destroy the connection.
- log.warn("Destroying connection that could not be successfully matched: " + connectionListener);
- removesAndDestorysConnectionListener(connectionListener);
-
- }
- catch (Throwable t)
- {
- log.warn("Throwable while trying to match ManagedConnection,destroying connection: "
- + connectionListener, t);
- removesAndDestorysConnectionListener(connectionListener);
- }
-
- //We made it here, something went wrong and we should validate if
- //we should continue attempting to acquire a connection
- if (this.poolConfiguration.isUseFastFail())
- {
- 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");
- break;
- }
-
- } //connectionListener != null
- } //cls.size > 0
- }
- while (this.cls.size() > 0);
-
- //Check connection
- if (connectionListener == null)
- {
- //Ok, no connection in the pool. Creates a new managed connection instance!
- connectionListener = createsNewManagedConnection(subject, cri);
- }
-
- }
- else
- {
- // we timed out
- throw new ResourceException("No ManagedConnections available within configured blocking timeout ( "
- + this.poolConfiguration.getBlockingTimeout() + " [ms] )");
- }
-
- }
- catch (InterruptedException e)
- {
- long end = System.currentTimeMillis() - startWait;
- throw new ResourceException("Interrupted while requesting permit! Waited " + end + " ms");
- }
-
- return connectionListener;
- }
-
- /**
- * Removes and destroys given connection.
- * @param connectionListener connection listener
- */
- private void removesAndDestorysConnectionListener(ConnectionListener connectionListener)
- {
- this.checkedOut.remove(connectionListener);
-
- //Destroy it
- doDestroy(connectionListener);
- }
-
- /**
- * Returns given listener if there is a matched connection false ow.
- * @param connectionListener connection listener
- * @param subject subject
- * @param cri connection request info
- * @return true if there is a matched connection false ow.
- */
- private ConnectionListener isManagedConnectionMatched(ConnectionListener connectionListener,
- Subject subject, ConnectionRequestInfo cri) throws ResourceException
- {
- ManagedConnection managedConnection = connectionListener.getManagedConnection();
- managedConnection = this.mcf.matchManagedConnections(Collections.singleton(managedConnection), subject , cri);
-
- //There is a match
- if (managedConnection != null)
- {
- if (trace)
- {
- log.trace("supplying ManagedConnection from pool: " + connectionListener);
- }
-
- connectionListener.grantPermit(true);
-
- return connectionListener;
- }
-
- return null;
- }
-
- /**
- * Creates a new connection listener.
- * @param subject subject instance
- * @param cri connection request info
- * @return new connection listener
- * @throws ResourceException
- */
- private ConnectionListener createsNewManagedConnection(Subject subject, ConnectionRequestInfo cri)
- throws ResourceException
- {
- ConnectionListener cl = null;
- try
- {
- //No, the pool was empty, so we have to make a new one.
- cl = createsConnectionEventListener(subject, cri);
-
- checkedOut.add(cl);
- int size = (maxSize - permits.availablePermits());
- if (size > maxUsedConnections)
- {
- maxUsedConnections = size;
- }
-
- if (!started.get())
- {
- started.set(true);
- if (poolConfiguration.getMinSize() > 0)
- {
- PoolFiller.fillPool(this);
- }
- }
-
- if (trace)
- log.trace("supplying new ManagedConnection: " + cl);
-
- cl.grantPermit(true);
-
- return cl;
- }
- catch (Throwable t)
- {
- log.warn("Throwable while attempting to get a new connection: " + cl, t);
- //return permit and rethrow
-
- checkedOut.remove(cl);
- permits.release();
- JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying to create a connection: "
- + cl, t);
- throw new UnreachableStatementException();
- }
- }
-
-
- /**
- * Create a connection event listener
- *
- * @param subject the subject
- * @param cri the connection request information
- * @return the new listener
- * @throws ResourceException for any error
- */
- private ConnectionListener createsConnectionEventListener(Subject subject, ConnectionRequestInfo cri)
- throws ResourceException
- {
- ManagedConnection mc = mcf.createManagedConnection(subject, cri);
- try
- {
- return clf.createConnectionListener(mc, this);
- }
- catch (ResourceException re)
- {
- mc.destroy();
- throw re;
- }
- }
-
-
- /**
- * Destroy a connection
- *
- * @param cl the connection to destroy
- */
- private void doDestroy(ConnectionListener cl)
- {
- if (cl.getState() == ConnectionState.DESTROYED)
- {
- log.trace("ManagedConnection is already destroyed " + cl);
- return;
- }
-
- cl.setState(ConnectionState.DESTROYED);
-
- try
- {
- cl.getManagedConnection().destroy();
- }
- catch (Throwable t)
- {
- log.debug("Exception destroying ManagedConnection " + cl, t);
- }
-
- }
-
- /**
- * {@inheritDoc}
- */
- public void removeIdleConnections()
- {
- ArrayList<ConnectionListener> destroy = null;
- long timeout = System.currentTimeMillis() - poolConfiguration.getIdleTimeout();
-
- while (true)
- {
- // Nothing left to destroy
- if (cls.size() == 0)
- break;
-
- // Check the first in the list
- ConnectionListener cl = cls.get(0);
- if (cl.isTimedOut(timeout) && shouldRemove())
- {
- // We need to destroy this one
- cls.remove(0);
- if (destroy == null)
- {
- destroy = new ArrayList<ConnectionListener>();
- }
-
- destroy.add(cl);
- }
- else
- {
- //They were inserted chronologically, so if this one isn't timed out, following ones won't be either.
- break;
- }
- }
-
- // We found some connections to destroy
- if (destroy != null)
- {
- for (int i = 0; i < destroy.size(); ++i)
- {
- ConnectionListener cl = destroy.get(i);
- if (trace)
- {
- log.trace("Destroying timedout connection " + cl);
- }
-
- doDestroy(cl);
- }
-
- // We destroyed something, check the minimum.
- if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
- {
- PoolFiller.fillPool(this);
- }
-
-// // Empty sub-pool
-// if (jmcp != null)
-// {
-// jmcp.getPoolingStrategy().emptySubPool(this);
-// }
- }
-
- }
-
- /**
- * Returns true if check is ok.
- * @return true if check is ok.
- */
- private boolean shouldRemove()
- {
- boolean remove = true;
-
- if (this.poolConfiguration.isStrictMin())
- {
- remove = cls.size() > poolConfiguration.getMinSize();
-
- log.trace("StrictMin is active. Current connection will be removed is " + remove);
-
- }
-
- return remove;
-
- }
-
-
- /**
- * Initialize the subpool
- */
- public void initialize()
- {
- if (this.poolConfiguration.getIdleTimeout() != 0L)
- {
- //Register removal support
- IdleRemover.registerPool(this, this.poolConfiguration.getIdleTimeout());
- }
-
- if (this.poolConfiguration.getBackgroundValidationInterval() > 0)
- {
- log.debug("Registering for background validation at interval " +
- this.poolConfiguration.getBackgroundValidationInterval());
-
- //Register validation
- ConnectionValidator.registerPool(this, this.poolConfiguration.getBackgroundValidationInterval());
- }
-
- shutdown.set(false);
- }
-
- /**
- * Return connection to the pool.
- * @param cl connection listener
- * @param kill kill connection
- */
- public void returnConnection(ConnectionListener cl, boolean kill)
- {
- if (cl.getState().equals(ConnectionState.DESTROYED))
- {
- returnConnectionWithDestroyedState(cl);
- return;
- }
-
- if (trace)
- {
- log.trace("putting ManagedConnection back into pool kill=" + kill + " cl=" + cl);
- }
-
- returnConnectionWithKillState(cl, kill);
-
- }
-
- /**
- * Connection is returned with destroyed state.
- * @param cl connection listener
- */
- private void returnConnectionWithDestroyedState(ConnectionListener cl)
- {
- if (this.trace)
- {
- log.trace("ManagedConnection is being returned after it was destroyed" + cl);
- }
-
- if (cl.hasPermit())
- {
- cl.grantPermit(false);
- this.permits.release();
- }
- }
-
- /**
- * Connection is returned with destroyed state.
- * @param cl connection listener
- */
- private void returnConnectionWithKillState(ConnectionListener cl, boolean kill)
- {
- try
- {
- cl.getManagedConnection().cleanup();
- }
- catch (ResourceException re)
- {
- log.warn("ResourceException cleaning up ManagedConnection: " + cl, re);
- kill = true;
- }
-
- // We need to destroy this one
- if (cl.getState().equals(ConnectionState.DESTROY))
- {
- kill = true;
- checkedOut.remove(cl);
- }
-
- // This is really an error
- if (!kill && cls.size() >= poolConfiguration.getMaxSize())
- {
- log.warn("Destroying returned connection, maximum pool size exceeded " + cl);
- kill = true;
- }
-
- // If we are destroying, check the connection is not in the pool
- if (kill)
- {
- // Adrian Brock: A resource adapter can asynchronously notify us that
- // a connection error occurred.
- // This could happen while the connection is not checked out.
- // e.g. JMS can do this via an ExceptionListener on the connection.
- // I have twice had to reinstate this line of code, PLEASE DO NOT REMOVE IT!
- cls.remove(cl);
- }
- // return to the pool
- else
- {
- cl.used();
- if (!cls.contains(cl))
- {
- cls.add(cl);
- }
- else
- {
- log.warn("Attempt to return connection twice (ignored): " + cl, new Throwable("STACKTRACE"));
- }
- }
-
- if (cl.hasPermit())
- {
- // release semaphore
- cl.grantPermit(false);
- permits.release();
- }
-
- if (kill)
- {
- if (trace)
- {
- log.trace("Destroying returned connection " + cl);
- }
-
- doDestroy(cl);
- }
-
- }
-
- /**
- * Pool is shut down.
- */
- public void shutdown()
- {
- shutdown.set(true);
-
- //Unregister from idle check
- IdleRemover.unregisterPool(this);
-
- //Unregister from connection validation check
- ConnectionValidator.unregisterPool(this);
-
- //Destroy connections
- flush();
- }
-
- /**
- * Flush pool.
- */
- public void flush()
- {
- ArrayList<ConnectionListener> destroyList = new ArrayList<ConnectionListener>();
-
- if (this.trace)
- {
- log.trace("Flushing pool checkedOut=" + checkedOut + " inPool=" + cls);
- }
-
- Iterator<ConnectionListener> itCheckOut = this.checkedOut.iterator();
- ConnectionListener listener = null;
- while (itCheckOut.hasNext())
- {
- listener = itCheckOut.next();
- listener.setState(ConnectionState.DESTROY);
- }
-
- itCheckOut = this.cls.iterator();
- while (itCheckOut.hasNext())
- {
- listener = itCheckOut.next();
- destroyList.add(listener);
- }
-
- for (ConnectionListener listenerDestroy : destroyList)
- {
- if (this.trace)
- {
- log.trace("Destroying flushed connection " + listenerDestroy);
- }
-
- doDestroy(listenerDestroy);
- }
-
- // We destroyed something, check the minimum.
- if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
- {
- PoolFiller.fillPool(this);
- }
- }
-
- /**
- * Checks that pool is empty or not
- * @return true if is emtpy false otherwise
- */
- boolean isEmpty()
- {
- return this.cls.size() == 0;
- }
-
- /**
- * Gets connection listeners.
- * @return connection listeners
- */
- Set<ConnectionListener> getConnectionListeners()
- {
- Set<ConnectionListener> cls = new HashSet<ConnectionListener>();
- Iterator<ConnectionListener> it = this.cls.iterator();
- while (it.hasNext())
- {
- cls.add(it.next());
- }
-
- it = this.checkedOut.iterator();
- while (it.hasNext())
- {
- cls.add(it.next());
- }
-
- return cls;
- }
-
- /**
- * Returns true if pool is not shut down.
- * @return true if pool is not shut down
- */
- public boolean isRunning()
- {
- return !shutdown.get();
- }
-
- /**
- * Fill to min.
- */
- public void fillToMin()
- {
- while (true)
- {
- // Get a permit - avoids a race when the pool is nearly full
- // Also avoids unnessary fill checking when all connections are checked out
- try
- {
- if (permits.tryAcquire(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
- {
- try
- {
- //pool shuts down
- if (shutdown.get())
- {
- return;
- }
-
- // We already have enough connections -- TODO
- //if (getMinSize() - connectionCounter.getGuaranteedCount() <= 0)
- //{
- return;
- //}
-
- /* -- TODO
- // Create a connection to fill the pool
- try
- {
- ConnectionListener cl = createsConnectionEventListener(defaultSubject, defaultCri);
- if (trace)
- {
- log.trace("Filling pool cl=" + cl);
- }
-
- cls.add(cl);
- }
- catch (ResourceException re)
- {
- log.warn("Unable to fill pool ", re);
- return;
- }
- */
- }
- finally
- {
- permits.release();
- }
- }
- }
- catch (InterruptedException ignored)
- {
- log.trace("Interrupted while requesting permit in fillToMin");
- }
- }
- }
-
- /**
- * Guard against configurations or
- * dynamic changes that may increase the minimum
- * beyond the maximum
- */
- private int getMinSize()
- {
- if (this.poolConfiguration.getMinSize() > this.maxSize)
- {
- return maxSize;
- }
-
- return this.poolConfiguration.getMinSize();
- }
-
- /**
- * Validate connecitons.
- * @throws Exception for exception
- */
- @SuppressWarnings("unchecked")
- public void validateConnections() throws Exception
- {
- if (this.trace)
- {
- log.trace("Attempting to validate connections for pool " + this);
- }
-
- if (this.permits.tryAcquire(this.poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
- {
- boolean destroyed = false;
- try
- {
- while (true)
- {
- ConnectionListener cl = null;
- if (cls.size() == 0)
- {
- break;
- }
-
- cl = removeForFrequencyCheck();
-
- if (cl == null)
- {
- break;
- }
-
- try
- {
- Set<ManagedConnection> candidateSet = Collections.singleton(cl.getManagedConnection());
- if (mcf instanceof ValidatingManagedConnectionFactory)
- {
- ValidatingManagedConnectionFactory vcf = (ValidatingManagedConnectionFactory) mcf;
- candidateSet = vcf.getInvalidConnections(candidateSet);
-
- if (candidateSet != null && candidateSet.size() > 0)
- {
- if (!cl.getState().equals(ConnectionState.DESTROY))
- {
- doDestroy(cl);
- destroyed = true;
- }
- }
- }
- else
- {
- log.warn("warning: background validation was specified with a " +
- "non compliant ManagedConnectionFactory interface.");
- }
- }
- finally
- {
- if (!destroyed)
- {
- returnForFrequencyCheck(cl);
- }
- }
- }
- }
- finally
- {
- permits.release();
-
- //Check min size pool after validation
- if (destroyed && !shutdown.get() && poolConfiguration.getMinSize() > 0)
- {
- PoolFiller.fillPool(this);
- }
- }
- }
- }
-
- /**
- * Remove for frequency check.
- * @return connection listener
- */
- private ConnectionListener removeForFrequencyCheck()
- {
- log.debug("Checking for connection within frequency");
- ConnectionListener cl = null;
- for (Iterator<ConnectionListener> iter = cls.iterator(); iter.hasNext();)
- {
- cl = iter.next();
- long lastCheck = cl.getLastValidatedTime();
-
- if ((System.currentTimeMillis() - lastCheck) >= poolConfiguration.getBackgroundValidationInterval())
- {
- cls.remove(cl);
- break;
- }
- else
- {
- cl = null;
- }
- }
-
- return cl;
- }
-
- /**
- * Returns connection to pool again.
- * @param cl connection listener
- */
- private void returnForFrequencyCheck(ConnectionListener cl)
- {
-
- log.debug("Returning for connection within frequency");
-
- cl.setLastValidatedTime(System.currentTimeMillis());
- cls.add(cl);
- }
-
-}
Deleted: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/PoolFiller.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/PoolFiller.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/PoolFiller.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -1,153 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2006, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-package org.jboss.jca.core.connectionmanager.pool;
-
-import java.util.concurrent.LinkedBlockingQueue;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.Condition;
-import java.util.concurrent.locks.ReentrantLock;
-
-import org.jboss.logging.Logger;
-
-/**
- * PoolFiller
- *
- * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
- * @author Scott.Stark at jboss.org
- * @author <a href="mailto:adrian at jboss.com">Adrian Brock</a>
- * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
- * @version $Rev: $
- */
-public class PoolFiller implements Runnable
-{
- /** Log instance */
- private static Logger log = Logger.getLogger(PoolFiller.class);
-
- /** Singleton instance */
- private static final PoolFiller FILLER = new PoolFiller();
-
- /** Pools list */
- private final LinkedBlockingQueue<ManagedConnectionPool> pools =
- new LinkedBlockingQueue<ManagedConnectionPool>();
-
- /** Filler thread */
- private final Thread fillerThread;
-
- /** Thread name */
- private static final String THREAD_FILLER_NAME = "JCA PoolFiller";
-
- /** Lock instance */
- private ReentrantLock lock = new ReentrantLock();
-
- /** Lock condition */
- private Condition condition = this.lock.newCondition();
-
- /**Thread is configured or not*/
- private AtomicBoolean threadStarted = new AtomicBoolean(false);
-
- /**
- * Fill given pool.
- *
- * @param mcp internal managed connection pool
- */
- public static void fillPool(ManagedConnectionPool mcp)
- {
- FILLER.internalFillPool(mcp);
- }
-
- /**
- * Creates a new pool filler instance.
- */
- public PoolFiller()
- {
- fillerThread = new Thread(this, THREAD_FILLER_NAME);
- fillerThread.setDaemon(true);
- }
-
- /**
- * {@inheritDoc}
- */
- public void run()
- {
- final ClassLoader myClassLoader = getClass().getClassLoader();
- SecurityActions.setThreadContextClassLoader(myClassLoader);
-
- // keep going unless interrupted
- while (true)
- {
- ManagedConnectionPool mcp = null;
- try
- {
- // keep iterating through pools till empty, exception escapes.
- while (true)
- {
- mcp = pools.remove();
-
- if (mcp == null)
- {
- break;
- }
-
- mcp.fillToMin();
- }
- }
- catch (Exception e)
- {
- log.warn("Exception is occured while filling pool : " + mcp);
- }
-
- try
- {
- this.lock.lock();
-
- while (pools.isEmpty())
- {
- condition.await();
- }
- }
- catch (InterruptedException ie)
- {
- return;
-
- }
- finally
- {
- this.lock.unlock();
- }
- }
- }
-
- /**
- * fill pool.
- * @param mcp connection pool
- */
- private void internalFillPool(ManagedConnectionPool mcp)
- {
- if (this.threadStarted.compareAndSet(false, true))
- {
- this.fillerThread.start();
- }
-
- this.pools.add(mcp);
- this.condition.signal();
- }
-}
Deleted: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SecurityActions.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SecurityActions.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SecurityActions.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -1,58 +0,0 @@
-/*
- * JBoss, Home of Professional Open Source.
- * Copyright 2008, Red Hat Middleware LLC, and individual contributors
- * as indicated by the @author tags. See the copyright.txt file in the
- * distribution for a full listing of individual contributors.
- *
- * This is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as
- * published by the Free Software Foundation; either version 2.1 of
- * the License, or (at your option) any later version.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this software; if not, write to the Free
- * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
- */
-
-package org.jboss.jca.core.connectionmanager.pool;
-
-import java.security.AccessController;
-import java.security.PrivilegedAction;
-
-/**
- * Privileged Blocks
- *
- * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
- */
-class SecurityActions
-{
- /**
- * Set the context classloader.
- * @param cl classloader
- */
- public static void setThreadContextClassLoader(final ClassLoader cl)
- {
- if (System.getSecurityManager() == null)
- {
- Thread.currentThread().setContextClassLoader(cl);
- }
- else
- {
- AccessController.doPrivileged(new PrivilegedAction<Object>()
- {
- public Object run()
- {
- Thread.currentThread().setContextClassLoader(cl);
-
- return null;
- }
- });
- }
- }
-}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SubPoolContext.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SubPoolContext.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SubPoolContext.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -23,13 +23,18 @@
package org.jboss.jca.core.connectionmanager.pool;
import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.pool.api.Pool;
import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPoolFactory;
+import javax.resource.ResourceException;
import javax.resource.spi.ConnectionRequestInfo;
import javax.resource.spi.ManagedConnectionFactory;
import javax.security.auth.Subject;
import javax.transaction.TransactionManager;
+import org.jboss.logging.Logger;
import org.jboss.tm.TransactionLocal;
/**
@@ -55,15 +60,29 @@
* @param subject the subject
* @param cri the connection request info
* @param pc the pool configuration
+ * @param p the pool
+ * @param log The logger for the managed connection pool
+ * @throws ResourceException for any error
*/
public SubPoolContext(TransactionManager tm, ManagedConnectionFactory mcf, ConnectionListenerFactory clf,
- Subject subject, ConnectionRequestInfo cri, PoolConfiguration pc)
+ Subject subject, ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, Logger log)
+ throws ResourceException
{
- subPool = new ManagedConnectionPool(mcf, clf, subject, cri, pc, this);
- if (tm != null)
+ try
{
- trackByTx = new TransactionLocal(tm);
+ ManagedConnectionPoolFactory mcpf = new ManagedConnectionPoolFactory();
+
+ subPool = mcpf.create(mcf, clf, subject, cri, pc, p, this, log);
+
+ if (tm != null)
+ {
+ trackByTx = new TransactionLocal(tm);
+ }
}
+ catch (Throwable t)
+ {
+ throw new ResourceException("Exception while creating sub pool", t);
+ }
}
/**
@@ -85,13 +104,4 @@
{
return trackByTx;
}
-
- /**
- * Initialize the subpool context
- */
- public void initialize()
- {
- subPool.initialize();
- }
-
}
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/Pool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/Pool.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/Pool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -23,7 +23,7 @@
import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
-import org.jboss.jca.core.connectionmanager.pool.ManagedConnectionPool;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionRequestInfo;
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/PoolConfiguration.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/PoolConfiguration.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/api/PoolConfiguration.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -75,6 +75,9 @@
*/
public int getMinSize()
{
+ if (minSize > maxSize)
+ return maxSize;
+
return minSize;
}
@@ -91,6 +94,9 @@
*/
public int getMaxSize()
{
+ if (maxSize < minSize)
+ return minSize;
+
return maxSize;
}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ArrayBlockingQueueManagedConnectionPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ArrayBlockingQueueManagedConnectionPool.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ArrayBlockingQueueManagedConnectionPool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,831 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import org.jboss.jca.common.JBossResourceException;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionState;
+import org.jboss.jca.core.connectionmanager.pool.SubPoolContext;
+import org.jboss.jca.core.connectionmanager.pool.api.Pool;
+import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.idle.IdleRemover;
+import org.jboss.jca.core.connectionmanager.pool.validator.ConnectionValidator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.ConcurrentSkipListSet;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.RetryableUnavailableException;
+import javax.resource.spi.ValidatingManagedConnectionFactory;
+import javax.security.auth.Subject;
+
+import org.jboss.logging.Logger;
+
+/**
+ * A managed connection pool implementation using ArrayBlockingQueue
+ *
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ */
+public class ArrayBlockingQueueManagedConnectionPool implements ManagedConnectionPool
+{
+ /** The log */
+ private Logger log;
+
+ /** Whether trace is enabled */
+ private boolean trace;
+
+ /** The managed connection factory */
+ private ManagedConnectionFactory mcf;
+
+ /** The connection listener factory */
+ private ConnectionListenerFactory clf;
+
+ /** The default subject */
+ private Subject defaultSubject;
+
+ /** The default connection request information */
+ private ConnectionRequestInfo defaultCri;
+
+ /** The pool configuration */
+ private PoolConfiguration poolConfiguration;
+
+ /** The pool */
+ private Pool pool;
+
+ /**
+ * Copy of the maximum size from the pooling parameters.
+ * Dynamic changes to this value are not compatible with
+ * the semaphore which cannot change be dynamically changed.
+ */
+ private int maxSize;
+
+ /** The available connection event listeners */
+ private ArrayBlockingQueue<ConnectionListener> cls;
+
+ /** The permits used to control who can checkout a connection */
+ private ConcurrentMap<ConnectionListener, ConnectionListener> permits;
+
+ /** The subpool */
+ private SubPoolContext subPool;
+
+ /** The checked out connections */
+ private final ConcurrentSkipListSet<ConnectionListener> checkedOut =
+ new ConcurrentSkipListSet<ConnectionListener>();
+
+ /** Whether the pool has been started */
+ private AtomicBoolean started = new AtomicBoolean(false);
+
+ /** Whether the pool has been shutdown */
+ private AtomicBoolean shutdown = new AtomicBoolean(false);
+
+ /** the max connections ever checked out **/
+ private AtomicInteger maxUsedConnections = new AtomicInteger(0);
+
+ /**
+ * Constructor
+ */
+ public ArrayBlockingQueueManagedConnectionPool()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initialize(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
+ ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, SubPoolContext spc,
+ Logger log)
+ {
+ this.mcf = mcf;
+ this.clf = clf;
+ this.defaultSubject = subject;
+ this.defaultCri = cri;
+ this.poolConfiguration = pc;
+ this.maxSize = pc.getMaxSize();
+ this.pool = p;
+ this.subPool = spc;
+ this.log = log;
+ this.trace = log.isTraceEnabled();
+ this.cls = new ArrayBlockingQueue<ConnectionListener>(this.maxSize, true);
+ this.permits = new ConcurrentHashMap<ConnectionListener, ConnectionListener>(this.maxSize);
+
+ if (pc.isPrefill())
+ {
+ PoolFiller.fillPool(this);
+ }
+
+ reenable();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SubPoolContext getSubPool()
+ {
+ return subPool;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isRunning()
+ {
+ return !shutdown.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty()
+ {
+ return cls.size() == 0 && checkedOut.size() == 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void reenable()
+ {
+ if (poolConfiguration.getIdleTimeout() != 0L)
+ {
+ //Register removal support
+ IdleRemover.registerPool(this, poolConfiguration.getIdleTimeout());
+ }
+
+ if (poolConfiguration.getBackgroundValidationInterval() > 0)
+ {
+ log.debug("Registering for background validation at interval " +
+ poolConfiguration.getBackgroundValidationInterval());
+
+ //Register validation
+ ConnectionValidator.registerPool(this, poolConfiguration.getBackgroundValidationInterval());
+ }
+
+ shutdown.set(false);
+ }
+
+ private synchronized long getAvailableConnections()
+ {
+ int result = maxSize - permits.size();
+
+ return (result >= 0) ? result : 0;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException
+ {
+ subject = (subject == null) ? defaultSubject : subject;
+ cri = (cri == null) ? defaultCri : cri;
+
+ ConnectionListener cl = null;
+ boolean verifyConnectionListener = true;
+
+ long startWait = System.currentTimeMillis();
+ if (getAvailableConnections() > 0)
+ {
+ if (shutdown.get())
+ throw new RetryableUnavailableException("The pool has been shutdown");
+
+ cl = cls.peek();
+ if (cl != null)
+ {
+ try
+ {
+ cl = cls.poll(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS);
+ }
+ catch (InterruptedException ie)
+ {
+ long end = System.currentTimeMillis() - startWait;
+ throw new ResourceException("Interrupted while requesting connection! Waited " + end + " ms");
+ }
+ }
+ else
+ {
+ try
+ {
+ // No, the pool was empty, so we have to make a new one.
+ cl = createConnectionEventListener(subject, cri);
+
+ // Started is atomic, so pool filler won't be scheduled twice
+ if (!started.getAndSet(true))
+ {
+ if (poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+ }
+
+ if (trace)
+ log.trace("supplying new ManagedConnection: " + cl);
+
+ verifyConnectionListener = false;
+ }
+ catch (Throwable t)
+ {
+ log.warn("Throwable while attempting to get a new connection: " + cl, t);
+
+ JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying " +
+ "to create a connection: " + cl, t);
+ }
+ }
+ }
+ else
+ {
+ try
+ {
+ cl = cls.poll(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS);
+
+ if (shutdown.get())
+ throw new RetryableUnavailableException("The pool has been shutdown");
+ }
+ catch (InterruptedException ie)
+ {
+ if (!poolConfiguration.isUseFastFail())
+ {
+ throw new ResourceException("No ManagedConnections available within configured blocking timeout ( "
+ + poolConfiguration.getBlockingTimeout() + " [ms] )");
+ }
+ else
+ {
+ if (trace)
+ 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");
+
+ try
+ {
+ cl = createConnectionEventListener(subject, cri);
+
+ // Started is atomic, so pool filler won't be scheduled twice
+ if (!started.getAndSet(true))
+ {
+ if (poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+ }
+
+ if (trace)
+ log.trace("supplying new ManagedConnection: " + cl);
+
+ verifyConnectionListener = false;
+ }
+ catch (Throwable t)
+ {
+ log.warn("Throwable while attempting to get a new connection: " + cl, t);
+
+ JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying to " +
+ "create a connection: " + cl, t);
+ }
+ }
+ }
+ }
+
+ // Register the connection listener
+ checkedOut.add(cl);
+
+ // Update max used connections
+ int size = maxSize - permits.size();
+ if (size > maxUsedConnections.get())
+ maxUsedConnections.set(size);
+
+ if (!verifyConnectionListener)
+ {
+ // Register the connection listener with permits
+ permits.put(cl, cl);
+
+ // Return connection listener
+ return cl;
+ }
+ else
+ {
+ try
+ {
+ Object matchedMC =
+ mcf.matchManagedConnections(Collections.singleton(cl.getManagedConnection()), subject, cri);
+
+ if (matchedMC != null)
+ {
+ if (trace)
+ log.trace("supplying ManagedConnection from pool: " + cl);
+
+ // Register the connection listener with permits
+ permits.put(cl, cl);
+
+ // Return connection listener
+ return cl;
+ }
+
+ // Match did not succeed but no exception was thrown.
+ // Either we have the matching strategy wrong or the
+ // connection died while being checked. We need to
+ // distinguish these cases, but for now we always
+ // destroy the connection.
+ log.warn("Destroying connection that could not be successfully matched: " + cl + " for: " + mcf);
+
+ checkedOut.remove(cl);
+
+ doDestroy(cl);
+ cl = null;
+ }
+ catch (Throwable t)
+ {
+ log.warn("Throwable while trying to match ManagedConnection, destroying connection: " + cl, t);
+
+ checkedOut.remove(cl);
+
+ doDestroy(cl);
+ cl = null;
+
+ JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying " +
+ "to create a connection: " + cl, t);
+ }
+ }
+
+ throw new JBossResourceException("This should never happen", new Throwable("STACKTRACE"));
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void returnConnection(ConnectionListener cl, boolean kill)
+ {
+ if (cl.getState() == ConnectionState.DESTROYED)
+ {
+ if (trace)
+ log.trace("ManagedConnection is being returned after it was destroyed" + cl);
+
+ if (permits.containsKey(cl))
+ {
+ // release connection listener
+ permits.remove(cl);
+ }
+
+ return;
+ }
+
+ if (trace)
+ log.trace("putting ManagedConnection back into pool kill=" + kill + " cl=" + cl);
+
+ try
+ {
+ cl.getManagedConnection().cleanup();
+ }
+ catch (ResourceException re)
+ {
+ log.warn("ResourceException cleaning up ManagedConnection: " + cl, re);
+ kill = true;
+ }
+
+ // We need to destroy this one
+ if (cl.getState() == ConnectionState.DESTROY || cl.getState() == ConnectionState.DESTROYED)
+ kill = true;
+
+ checkedOut.remove(cl);
+
+ // This is really an error
+ if (!kill && cls.size() >= poolConfiguration.getMaxSize())
+ {
+ log.warn("Destroying returned connection, maximum pool size exceeded " + cl);
+ kill = true;
+ }
+
+ // If we are destroying, check the connection is not in the pool
+ if (kill)
+ {
+ // Adrian Brock: A resource adapter can asynchronously notify us that
+ // a connection error occurred.
+ // This could happen while the connection is not checked out.
+ // e.g. JMS can do this via an ExceptionListener on the connection.
+ // I have twice had to reinstate this line of code, PLEASE DO NOT REMOVE IT!
+ cls.remove(cl);
+ }
+ // return to the pool
+ else
+ {
+ cl.used();
+ if (!cls.contains(cl))
+ {
+ try
+ {
+ cls.put(cl);
+ }
+ catch (InterruptedException ie)
+ {
+ cl.setState(ConnectionState.DESTROY);
+ kill = true;
+ }
+ }
+ else
+ {
+ log.warn("Attempt to return connection twice (ignored): " + cl, new Throwable("STACKTRACE"));
+ }
+ }
+
+ if (permits.containsKey(cl))
+ {
+ // release connection listener
+ permits.remove(cl);
+ }
+
+ if (kill)
+ {
+ if (trace)
+ log.trace("Destroying returned connection " + cl);
+
+ doDestroy(cl);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void flush()
+ {
+ ArrayList<ConnectionListener> destroy = null;
+
+ if (trace)
+ log.trace("Flushing pool checkedOut=" + checkedOut + " inPool=" + cls);
+
+ // Mark checked out connections as requiring destruction
+ for (Iterator<ConnectionListener> i = checkedOut.iterator(); i.hasNext();)
+ {
+ ConnectionListener cl = i.next();
+
+ if (trace)
+ log.trace("Flush marking checked out connection for destruction " + cl);
+
+ cl.setState(ConnectionState.DESTROY);
+ }
+
+ // Destroy connections in the pool
+ ConnectionListener cl = cls.poll();
+ while (cl != null)
+ {
+ if (destroy == null)
+ destroy = new ArrayList<ConnectionListener>();
+
+ destroy.add(cl);
+ cl = cls.poll();
+ }
+
+ // We need to destroy some connections
+ if (destroy != null)
+ {
+ for (int i = 0; i < destroy.size(); ++i)
+ {
+ ConnectionListener l = destroy.get(i);
+ if (trace)
+ log.trace("Destroying flushed connection " + l);
+
+ doDestroy(l);
+ }
+
+ // We destroyed something, check the minimum.
+ if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeIdleConnections()
+ {
+ ArrayList<ConnectionListener> destroy = null;
+ long timeout = System.currentTimeMillis() - poolConfiguration.getIdleTimeout();
+
+ boolean cont = true;
+ while (cont)
+ {
+ // Check the first in the list
+ ConnectionListener cl = cls.peek();
+ if (cl != null && cl.isTimedOut(timeout) && shouldRemove())
+ {
+ // We need to destroy this one
+ if (destroy == null)
+ destroy = new ArrayList<ConnectionListener>(1);
+
+ cl = cls.poll();
+
+ if (cl != null)
+ {
+ destroy.add(cl);
+ }
+ else
+ {
+ // The connection list were empty
+ cont = false;
+ }
+ }
+ else
+ {
+ // They were inserted chronologically, so if this one
+ // isn't timed out, following ones won't be either.
+ cont = false;
+ }
+ }
+
+ // We found some connections to destroy
+ if (destroy != null)
+ {
+ for (int i = 0; i < destroy.size(); ++i)
+ {
+ ConnectionListener cl = destroy.get(i);
+
+ if (trace)
+ log.trace("Destroying timedout connection " + cl);
+
+ doDestroy(cl);
+ }
+
+ // We destroyed something, check the minimum.
+ if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+
+ // Empty sub-pool
+ if (pool != null)
+ pool.emptySubPool(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void shutdown()
+ {
+ shutdown.set(true);
+ IdleRemover.unregisterPool(this);
+ ConnectionValidator.unregisterPool(this);
+ flush();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void fillToMin()
+ {
+ while (poolConfiguration.getMinSize() - (cls.size() + checkedOut.size()) > 0)
+ {
+ if (shutdown.get())
+ return;
+
+ // Create a connection to fill the pool
+ ConnectionListener cl = null;
+ boolean destroy = false;
+ try
+ {
+ cl = createConnectionEventListener(defaultSubject, defaultCri);
+
+ if ((checkedOut.size() + cls.size()) < poolConfiguration.getMinSize())
+ {
+ if (trace)
+ log.trace("Filling pool cl=" + cl);
+
+ if (!cls.offer(cl))
+ {
+ log.debug("Connection couldn't be inserted during fillToMin");
+ destroy = true;
+ }
+ }
+ else
+ {
+ log.debug("MinSize reached during fillToMin");
+ destroy = true;
+ }
+ }
+ catch (ResourceException re)
+ {
+ log.warn("Unable to fill pool ", re);
+ destroy = true;
+ }
+ finally
+ {
+ if (destroy)
+ {
+ if (cl != null)
+ {
+ doDestroy(cl);
+ }
+
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Create a connection event listener
+ *
+ * @param subject the subject
+ * @param cri the connection request information
+ * @return the new listener
+ * @throws ResourceException for any error
+ */
+ private ConnectionListener createConnectionEventListener(Subject subject, ConnectionRequestInfo cri)
+ throws ResourceException
+ {
+ ManagedConnection mc = mcf.createManagedConnection(subject, cri);
+ try
+ {
+ return clf.createConnectionListener(mc, this);
+ }
+ catch (ResourceException re)
+ {
+ mc.destroy();
+ throw re;
+ }
+ }
+
+ /**
+ * Destroy a connection
+ *
+ * @param cl the connection to destroy
+ */
+ private void doDestroy(ConnectionListener cl)
+ {
+ if (cl.getState() == ConnectionState.DESTROYED)
+ {
+ log.trace("ManagedConnection is already destroyed " + cl);
+ return;
+ }
+
+ cl.setState(ConnectionState.DESTROYED);
+ try
+ {
+ cl.getManagedConnection().destroy();
+ }
+ catch (Throwable t)
+ {
+ log.debug("Exception destroying ManagedConnection " + cl, t);
+ }
+
+ }
+
+ private boolean shouldRemove()
+ {
+ boolean remove = true;
+
+ if (poolConfiguration.isStrictMin())
+ {
+ remove = cls.size() > poolConfiguration.getMinSize();
+
+ if (trace)
+ log.trace("StrictMin is active. Current connection will be removed is " + remove);
+ }
+
+ return remove;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void validateConnections() throws Exception
+ {
+ if (trace)
+ log.trace("Attempting to validate connections for pool " + this);
+
+ boolean anyDestroyed = false;
+
+ try
+ {
+ while (true)
+ {
+ ConnectionListener cl = null;
+ boolean destroyed = false;
+
+ if (cls.size() == 0)
+ {
+ break;
+ }
+
+ cl = removeForFrequencyCheck();
+
+ if (cl == null)
+ {
+ break;
+ }
+
+ try
+ {
+ Set candidateSet = Collections.singleton(cl.getManagedConnection());
+
+ if (mcf instanceof ValidatingManagedConnectionFactory)
+ {
+ ValidatingManagedConnectionFactory vcf = (ValidatingManagedConnectionFactory) mcf;
+ candidateSet = vcf.getInvalidConnections(candidateSet);
+
+ if (candidateSet != null && candidateSet.size() > 0)
+ {
+ if (cl.getState() != ConnectionState.DESTROY)
+ {
+ doDestroy(cl);
+ destroyed = true;
+ anyDestroyed = true;
+ }
+ }
+ }
+ else
+ {
+ log.warn("Warning: Background validation was specified with a non compliant " +
+ "ManagedConnectionFactory interface.");
+ }
+ }
+ finally
+ {
+ if (!destroyed)
+ {
+ if (!returnForFrequencyCheck(cl))
+ anyDestroyed = true;
+ }
+ }
+ }
+ }
+ finally
+ {
+ if (anyDestroyed && !shutdown.get() && poolConfiguration.getMinSize() > 0)
+ {
+ PoolFiller.fillPool(this);
+ }
+ }
+ }
+
+ /**
+ * Remove a connection to the pool for a frequency check
+ * @return A connection; <code>null</code> if no connections needs to be checked
+ */
+ private ConnectionListener removeForFrequencyCheck()
+ {
+ log.debug("Checking for connection within frequency");
+
+ ConnectionListener result = null;
+ Iterator<ConnectionListener> iter = cls.iterator();
+
+ while (result == null && iter.hasNext())
+ {
+ ConnectionListener cl = iter.next();
+ long lastCheck = cl.getLastValidatedTime();
+
+ if ((System.currentTimeMillis() - lastCheck) >= poolConfiguration.getBackgroundValidationInterval())
+ {
+ result = cl;
+ cls.remove(cl);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Return a connection to the pool
+ * @param cl The connection
+ * @return <code>True</code> if the connection was returned; otherwise <code>false</code>
+ */
+ private boolean returnForFrequencyCheck(ConnectionListener cl)
+ {
+ log.debug("Returning for connection within frequency: " + cl);
+
+ if (cl == null)
+ return true;
+
+ cl.setLastValidatedTime(System.currentTimeMillis());
+
+ if (!cls.offer(cl))
+ {
+ log.debug("Connection couldn't be returned");
+ doDestroy(cl);
+ return false;
+ }
+
+ return true;
+ }
+}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPool.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,121 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.pool.SubPoolContext;
+import org.jboss.jca.core.connectionmanager.pool.api.Pool;
+import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.idle.IdleConnectionRemovalSupport;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.security.auth.Subject;
+
+import org.jboss.logging.Logger;
+
+/**
+ * Represents a managed connection pool, which manages all connection listeners
+ *
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ */
+public interface ManagedConnectionPool extends IdleConnectionRemovalSupport
+{
+ /**
+ * Initialize the managed connection pool
+ *
+ * @param mcf The managed connection factory
+ * @param clf The connection listener factory
+ * @param subject The subject
+ * @param cri The connection request info
+ * @param pc The pool configuration
+ * @param p The pool
+ * @param spc The subpool context
+ * @param log The logger for the managed connection pool
+ */
+ public void initialize(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
+ ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, SubPoolContext spc,
+ Logger log);
+
+ /**
+ * Get the subpool context
+ * @return The context
+ */
+ public SubPoolContext getSubPool();
+
+ /**
+ * Returns a connection listener that wraps managed connection.
+ * @param subject subject
+ * @param cri connection request info
+ * @return connection listener wrapped managed connection
+ * @throws ResourceException exception
+ */
+ public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException;
+
+ /**
+ * Return connection to the pool.
+ * @param cl connection listener
+ * @param kill kill connection
+ */
+ public void returnConnection(ConnectionListener cl, boolean kill);
+
+ /**
+ * Checks if the pool is empty or not
+ * @return True if is emtpy; otherwise false
+ */
+ public boolean isEmpty();
+
+ /**
+ * Checks if the pool is running or not
+ * @return True if is running; otherwise false
+ */
+ public boolean isRunning();
+
+ /**
+ * Reenable a pool
+ */
+ public void reenable();
+
+ /**
+ * Flush
+ */
+ public void flush();
+
+ /**
+ * Shutdown
+ */
+ public void shutdown();
+
+ /**
+ * Fill to min
+ */
+ public void fillToMin();
+
+ /**
+ * Validate connecitons.
+ * @throws Exception for exception
+ */
+ public void validateConnections() throws Exception;
+}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPoolFactory.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPoolFactory.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/ManagedConnectionPoolFactory.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,124 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.pool.SubPoolContext;
+import org.jboss.jca.core.connectionmanager.pool.api.Pool;
+import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.security.auth.Subject;
+
+import org.jboss.logging.Logger;
+
+/**
+ * Factory to create a managed connection pool
+ *
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ */
+public class ManagedConnectionPoolFactory
+{
+ /** Default implementation */
+ private static final String DEFAULT_IMPLEMENTATION =
+ "org.jboss.jca.core.connectionmanager.pool.mcp.SemaphoreArrayListManagedConnectionPool";
+
+ /** Actual implementation */
+ private static String defaultImplementation;
+
+ static
+ {
+ String clz = SecurityActions.getSystemProperty("ironjacamar.mcp");
+
+ if (clz != null && !clz.trim().equals(""))
+ {
+ defaultImplementation = clz.trim();
+ }
+ else
+ {
+ defaultImplementation = DEFAULT_IMPLEMENTATION;
+ }
+ }
+
+ /**
+ * Constructor
+ */
+ public ManagedConnectionPoolFactory()
+ {
+ }
+
+ /**
+ * Create a managed connection pool using the default implementation strategy
+ *
+ * @param mcf the managed connection factory
+ * @param clf the connection listener factory
+ * @param subject the subject
+ * @param cri the connection request info
+ * @param pc the pool configuration
+ * @param p The pool
+ * @param spc The subpool context
+ * @param log The logger for the managed connection pool
+ * @return The initialized managed connection pool
+ * @exception Throwable Thrown in case of an error
+ */
+ public ManagedConnectionPool create(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
+ ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, SubPoolContext spc,
+ Logger log)
+ throws Throwable
+ {
+ return create(defaultImplementation, mcf, clf, subject, cri, pc, p, spc, log);
+ }
+
+ /**
+ * Create a managed connection pool using a specific implementation strategy
+ *
+ * @param strategy Fullt qualified class name for the managed connection pool strategy
+ * @param mcf the managed connection factory
+ * @param clf the connection listener factory
+ * @param subject the subject
+ * @param cri the connection request info
+ * @param pc the pool configuration
+ * @param p The pool
+ * @param spc The subpool context
+ * @param log The logger for the managed connection pool
+ * @return The initialized managed connection pool
+ * @exception Throwable Thrown in case of an error
+ */
+ public ManagedConnectionPool create(String strategy,
+ ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
+ ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, SubPoolContext spc,
+ Logger log)
+ throws Throwable
+ {
+ Class<?> clz = Class.forName(strategy,
+ true,
+ ManagedConnectionPoolFactory.class.getClassLoader());
+
+ ManagedConnectionPool mcp = (ManagedConnectionPool)clz.newInstance();
+
+ mcp.initialize(mcf, clf, subject, cri, pc, p, spc, log);
+
+ return mcp;
+ }
+}
Copied: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/PoolFiller.java (from rev 107913, projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/PoolFiller.java)
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/PoolFiller.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/PoolFiller.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,153 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2006, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+import org.jboss.logging.Logger;
+
+/**
+ * PoolFiller
+ *
+ * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
+ * @author Scott.Stark at jboss.org
+ * @author <a href="mailto:adrian at jboss.com">Adrian Brock</a>
+ * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
+ * @version $Rev: $
+ */
+class PoolFiller implements Runnable
+{
+ /** Log instance */
+ private static Logger log = Logger.getLogger(PoolFiller.class);
+
+ /** Singleton instance */
+ private static final PoolFiller FILLER = new PoolFiller();
+
+ /** Pools list */
+ private final LinkedBlockingQueue<ManagedConnectionPool> pools =
+ new LinkedBlockingQueue<ManagedConnectionPool>();
+
+ /** Filler thread */
+ private final Thread fillerThread;
+
+ /** Thread name */
+ private static final String THREAD_FILLER_NAME = "JCA PoolFiller";
+
+ /** Lock instance */
+ private ReentrantLock lock = new ReentrantLock();
+
+ /** Lock condition */
+ private Condition condition = this.lock.newCondition();
+
+ /**Thread is configured or not*/
+ private AtomicBoolean threadStarted = new AtomicBoolean(false);
+
+ /**
+ * Fill given pool.
+ *
+ * @param mcp internal managed connection pool
+ */
+ static void fillPool(ManagedConnectionPool mcp)
+ {
+ FILLER.internalFillPool(mcp);
+ }
+
+ /**
+ * Creates a new pool filler instance.
+ */
+ PoolFiller()
+ {
+ fillerThread = new Thread(this, THREAD_FILLER_NAME);
+ fillerThread.setDaemon(true);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void run()
+ {
+ final ClassLoader myClassLoader = getClass().getClassLoader();
+ SecurityActions.setThreadContextClassLoader(myClassLoader);
+
+ // keep going unless interrupted
+ while (true)
+ {
+ ManagedConnectionPool mcp = null;
+ try
+ {
+ // keep iterating through pools till empty, exception escapes.
+ while (true)
+ {
+ mcp = pools.remove();
+
+ if (mcp == null)
+ {
+ break;
+ }
+
+ mcp.fillToMin();
+ }
+ }
+ catch (Exception e)
+ {
+ log.warn("Exception is occured while filling pool : " + mcp);
+ }
+
+ try
+ {
+ this.lock.lock();
+
+ while (pools.isEmpty())
+ {
+ condition.await();
+ }
+ }
+ catch (InterruptedException ie)
+ {
+ return;
+
+ }
+ finally
+ {
+ this.lock.unlock();
+ }
+ }
+ }
+
+ /**
+ * fill pool.
+ * @param mcp connection pool
+ */
+ private void internalFillPool(ManagedConnectionPool mcp)
+ {
+ if (this.threadStarted.compareAndSet(false, true))
+ {
+ this.fillerThread.start();
+ }
+
+ this.pools.add(mcp);
+ this.condition.signal();
+ }
+}
Copied: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SecurityActions.java (from rev 107913, projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/SecurityActions.java)
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SecurityActions.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SecurityActions.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,74 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2008, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Privileged Blocks
+ *
+ * @author <a href="mailto:gurkanerdogdu at yahoo.com">Gurkan Erdogdu</a>
+ */
+class SecurityActions
+{
+ /**
+ * Set the context classloader.
+ * @param cl classloader
+ */
+ public static void setThreadContextClassLoader(final ClassLoader cl)
+ {
+ if (System.getSecurityManager() == null)
+ {
+ Thread.currentThread().setContextClassLoader(cl);
+ }
+ else
+ {
+ AccessController.doPrivileged(new PrivilegedAction<Object>()
+ {
+ public Object run()
+ {
+ Thread.currentThread().setContextClassLoader(cl);
+
+ return null;
+ }
+ });
+ }
+ }
+
+ /**
+ * Get a system property
+ * @param name The property name
+ * @return The property value
+ */
+ static String getSystemProperty(final String name)
+ {
+ return AccessController.doPrivileged(new PrivilegedAction<String>()
+ {
+ public String run()
+ {
+ return System.getProperty(name);
+ }
+ });
+ }
+}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SemaphoreArrayListManagedConnectionPool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SemaphoreArrayListManagedConnectionPool.java (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/SemaphoreArrayListManagedConnectionPool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,823 @@
+/*
+ * JBoss, Home of Professional Open Source.
+ * Copyright 2010, Red Hat Middleware LLC, and individual contributors
+ * as indicated by the @author tags. See the copyright.txt file in the
+ * distribution for a full listing of individual contributors.
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this software; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
+ * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
+ */
+
+package org.jboss.jca.core.connectionmanager.pool.mcp;
+
+import org.jboss.jca.common.JBossResourceException;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionListenerFactory;
+import org.jboss.jca.core.connectionmanager.listener.ConnectionState;
+import org.jboss.jca.core.connectionmanager.pool.SubPoolContext;
+import org.jboss.jca.core.connectionmanager.pool.api.Pool;
+import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.idle.IdleRemover;
+import org.jboss.jca.core.connectionmanager.pool.validator.ConnectionValidator;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.concurrent.Semaphore;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import javax.resource.ResourceException;
+import javax.resource.spi.ConnectionRequestInfo;
+import javax.resource.spi.ManagedConnection;
+import javax.resource.spi.ManagedConnectionFactory;
+import javax.resource.spi.RetryableUnavailableException;
+import javax.resource.spi.ValidatingManagedConnectionFactory;
+import javax.security.auth.Subject;
+
+import org.jboss.logging.Logger;
+import org.jboss.util.UnreachableStatementException;
+
+/**
+ * The internal pool implementation
+ *
+ * @author <a href="mailto:d_jencks at users.sourceforge.net">David Jencks</a>
+ * @author <a href="mailto:adrian at jboss.org">Adrian Brock</a>
+ * @author <a href="mailto:weston.price at jboss.com">Weston Price</a>
+ * @author <a href="mailto:jesper.pedersen at jboss.org">Jesper Pedersen</a>
+ * @version $Revision: 107890 $
+ */
+public class SemaphoreArrayListManagedConnectionPool implements ManagedConnectionPool
+{
+ /** The log */
+ private Logger log;
+
+ /** Whether trace is enabled */
+ private boolean trace;
+
+ /** The managed connection factory */
+ private ManagedConnectionFactory mcf;
+
+ /** The connection listener factory */
+ private ConnectionListenerFactory clf;
+
+ /** The default subject */
+ private Subject defaultSubject;
+
+ /** The default connection request information */
+ private ConnectionRequestInfo defaultCri;
+
+ /** The pool configuration */
+ private PoolConfiguration poolConfiguration;
+
+ /** The pool */
+ private Pool pool;
+
+ /**
+ * Copy of the maximum size from the pooling parameters.
+ * Dynamic changes to this value are not compatible with
+ * the semaphore which cannot change be dynamically changed.
+ */
+ private int maxSize;
+
+ /** The available connection event listeners */
+ private ArrayList<ConnectionListener> cls;
+
+ /** The permits used to control who can checkout a connection */
+ private Semaphore permits;
+
+ /** The map of connection listeners which has a permit */
+ private ConcurrentMap<ConnectionListener, ConnectionListener> clPermits =
+ new ConcurrentHashMap<ConnectionListener, ConnectionListener>();
+
+ /** The sub pool */
+ private SubPoolContext subPool;
+
+ /** The checked out connections */
+ private HashSet<ConnectionListener> checkedOut = new HashSet<ConnectionListener>();
+
+ /** Whether the pool has been started */
+ private AtomicBoolean started = new AtomicBoolean(false);
+
+ /** Whether the pool has been shutdown */
+ private AtomicBoolean shutdown = new AtomicBoolean(false);
+
+ /** the max connections ever checked out **/
+ private volatile int maxUsedConnections = 0;
+
+ /**
+ * Constructor
+ */
+ public SemaphoreArrayListManagedConnectionPool()
+ {
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void initialize(ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
+ ConnectionRequestInfo cri, PoolConfiguration pc, Pool p, SubPoolContext spc,
+ Logger log)
+ {
+ this.mcf = mcf;
+ this.clf = clf;
+ this.defaultSubject = subject;
+ this.defaultCri = cri;
+ this.poolConfiguration = pc;
+ this.maxSize = pc.getMaxSize();
+ this.pool = p;
+ this.subPool = spc;
+ this.log = log;
+ this.trace = log.isTraceEnabled();
+ this.cls = new ArrayList<ConnectionListener>(this.maxSize);
+ this.permits = new Semaphore(this.maxSize, true);
+
+ if (pc.isPrefill())
+ {
+ PoolFiller.fillPool(this);
+ }
+
+ reenable();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public SubPoolContext getSubPool()
+ {
+ return subPool;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isRunning()
+ {
+ return !shutdown.get();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isEmpty()
+ {
+ synchronized (cls)
+ {
+ return cls.size() == 0 && checkedOut.size() == 0;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void reenable()
+ {
+ if (poolConfiguration.getIdleTimeout() != 0L)
+ {
+ //Register removal support
+ IdleRemover.registerPool(this, poolConfiguration.getIdleTimeout());
+ }
+
+ if (poolConfiguration.getBackgroundValidationInterval() > 0)
+ {
+ log.debug("Registering for background validation at interval " +
+ poolConfiguration.getBackgroundValidationInterval());
+
+ //Register validation
+ ConnectionValidator.registerPool(this, poolConfiguration.getBackgroundValidationInterval());
+ }
+
+ shutdown.set(false);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConnectionListener getConnection(Subject subject, ConnectionRequestInfo cri) throws ResourceException
+ {
+ subject = (subject == null) ? defaultSubject : subject;
+ cri = (cri == null) ? defaultCri : cri;
+ long startWait = System.currentTimeMillis();
+ try
+ {
+ if (permits.tryAcquire(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
+ {
+ //We have a permit to get a connection. Is there one in the pool already?
+ ConnectionListener cl = null;
+ do
+ {
+ synchronized (cls)
+ {
+ if (shutdown.get())
+ {
+ permits.release();
+ throw new RetryableUnavailableException("The pool has been shutdown");
+ }
+
+ int clsSize = cls.size();
+ if (clsSize > 0)
+ {
+ cl = cls.remove(clsSize - 1);
+ checkedOut.add(cl);
+ int size = maxSize - permits.availablePermits();
+ if (size > maxUsedConnections)
+ maxUsedConnections = size;
+ }
+ }
+ if (cl != null)
+ {
+ //Yes, we retrieved a ManagedConnection from the pool. Does it match?
+ try
+ {
+ Object matchedMC = mcf.matchManagedConnections(Collections.singleton(cl.getManagedConnection()),
+ subject, cri);
+
+ if (matchedMC != null)
+ {
+ if (trace)
+ log.trace("supplying ManagedConnection from pool: " + cl);
+
+ clPermits.put(cl, cl);
+
+ return cl;
+ }
+
+ // Match did not succeed but no exception was thrown.
+ // Either we have the matching strategy wrong or the
+ // connection died while being checked. We need to
+ // distinguish these cases, but for now we always
+ // destroy the connection.
+ log.warn("Destroying connection that could not be successfully matched: " + cl);
+
+ synchronized (cls)
+ {
+ checkedOut.remove(cl);
+ }
+
+ doDestroy(cl);
+ cl = null;
+ }
+ catch (Throwable t)
+ {
+ log.warn("Throwable while trying to match ManagedConnection, destroying connection: " + cl, t);
+
+ synchronized (cls)
+ {
+ checkedOut.remove(cl);
+ }
+
+ doDestroy(cl);
+ cl = null;
+ }
+
+ // We made it here, something went wrong and we should validate
+ // if we should continue attempting to acquire a connection
+ if (poolConfiguration.isUseFastFail())
+ {
+ 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");
+ break;
+ }
+
+ }
+ }
+ while (cls.size() > 0);
+
+ // OK, we couldnt find a working connection from the pool. Make a new one.
+ try
+ {
+ // No, the pool was empty, so we have to make a new one.
+ cl = createConnectionEventListener(subject, cri);
+
+ synchronized (cls)
+ {
+ checkedOut.add(cl);
+ int size = maxSize - permits.availablePermits();
+ if (size > maxUsedConnections)
+ maxUsedConnections = size;
+ }
+
+ if (!started.getAndSet(true))
+ {
+ if (poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+ }
+
+ if (trace)
+ log.trace("supplying new ManagedConnection: " + cl);
+
+ clPermits.put(cl, cl);
+
+ return cl;
+ }
+ catch (Throwable t)
+ {
+ log.warn("Throwable while attempting to get a new connection: " + cl, t);
+
+ // Return permit and rethrow
+ synchronized (cls)
+ {
+ checkedOut.remove(cl);
+ }
+
+ permits.release();
+
+ JBossResourceException.rethrowAsResourceException("Unexpected throwable while trying to " +
+ "create a connection: " + cl, t);
+ throw new UnreachableStatementException();
+ }
+ }
+ else
+ {
+ // We timed out
+ throw new ResourceException("No ManagedConnections available within configured blocking timeout ( "
+ + poolConfiguration.getBlockingTimeout() + " [ms] )");
+ }
+
+ }
+ catch (InterruptedException ie)
+ {
+ long end = System.currentTimeMillis() - startWait;
+ throw new ResourceException("Interrupted while requesting permit! Waited " + end + " ms");
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void returnConnection(ConnectionListener cl, boolean kill)
+ {
+ synchronized (cls)
+ {
+ if (cl.getState() == ConnectionState.DESTROYED)
+ {
+ if (trace)
+ log.trace("ManagedConnection is being returned after it was destroyed" + cl);
+
+ if (clPermits.containsKey(cl))
+ {
+ clPermits.remove(cl);
+ permits.release();
+ }
+
+ return;
+ }
+ }
+
+ if (trace)
+ log.trace("putting ManagedConnection back into pool kill=" + kill + " cl=" + cl);
+
+ try
+ {
+ cl.getManagedConnection().cleanup();
+ }
+ catch (ResourceException re)
+ {
+ log.warn("ResourceException cleaning up ManagedConnection: " + cl, re);
+ kill = true;
+ }
+
+ synchronized (cls)
+ {
+ // We need to destroy this one
+ if (cl.getState() == ConnectionState.DESTROY || cl.getState() == ConnectionState.DESTROYED)
+ kill = true;
+
+ checkedOut.remove(cl);
+
+ // This is really an error
+ if (!kill && cls.size() >= poolConfiguration.getMaxSize())
+ {
+ log.warn("Destroying returned connection, maximum pool size exceeded " + cl);
+ kill = true;
+ }
+
+ // If we are destroying, check the connection is not in the pool
+ if (kill)
+ {
+ // Adrian Brock: A resource adapter can asynchronously notify us that
+ // a connection error occurred.
+ // This could happen while the connection is not checked out.
+ // e.g. JMS can do this via an ExceptionListener on the connection.
+ // I have twice had to reinstate this line of code, PLEASE DO NOT REMOVE IT!
+ cls.remove(cl);
+ }
+ // return to the pool
+ else
+ {
+ cl.used();
+ if (!cls.contains(cl))
+ {
+ cls.add(cl);
+ }
+ else
+ {
+ log.warn("Attempt to return connection twice (ignored): " + cl, new Throwable("STACKTRACE"));
+ }
+ }
+
+ if (clPermits.containsKey(cl))
+ {
+ clPermits.remove(cl);
+ permits.release();
+ }
+ }
+
+ if (kill)
+ {
+ if (trace)
+ log.trace("Destroying returned connection " + cl);
+
+ doDestroy(cl);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void flush()
+ {
+ ArrayList<ConnectionListener> destroy = null;
+
+ synchronized (cls)
+ {
+ if (trace)
+ log.trace("Flushing pool checkedOut=" + checkedOut + " inPool=" + cls);
+
+ // Mark checked out connections as requiring destruction
+ for (Iterator<ConnectionListener> i = checkedOut.iterator(); i.hasNext();)
+ {
+ ConnectionListener cl = i.next();
+
+ if (trace)
+ log.trace("Flush marking checked out connection for destruction " + cl);
+
+ cl.setState(ConnectionState.DESTROY);
+ }
+
+ // Destroy connections in the pool
+ while (cls.size() > 0)
+ {
+ ConnectionListener cl = cls.remove(0);
+
+ if (destroy == null)
+ destroy = new ArrayList<ConnectionListener>(1);
+
+ destroy.add(cl);
+ }
+ }
+
+ // We need to destroy some connections
+ if (destroy != null)
+ {
+ for (int i = 0; i < destroy.size(); ++i)
+ {
+ ConnectionListener cl = destroy.get(i);
+
+ if (trace)
+ log.trace("Destroying flushed connection " + cl);
+
+ doDestroy(cl);
+ }
+
+ // We destroyed something, check the minimum.
+ if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void removeIdleConnections()
+ {
+ ArrayList<ConnectionListener> destroy = null;
+ long timeout = System.currentTimeMillis() - poolConfiguration.getIdleTimeout();
+
+ while (true)
+ {
+ synchronized (cls)
+ {
+ // Nothing left to destroy
+ if (cls.size() == 0)
+ break;
+
+ // Check the first in the list
+ ConnectionListener cl = cls.get(0);
+ if (cl.isTimedOut(timeout) && shouldRemove())
+ {
+ // We need to destroy this one
+ cls.remove(0);
+
+ if (destroy == null)
+ destroy = new ArrayList<ConnectionListener>(1);
+
+ destroy.add(cl);
+ }
+ else
+ {
+ // They were inserted chronologically, so if this one isn't timed out, following ones won't be either.
+ break;
+ }
+ }
+ }
+
+ // We found some connections to destroy
+ if (destroy != null)
+ {
+ for (int i = 0; i < destroy.size(); ++i)
+ {
+ ConnectionListener cl = destroy.get(i);
+
+ if (trace)
+ log.trace("Destroying timedout connection " + cl);
+
+ doDestroy(cl);
+ }
+
+ // We destroyed something, check the minimum.
+ if (!shutdown.get() && poolConfiguration.getMinSize() > 0)
+ PoolFiller.fillPool(this);
+
+ // Empty sub-pool
+ if (pool != null)
+ pool.emptySubPool(this);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void shutdown()
+ {
+ shutdown.set(true);
+ IdleRemover.unregisterPool(this);
+ ConnectionValidator.unregisterPool(this);
+ flush();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void fillToMin()
+ {
+ while (true)
+ {
+ // Get a permit - avoids a race when the pool is nearly full
+ // Also avoids unnessary fill checking when all connections are checked out
+ try
+ {
+ if (permits.tryAcquire(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
+ {
+ try
+ {
+ if (shutdown.get())
+ return;
+
+ // We already have enough connections
+ if (poolConfiguration.getMinSize() - (cls.size() + checkedOut.size()) <= 0)
+ return;
+
+ // Create a connection to fill the pool
+ try
+ {
+ ConnectionListener cl = createConnectionEventListener(defaultSubject, defaultCri);
+
+ synchronized (cls)
+ {
+ if (trace)
+ log.trace("Filling pool cl=" + cl);
+
+ cls.add(cl);
+ }
+ }
+ catch (ResourceException re)
+ {
+ log.warn("Unable to fill pool ", re);
+ return;
+ }
+ }
+ finally
+ {
+ permits.release();
+ }
+ }
+ }
+ catch (InterruptedException ignored)
+ {
+ log.trace("Interrupted while requesting permit in fillToMin");
+ }
+ }
+ }
+
+ /**
+ * Create a connection event listener
+ *
+ * @param subject the subject
+ * @param cri the connection request information
+ * @return the new listener
+ * @throws ResourceException for any error
+ */
+ private ConnectionListener createConnectionEventListener(Subject subject, ConnectionRequestInfo cri)
+ throws ResourceException
+ {
+ ManagedConnection mc = mcf.createManagedConnection(subject, cri);
+
+ try
+ {
+ return clf.createConnectionListener(mc, this);
+ }
+ catch (ResourceException re)
+ {
+ mc.destroy();
+ throw re;
+ }
+ }
+
+ /**
+ * Destroy a connection
+ *
+ * @param cl the connection to destroy
+ */
+ private void doDestroy(ConnectionListener cl)
+ {
+ if (cl.getState() == ConnectionState.DESTROYED)
+ {
+ if (trace)
+ log.trace("ManagedConnection is already destroyed " + cl);
+
+ return;
+ }
+
+ cl.setState(ConnectionState.DESTROYED);
+
+ try
+ {
+ cl.getManagedConnection().destroy();
+ }
+ catch (Throwable t)
+ {
+ log.debug("Exception destroying ManagedConnection " + cl, t);
+ }
+ }
+
+ /**
+ * Should any connections be removed from the pool
+ * @return True if connections should be removed; otherwise false
+ */
+ private boolean shouldRemove()
+ {
+ boolean remove = true;
+
+ if (poolConfiguration.isStrictMin())
+ {
+ remove = cls.size() > poolConfiguration.getMinSize();
+
+ if (trace)
+ log.trace("StrictMin is active. Current connection will be removed is " + remove);
+ }
+
+ return remove;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void validateConnections() throws Exception
+ {
+
+ if (trace)
+ log.trace("Attempting to validate connections for pool " + this);
+
+ if (permits.tryAcquire(poolConfiguration.getBlockingTimeout(), TimeUnit.MILLISECONDS))
+ {
+ boolean anyDestroyed = false;
+
+ try
+ {
+ while (true)
+ {
+ ConnectionListener cl = null;
+ boolean destroyed = false;
+
+ synchronized (cls)
+ {
+ if (cls.size() == 0)
+ {
+ break;
+ }
+
+ cl = removeForFrequencyCheck();
+ }
+
+ if (cl == null)
+ {
+ break;
+ }
+
+ try
+ {
+ Set candidateSet = Collections.singleton(cl.getManagedConnection());
+
+ if (mcf instanceof ValidatingManagedConnectionFactory)
+ {
+ ValidatingManagedConnectionFactory vcf = (ValidatingManagedConnectionFactory) mcf;
+ candidateSet = vcf.getInvalidConnections(candidateSet);
+
+ if (candidateSet != null && candidateSet.size() > 0)
+ {
+ if (cl.getState() != ConnectionState.DESTROY)
+ {
+ doDestroy(cl);
+ destroyed = true;
+ anyDestroyed = true;
+ }
+ }
+ }
+ else
+ {
+ log.warn("Warning: background validation was specified with a non " +
+ "compliant ManagedConnectionFactory interface.");
+ }
+ }
+ finally
+ {
+ if (!destroyed)
+ {
+ synchronized (cls)
+ {
+ returnForFrequencyCheck(cl);
+ }
+ }
+ }
+ }
+ }
+ finally
+ {
+ permits.release();
+
+ if (anyDestroyed && !shutdown.get() && poolConfiguration.getMinSize() > 0)
+ {
+ PoolFiller.fillPool(this);
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the connection listener that should be removed due to background validation
+ * @return The listener; otherwise null if none should be removed
+ */
+ private ConnectionListener removeForFrequencyCheck()
+ {
+ log.debug("Checking for connection within frequency");
+
+ ConnectionListener cl = null;
+
+ for (Iterator<ConnectionListener> iter = cls.iterator(); iter.hasNext();)
+ {
+ cl = iter.next();
+ long lastCheck = cl.getLastValidatedTime();
+
+ if ((System.currentTimeMillis() - lastCheck) >= poolConfiguration.getBackgroundValidationInterval())
+ {
+ cls.remove(cl);
+ break;
+ }
+ else
+ {
+ cl = null;
+ }
+ }
+
+ return cl;
+ }
+
+ /**
+ * Return a connection listener to the pool and update its validation timestamp
+ * @param cl The listener
+ */
+ private void returnForFrequencyCheck(ConnectionListener cl)
+ {
+ log.debug("Returning for connection within frequency");
+
+ cl.setLastValidatedTime(System.currentTimeMillis());
+ cls.add(cl);
+ }
+}
Added: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/package.html
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/package.html (rev 0)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/mcp/package.html 2010-09-02 14:59:31 UTC (rev 107950)
@@ -0,0 +1,4 @@
+<body>
+This package contains the managed connection pool implementations and the
+factory to create one with.
+</body>
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/strategy/OnePool.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/strategy/OnePool.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/strategy/OnePool.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -23,8 +23,8 @@
package org.jboss.jca.core.connectionmanager.pool.strategy;
import org.jboss.jca.core.connectionmanager.pool.AbstractPrefillPool;
-import org.jboss.jca.core.connectionmanager.pool.ManagedConnectionPool;
import org.jboss.jca.core.connectionmanager.pool.api.PoolConfiguration;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
import javax.resource.ResourceException;
import javax.resource.spi.ConnectionRequestInfo;
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/validator/ConnectionValidator.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/validator/ConnectionValidator.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/pool/validator/ConnectionValidator.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -22,7 +22,7 @@
package org.jboss.jca.core.connectionmanager.pool.validator;
-import org.jboss.jca.core.connectionmanager.pool.ManagedConnectionPool;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
import java.security.AccessController;
import java.security.PrivilegedAction;
Modified: projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java
===================================================================
--- projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java 2010-09-02 14:38:16 UTC (rev 107949)
+++ projects/jboss-jca/trunk/core/src/main/java/org/jboss/jca/core/connectionmanager/tx/TxConnectionManager.java 2010-09-02 14:59:31 UTC (rev 107950)
@@ -26,8 +26,8 @@
import org.jboss.jca.core.connectionmanager.ConnectionRecord;
import org.jboss.jca.core.connectionmanager.listener.ConnectionListener;
import org.jboss.jca.core.connectionmanager.listener.TxConnectionListener;
-import org.jboss.jca.core.connectionmanager.pool.ManagedConnectionPool;
import org.jboss.jca.core.connectionmanager.pool.SubPoolContext;
+import org.jboss.jca.core.connectionmanager.pool.mcp.ManagedConnectionPool;
import org.jboss.jca.core.connectionmanager.xa.LocalXAResource;
import org.jboss.jca.core.connectionmanager.xa.XAResourceWrapperImpl;
More information about the jboss-cvs-commits
mailing list