Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » resource » connectionmanager » [javadoc | source]
    1   /*
    2    * JBoss, Home of Professional Open Source.
    3    * Copyright 2006, Red Hat Middleware LLC, and individual contributors
    4    * as indicated by the @author tags. See the copyright.txt file in the
    5    * distribution for a full listing of individual contributors.
    6    *
    7    * This is free software; you can redistribute it and/or modify it
    8    * under the terms of the GNU Lesser General Public License as
    9    * published by the Free Software Foundation; either version 2.1 of
   10    * the License, or (at your option) any later version.
   11    *
   12    * This software is distributed in the hope that it will be useful,
   13    * but WITHOUT ANY WARRANTY; without even the implied warranty of
   14    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   15    * Lesser General Public License for more details.
   16    *
   17    * You should have received a copy of the GNU Lesser General Public
   18    * License along with this software; if not, write to the Free
   19    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
   20    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
   21    */
   22   package org.jboss.resource.connectionmanager;
   23   
   24   import java.security.AccessController;
   25   import java.security.PrivilegedAction;
   26   import java.util.Iterator;
   27   import java.util.Map;
   28   import java.util.Set;
   29   
   30   import javax.management.Notification;
   31   import javax.management.NotificationFilter;
   32   import javax.management.NotificationListener;
   33   import javax.management.ObjectName;
   34   import javax.resource.ResourceException;
   35   import javax.resource.spi.ConnectionRequestInfo;
   36   import javax.resource.spi.ManagedConnection;
   37   import javax.resource.spi.ManagedConnectionFactory;
   38   import javax.security.auth.Subject;
   39   import javax.transaction.Transaction;
   40   import javax.transaction.TransactionManager;
   41   
   42   import org.jboss.deployers.spi.DeploymentException;
   43   import org.jboss.logging.Logger;
   44   import org.jboss.managed.api.ManagedOperation.Impact;
   45   import org.jboss.managed.api.annotation.ManagementObject;
   46   import org.jboss.managed.api.annotation.ManagementObjectID;
   47   import org.jboss.managed.api.annotation.ManagementOperation;
   48   import org.jboss.managed.api.annotation.ManagementParameter;
   49   import org.jboss.managed.api.annotation.ManagementProperties;
   50   import org.jboss.managed.api.annotation.ManagementProperty;
   51   import org.jboss.managed.api.annotation.ViewUse;
   52   import org.jboss.mx.util.JMXExceptionDecoder;
   53   import org.jboss.resource.JBossResourceException;
   54   import org.jboss.resource.connectionmanager.InternalManagedConnectionPool.PoolParams;
   55   import org.jboss.resource.statistic.JBossStatistics;
   56   import org.jboss.resource.statistic.StatisticsReporter;
   57   import org.jboss.resource.statistic.formatter.StatisticsFormatter;
   58   import org.jboss.resource.statistic.pool.JBossDefaultSubPoolStatisticFormatter;
   59   import org.jboss.resource.statistic.pool.JBossManagedConnectionPoolStatistics;
   60   import org.jboss.resource.statistic.pool.JBossSubPoolStatistics;
   61   import org.jboss.resource.statistic.pool.ManagedConnectionPoolStatistics;
   62   import org.jboss.system.ServiceMBeanSupport;
   63   import org.jboss.tm.TransactionLocal;
   64   
   65   import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
   66   
   67   /**
   68    * The JBossManagedConnectionPool mbean configures and supplies pooling of
   69    * JBossConnectionEventListeners to the BaseConnectionManager2 mbean.<p>
   70    *   
   71    * It may be replaced by any mbean with a readable ManagedConnectionPool attribute
   72    * of type ManagedConnectionPool.  Normal pooling parameters are supplied,
   73    * and the criteria to distinguish ManagedConnections is set in the Criteria attribute.
   74    *
   75    * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks</a>
   76    * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a>
   77    * @author <a href="mailto:weston.price@jboss.com">Weston Price</a>
   78    * 
   79    * @version $Revision: 74342 $
   80    */
   81   @ManagementObject(isRuntime=true, properties=ManagementProperties.EXPLICIT)
   82   public class JBossManagedConnectionPool extends ServiceMBeanSupport 
   83      implements JBossManagedConnectionPoolMBean, NotificationListener
   84   {
   85      
   86      static Logger log = Logger.getLogger(JBossManagedConnectionPool.class);
   87      
   88      /** The managed connection factory name */
   89      private ObjectName managedConnectionFactoryName;
   90   
   91      /** The pooling criteria */
   92      private String criteria;
   93   
   94      /** The pooling strategy */
   95      private ManagedConnectionPool poolingStrategy;
   96   
   97      /** The pooling parameters */
   98      private final InternalManagedConnectionPool.PoolParams poolParams = new InternalManagedConnectionPool.PoolParams();
   99   
  100      /** Whether to use separate pools for transactional and non-transaction use */
  101      private boolean noTxSeparatePools;
  102   
  103      /** The statisticsFormatter 
  104       *
  105       * */
  106      private String statisticsFormatter;
  107      /** The mcf jndi name */
  108      private String poolJndiName;
  109   
  110      public JBossManagedConnectionPool()
  111      {
  112      }
  113      
  114      @ManagementOperation(description="Obtain a formatted statistics report",
  115            impact=Impact.ReadOnly,
  116            params={@ManagementParameter(name="formatClassName",description="The StatisticsFormatter class name")})
  117      public Object listFormattedSubPoolStatistics(String formatClassName)
  118      {
  119         final JBossStatistics stats = (JBossStatistics)listStatistics();
  120         final ClassLoader cl = Thread.currentThread().getContextClassLoader();
  121         Class clazz;
  122         StatisticsFormatter formatter = null;
  123         
  124         try
  125         {
  126            clazz = cl.loadClass(formatClassName);
  127            formatter = (StatisticsFormatter)clazz.newInstance();
  128         }
  129         catch (Exception e)
  130         {
  131            log.warn("warn: statistics formatter not found, setting to " + statisticsFormatter);
  132            formatter = new JBossDefaultSubPoolStatisticFormatter();
  133            
  134         }
  135      
  136         return formatter.formatStatistics(stats);      
  137      }
  138   
  139      @ManagementOperation(description="Obtain a formatted statistics report",
  140            impact=Impact.ReadOnly)
  141      public Object listFormattedSubPoolStatistics()
  142      {
  143         
  144         Object formatted = listFormattedSubPoolStatistics(statisticsFormatter);
  145         return formatted;  
  146      }
  147      
  148      @ManagementOperation(description="Obtain a statistics report",
  149            impact=Impact.ReadOnly)
  150      public Object listStatistics()
  151      {
  152         ManagedConnectionPoolStatistics stats = null;
  153         
  154         if (poolingStrategy instanceof StatisticsReporter)
  155         {
  156            
  157            StatisticsReporter reporter = (StatisticsReporter) poolingStrategy;
  158            stats = (ManagedConnectionPoolStatistics)reporter.listStatistics();
  159            stats.setCriteria(getCriteria());
  160            stats.setName(getManagedConnectionFactoryName().toString());
  161            
  162         }
  163         
  164         return stats;      
  165      }
  166      
  167      public Object listUnderlyingNativeConnectionStatistics()
  168      {
  169          return poolingStrategy.listUnderlyingNativeConnectionStatistics();
  170      }
  171    
  172      public ManagedConnectionPool getManagedConnectionPool()
  173      {
  174         return poolingStrategy;
  175      }
  176   
  177      public ObjectName getManagedConnectionFactoryName()
  178      {
  179         return managedConnectionFactoryName;
  180      }
  181   
  182      public void setManagedConnectionFactoryName(ObjectName newManagedConnectionFactoryName)
  183      {
  184         this.managedConnectionFactoryName = newManagedConnectionFactoryName;
  185      }
  186   
  187      @ManagementProperty(use={ViewUse.STATISTIC}, description="number of available connection")
  188      public long getAvailableConnectionCount()
  189      {
  190         return (poolingStrategy == null) ? 0 : poolingStrategy.getAvailableConnectionCount();
  191      }
  192   
  193      @ManagementProperty(use={ViewUse.STATISTIC}, description="number of maximum connections in use")
  194      public long getMaxConnectionsInUseCount()
  195      {
  196         return (poolingStrategy == null) ? 0 : poolingStrategy.getMaxConnectionsInUseCount();
  197      }
  198   
  199      @ManagementProperty(use={ViewUse.STATISTIC}, description="number of connections currently in use")
  200      public long getInUseConnectionCount ()
  201      {
  202         return (poolingStrategy == null) ? 0 : poolingStrategy.getInUseConnectionCount();
  203      }
  204   
  205      @ManagementProperty(use={ViewUse.STATISTIC})
  206      public int getMinSize()
  207      {
  208         return poolParams.minSize;
  209      }
  210   
  211      public void setMinSize(int newMinSize)
  212      {
  213         poolParams.minSize = newMinSize;
  214      }
  215   
  216      @ManagementProperty(use={ViewUse.STATISTIC})
  217      public int getMaxSize()
  218      {
  219         return poolParams.maxSize;
  220      }
  221   
  222      public void setMaxSize(int newMaxSize)
  223      {
  224         poolParams.maxSize = newMaxSize;
  225      }
  226   
  227      public int getBlockingTimeoutMillis()
  228      {
  229         return poolParams.blockingTimeout;
  230      }
  231   
  232      public void setBlockingTimeoutMillis(int newBlockingTimeout)
  233      {
  234         poolParams.blockingTimeout = newBlockingTimeout;
  235      }
  236   
  237      public long getIdleTimeoutMinutes()
  238      {
  239         return poolParams.idleTimeout / (1000 * 60);
  240      }
  241   
  242      public void setIdleTimeoutMinutes(long newIdleTimeoutMinutes)
  243      {
  244         poolParams.idleTimeout = newIdleTimeoutMinutes * 1000 * 60;
  245      }
  246   
  247      /**
  248       * Get the IdleTimeout value.
  249       *
  250       * @return the IdleTimeout value.
  251       */
  252      public long getIdleTimeout()
  253      {
  254         return poolParams.idleTimeout;
  255      }
  256   
  257      /**
  258       * Set the IdleTimeout value.
  259       *
  260       * @param newIdleTimeout The new IdleTimeout value.
  261       */
  262      public void setIdleTimeout(long newIdleTimeout)
  263      {
  264         poolParams.idleTimeout = newIdleTimeout;
  265      }
  266   
  267      public String getCriteria()
  268      {
  269         return criteria;
  270      }
  271   
  272      public void setCriteria(String newCriteria)
  273      {
  274         this.criteria = newCriteria;
  275      }
  276   
  277      public boolean getNoTxSeparatePools()
  278      {
  279         return noTxSeparatePools;
  280      }
  281   
  282      public void setNoTxSeparatePools(boolean value)
  283      {
  284         this.noTxSeparatePools = value;
  285      }
  286   
  287      public boolean getPreFill(){
  288         
  289         return poolParams.prefill;
  290         
  291      }
  292      
  293      public void setPreFill(boolean prefill){
  294         
  295         poolParams.prefill = prefill;
  296      }
  297      
  298      public void setStrictMin(boolean strictMin)
  299      {
  300         poolParams.stictMin = strictMin;
  301         
  302      }
  303      
  304      public boolean getStrictMin()
  305      {
  306            
  307         return poolParams.stictMin;
  308         
  309      }
  310      
  311      public boolean getUseFastFail()
  312      {
  313         return this.poolParams.useFastFail;
  314      }
  315      
  316      public void setUseFastFail(boolean useFastFail)
  317      {
  318         this.poolParams.useFastFail = useFastFail;
  319      }
  320      @ManagementOperation(description="Flush the connections in the pool",
  321            impact=Impact.WriteOnly)
  322      public void flush()
  323      {
  324   	   if (poolingStrategy == null)
  325            throw new IllegalStateException("The connection pool is not started");
  326   
  327         poolingStrategy.flush();
  328   
  329         if (poolingStrategy instanceof PreFillPoolSupport)
  330         {
  331            final PreFillPoolSupport pfs = (PreFillPoolSupport) poolingStrategy;
  332   
  333            if (pfs.shouldPreFill())
  334               pfs.prefill(noTxSeparatePools);
  335   
  336         }
  337      }
  338   
  339      @ManagementProperty(use={ViewUse.STATISTIC})
  340      public int getConnectionCount()
  341      {
  342         return (poolingStrategy == null)? 0: poolingStrategy.getConnectionCount();
  343      }
  344   
  345      @ManagementProperty(use={ViewUse.STATISTIC})
  346      public int getConnectionCreatedCount()
  347      {
  348         return (poolingStrategy == null)? 0: poolingStrategy.getConnectionCreatedCount();
  349      }
  350   
  351      @ManagementProperty(use={ViewUse.STATISTIC})
  352      public int getConnectionDestroyedCount()
  353      {
  354         return (poolingStrategy == null)? 0: poolingStrategy.getConnectionDestroyedCount();
  355      }
  356   
  357      public String getName()
  358      {
  359         return "JBossManagedConnectionPool";
  360      }
  361      public String getStatisticsFormatter()
  362      {
  363         return statisticsFormatter;
  364      }
  365   
  366      public void setStatisticsFormatter(String statisticsFormatter)
  367      {
  368         this.statisticsFormatter = statisticsFormatter;
  369      }
  370   
  371      /**
  372       * The connection factory jndi name. This is used to tie the pool
  373       * ManagedObject back to the ManagedConnectionFactoryDeploymentMetaData
  374       * @return
  375       */
  376      @ManagementObjectID(type="DataSource")
  377      @ManagementProperty(use={ViewUse.RUNTIME})
  378      public String getPoolJndiName()
  379      {
  380         return this.poolJndiName;
  381      }
  382   
  383      public void setPoolJndiName(String poolName)
  384      {
  385         this.poolJndiName = poolName;
  386      }
  387   
  388      public long getBackGroundValidationMillis()
  389      {
  390         return poolParams.backgroundInterval;
  391      }
  392   
  393      public void setBackGroundValidationMillis(long backgroundValidationInterval)
  394      {
  395   
  396         poolParams.backgroundInterval = backgroundValidationInterval;
  397      }
  398   
  399      protected void startService() throws Exception
  400      {
  401         ManagedConnectionFactory mcf = null;
  402         
  403         if(managedConnectionFactoryName == null)
  404         {
  405            throw new org.jboss.deployers.spi.DeploymentException("ManagedConnectionFactory is not set.");          
  406         
  407         }
  408            
  409         try
  410         {
  411            //We are getting the actual mcf instance itself.  This will require
  412            //some work if the mcf is an xmbean of itself.
  413            mcf = (ManagedConnectionFactory)server.getAttribute(managedConnectionFactoryName, "McfInstance");
  414         }
  415         catch (Exception e)
  416         {
  417            JMXExceptionDecoder.rethrow(e);
  418         }
  419   
  420         getServer().addNotificationListener
  421         (
  422            managedConnectionFactoryName,
  423            this,
  424            new NotificationFilter()
  425            {
  426               private static final long serialVersionUID = -9211456539783257343L;
  427   
  428               public boolean isNotificationEnabled(Notification n)
  429               {
  430                  return RARDeployment.MCF_ATTRIBUTE_CHANGED_NOTIFICATION.equals(n.getType())
  431                         && managedConnectionFactoryName.equals(n.getSource());
  432               }
  433            },
  434            null
  435         );
  436   
  437         if ("ByContainerAndApplication".equals(criteria))
  438            poolingStrategy = new PoolBySubjectAndCri(mcf, poolParams, noTxSeparatePools, log);
  439         else if ("ByContainer".equals(criteria))
  440            poolingStrategy = new PoolBySubject(mcf, poolParams, noTxSeparatePools, log);
  441         else if ("ByApplication".equals(criteria))
  442            poolingStrategy = new PoolByCri(mcf, poolParams, noTxSeparatePools, log);
  443         else if ("ByNothing".equals(criteria))
  444            poolingStrategy = new OnePool(mcf, poolParams, noTxSeparatePools, log);
  445         else
  446            throw new DeploymentException("Unknown pooling criteria: " + criteria); 
  447            
  448      }
  449   
  450      protected void stopService() throws Exception
  451      {
  452         if (poolingStrategy != null)
  453         {
  454            poolingStrategy.shutdown();
  455            
  456         }
  457   
  458         getServer().removeNotificationListener(managedConnectionFactoryName, this);
  459         poolingStrategy = null;
  460      }
  461   
  462      public void handleNotification(Notification notification, Object handback)
  463      {
  464         log.trace("Flushing pool due to notification from ManagedConnectionFactory" + notification);      
  465         flush();
  466      }
  467   
  468      public static class SubPoolContext
  469      {
  470         /** The subpool */
  471         private InternalManagedConnectionPool subPool;
  472         
  473         /** The track by transaction transaction local */
  474         private TransactionLocal trackByTx;
  475   
  476         /**
  477          * Create a new SubPoolContext.
  478          * 
  479          * @param tm the transaction manager
  480          * @param mcf the managed connection factory
  481          * @param clf the connection listener factory
  482          * @param subject the subject
  483          * @param cri the connection request info
  484          * @param poolParams the pool parameters
  485          * @param log the log
  486          */
  487         public SubPoolContext(TransactionManager tm, ManagedConnectionFactory mcf, ConnectionListenerFactory clf, Subject subject,
  488               ConnectionRequestInfo cri, PoolParams poolParams, Logger log)
  489         {
  490            subPool = new InternalManagedConnectionPool(mcf, clf, subject, cri, poolParams, log);
  491            if (tm != null)
  492               trackByTx = new TransactionLocal(tm);
  493         }
  494         
  495         /**
  496          * Get the sub pool
  497          * 
  498          * @return the sub pool
  499          */
  500         public InternalManagedConnectionPool getSubPool()
  501         {
  502            return subPool;
  503         }
  504         
  505         /**
  506          * Get the track by transaction
  507          * 
  508          * @return the transaction local
  509          */
  510         public TransactionLocal getTrackByTx()
  511         {
  512            return trackByTx;
  513         }
  514         
  515         /**
  516          * Initialize the subpool context
  517          */
  518         public void initialize()
  519         {
  520            subPool.initialize();
  521         }
  522      }
  523      
  524      /**
  525       * The base pool implementation
  526       */
  527      public abstract static class BasePool implements ManagedConnectionPool, StatisticsReporter, PreFillPoolSupport
  528      {
  529         /** The subpools */
  530         private final Map subPools = new ConcurrentReaderHashMap();
  531   
  532         /** The managed connection factory */
  533         private final ManagedConnectionFactory mcf;
  534         
  535         /** The connection listener factory */
  536         private ConnectionListenerFactory clf;
  537   
  538         /** The pool parameters */
  539         private final InternalManagedConnectionPool.PoolParams poolParams;
  540   
  541         /** Whether to use separate pools for transactional and non-transaction use */
  542         private boolean noTxSeparatePools;
  543   
  544         /** The poolName */
  545         private String poolName;
  546         /** The logger */
  547         private final Logger log;
  548   
  549         /** Is trace enabled */
  550         private boolean traceEnabled = false;
  551   
  552         /**
  553          * Create a new base pool
  554          * 
  555          * @param mcf the managed connection factory
  556          * @param poolParams the pooling parameters
  557          * @param log the log
  558          */
  559         public BasePool(final ManagedConnectionFactory mcf, final InternalManagedConnectionPool.PoolParams poolParams,
  560                         final boolean noTxSeparatePools, final Logger log)
  561         {
  562            this.mcf = mcf;
  563            this.poolParams = poolParams;
  564            this.noTxSeparatePools = noTxSeparatePools;
  565            this.log = log;
  566            this.traceEnabled = log.isTraceEnabled();
  567         }
  568   
  569         /**
  570          * Retrieve the key for this request
  571          * 
  572          * @param subject the subject 
  573          * @param cri the connection request information
  574          * @return the key
  575          * @throws ResourceException for any error
  576          */
  577         protected abstract Object getKey(Subject subject, ConnectionRequestInfo cri, boolean separateNoTx) throws ResourceException;
  578         
  579        
  580         public ManagedConnectionFactory getManagedConnectionFactory()
  581         {
  582            return mcf;
  583         }
  584   
  585         public void setConnectionListenerFactory(ConnectionListenerFactory clf)
  586         {
  587            this.clf = clf;
  588         }
  589        
  590         public ConnectionListener getConnection(Transaction trackByTransaction, Subject subject, ConnectionRequestInfo cri)
  591            throws ResourceException
  592         {
  593            // Determine the pool key for this request
  594            boolean separateNoTx = false;
  595            if (noTxSeparatePools)
  596               separateNoTx = clf.isTransactional();
  597            Object key = getKey(subject, cri, separateNoTx);
  598            SubPoolContext subPool = getSubPool(key, subject, cri);
  599            
  600            InternalManagedConnectionPool mcp = subPool.getSubPool();
  601            
  602            // Are we doing track by connection?
  603            TransactionLocal trackByTx = subPool.getTrackByTx();
  604   
  605            // Simple case
  606            if (trackByTransaction == null || trackByTx == null)
  607            {
  608               ConnectionListener cl = mcp.getConnection(subject, cri);
  609               if (traceEnabled)
  610                  dump("Got connection from pool " + cl);
  611               return cl;
  612            }
  613   
  614            // Track by transaction
  615            try
  616            {
  617               trackByTx.lock(trackByTransaction);
  618            }
  619            catch (Throwable t)
  620            {
  621               JBossResourceException.rethrowAsResourceException("Unable to get connection from the pool for tx=" + trackByTransaction, t);
  622            }
  623            try
  624            {
  625               // Already got one
  626               ConnectionListener cl = (ConnectionListener) trackByTx.get(trackByTransaction);
  627               if (cl != null)
  628               {
  629                  if (traceEnabled)
  630                     dump("Previous connection tracked by transaction " + cl + " tx=" + trackByTransaction);
  631                  return cl;
  632               }
  633            }
  634            finally
  635            {
  636               trackByTx.unlock(trackByTransaction);
  637            }
  638   
  639            // Need a new one for this transaction
  640            // This must be done outside the tx local lock, otherwise
  641            // the tx timeout won't work and get connection can do a lot of other work
  642            // with many opportunities for deadlocks.
  643            // Instead we do a double check after we got the transaction to see
  644            // whether another thread beat us to the punch.
  645            ConnectionListener cl = mcp.getConnection(subject, cri);
  646            if (traceEnabled)
  647               dump("Got connection from pool tracked by transaction " + cl + " tx=" + trackByTransaction);
  648            
  649            // Relock and check/set status
  650            try
  651            {
  652               trackByTx.lock(trackByTransaction);
  653            }
  654            catch (Throwable t)
  655            {
  656               mcp.returnConnection(cl, false);
  657               if (traceEnabled)
  658                  dump("Had to return connection tracked by transaction " + cl + " tx=" + trackByTransaction + " error=" + t.getMessage());
  659               JBossResourceException.rethrowAsResourceException("Unable to get connection from the pool for tx=" + trackByTransaction, t);
  660            }
  661            try
  662            {
  663               // Check we weren't racing with another transaction
  664               ConnectionListener other = (ConnectionListener) trackByTx.get(trackByTransaction);
  665               if (other != null)
  666               {
  667                  mcp.returnConnection(cl, false);
  668                  if (traceEnabled)
  669                     dump("Another thread already got a connection tracked by transaction " + other + " tx=" + trackByTransaction);
  670                  return other;
  671               }
  672               
  673               // This is the connection for this transaction
  674               cl.setTrackByTx(true);
  675               trackByTx.set(cl);
  676               if (traceEnabled)
  677                  dump("Using connection from pool tracked by transaction " + cl + " tx=" + trackByTransaction);
  678               return cl;
  679            }
  680            finally
  681            {
  682               trackByTx.unlock(trackByTransaction);
  683            }
  684         }
  685   
  686         public void returnConnection(ConnectionListener cl, boolean kill) throws ResourceException
  687         {
  688            cl.setTrackByTx(false);
  689            InternalManagedConnectionPool mcp = (InternalManagedConnectionPool) cl.getContext();
  690            mcp.returnConnection(cl, kill);
  691            if (traceEnabled)
  692               dump("Returning connection to pool " + cl);
  693         }
  694         
  695         /**
  696          * Return the inuse count
  697          * 
  698          * @return the count
  699          */
  700         public int getInUseConnectionCount()
  701         {
  702            int count = 0;
  703            synchronized (subPools)
  704            {
  705               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  706               {
  707                  SubPoolContext subPool = (SubPoolContext) i.next();
  708                  count += subPool.getSubPool().getConnectionInUseCount();
  709               }
  710            }
  711            return count;
  712         }
  713         public boolean getPreFill()
  714         {
  715            return this.poolParams.prefill;
  716   
  717         }
  718   
  719         public boolean shouldPreFill()
  720         {
  721            return getPreFill();
  722         }
  723   
  724         public void prefill()
  725         {
  726   
  727            prefill(null, null, false);
  728   
  729         }
  730   
  731         public void prefill(boolean noTxSeperatePool)
  732         {
  733   
  734            prefill(null, null, noTxSeperatePool);
  735   
  736         }
  737   
  738         public void prefill(Subject subject, ConnectionRequestInfo cri, boolean noTxSeperatePool)
  739         {
  740            if (getPreFill())
  741            {
  742   
  743               log.debug("Attempting to prefill pool for pool with jndi name" + poolName);
  744   
  745               try
  746               {
  747   
  748                  getSubPool(getKey(subject, cri, noTxSeparatePools), subject, cri);
  749   
  750               }
  751               catch (Throwable t)
  752               {
  753                  //No real need to throw here being that pool remains in the same state as before.
  754                  log.error("Unable to prefill pool with jndi name" + getPoolName(), t);
  755   
  756               }
  757   
  758            }
  759   
  760         }
  761   
  762         public int getConnectionCount()
  763         {
  764            int count = 0;
  765            synchronized (subPools)
  766            {
  767               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  768               {
  769                  SubPoolContext subPool = (SubPoolContext) i.next();
  770                  count += subPool.getSubPool().getConnectionCount();
  771               }
  772            }
  773            return count;
  774         }
  775         
  776         public String getPoolName()
  777         {
  778            return poolName;
  779         }
  780         public int getConnectionCreatedCount()
  781         {
  782            int count = 0;
  783            synchronized (subPools)
  784            {
  785               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  786               {
  787                  SubPoolContext subPool = (SubPoolContext) i.next();
  788                  count += subPool.getSubPool().getConnectionCreatedCount();
  789               }
  790            }
  791            return count;
  792         }
  793   
  794         public int getConnectionDestroyedCount()
  795         {
  796            int count = 0;
  797            synchronized (subPools)
  798            {
  799               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  800               {
  801                  SubPoolContext subPool = (SubPoolContext) i.next();
  802                  count += subPool.getSubPool().getConnectionDestroyedCount();
  803               }
  804            }
  805            return count;
  806         }
  807   
  808         public long getAvailableConnectionCount()
  809         {
  810            long count = 0;
  811            synchronized (subPools)
  812            {
  813               if (subPools.size() == 0)
  814                  return poolParams.maxSize;
  815               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  816               {
  817                  SubPoolContext subPool = (SubPoolContext) i.next();
  818                  count += subPool.getSubPool().getAvailableConnections();
  819               }
  820            }
  821            return count;
  822         }
  823   
  824         public int getMaxConnectionsInUseCount()
  825         {
  826            int count = 0;
  827            synchronized (subPools)
  828            {
  829               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  830               {
  831                  SubPoolContext subPool = (SubPoolContext) i.next();
  832                  count += subPool.getSubPool().getMaxConnectionsInUseCount();
  833               }
  834            }
  835            return count;
  836         }
  837         
  838         public void shutdown()
  839         {
  840            synchronized (subPools)
  841            {
  842               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  843               {
  844                  SubPoolContext subPool = (SubPoolContext) i.next();
  845                  subPool.getSubPool().shutdown();
  846               }
  847               subPools.clear();
  848            }
  849         }
  850   
  851         public void flush()
  852         {
  853            synchronized (subPools)
  854            {
  855               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  856               {
  857                  SubPoolContext subPool = (SubPoolContext) i.next();
  858                  subPool.getSubPool().shutdown();
  859               }
  860               subPools.clear();
  861            }
  862         }
  863   
  864         /**
  865          * For testing
  866          */
  867         protected void shutdownWithoutClear()
  868         {
  869            synchronized (subPools)
  870            {
  871               for (Iterator i = subPools.values().iterator(); i.hasNext(); )
  872               {
  873                  SubPoolContext subPool = (SubPoolContext) i.next();
  874                  subPool.getSubPool().shutdown();
  875               }
  876            }
  877         }
  878         
  879         /**
  880          * Get any transaction manager associated with the pool
  881          * 
  882          * @return the transaction manager
  883          */
  884         protected TransactionManager getTransactionManager()
  885         {
  886            if (clf != null)
  887               return clf.getTransactionManagerInstance();
  888            else
  889               return null;
  890         }
  891   
  892         /**
  893          * Determine the correct pool for this request,
  894          * creates a new one when necessary
  895          * 
  896          * @param key the key to the pool
  897          * @param subject the subject of the pool
  898          * @param cri the connection request info
  899          * @return the subpool context
  900          * @throws ResourceException for any error
  901          */
  902         protected SubPoolContext getSubPool(Object key, Subject subject, ConnectionRequestInfo cri) throws ResourceException
  903         {
  904            SubPoolContext subPool = (SubPoolContext) subPools.get(key);
  905            if (subPool == null)
  906            {
  907               TransactionManager tm = getTransactionManager();
  908               subPool = new SubPoolContext(tm, mcf, clf, subject, cri, poolParams, log);
  909               synchronized (subPools)
  910               {
  911                  if (subPools.containsKey(key))
  912                     subPool = (SubPoolContext) subPools.get(key);
  913                  else
  914                  {
  915                     subPool.initialize();
  916                     subPools.put(key, subPool);
  917                  }
  918               }
  919            }
  920            return subPool;
  921         }
  922   
  923         /**
  924          * Dump the stats to the trace log
  925          * 
  926          * @param info some context
  927          */
  928         private void dump(String info)
  929         {
  930            if (traceEnabled)
  931            {
  932               StringBuffer toLog = new StringBuffer(100);
  933               toLog.append(info).append(" [InUse/Available/Max]: [");
  934               toLog.append(this.getInUseConnectionCount()).append("/");
  935               toLog.append(this.getAvailableConnectionCount()).append("/");
  936               toLog.append(this.poolParams.maxSize);
  937               toLog.append("]");;
  938               log.trace(toLog);
  939            }
  940         }
  941            
  942         public JBossStatistics listStatistics()
  943         {   
  944            final ManagedConnectionPoolStatistics subPoolStats = new JBossManagedConnectionPoolStatistics(subPools.size());
  945            
  946            subPoolStats.setBlockingTimeout(poolParams.blockingTimeout);
  947            subPoolStats.setIdleTimeout(poolParams.idleTimeout);
  948            subPoolStats.setMax(poolParams.maxSize);
  949            subPoolStats.setMin(poolParams.minSize);
  950            subPoolStats.setPrefill(poolParams.prefill);
  951            subPoolStats.setNoTxnSeperatePool(noTxSeparatePools);
  952            
  953            for(Iterator iter = subPools.values().iterator(); iter.hasNext();)
  954            {   
  955               JBossSubPoolStatistics stat = new JBossSubPoolStatistics();
  956               SubPoolContext subContext = (SubPoolContext)iter.next();
  957               Boolean trackByTxn = (subContext.getTrackByTx() != null) ? Boolean.TRUE : Boolean.FALSE;
  958               stat.setTrackByTxn(trackByTxn);
  959               final InternalManagedConnectionPool internalPool = subContext.getSubPool();
  960               stat.setAvailableConnections(internalPool.getAvailableConnections());
  961               stat.setConnectionsDestroyed(internalPool.getConnectionDestroyedCount());
  962               stat.setConnectionsInUse(internalPool.getMaxConnectionsInUseCount());
  963               stat.setMaxConnectionsInUse(internalPool.getMaxConnectionsInUseCount());
  964               stat.setTotalBlockTime(internalPool.getTotalBlockTime());
  965               stat.setAverageBlockTime(internalPool.getAverageBlockTime());
  966               stat.setMaxWaitTime(internalPool.getMaxWaitTime());
  967               stat.setTotalTimedOut(internalPool.getTimedOut());
  968               subPoolStats.addSubPool(stat);
  969            }
  970   
  971            return (JBossStatistics)subPoolStats;
  972         }
  973         
  974         public Object listUnderlyingNativeConnectionStatistics()
  975         {
  976             String statistics = "";
  977             for(Iterator iter = subPools.values().iterator(); iter.hasNext();)
  978             {                      
  979                 SubPoolContext subContext = (SubPoolContext)iter.next();
  980                 InternalManagedConnectionPool internalPool = subContext.getSubPool();
  981                 Set cels = internalPool.getConnectionListeners();
  982                 for(Iterator celsIter = cels.iterator(); celsIter.hasNext();)
  983                 {
  984                    ConnectionListener cl = (ConnectionListener) celsIter.next();
  985                    ManagedConnection mc = cl.getManagedConnection();
  986                    if (mc instanceof org.jboss.resource.statistic.JBossConnectionStatistics)
  987                    {
  988                       org.jboss.resource.statistic.JBossConnectionStatistics stats = (org.jboss.resource.statistic.JBossConnectionStatistics)mc;
  989                       statistics += stats.listConnectionStats();
  990                       if(statistics.startsWith("-1")){
  991                         statistics = " ManagedConnetion in a Pool does not expose NativeConnectionStatistics !!!... ";
  992                         break;
  993                       }
  994                    }
  995                    else
  996                    {
  997                        statistics = mc + " does not implement org.jboss.resource.statistic.JBossConnectionStatistics , <br><font color='red'>So this Operation is Not available!!!</font> ";                       
  998                        break;                      
  999                    }
 1000                 }
 1001             }   
 1002             return statistics;
 1003         }
 1004      }
 1005   
 1006      /**
 1007       * Pooling by subject and connection request information
 1008       */
 1009      public static class PoolBySubjectAndCri
 1010         extends BasePool
 1011      {
 1012         public PoolBySubjectAndCri(final ManagedConnectionFactory mcf,
 1013                                    final InternalManagedConnectionPool.PoolParams poolParams,
 1014                                    final boolean noTxSeparatePools, 
 1015                                    final Logger log)
 1016         {
 1017            super(mcf, poolParams, noTxSeparatePools, log);
 1018         
 1019         }
 1020   
 1021         protected Object getKey(final Subject subject, final ConnectionRequestInfo cri, final boolean separateNoTx) throws ResourceException
 1022         {
 1023            return new SubjectCriKey(subject, cri, separateNoTx);
 1024         }
 1025      
 1026         public void prefill()
 1027         {
 1028            prefill(null, null, false);
 1029         }
 1030   
 1031         public void prefill(boolean noTxSeperatePool)
 1032         {
 1033            prefill(null, null, noTxSeperatePool);
 1034         }
 1035   
 1036         public void prefill(Subject subject, ConnectionRequestInfo cri)
 1037         {
 1038            prefill(subject, cri, false);
 1039   
 1040         }
 1041   
 1042         public void prefill(Subject subject, ConnectionRequestInfo cri, boolean noTxSeperatePool)
 1043         {
 1044            if (getPreFill())
 1045            {
 1046               log.warn("Prefill pool option was selected for pool with JNDI name " + getPoolName()
 1047                     + " that does not support this feature.");
 1048               log
 1049                     .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
 1050   
 1051            }
 1052         }
 1053      }
 1054   
 1055      /**
 1056       * Pool by subject and criteria
 1057       */
 1058      private static class SubjectCriKey
 1059      {
 1060         /** Identifies no subject */
 1061         private static final Subject NOSUBJECT = new Subject();
 1062         
 1063         /** Identifies no connection request information */
 1064         private static final Object NOCRI = new Object();
 1065   
 1066         /** The subject */
 1067         private final Subject subject;
 1068         
 1069         /** The connection request information */
 1070         private final Object cri;
 1071         
 1072         /** The cached hashCode */
 1073         private int hashCode = Integer.MAX_VALUE;
 1074   
 1075         /** Separate no tx */
 1076         private boolean separateNoTx;
 1077   
 1078         SubjectCriKey(Subject subject, ConnectionRequestInfo cri, boolean separateNoTx)
 1079         {
 1080            this.subject = (subject == null)? NOSUBJECT:subject;
 1081            this.cri = (cri == null)? NOCRI:cri;
 1082            this.separateNoTx = separateNoTx;
 1083         }
 1084   
 1085         public int hashCode()
 1086         {
 1087            if (hashCode == Integer.MAX_VALUE)
 1088               hashCode = SubjectActions.hashCode(subject) ^ cri.hashCode();
 1089            return hashCode;
 1090         }
 1091   
 1092         public boolean equals(Object obj)
 1093         {
 1094            if (this == obj)
 1095               return true;
 1096            if (obj == null || (obj instanceof SubjectCriKey) == false)
 1097               return false;
 1098            SubjectCriKey other = (SubjectCriKey) obj;
 1099            return SubjectActions.equals(subject, other.subject) 
 1100               && cri.equals(other.cri)
 1101               && separateNoTx == other.separateNoTx;
 1102         }
 1103      }
 1104   
 1105      /**
 1106       * Pool by subject
 1107       */
 1108      public static class PoolBySubject
 1109         extends BasePool
 1110      {
 1111   
 1112         public PoolBySubject(final ManagedConnectionFactory mcf,
 1113                              final InternalManagedConnectionPool.PoolParams poolParams,
 1114                              final boolean noTxSeparatePools, 
 1115                              final Logger log)
 1116         {
 1117            super(mcf, poolParams, noTxSeparatePools, log);
 1118         }
 1119   
 1120         protected Object getKey(final Subject subject, final ConnectionRequestInfo cri, boolean separateNoTx)
 1121         {
 1122            return new SubjectKey(subject, separateNoTx);
 1123         }
 1124      
 1125         public void prefill()
 1126         {
 1127            prefill(null, null, false);
 1128         }
 1129   
 1130         public void prefill(boolean noTxSeperatePool)
 1131         {
 1132            prefill(null, null, noTxSeperatePool);
 1133         }
 1134   
 1135         public void prefill(Subject subject, ConnectionRequestInfo cri)
 1136         {
 1137            prefill(subject, cri, false);
 1138   
 1139         }
 1140   
 1141         public void prefill(Subject subject, ConnectionRequestInfo cri, boolean noTxSeperatePool)
 1142         {
 1143            if (getPreFill())
 1144            {
 1145               log.warn("Prefill pool option was selected for pool with JNDI name " + getPoolName()
 1146                     + " that does not support this feature.");
 1147               log
 1148                     .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
 1149   
 1150            }
 1151         }
 1152      }
 1153   
 1154      /**
 1155       * Pool by subject
 1156       */
 1157      private static class SubjectKey
 1158      {
 1159         /** Identifies no subject */
 1160         private static final Subject NOSUBJECT = new Subject();
 1161   
 1162         /** The subject */
 1163         private final Subject subject;
 1164   
 1165         /** Separate no tx */
 1166         private boolean separateNoTx;
 1167         
 1168         /** The cached hashCode */
 1169         private int hashCode = Integer.MAX_VALUE;
 1170   
 1171         SubjectKey(Subject subject, boolean separateNoTx)
 1172         {
 1173            this.subject = (subject == null)? NOSUBJECT:subject;
 1174            this.separateNoTx = separateNoTx;
 1175         }
 1176   
 1177         public int hashCode()
 1178         {
 1179            if (hashCode == Integer.MAX_VALUE)
 1180               hashCode = SubjectActions.hashCode(subject);
 1181            return hashCode;
 1182         }
 1183   
 1184         public boolean equals(Object obj)
 1185         {
 1186            if (this == obj)
 1187               return true;
 1188            if (obj == null || (obj instanceof SubjectKey) == false)
 1189               return false;
 1190            SubjectKey other = (SubjectKey) obj;
 1191            return SubjectActions.equals(subject, other.subject)
 1192               && separateNoTx == other.separateNoTx;
 1193         }
 1194      }
 1195   
 1196      /**
 1197       * Pool by connection request information
 1198       */
 1199      public static class PoolByCri
 1200         extends BasePool
 1201      {
 1202         public PoolByCri(final ManagedConnectionFactory mcf,
 1203                          final InternalManagedConnectionPool.PoolParams poolParams,
 1204                          final boolean noTxSeparatePools, 
 1205                          final Logger log)
 1206         {
 1207            super(mcf, poolParams, noTxSeparatePools, log);
 1208         }
 1209   
 1210         protected Object getKey(final Subject subject, final ConnectionRequestInfo cri, boolean separateNoTx)
 1211         {
 1212            return new CriKey(cri, separateNoTx);
 1213         }
 1214      
 1215         public void prefill()
 1216         {
 1217            prefill(null, null, false);
 1218         }
 1219   
 1220         public void prefill(boolean noTxSeperatePool)
 1221         {
 1222            prefill(null, null, noTxSeperatePool);
 1223         }
 1224   
 1225         public void prefill(Subject subject, ConnectionRequestInfo cri)
 1226         {
 1227            prefill(subject, cri, false);
 1228   
 1229         }
 1230   
 1231         public void prefill(Subject subject, ConnectionRequestInfo cri, boolean noTxSeperatePool)
 1232         {
 1233            if (getPreFill())
 1234            {
 1235               log.warn("Prefill pool option was selected for pool with JNDI name " + getPoolName()
 1236                     + " that does not support this feature.");
 1237               log
 1238                     .warn("Please verify your *-ds.xml file that corresponds with this resource and either remove the <prefill>true|false</prefill element or explicitly set this value to false.");
 1239   
 1240            }
 1241         }
 1242      }
 1243   
 1244      /**
 1245       * Pool by subject and criteria
 1246       */
 1247      private static class CriKey
 1248      {
 1249         /** Identifies no connection request information */
 1250         private static final Object NOCRI = new Object();
 1251         
 1252         /** The connection request information */
 1253         private final Object cri;
 1254   
 1255         /** Separate no tx */
 1256         private boolean separateNoTx;
 1257         
 1258         /** The cached hashCode */
 1259         private int hashCode = Integer.MAX_VALUE;
 1260   
 1261         CriKey(ConnectionRequestInfo cri, boolean separateNoTx) 
 1262         {
 1263            this.cri = (cri == null)? NOCRI : cri;
 1264            this.separateNoTx = separateNoTx;
 1265         }
 1266   
 1267         public int hashCode()
 1268         {
 1269            if (hashCode == Integer.MAX_VALUE)
 1270               hashCode = cri.hashCode();
 1271            return hashCode;
 1272         }
 1273   
 1274         public boolean equals(Object obj)
 1275         {
 1276            if (this == obj)
 1277               return true;
 1278            if (obj == null || (obj instanceof CriKey) == false)
 1279               return false;
 1280            CriKey other = (CriKey) obj;
 1281            return cri.equals(other.cri) && separateNoTx == other.separateNoTx;
 1282         }
 1283      }
 1284   
 1285      /**
 1286       * One pool
 1287       */
 1288      public static class OnePool
 1289         extends BasePool
 1290      {
 1291         public OnePool(final ManagedConnectionFactory mcf,
 1292                        final InternalManagedConnectionPool.PoolParams poolParams,
 1293                        final boolean noTxSeparatePools, 
 1294                        final Logger log)
 1295         {
 1296            super(mcf, poolParams, noTxSeparatePools, log);
 1297         }
 1298   
 1299         protected Object getKey(final Subject subject, final ConnectionRequestInfo cri, boolean separateNoTx)
 1300         {
 1301            if (separateNoTx)
 1302               return Boolean.TRUE;
 1303            else
 1304               return Boolean.FALSE;
 1305         }
 1306   
 1307         public void prefill(Subject sub){
 1308            
 1309            log.debug("Attempting to prefill pool" + getClass());
 1310            
 1311            try
 1312            {
 1313               //WMP is this really the best way to do this? 
 1314               getSubPool(getKey(null, null, false), null, null);
 1315   
 1316            }
 1317   
 1318            catch (ResourceException e)
 1319            {
 1320               log.error("Prefill failed for pool instance " + getClass(), e);
 1321               
 1322            }
 1323            
 1324         }
 1325      }
 1326   
 1327      private static class SubjectActions implements PrivilegedAction
 1328      {
 1329         Subject subject;
 1330         Subject other;
 1331         SubjectActions(Subject subject, Subject other)
 1332         {
 1333            this.subject = subject;
 1334            this.other = other;
 1335         }
 1336         public Object run()
 1337         {
 1338            Object value = null;
 1339            if( other == null )
 1340               value = Integer.valueOf(subject.hashCode());
 1341            else
 1342               value = Boolean.valueOf(subject.equals(other));
 1343            return value;
 1344         }
 1345         static int hashCode(Subject subject)
 1346         {
 1347            SubjectActions action = new SubjectActions(subject, null);
 1348            return ((Integer) AccessController.doPrivileged(action)).intValue();
 1349         }
 1350         static boolean equals(Subject subject, Subject other)
 1351         {
 1352            SubjectActions action = new SubjectActions(subject, other);
 1353            return ((Boolean) AccessController.doPrivileged(action)).booleanValue();
 1354         }
 1355      }
 1356   }

Save This Page
Home » jboss-5.0.0.CR1-src » org » jboss » resource » connectionmanager » [javadoc | source]