User: allsopp 
  Date: 01/01/14 21:07:00

  Added:       src/main/org/jboss/resource/pool
                        GroupBySecurityStrategy.java PoolStrategy.java
                        PoolStrategyFactory.java SinglePoolStrategy.java
  Log:
  First cut at the J2EE Connector Architecture.
  
  Revision  Changes    Path
  1.1                  
jboss/src/main/org/jboss/resource/pool/GroupBySecurityStrategy.java
  
  Index: GroupBySecurityStrategy.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.resource.pool;
  
  import java.sql.SQLException;
  import java.util.Collections;
  import java.util.HashMap;
  import java.util.Iterator;
  import java.util.Map;
  import java.util.Set;
  
  import javax.resource.ResourceException;
  import javax.resource.spi.ApplicationServerInternalException;
  import javax.resource.spi.ConnectionEvent;
  import javax.resource.spi.ConnectionEventListener;
  import javax.resource.spi.ConnectionRequestInfo;
  import javax.resource.spi.ManagedConnection;
  import javax.resource.spi.ManagedConnectionFactory;
  
  import javax.security.auth.Subject;
  
  import org.jboss.logging.Log;
  import org.jboss.logging.LogWriter;
  import org.jboss.minerva.pools.ObjectPool;
  import org.jboss.minerva.pools.PoolEvent;
  import org.jboss.minerva.pools.PoolObjectFactory;
  
  /**
   *   This strategy uses many pools of managed connections, one for
   *   each security context used by the application. This should
   *   provide more efficient matching in the case when there are many
   *   different security contexts and the resource adapter does not
   *   support reauthentication. This will be the case, for example,
   *   when using JDBC with many different resource principals.
   *
   *   @author Toby Allsopp ([EMAIL PROTECTED])
   *   @version $Revision: 1.1 $
   *
   *   @see org.jboss.resource.pool.PoolObjectFactory
   */
  class GroupBySecurityStrategy
     implements PoolStrategy
  {
     // Attributes ----------------------------------------------------
  
     /** Maps from <code>SecurityContext</code> to <code>ObjectPool</code> */
     private Map pools = new HashMap();
  
     /** Maps from <code>ManagedConnection</code> to
         <code>ObjectPool</code> for identifying which pool a managed
         connectino was issued from. */
     private Map issuingPools = Collections.synchronizedMap(new HashMap());
  
     private ManagedConnectionFactory mcf;
     private Log log;
     private ConnectionEventListener listener;
  
     // Constructors --------------------------------------------------
  
     /**
      * Constructed by <code>PoolObjectFactory</code>.
      */
     GroupBySecurityStrategy(ManagedConnectionFactory mcf, Log log)
     {
        this.log = log;
        this.mcf = mcf;
     }
  
     // PoolStrategy implementation -----------------------------------
  
     public void setConnectionEventListener(ConnectionEventListener listener)
     {
        this.listener = listener;
     }
  
     public ManagedConnection getManagedConnection(
        Subject subject, ConnectionRequestInfo cxRequestInfo
        ) throws ResourceException
     {
        SecurityContext secCtx = new SecurityContext(subject, cxRequestInfo);
  
        // First, find the appropriate pool
        ObjectPool pool;
  
        // The synchronisation avoids a race if two threads both use the
        // same new security context. Shutdown is the only other time
        // pools is modified.
        synchronized (pools)
        {
           pool = (ObjectPool) pools.get(secCtx);
           if (pool == null)
           {
              log.debug("No pool for security context '" + secCtx + "', " +
                        "creating one");
              pool = createPool(secCtx);
              pools.put(secCtx, pool);
              // Note that nothing is removed from pools, so it can grow
              // and potentially run the system into the ground, but only
              // if there are a *very* large number of security contexts.
           }
        }
  
        // Then, find an appropriate managed connection from it
        ManagedConnection mc;
        synchronized (pool)
        {
           if (subject == null && cxRequestInfo == null)
           {
              // We don't bother the managed connection factory with
              // connection matching if there's no information for it
              // to use. This is actually a work-around for a NPE in
              // the black-box reference resource adapter.
              mc = (ManagedConnection) pool.getObject();
           }
           else
           {
              Set mcs = pool.getObjects();
              try
              {
                 mc = mcf.matchManagedConnections(mcs, subject, cxRequestInfo);
                 if (mc == null)
                    // This must return an appropriate managed
                    // connection because the pool is guaranteed to
                    // be empty after getObjects() so the pool will
                    // create a new managed connection using the
                    // correct subject and cxRequestInfo
                    mc = (ManagedConnection) pool.getObject();
                 else
                    mcs.remove(mc);
              }
              finally
              {
                 pool.releaseObjects(mcs);
              }
           }
        }
  
        issuingPools.put(mc, pool);
        return mc;
     }
  
     public void releaseManagedConnection(ManagedConnection mc)
        throws ResourceException
     {
        ObjectPool pool = (ObjectPool) issuingPools.remove(mc);
        if (pool == null)
           throw new ApplicationServerInternalException(
              "It appears that the managed connection '" + mc + "' was not " +
              "issued by this instance, so it can't be returned to its pool.");
  
        synchronized (pool)
        {
           pool.releaseObject(mc);
        }
     }
  
     public void condemnManagedConnection(ManagedConnection mc)
        throws ResourceException
     {
        ObjectPool pool = (ObjectPool) issuingPools.get(mc);
        if (pool == null)
           throw new ApplicationServerInternalException(
              "It appears that the managed connection '" + mc + "' was not " +
              "issued by this instance, so it can't be condemned.");
        synchronized (pool)
        {
           pool.markObjectAsInvalid(mc);
        }
     }
  
     public void shutdown()
     {
        if (issuingPools.size() > 0)
           log.warning("Pools being shut down with outstanding connections");
        synchronized (pools)
        {
           for (Iterator i=pools.values().iterator(); i.hasNext();)
           {
              ObjectPool pool = (ObjectPool) i.next();
              i.remove();
              synchronized (pool)
              {
                 log.debug("Shutting down pool '" + pool + "'");
                 pool.shutDown();
              }
           }
        }
     }
  
     // Private -------------------------------------------------------
  
     private ObjectPool createPool(SecurityContext secCtx)
     {
        ObjectPool pool = new ObjectPool(new MCPoolObjectFactory(secCtx),
                                         mcf.toString());
        try
        {
           pool.setLogWriter(new LogWriter(log));
        }
        catch (SQLException sqle)
        {
           log.exception(sqle);
        }
        //FIXME set the pool properties from the ConnectionFactoryLoader
        //(pass them in in some kind of metadata?)
        pool.initialize();
        return pool;
     }
  
     // Inner classes -------------------------------------------------
  
     private static class SecurityContext
     {
        public Subject subject;
        public ConnectionRequestInfo cxRequestInfo;
  
        public SecurityContext(Subject subject,
                               ConnectionRequestInfo cxRequestInfo)
        {
           this.subject = subject;
           this.cxRequestInfo = cxRequestInfo;
        }
  
        public boolean equals(Object o)
        {
           if (o instanceof SecurityContext)
           {
              SecurityContext other = (SecurityContext) o;
              boolean result = true;
              if (subject == null)
                 result = result && other.subject == null;
              else
              {
                 result = result && other.subject != null;
                 result = result && subject.equals(other.subject);
              }
              if (cxRequestInfo == null)
                 result = result && other.cxRequestInfo == null;
              else
              {
                 result = result && other.cxRequestInfo != null;
                 result = result && cxRequestInfo.equals(other.cxRequestInfo);
              }
              return result;
           }
           return false;
        }
  
        public int hashCode()
        {
           return ((subject==null) ? 0 : subject.hashCode()) ^
              ((cxRequestInfo==null) ? 0 : cxRequestInfo.hashCode());
        }
  
        public String toString()
        {
           return super.toString() + ": subject = \"" + subject + "\", " +
              "cxRequestInfo = \"" + cxRequestInfo + "\"";
        }
     }
  
     private class MCPoolObjectFactory
        extends PoolObjectFactory
     {
        private SecurityContext secCtx;
  
        public MCPoolObjectFactory(SecurityContext secCtx)
        {
           this.secCtx = secCtx;
        }
  
        public Object createObject()
        {
           log.debug("Creating mamanged connection");
           try
           {
              return mcf.createManagedConnection(secCtx.subject,
                                                 secCtx.cxRequestInfo);
           }
           catch (ResourceException re)
           {
              log.exception(re);
              return null;
           }
        }
  
        public Object prepareObject(Object pooledObject)
        {
           ManagedConnection mc = (ManagedConnection) pooledObject;
           mc.addConnectionEventListener(listener);
           return mc;
        }
  
        public Object returnObject(Object pooledObject)
        {
           ManagedConnection mc = (ManagedConnection) pooledObject;
           try
           {
              mc.removeConnectionEventListener(listener);
              mc.cleanup();
              return mc;
           }
           catch (ResourceException re)
           {
              // Oh, no! What do we do now?
              log.exception(re);
              throw new RuntimeException(re.toString());
           }
        }
  
        public void deleteObject(Object pooledObject)
        {
           log.debug("Destroying mamanged connection '" + pooledObject + "'");
           ManagedConnection mc = (ManagedConnection) pooledObject;
           try
           {
              mc.destroy();
           }
           catch (ResourceException re)
           {
              log.exception(re);
           }
        }
     }
  }
  
  
  
  1.1                  jboss/src/main/org/jboss/resource/pool/PoolStrategy.java
  
  Index: PoolStrategy.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.resource.pool;
  
  import java.util.Set;
  
  import javax.resource.ResourceException;
  import javax.resource.spi.ConnectionEvent;
  import javax.resource.spi.ConnectionEventListener;
  import javax.resource.spi.ConnectionRequestInfo;
  import javax.resource.spi.ManagedConnection;
  import javax.resource.spi.ManagedConnectionFactory;
  
  import javax.security.auth.Subject;
  
  import org.jboss.logging.Log;
  import org.jboss.minerva.pools.ObjectPool;
  import org.jboss.minerva.pools.PoolEvent;
  import org.jboss.minerva.pools.PoolObjectFactory;
  import org.jboss.resource.RARMetaData;
  
  /**
   *   Pooling strategy for the connection manager
   *
   *   @see org.jboss.resource.ConnectionManagerImpl
   *   @author Toby Allsopp ([EMAIL PROTECTED])
   *   @version $Revision: 1.1 $
   */
  public interface PoolStrategy
  {
     // Constants -----------------------------------------------------
  
     // Static --------------------------------------------------------
  
     // Public --------------------------------------------------------
  
     /**
      * Sets the connection event listener that will be registered with
      * every connection returned by <code>getManagedConnection</code>.
      */
     void setConnectionEventListener(ConnectionEventListener listener);
  
     /**
      * Obtains a managed connection, returning either a newly created
      * connection or one from a pool. The parameters are passed as-is
      * to the managed connection factory.
      */
     ManagedConnection getManagedConnection(Subject subject,
                                            ConnectionRequestInfo cxRequestInfo)
        throws ResourceException;
  
     /**
      * Indicates that the application component has finished with the
      * managed connection and it can be returned to the pool from
      * whence it came.
      */
     void releaseManagedConnection(ManagedConnection conn)
        throws ResourceException;
  
     /**
      * Consigns the managed connection to the deepest pits of hell, for
      * example in the case of a connection error. Note that the managed
      * connection <b>must still be released using
      * <code>releaseManagedConnection</code></b>.
      */
     void condemnManagedConnection(ManagedConnection conn)
        throws ResourceException;
  
     /**
      * Destroys all pooled managed connections.
      */
     void shutdown();
  
     // Inner classes -------------------------------------------------
  }
  
  
  
  1.1                  jboss/src/main/org/jboss/resource/pool/PoolStrategyFactory.java
  
  Index: PoolStrategyFactory.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.resource.pool;
  
  import javax.resource.spi.ManagedConnectionFactory;
  
  import org.jboss.logging.Log;
  import org.jboss.resource.ConnectionFactoryConfig;
  import org.jboss.resource.RARMetaData;
  
  /**
   *   Creates {@link org.jboss.resource.pool.PoolStrategy}
   *   implementations.
   *
   *   @see org.jboss.resource.ConnectionManagerImpl
   *   @author Toby Allsopp ([EMAIL PROTECTED])
   *   @version $Revision: 1.1 $
   */
  public class PoolStrategyFactory
  {
     // Constants -----------------------------------------------------
  
     // Attributes ----------------------------------------------------
  
     // Static --------------------------------------------------------
  
     /**
      * Creates a new instance of an implementation of
      * <code>PoolStrategy</code> for managing connections created by
      * the specified managed connection factory.
      *
      * @param metadata used to select the pool strategy implementation
      * @param mcf the managed connection factory from which connections
      *            will be managed
      */
     public static PoolStrategy getStrategy(RARMetaData rarMetadata,
                                            ConnectionFactoryConfig cfConfig,
                                            ManagedConnectionFactory mcf,
                                            Log log)
     {
        String manualStrategy = cfConfig.getPoolStrategy();
        if (manualStrategy != null)
        {
           if (manualStrategy.equals("Single"))
              return new SinglePoolStrategy(mcf, log);
           if (manualStrategy.equals("Group"))
              return new GroupBySecurityStrategy(mcf, log);
           log.warning("Unrecognized pool strategy '" + manualStrategy + "', " +
                       "using automatic selection");
        }
  
        // We only want to use the single pool strategy if we know that
        // there's likely to only be one security context, i.e. only one
        // resource principal. Also, we should avoid the single pool
        // strategy if the resource adapter can't do reauthentication
        // because otherwise we might end up with lengthy
        // matchManagedConnection calls.
        if (!rarMetadata.getReauthenticationSupport() ||
            !cfConfig.getPrincipalMappingClass().equals(
               "org.jboss.resource.security.ManyToOnePrincipalMapping"))
        {
           log.debug("Choosing \"group by security\" pool strategy");
           return new GroupBySecurityStrategy(mcf, log);
        }
        else
        {
           log.debug("Choosing \"single pool \" pool strategy");
           return new SinglePoolStrategy(mcf, log);
        }
     }
  
     // Constructors --------------------------------------------------
  
     /**
      * Do not instantiate.
      */
     private PoolStrategyFactory() {}
  
     // Public --------------------------------------------------------
  
     // Package protected ---------------------------------------------
  
     // Protected -----------------------------------------------------
  
     // Private -------------------------------------------------------
  
     // Inner classes -------------------------------------------------
  }
  
  
  
  1.1                  jboss/src/main/org/jboss/resource/pool/SinglePoolStrategy.java
  
  Index: SinglePoolStrategy.java
  ===================================================================
  /*
   * JBoss, the OpenSource EJB server
   *
   * Distributable under LGPL license.
   * See terms of license at gnu.org.
   */
  package org.jboss.resource.pool;
  
  import java.sql.SQLException;
  import java.util.Set;
  
  import javax.resource.ResourceException;
  import javax.resource.spi.ApplicationServerInternalException;
  import javax.resource.spi.ConnectionEvent;
  import javax.resource.spi.ConnectionEventListener;
  import javax.resource.spi.ConnectionRequestInfo;
  import javax.resource.spi.ManagedConnection;
  import javax.resource.spi.ManagedConnectionFactory;
  
  import javax.security.auth.Subject;
  
  import org.jboss.logging.Log;
  import org.jboss.logging.LogWriter;
  import org.jboss.minerva.pools.ObjectPool;
  import org.jboss.minerva.pools.PoolEvent;
  import org.jboss.minerva.pools.PoolObjectFactory;
  
  /**
   *   This strategy uses a single pool of managed connections; it is
   *   left up to the managed connection factory to select an
   *   appropriate connection. The efficiency of this strategy depends
   *   on how the resource adapter implements
   *   <code>matchManagedConnections</code>.
   *
   *   @author Toby Allsopp ([EMAIL PROTECTED])
   *   @version $Revision: 1.1 $
   */
  class SinglePoolStrategy
     implements PoolStrategy
  {
     // Attributes ----------------------------------------------------
  
     private ObjectPool pool;
     private ManagedConnectionFactory mcf;
     private Log log;
     private ConnectionEventListener listener;
  
     // These are used as communication from getManagedConnection to
     // MCPoolObjectFactory.createObject
     private boolean okToCreate = false;
     private Subject subject;
     private ConnectionRequestInfo cxRequestInfo;
  
     // Constructors --------------------------------------------------
  
     SinglePoolStrategy(ManagedConnectionFactory mcf, Log log)
     {
        this.log = log;
        this.mcf = mcf;
        pool = new ObjectPool(new MCPoolObjectFactory(), mcf.toString());
        try
        {
           pool.setLogWriter(new LogWriter(log));
        }
        catch (SQLException sqle)
        {
           log.exception(sqle);
        }
        //FIXME set the pool properties from the ConnectionFactoryLoader
        //(pass them in in some kind of metadata?)
        pool.initialize();
     }
  
     // PoolStrategy implementation -----------------------------------
  
     public void setConnectionEventListener(ConnectionEventListener listener)
     {
        this.listener = listener;
     }
  
     public ManagedConnection getManagedConnection(
        Subject subject, ConnectionRequestInfo cxRequestInfo
        ) throws ResourceException
     {
        ManagedConnection mc;
        synchronized (pool)
        {
           this.subject = subject;
           this.cxRequestInfo = cxRequestInfo;
           okToCreate = true;
           try
           {
              if (subject == null && cxRequestInfo == null)
              {
                 // We don't bother the managed connection factory with
                 // connection matching if there's no information for it
                 // to use. This is actually a work-around for a NPE in
                 // the black-box reference resource adapter.
                 mc = (ManagedConnection) pool.getObject();
              }
              else
              {
                 Set mcs = pool.getObjects();
                 try
                 {
                    mc = mcf.matchManagedConnections(mcs, subject, cxRequestInfo);
                    if (mc == null)
                       // This must return an appropriate managed
                       // connection because the pool is guaranteed to
                       // be empty after getObjects() so the pool will
                       // create a new managed connection using the
                       // correct subject and cxRequestInfo
                       mc = (ManagedConnection) pool.getObject();
                    else
                       mcs.remove(mc);
                 }
                 finally
                 {
                    pool.releaseObjects(mcs);
                 }
              }
           }
           finally
           {
              okToCreate = false;
              this.subject = null;
              this.cxRequestInfo = null;
           }
        }
  
        return mc;
     }
  
     public void releaseManagedConnection(ManagedConnection mc)
        throws ResourceException
     {
        synchronized (pool)
        {
           pool.releaseObject(mc);
        }
     }
  
     public void condemnManagedConnection(ManagedConnection mc)
     {
        synchronized (pool)
        {
           pool.markObjectAsInvalid(mc);
        }
     }
  
     public void shutdown()
     {
        synchronized (pool)
        {
           pool.shutDown();
        }
     }
  
     // Inner classes -------------------------------------------------
  
     private class MCPoolObjectFactory
        extends PoolObjectFactory
     {
        public Object createObject()
        {
           log.debug("Creating mamanged connection");
           try
           {
              synchronized (pool)
              {
                 if (!okToCreate)
                 {
                    // This means that the pool has taken it upon itself
                    // to create a connection. We can't do this because
                    // we don't know what to use for subject or
                    // cxRequestInfo.
                    throw new ApplicationServerInternalException(
                       "Pool attempted to create a connection not in response " +
                       "to getManagedConnection");
                 }
                 ManagedConnection mc =
                    mcf.createManagedConnection(subject, cxRequestInfo);
                 return mc;
              }
           }
           catch (ResourceException re)
           {
              log.exception(re);
              return null;
           }
        }
  
        public Object prepareObject(Object pooledObject)
        {
           ManagedConnection mc = (ManagedConnection) pooledObject;
           mc.addConnectionEventListener(listener);
           return mc;
        }
  
        public Object returnObject(Object pooledObject)
        {
           ManagedConnection mc = (ManagedConnection) pooledObject;
           try
           {
              mc.removeConnectionEventListener(listener);
              mc.cleanup();
              return mc;
           }
           catch (ResourceException re)
           {
              // Oh, no! What do we do now?
              log.exception(re);
              throw new RuntimeException(re.toString());
           }
        }
  
        public void deleteObject(Object pooledObject)
        {
           log.debug("Destroying mamanged connection '" + pooledObject + "'");
           ManagedConnection mc = (ManagedConnection) pooledObject;
           try
           {
              mc.destroy();
           }
           catch (ResourceException re)
           {
              log.exception(re);
           }
        }
     }
  }
  
  
  

Reply via email to