[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