You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@avalon.apache.org by le...@apache.org on 2002/04/22 02:41:39 UTC

cvs commit: jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource ResourceLimitingJdbcConnectionPool.java ResourceLimitingJdbcDataSource.java

leif        02/04/21 17:41:39

  Modified:    datasource build.xml
  Added:       datasource/src/java/org/apache/avalon/excalibur/datasource
                        ResourceLimitingJdbcConnectionPool.java
                        ResourceLimitingJdbcDataSource.java
  Log:
  Promote ResourceLimitingJdbcDataSource to the datasource subproject.
  
  Revision  Changes    Path
  1.14      +1 -0      jakarta-avalon-excalibur/datasource/build.xml
  
  Index: build.xml
  ===================================================================
  RCS file: /home/cvs/jakarta-avalon-excalibur/datasource/build.xml,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- build.xml	16 Apr 2002 12:00:40 -0000	1.13
  +++ build.xml	22 Apr 2002 00:41:39 -0000	1.14
  @@ -17,6 +17,7 @@
           <pathelement location="${jdbc.jar}"/>
           <pathelement location="${avalon-framework.jar}"/>
           <pathelement location="${avalon-logkit.jar}"/>
  +        <pathelement location="${excalibur-instrument.jar}"/>
           <pathelement location="${excalibur-pool.jar}"/>
       </path>
   
  
  
  
  1.1                  jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ResourceLimitingJdbcConnectionPool.java
  
  Index: ResourceLimitingJdbcConnectionPool.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.avalon.excalibur.datasource;
  
  import java.sql.SQLException;
  import org.apache.avalon.excalibur.pool.ObjectFactory;
  import org.apache.avalon.excalibur.pool.Poolable;
  import org.apache.avalon.excalibur.pool.ValidatedResourceLimitingPool;
  
  /**
   * A ResourceLimiting JdbcConnectionPool which allows for fine configuration of
   *  how the pool scales to loads.
   *
   * The pool supports; weak and strong pool size limits, optional blocking gets
   *  when connections are not available, and automatic trimming of unused
   *  connections.
   *
   * @author <a href="mailto:leif@tanukisoftware.com">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/22 00:41:39 $
   * @since 4.1
   */
  public class ResourceLimitingJdbcConnectionPool
      extends ValidatedResourceLimitingPool
  {
      private boolean m_autoCommit;
  
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      /**
       * Creates a new ResourceLimitingJdbcConnectionPool
       *
       * @param factory The ObjectFactory which will be used to create new connections as needed
       *  by the pool.
       * @param max Maximum number of connections which can be stored in the pool, 0 implies
       *  no limit.
       * @param maxStrict true if the pool should never allow more than max connections to be
       *  created.  Will cause an exception to be thrown if more than max connections are
       *  requested and blocking is false.
       * @param blocking true if the pool should cause a thread calling get() to block when
       *  connections are not currently available in the pool.
       * @param blockTimeout The maximum amount of time, in milliseconds, that a call to get() will
       *  block before an exception is thrown.  A value of 0 implies an indefinate wait.
       * @param trimInterval The minimum interval with which old unused connections will be removed
       *  from the pool.  A value of 0 will cause the pool to never trim old connections.
       * @param autoCommit true if connections created by this pool should have autoCommit enabled.
       */
      public ResourceLimitingJdbcConnectionPool( final ObjectFactory factory,
                                                 int max,
                                                 boolean maxStrict,
                                                 boolean blocking,
                                                 long blockTimeout,
                                                 long trimInterval,
                                                 boolean autoCommit )
      {
  
          super( factory, max, maxStrict, blocking, blockTimeout, trimInterval );
  
          m_autoCommit = autoCommit;
      }
  
      /*---------------------------------------------------------------
       * ValidatedResourceLimitingPool Methods
       *-------------------------------------------------------------*/
      /**
       * Create a new poolable instance by by calling the newInstance method
       *  on the pool's ObjectFactory.
       * This is the method to override when you need to enforce creational
       *  policies.
       * This method is only called by threads that have m_semaphore locked.
       */
      protected Poolable newPoolable() throws Exception
      {
          AbstractJdbcConnection conn = (AbstractJdbcConnection)super.newPoolable();
  
          // Store a reference to this pool in the connection
          conn.setPool( this );
  
          // Set the auto commit flag for new connections.
          conn.setAutoCommit( m_autoCommit );
  
          return conn;
      }
  
      /**
       * Validates the poolable before it is provided to the caller of get on this pool.
       *  This implementation of the validation method always returns true indicating
       *  that the Poolable is valid.
       * The pool is not locked by the current thread when this method is called.
       *
       * @param poolable The Poolable to be validated
       * @return true if the Poolable is valid, false if it should be removed from the pool.
       */
      protected boolean validatePoolable( Poolable poolable )
      {
          AbstractJdbcConnection conn = (AbstractJdbcConnection)poolable;
          try
          {
              // Calling isClosed() may take time if the connection has not been
              //  used for a while.  Is this a problem because the m_semaphore
              //  is currently locked?  I am thinking no because isClosed() will
              //  return immediately when connections are being used frequently.
              if( conn.isClosed() )
              {
                  getLogger().debug( "JdbcConnection was closed." );
                  return false;
              }
          }
          catch( SQLException e )
          {
              getLogger().debug(
                  "Failed to check whether JdbcConnection was closed. " + e.getMessage() );
          }
  
          return true;
      }
  }
  
  
  
  
  1.1                  jakarta-avalon-excalibur/datasource/src/java/org/apache/avalon/excalibur/datasource/ResourceLimitingJdbcDataSource.java
  
  Index: ResourceLimitingJdbcDataSource.java
  ===================================================================
  /*
   * Copyright (C) The Apache Software Foundation. All rights reserved.
   *
   * This software is published under the terms of the Apache Software License
   * version 1.1, a copy of which has been included with this distribution in
   * the LICENSE.txt file.
   */
  package org.apache.avalon.excalibur.datasource;
  
  import java.sql.Connection;
  import java.sql.SQLException;
  import org.apache.avalon.excalibur.instrument.Instrument;
  import org.apache.avalon.excalibur.instrument.Instrumentable;
  import org.apache.avalon.framework.activity.Disposable;
  import org.apache.avalon.framework.configuration.Configuration;
  import org.apache.avalon.framework.configuration.ConfigurationException;
  import org.apache.avalon.framework.logger.AbstractLogEnabled;
  
  /**
   * The ResourceLimiting implementation for DataSources in Avalon.
   * This uses the normal <code>java.sql.Connection</code> object and
   * <code>java.sql.DriverManager</code>.
   * <p>
   * This datasource pool implementation is designed to make as many
   * database connections as are needed available without placing
   * undo load on the database server.
   * <p>
   * If an application under normal load needs 3 database connections
   * for example, then the <code>max</code> pool size should be set
   * to a value like 10.  This will allow the pool to grow to accomodate
   * a sudden spike in load without allowing the pool to grow to such
   * a large size as to place undo load on the database server.  The
   * pool's trimming features will keep track of how many connections
   * are actually needed and close those connections which are no longer
   * required.
   * <p>
   * Configuration Example:
   * <pre>
   *   &lt;jdbc&gt;
   *     &lt;pool-controller max="<i>10</i>" maxStrict="<i>true</i>"
   *       blocking="<i>true</i>" timeout="<i>-1</i>"
   *       trim-interval="<i>60000</i>" auto-commit="true"
   *       connection-class="<i>my.overrided.ConnectionClass</i>"&gt;
   *       &lt;keep-alive disable="false"&gt;select 1&lt;/keep-alive&gt;
   *     &lt;/pool-controller&gt;
   *     &lt;driver&gt;<i>com.database.jdbc.JdbcDriver</i>&lt;/driver&gt;
   *     &lt;dburl&gt;<i>jdbc:driver://host/mydb</i>&lt;/dburl&gt;
   *     &lt;user&gt;<i>username</i>&lt;/user&gt;
   *     &lt;password&gt;<i>password</i>&lt;/password&gt;
   *   &lt;/jdbc&gt;
   * </pre>
   * <p>
   * Roles Example:
   * <pre>
   *   &lt;role name="org.apache.avalon.excalibur.datasource.DataSourceComponentSelector"
   *     shorthand="datasources"
   *     default-class="org.apache.avalon.excalibur.component.ExcaliburComponentSelector"&gt;
   *     &lt;hint shorthand="jdbc"
   *       class="org.apache.avalon.excalibur.datasource.ResourceLimitingJdbcDataSource"/&gt;
   *   &lt;/role&gt;
   * </pre>
   * <p>
   * Configuration Attributes:
   * <ul>
   * <li>The <code>max</code> attribute is used to set the maximum
   * number of connections which will be opened.  See the
   * <code>blocking</code> attribute.  (Defaults to "3")</li>
   *
   * <li>The <code>max-strict</code> attribute is used to determine whether
   * or not the maximum number of connections can be exceeded.  If true,
   * then an exception will be thrown if more than max connections are
   * requested and blocking is false.  (Defaults to "true")<br>
   * <i>WARNING: In most cases, this value
   * should always be set to true.  Setting it to false means that under
   * heavy load, your application may open a very large number of
   * connections to the database.  Some database servers behave very poorly
   * under large connection loads and can even crash.</i></li>
   *
   * <li>The <code>blocking</code> attributes is used to specify the
   * behavior of the DataSource pool when an attempt is made to allocate
   * more than <code>max</code> concurrent connections.  If true, the
   * request will block until a connection is released, otherwise, a
   * NoAvailableConnectionException will be thrown.  Ignored if
   * <code>max-strict</code> is false.  (Defaults to "true")</li>
   *
   * <li>The <code>timeout</code> attribute is used to specify the
   * maximum amount of time in milliseconds that a request for a
   * connection will be allowed to block before a
   * NoAvailableConnectionException is thrown.  A value of "0" specifies
   * that the block will never timeout.  (Defaults to "0")</li>
   *
   * <li>The <code>trim-interval</code> attribute is used to specify how
   * long idle connections will be maintained in the pool before being
   * closed.  For a complete explanation on how this works, see {@link
   * org.apache.avalon.excalibur.pool.ResourceLimitingPool#trim()}
   * (Defaults to "60000", 1 minute)</li>
   *
   * <li>The <code>auto-commit</code> attribute is used to determine the
   * default auto-commit mode for the <code>Connection</code>s returned
   * by this <code>DataSource</code>.
   *
   * <li>The <code>connection-class</code> attribute is used to override
   * the Connection class returned by the DataSource from calls to
   * getConnection().  Set this to
   * "org.apache.avalon.excalibur.datasource.Jdbc3Connection" to gain
   * access to JDBC3 features.  Jdbc3Connection does not exist if your
   * JVM does not support JDBC3.  (Defaults to
   * "org.apache.avalon.excalibur.datasource.JdbcConnection")</li>
   *
   * <li>The <code>keep-alive</code> element is used to override the
   * query used to monitor the health of connections.  If a connection
   * has not been used for 5 seconds then before returning the
   * connection from a call to getConnection(), the connection is first
   * used to ping the database to make sure that it is still alive.
   * Setting the <code>disable</code> attribute to true will disable
   * this feature.  (Defaults to a query of "SELECT 1" and being
   * enabled)</li>
   *
   * <li>The <code>driver</code> element is used to specify the driver
   * to use when connecting to the database.  The specified class must
   * be in the classpath.  (Required)</li>
   *
   * <li>The <code>dburl</code> element is the JDBC connection string
   * which will be used to connect to the database.  (Required)</li>
   *
   * <li>The <code>user</code> and <code>password</code> attributes are
   * used to specify the user and password for connections to the
   * database. (Required)</li>
   * </ul>
   *
   * @author <a href="mailto:leif@tanukisoftware.com">Leif Mortenson</a>
   * @version CVS $Revision: 1.1 $ $Date: 2002/04/22 00:41:39 $
   * @since 4.1
   */
  public class ResourceLimitingJdbcDataSource
      extends AbstractLogEnabled
      implements DataSourceComponent, Instrumentable, Disposable
  {
      private boolean m_configured;
      private boolean m_disposed;
      protected ResourceLimitingJdbcConnectionPool m_pool;
  
      /** Instrumentable Name assigned to this Instrumentable */
      private String m_instrumentableName;
  
      /*---------------------------------------------------------------
       * Constructors
       *-------------------------------------------------------------*/
      public ResourceLimitingJdbcDataSource()
      {
      }
  
      /*---------------------------------------------------------------
       * DataSourceComponent Methods
       *-------------------------------------------------------------*/
      /**
       * Gets the Connection to the database
       *
       * @throws NoValidConnectionException when there is no valid Connection wrapper
       *         available in the classloader.
       *
       * @throws NoAvailableConnectionException when there are no more available
       *         Connections in the pool.
       */
      public Connection getConnection()
          throws SQLException
      {
          if( !m_configured ) throw new IllegalStateException( "Not Configured" );
          if( m_disposed ) throw new IllegalStateException( "Already Disposed" );
  
          Connection connection;
          try
          {
              connection = (Connection)m_pool.get();
          }
          catch( SQLException e )
          {
              if( getLogger().isWarnEnabled() )
              {
                  getLogger().warn( "Could not return Connection", e );
              }
  
              throw e;
          }
          catch( Exception e )
          {
              if( getLogger().isWarnEnabled() )
              {
                  getLogger().warn( "Could not return Connection", e );
              }
  
              throw new NoAvailableConnectionException( e.getMessage() );
          }
  
          return connection;
      }
  
      /*---------------------------------------------------------------
       * DataSourceComponent (Configurable) Methods
       *-------------------------------------------------------------*/
      /**
       * Pass the <code>Configuration</code> to the <code>Configurable</code>
       * class. This method must always be called after the constructor
       * and before any other method.
       *
       * @param configuration the class configurations.
       */
      public void configure( Configuration configuration ) throws ConfigurationException
      {
          if( m_configured ) throw new IllegalStateException( "Already Configured" );
  
          final String driver = configuration.getChild( "driver" ).getValue( "" );
          final String dburl = configuration.getChild( "dburl" ).getValue( null );
          final String user = configuration.getChild( "user" ).getValue( null );
          final String passwd = configuration.getChild( "password" ).getValue( null );
  
          final Configuration controller = configuration.getChild( "pool-controller" );
          String keepAlive = controller.getChild( "keep-alive" ).getValue( "SELECT 1" );
          final boolean disableKeepAlive =
              controller.getChild( "keep-alive" ).getAttributeAsBoolean( "disable", false );
  
          final int max = controller.getAttributeAsInteger( "max", 3 );
          final boolean maxStrict = controller.getAttributeAsBoolean( "max-strict", true );
          final boolean blocking = controller.getAttributeAsBoolean( "blocking", true );
          final long timeout = controller.getAttributeAsLong( "timeout", 0 );
          final long trimInterval = controller.getAttributeAsLong( "trim-interval", 60000 );
          final boolean oradb = controller.getAttributeAsBoolean( "oradb", false );
  
          final boolean autoCommit = configuration.getChild( "auto-commit" ).getValueAsBoolean( true );
          // Get the JdbcConnection class.  The factory will resolve one if null.
          final String connectionClass = controller.getAttribute( "connection-class", null );
  
          final int l_max;
  
          // If driver is specified....
          if( !"".equals( driver ) )
          {
              if( getLogger().isDebugEnabled() )
              {
                  getLogger().debug( "Loading new driver: " + driver );
              }
  
              try
              {
                  Class.forName( driver, true, Thread.currentThread().getContextClassLoader() );
              }
              catch( ClassNotFoundException cnfe )
              {
                  if( getLogger().isWarnEnabled() )
                  {
                      getLogger().warn( "Could not load driver: " + driver, cnfe );
                  }
              }
          }
  
          // Validate the max pool size values.
          if( max < 1 )
          {
              if( getLogger().isWarnEnabled() )
              {
                  getLogger().warn( "Maximum number of connections specified must be at least 1." );
              }
  
              l_max = 1;
          }
          else
          {
              l_max = max;
          }
  
          // If the keepAlive disable attribute was set, then set the keepAlive query to null,
          //  disabling it.
          if( disableKeepAlive )
          {
              keepAlive = null;
          }
  
          // If the oradb attribute was set, then override the keepAlive query.
          // This will override any specified keepalive value even if disabled.
          //  (Deprecated, but keep this for backwards-compatability)
          if( oradb )
          {
              keepAlive = "SELECT 1 FROM DUAL";
  
              if( getLogger().isWarnEnabled() )
              {
                  getLogger().warn( "The oradb attribute is deprecated, please use the" +
                                    "keep-alive element instead." );
              }
          }
  
          final JdbcConnectionFactory factory = new JdbcConnectionFactory
              ( dburl, user, passwd, autoCommit, keepAlive, connectionClass );
  
          factory.enableLogging( getLogger() );
  
          try
          {
              m_pool = new ResourceLimitingJdbcConnectionPool(
                  factory, l_max, maxStrict, blocking, timeout, trimInterval, autoCommit );
  
              m_pool.enableLogging( getLogger() );
          }
          catch( Exception e )
          {
              if( getLogger().isDebugEnabled() )
              {
                  getLogger().debug( "Error configuring ResourceLimitingJdbcDataSource", e );
              }
  
              throw new ConfigurationException( "Error configuring ResourceLimitingJdbcDataSource", e );
          }
  
          m_configured = true;
      }
  
      /*---------------------------------------------------------------
       * Instrumentable Methods
       *-------------------------------------------------------------*/
      /**
       * Sets the name for the Instrumentable.  The Instrumentable Name is used
       *  to uniquely identify the Instrumentable during the configuration of
       *  the InstrumentManager and to gain access to an InstrumentableDescriptor
       *  through the InstrumentManager.  The value should be a string which does
       *  not contain spaces or periods.
       * <p>
       * This value may be set by a parent Instrumentable, or by the
       *  InstrumentManager using the value of the 'instrumentable' attribute in
       *  the configuration of the component.
       *
       * @param name The name used to identify a Instrumentable.
       */
      public void setInstrumentableName( String name )
      {
          m_instrumentableName = name;
      }
  
      /**
       * Gets the name of the Instrumentable.
       *
       * @return The name used to identify a Instrumentable.
       */
      public String getInstrumentableName()
      {
          return m_instrumentableName;
      }
  
      /**
       * Obtain a reference to all the Instruments that the Instrumentable object
       *  wishes to expose.  All sampling is done directly through the
       *  Instruments as opposed to the Instrumentable interface.
       *
       * @return An array of the Instruments available for profiling.  Should
       *         never be null.  If there are no Instruments, then
       *         EMPTY_INSTRUMENT_ARRAY can be returned.  This should never be
       *         the case though unless there are child Instrumentables with
       *         Instruments.
       */
      public Instrument[] getInstruments()
      {
          return Instrumentable.EMPTY_INSTRUMENT_ARRAY;
      }
  
      /**
       * Any Object which implements Instrumentable can also make use of other
       *  Instrumentable child objects.  This method is used to tell the
       *  InstrumentManager about them.
       *
       * @return An array of child Instrumentables.  This method should never
       *         return null.  If there are no child Instrumentables, then
       *         EMPTY_INSTRUMENTABLE_ARRAY can be returned.
       */
      public Instrumentable[] getChildInstrumentables()
      {
          return new Instrumentable[]{ m_pool };
      }
  
      /*---------------------------------------------------------------
       * Disposable Methods
       *-------------------------------------------------------------*/
      /**
       * The dispose operation is called at the end of a components lifecycle.
       * This method will be called after Startable.stop() method (if implemented
       * by component). Components use this method to release and destroy any
       * resources that the Component owns.
       */
      public void dispose()
      {
          m_disposed = true;
          m_pool.dispose();
          m_pool = null;
      }
  }
  
  
  
  

--
To unsubscribe, e-mail:   <ma...@jakarta.apache.org>
For additional commands, e-mail: <ma...@jakarta.apache.org>