Package com.alibaba.wasp.jdbcx

Source Code of com.alibaba.wasp.jdbcx.JdbcConnectionPool

/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.  You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.wasp.jdbcx;

import com.alibaba.wasp.FConstants;
import com.alibaba.wasp.jdbc.JdbcException;
import com.alibaba.wasp.util.New;
import org.apache.commons.lang.NotImplementedException;
import org.apache.hadoop.conf.Configuration;

import javax.sql.ConnectionEvent;
import javax.sql.ConnectionEventListener;
import javax.sql.ConnectionPoolDataSource;
import javax.sql.DataSource;
import javax.sql.PooledConnection;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

/**
* A simple standalone JDBC connection pool.
*
*/
public class JdbcConnectionPool implements DataSource, ConnectionEventListener {

  private final ConnectionPoolDataSource dataSource;
  private final ArrayList<PooledConnection> recycledConnections = New
      .arrayList();
  private PrintWriter logWriter;
  private int maxConnections;
  private int timeout;
  private AtomicInteger activeConnections = new AtomicInteger(0);
  private boolean isDisposed;
  private Configuration conf;

  protected JdbcConnectionPool(ConnectionPoolDataSource dataSource,
      Configuration conf) {
    this.dataSource = dataSource;
    this.conf = conf;
    this.maxConnections = conf.getInt(FConstants.JDBC_POOL_MAX_CONNECTIONS,
        FConstants.DEFAULT_JDBC_POOL_MAX_CONNECTIONS);
    this.timeout = conf.getInt(FConstants.JDBC_CONNECTION_TIMEOUT,
        FConstants.DEFAULT_JDBC_CONNECTION_TIMEOUT);
    if (dataSource != null) {
      try {
        logWriter = dataSource.getLogWriter();
      } catch (SQLException e) {
        // ignore
      }
    }
  }

  /**
   * Constructs a new connection pool.
   *
   * @param dataSource
   *          the data source to create connections
   * @return the connection pool
   */
  public static JdbcConnectionPool create(ConnectionPoolDataSource dataSource,
      Configuration conf) {
    return new JdbcConnectionPool(dataSource, conf);
  }

  /**
   * Constructs a new connection pool for wasp.
   *
   * @param url
   *          the database URL of the wasp connection
   * @param user
   *          the user name
   * @param password
   *          the password
   * @return the connection pool
   */
  public static JdbcConnectionPool create(String url, String user,
      String password, Configuration conf) {
    JdbcDataSource ds = new JdbcDataSource(conf);
    ds.setURL(url);
    ds.setUser(user);
    ds.setPassword(password);
    return new JdbcConnectionPool(ds, conf);
  }

  /**
   * Sets the maximum number of connections to use from now on. The default
   * value is 20 connections.
   *
   * @param max
   *          the maximum number of connections
   */
  public synchronized void setMaxConnections(int max) {
    if (max < 1) {
      throw new IllegalArgumentException("Invalid maxConnections value: " + max);
    }
    this.maxConnections = max;
    // notify waiting threads if the value was increased
    notifyAll();
  }

  /**
   * Gets the maximum number of connections to use.
   *
   * @return the max the maximum number of connections
   */
  public synchronized int getMaxConnections() {
    return maxConnections;
  }

  /**
   * Gets the maximum time in seconds to wait for a free connection.
   *
   * @return the timeout in seconds
   */
  public synchronized int getLoginTimeout() {
    return timeout;
  }

  /**
   * Sets the maximum time in seconds to wait for a free connection. The default
   * timeout is 30 seconds. Calling this method with the value 0 will set the
   * timeout to the default value.
   *
   * @param seconds
   *          the timeout, 0 meaning the default
   */
  public synchronized void setLoginTimeout(int seconds) {
    if (seconds == 0) {
      seconds = FConstants.DEFAULT_JDBC_CONNECTION_TIMEOUT;
    }
    this.timeout = seconds;
  }

  /**
   * Closes all unused pooled connections. Exceptions while closing are written
   * to the log stream (if set).
   */
  public synchronized void dispose() {
    if (isDisposed) {
      return;
    }
    isDisposed = true;
    ArrayList<PooledConnection> list = recycledConnections;
    for (int i = 0, size = list.size(); i < size; i++) {
      closeConnection(list.get(i));
    }
  }

  /**
   * Retrieves a connection from the connection pool. If
   * <code>maxConnections</code> connections are already in use, the method
   * waits until a connection becomes available or <code>timeout</code> seconds
   * elapsed. When the application is finished using the connection, it must
   * close it in order to return it to the pool. If no connection becomes
   * available within the given timeout, an exception with SQL state 08001 and
   * vendor code 8001 is thrown.
   *
   * @return a new Connection object.
   * @throws java.sql.SQLException
   *           when a new connection could not be established, or a timeout
   *           occurred
   */
  public Connection getConnection() throws SQLException {
    long max = System.currentTimeMillis() + timeout * 1000;
    do {
      synchronized (this) {
        if (activeConnections.get() < maxConnections) {
          return getConnectionNow();
        }
        try {
          wait(1000);
        } catch (InterruptedException e) {
          // ignore
        }
      }
    } while (System.currentTimeMillis() <= max);
    throw new SQLException("get connection timeout. activeConnections=" + activeConnections + ". maxConnections="
        + maxConnections, "08001", 8001);
  }

  /**
   * INTERNAL
   */
  public Connection getConnection(String user, String password) {
    throw new UnsupportedOperationException();
  }

  private Connection getConnectionNow() throws SQLException {
    if (isDisposed) {
      throw new IllegalStateException("Connection pool has been disposed.");
    }
    PooledConnection pc;
    if (!recycledConnections.isEmpty()) {
      pc = recycledConnections.remove(recycledConnections.size() - 1);
    } else {
      pc = dataSource.getPooledConnection();
    }
    Connection conn = pc.getConnection();
    activeConnections.incrementAndGet();
    pc.addConnectionEventListener(this);
    return conn;
  }

  /**
   * This method usually puts the connection back into the pool. There are some
   * exceptions: if the pool is disposed, the connection is disposed as well. If
   * the pool is full, the connection is closed.
   *
   * @param pc
   *          the pooled connection
   */
  synchronized void recycleConnection(PooledConnection pc) {
    if (activeConnections.get() <= 0) {
      throw new AssertionError();
    }
    activeConnections.decrementAndGet();
    if (!isDisposed && activeConnections.get() < maxConnections) {
      recycledConnections.add(pc);
    } else {
      closeConnection(pc);
    }
    if (activeConnections.get() >= maxConnections - 1) {
      notifyAll();
    }
  }

  private void closeConnection(PooledConnection pc) {
    try {
      pc.close();
    } catch (SQLException e) {
      if (logWriter != null) {
        e.printStackTrace(logWriter);
      }
    }
  }

  /**
   * INTERNAL
   */
  public void connectionClosed(ConnectionEvent event) {
    PooledConnection pc = (PooledConnection) event.getSource();
    pc.removeConnectionEventListener(this);
    recycleConnection(pc);
  }

  /**
   * INTERNAL
   */
  public void connectionErrorOccurred(ConnectionEvent event) {
    // not used
  }

  /**
   * Returns the number of active (open) connections of this pool. This is the
   * number of <code>Connection</code> objects that have been issued by
   * getConnection() for which <code>Connection.close()</code> has not yet been
   * called.
   *
   * @return the number of active connections.
   */
  public int getActiveConnections() {
    return activeConnections.get();
  }

  /**
   * INTERNAL
   */
  public PrintWriter getLogWriter() {
    return logWriter;
  }

  /**
   * INTERNAL
   */
  public void setLogWriter(PrintWriter logWriter) {
    this.logWriter = logWriter;
  }

  /**
   * [Not supported] Return an object of this class if possible.
   *
   * @param iface
   *          the class
   */
  // ## Java 1.6 ##
  public <T> T unwrap(Class<T> iface) throws SQLException {
    throw JdbcException.getUnsupportedException("unwrap");
  }

  // */

  /**
   * [Not supported] Checks if unwrap can return an object of this class.
   *
   * @param iface
   *          the class
   */
  // ## Java 1.6 ##
  public boolean isWrapperFor(Class<?> iface) throws SQLException {
    throw JdbcException.getUnsupportedException("isWrapperFor");
  }

  // */

  /**
   * [Not supported]
   */
  // ## Java 1.7 ##
  public Logger getParentLogger() {
    throw new NotImplementedException();
  }

}
TOP

Related Classes of com.alibaba.wasp.jdbcx.JdbcConnectionPool

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.