Example #1
0
  public static boolean registerDriver(Driver driver) {
    try {
      DriverManager.registerDriver(driver);

      try {
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

        ObjectName objectName = new ObjectName(MBEAN_NAME);
        if (!mbeanServer.isRegistered(objectName)) {
          mbeanServer.registerMBean(instance, objectName);
        }
      } catch (Throwable ex) {
        if (LOG == null) {
          LOG = LogFactory.getLog(DruidDriver.class);
        }
        LOG.warn("register druid-driver mbean error", ex);
      }

      return true;
    } catch (Exception e) {
      if (LOG == null) {
        LOG = LogFactory.getLog(DruidDriver.class);
      }

      LOG.error("registerDriver error", e);
    }

    return false;
  }
public class OracleValidConnectionChecker implements ValidConnectionChecker, Serializable {

  private static final long serialVersionUID = -2227528634302168877L;

  private static final Log LOG = LogFactory.getLog(OracleValidConnectionChecker.class);

  private final Class<?> clazz;
  private final Method ping;
  private static final Object[] params = new Object[] {new Integer(5000)};

  public OracleValidConnectionChecker() {
    try {
      clazz = JdbcUtils.loadDriverClass("oracle.jdbc.driver.OracleConnection");
      if (clazz != null) {
        ping = clazz.getMethod("pingDatabase", new Class[] {Integer.TYPE});
      } else {
        ping = null;
      }
    } catch (Exception e) {
      throw new RuntimeException("Unable to resolve pingDatabase method:", e);
    }
  }

  public boolean isValidConnection(
      Connection conn, String valiateQuery, int validationQueryTimeout) {
    try {
      if (conn.isClosed()) {
        return false;
      }
    } catch (SQLException ex) {
      // skip
      return false;
    }

    if (valiateQuery == null) {
      return true;
    }

    try {
      if (conn instanceof DruidPooledConnection) {
        conn = ((DruidPooledConnection) conn).getConnection();
      }

      if (conn instanceof ConnectionProxy) {
        conn = ((ConnectionProxy) conn).getRawObject();
      }

      // unwrap
      if (clazz != null && clazz.isAssignableFrom(conn.getClass())) {
        Integer status = (Integer) ping.invoke(conn, params);

        // Error
        if (status.intValue() < 0) {
          return false;
        }

        return true;
      }

      Statement stmt = null;
      ResultSet rs = null;
      try {
        stmt = conn.createStatement();
        rs = stmt.executeQuery(valiateQuery);
        return true;
      } catch (SQLException e) {
        return false;
      } catch (Exception e) {
        LOG.warn("Unexpected error in ping", e);
        return false;
      } finally {
        JdbcUtils.close(rs);
        JdbcUtils.close(stmt);
      }
    } catch (Exception e) {
      LOG.warn("Unexpected error in pingDatabase", e);
    }

    // OK
    return true;
  }
}
Example #3
0
public class JdbcDataSourceStat implements JdbcDataSourceStatMBean {

  private static final Log LOG = LogFactory.getLog(JdbcDataSourceStat.class);

  private final String name;
  private final String url;
  private String dbType;

  private final JdbcConnectionStat connectionStat = new JdbcConnectionStat();
  private final JdbcResultSetStat resultSetStat = new JdbcResultSetStat();
  private final JdbcStatementStat statementStat = new JdbcStatementStat();

  private int maxSize = 1000 * 1;

  private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  private final LinkedHashMap<String, JdbcSqlStat> sqlStatMap;

  private final Histogram connectionHoldHistogram =
      new Histogram(
          new long[] { //
            //
            1,
            10,
            100,
            1000,
            10 * 1000, //
            100 * 1000,
            1000 * 1000
            //
          });

  private final ConcurrentMap<Long, JdbcConnectionStat.Entry> connections =
      new ConcurrentHashMap<Long, JdbcConnectionStat.Entry>();

  private final AtomicLong clobOpenCount = new AtomicLong();

  private final AtomicLong blobOpenCount = new AtomicLong();

  public JdbcDataSourceStat(String name, String url) {
    this(name, url, null);
  }

  public JdbcDataSourceStat(String name, String url, String dbType) {
    this(name, url, dbType, null);
  }

  public JdbcDataSourceStat(String name, String url, String dbType, Properties connectProperties) {
    this.name = name;
    this.url = url;
    this.dbType = dbType;

    if (connectProperties != null) {
      Object arg = connectProperties.get(Constants.DRUID_STAT_SQL_MAX_SIZE);

      if (arg == null) {
        arg = System.getProperty(Constants.DRUID_STAT_SQL_MAX_SIZE);
      }

      if (arg != null) {
        try {
          maxSize = Integer.parseInt(arg.toString());
        } catch (NumberFormatException ex) {
          LOG.error("maxSize parse error", ex);
        }
      }
    }

    sqlStatMap = new LRUCache<String, JdbcSqlStat>(maxSize, 16, 0.75f, false);
  }

  public void reset() {
    blobOpenCount.set(0);
    clobOpenCount.set(0);

    connectionStat.reset();
    statementStat.reset();
    resultSetStat.reset();
    connectionHoldHistogram.reset();

    lock.writeLock().lock();
    try {
      Iterator<Map.Entry<String, JdbcSqlStat>> iter = sqlStatMap.entrySet().iterator();
      while (iter.hasNext()) {
        Map.Entry<String, JdbcSqlStat> entry = iter.next();
        JdbcSqlStat stat = entry.getValue();
        if (stat.getExecuteCount() == 0 && stat.getRunningCount() == 0) {
          stat.setRemoved(true);
          iter.remove();
        } else {
          stat.reset();
        }
      }
    } finally {
      lock.writeLock().unlock();
    }

    for (JdbcConnectionStat.Entry connectionStat : connections.values()) {
      connectionStat.reset();
    }
  }

  public Histogram getConnectionHoldHistogram() {
    return connectionHoldHistogram;
  }

  public JdbcConnectionStat getConnectionStat() {
    return connectionStat;
  }

  public JdbcResultSetStat getResultSetStat() {
    return resultSetStat;
  }

  public JdbcStatementStat getStatementStat() {
    return statementStat;
  }

  @Override
  public String getConnectionUrl() {
    return url;
  }

  @Override
  public TabularData getSqlList() throws JMException {
    Map<String, JdbcSqlStat> sqlStatMap = this.getSqlStatMap();
    CompositeType rowType = JdbcSqlStat.getCompositeType();
    String[] indexNames = rowType.keySet().toArray(new String[rowType.keySet().size()]);

    TabularType tabularType =
        new TabularType("SqlListStatistic", "SqlListStatistic", rowType, indexNames);
    TabularData data = new TabularDataSupport(tabularType);

    for (Map.Entry<String, JdbcSqlStat> entry : sqlStatMap.entrySet()) {
      data.put(entry.getValue().getCompositeData());
    }

    return data;
  }

  public static StatFilter getStatFilter(DataSourceProxy dataSource) {
    for (Filter filter : dataSource.getProxyFilters()) {
      if (filter instanceof StatFilter) {
        return (StatFilter) filter;
      }
    }

    return null;
  }

  public JdbcSqlStat getSqlStat(int id) {
    return getSqlStat((long) id);
  }

  public JdbcSqlStat getSqlStat(long id) {
    lock.readLock().lock();
    try {
      for (Map.Entry<String, JdbcSqlStat> entry : this.sqlStatMap.entrySet()) {
        if (entry.getValue().getId() == id) {
          return entry.getValue();
        }
      }

      return null;
    } finally {
      lock.readLock().unlock();
    }
  }

  public final ConcurrentMap<Long, JdbcConnectionStat.Entry> getConnections() {
    return connections;
  }

  @Override
  public TabularData getConnectionList() throws JMException {
    CompositeType rowType = JdbcConnectionStat.Entry.getCompositeType();
    String[] indexNames = rowType.keySet().toArray(new String[rowType.keySet().size()]);

    TabularType tabularType =
        new TabularType("ConnectionListStatistic", "ConnectionListStatistic", rowType, indexNames);
    TabularData data = new TabularDataSupport(tabularType);

    for (Map.Entry<Long, JdbcConnectionStat.Entry> entry : getConnections().entrySet()) {
      data.put(entry.getValue().getCompositeData());
    }

    return data;
  }

  public String getName() {
    return name;
  }

  public String getUrl() {
    return url;
  }

  public Map<String, JdbcSqlStat> getSqlStatMap() {
    Map<String, JdbcSqlStat> map = new HashMap<String, JdbcSqlStat>();
    lock.readLock().lock();
    try {
      map.putAll(sqlStatMap);
    } finally {
      lock.readLock().unlock();
    }
    return map;
  }

  public JdbcSqlStat getSqlStat(String sql) {
    lock.readLock().lock();
    try {
      return sqlStatMap.get(sql);
    } finally {
      lock.readLock().unlock();
    }
  }

  public JdbcSqlStat createSqlStat(String sql) {
    lock.writeLock().lock();
    try {
      JdbcSqlStat sqlStat = sqlStatMap.get(sql);
      if (sqlStat == null) {
        sqlStat = new JdbcSqlStat(sql);
        sqlStat.setDbType(this.dbType);
        sqlStatMap.put(sql, sqlStat);
      }

      return sqlStat;
    } finally {
      lock.writeLock().unlock();
    }
  }

  @Override
  public long getConnectionActiveCount() {
    return this.connections.size();
  }

  @Override
  public long getConnectionConnectAliveMillis() {
    long nowNano = System.nanoTime();
    long aliveNanoSpan = this.getConnectionStat().getAliveTotal();

    for (JdbcConnectionStat.Entry connection : connections.values()) {
      aliveNanoSpan += nowNano - connection.getEstablishNano();
    }
    return aliveNanoSpan / (1000 * 1000);
  }

  public long getConnectionConnectAliveMillisMax() {
    long max = this.getConnectionStat().getAliveNanoMax();

    long nowNano = System.nanoTime();
    for (JdbcConnectionStat.Entry connection : connections.values()) {
      long connectionAliveNano = nowNano - connection.getEstablishNano();
      if (connectionAliveNano > max) {
        max = connectionAliveNano;
      }
    }
    return max / (1000 * 1000);
  }

  public long getConnectionConnectAliveMillisMin() {
    long min = this.getConnectionStat().getAliveNanoMin();

    long nowNano = System.nanoTime();
    for (JdbcConnectionStat.Entry connection : connections.values()) {
      long connectionAliveNano = nowNano - connection.getEstablishNano();
      if (connectionAliveNano < min || min == 0) {
        min = connectionAliveNano;
      }
    }
    return min / (1000 * 1000);
  }

  public long[] getConnectionHistogramRanges() {
    return connectionStat.getHistogramRanges();
  }

  public long[] getConnectionHistogramValues() {
    return connectionStat.getHistorgramValues();
  }

  public long getClobOpenCount() {
    return clobOpenCount.get();
  }

  public void incrementClobOpenCount() {
    clobOpenCount.incrementAndGet();
  }

  public long getBlobOpenCount() {
    return blobOpenCount.get();
  }

  public void incrementBlobOpenCount() {
    blobOpenCount.incrementAndGet();
  }
}
Example #4
0
/**
 * 注意:避免直接调用Druid相关对象例如DruidDataSource等,相关调用要到DruidStatManagerFacade里用反射实现
 *
 * @author sandzhang[[email protected]]
 */
public final class DruidStatService implements DruidStatServiceMBean {

  private static final Log LOG = LogFactory.getLog(DruidStatService.class);

  public static final String MBEAN_NAME = "com.alibaba.druid:type=DruidStatService";

  private static final DruidStatService instance = new DruidStatService();

  private static DruidStatManagerFacade statManagerFacade = DruidStatManagerFacade.getInstance();

  public static final int RESULT_CODE_SUCCESS = 1;
  public static final int RESULT_CODE_ERROR = -1;

  private static final int DEFAULT_PAGE = 1;
  private static final int DEFAULT_PER_PAGE_COUNT = Integer.MAX_VALUE;
  private static final String DEFAULT_ORDER_TYPE = "asc";
  private static final String DEFAULT_ORDERBY = "SQL";

  private DruidStatService() {}

  public static DruidStatService getInstance() {
    return instance;
  }

  public boolean isResetEnable() {
    return statManagerFacade.isResetEnable();
  }

  public void setResetEnable(boolean value) {
    statManagerFacade.setResetEnable(value);
  }

  public String service(String url) {

    Map<String, String> parameters = getParameters(url);

    if (url.equals("/basic.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.returnJSONBasicStat());
    }

    if (url.equals("/reset-all.json")) {
      statManagerFacade.resetAll();

      return returnJSONResult(RESULT_CODE_SUCCESS, null);
    }

    if (url.equals("/log-and-reset.json")) {
      statManagerFacade.logAndResetDataSource();

      return returnJSONResult(RESULT_CODE_SUCCESS, null);
    }

    if (url.equals("/datasource.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getDataSourceStatDataList());
    }

    if (url.equals("/activeConnectionStackTrace.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, statManagerFacade.getActiveConnStackTraceList());
    }

    if (url.startsWith("/datasource-")) {
      Integer id = StringUtils.subStringToInteger(url, "datasource-", ".");
      Object result = statManagerFacade.getDataSourceStatData(id);
      return returnJSONResult(result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result);
    }

    if (url.startsWith("/connectionInfo-") && url.endsWith(".json")) {
      Integer id = StringUtils.subStringToInteger(url, "connectionInfo-", ".");
      List<?> connectionInfoList = statManagerFacade.getPoolingConnectionInfoByDataSourceId(id);
      return returnJSONResult(
          connectionInfoList == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, connectionInfoList);
    }

    if (url.startsWith("/activeConnectionStackTrace-") && url.endsWith(".json")) {
      Integer id = StringUtils.subStringToInteger(url, "activeConnectionStackTrace-", ".");
      return returnJSONActiveConnectionStackTrace(id);
    }

    if (url.startsWith("/sql.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getSqlStatDataList(parameters));
    }

    if (url.startsWith("/wall.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getWallStatMap(parameters));
    }

    if (url.startsWith("/wall-") && url.indexOf(".json") > 0) {
      Integer dataSourceId = StringUtils.subStringToInteger(url, "wall-", ".json");
      Object result = statManagerFacade.getWallStatMap(dataSourceId);
      return returnJSONResult(result == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, result);
    }

    if (url.startsWith("/sql-") && url.indexOf(".json") > 0) {
      Integer id = StringUtils.subStringToInteger(url, "sql-", ".json");
      return getSqlStat(id);
    }

    if (url.startsWith("/weburi.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getWebURIStatDataList(parameters));
    }

    if (url.startsWith("/weburi-") && url.indexOf(".json") > 0) {
      String uri = StringUtils.subString(url, "weburi-", ".json");
      return returnJSONResult(RESULT_CODE_SUCCESS, getWebURIStatData(uri));
    }

    if (url.startsWith("/webapp.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getWebAppStatDataList(parameters));
    }

    if (url.startsWith("/websession.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatDataList(parameters));
    }

    if (url.startsWith("/websession-") && url.indexOf(".json") > 0) {
      String id = StringUtils.subString(url, "websession-", ".json");
      return returnJSONResult(RESULT_CODE_SUCCESS, getWebSessionStatData(id));
    }

    if (url.startsWith("/spring.json")) {
      return returnJSONResult(RESULT_CODE_SUCCESS, getSpringStatDataList(parameters));
    }

    if (url.startsWith("/spring-detail.json")) {
      String clazz = parameters.get("class");
      String method = parameters.get("method");
      return returnJSONResult(RESULT_CODE_SUCCESS, getSpringMethodStatData(clazz, method));
    }

    return returnJSONResult(
        RESULT_CODE_ERROR, "Do not support this request, please contact with administrator.");
  }

  private List<Map<String, Object>> getSpringStatDataList(Map<String, String> parameters) {
    List<Map<String, Object>> array = SpringStatManager.getInstance().getMethodStatData();
    return comparatorOrderBy(array, parameters);
  }

  private List<Map<String, Object>> getWebURIStatDataList(Map<String, String> parameters) {
    List<Map<String, Object>> array = WebAppStatManager.getInstance().getURIStatData();
    return comparatorOrderBy(array, parameters);
  }

  private Map<String, Object> getWebURIStatData(String uri) {
    return WebAppStatManager.getInstance().getURIStatData(uri);
  }

  private Map<String, Object> getWebSessionStatData(String sessionId) {
    return WebAppStatManager.getInstance().getSessionStat(sessionId);
  }

  private Map<String, Object> getSpringMethodStatData(String clazz, String method) {
    return SpringStatManager.getInstance().getMethodStatData(clazz, method);
  }

  private List<Map<String, Object>> getWebSessionStatDataList(Map<String, String> parameters) {
    List<Map<String, Object>> array = WebAppStatManager.getInstance().getSessionStatData();
    return comparatorOrderBy(array, parameters);
  }

  private List<Map<String, Object>> getWebAppStatDataList(Map<String, String> parameters) {
    List<Map<String, Object>> array = WebAppStatManager.getInstance().getWebAppStatData();
    return comparatorOrderBy(array, parameters);
  }

  private List<Map<String, Object>> comparatorOrderBy(
      List<Map<String, Object>> array, Map<String, String> parameters) {
    // when open the stat page before executing some sql
    if (array == null || array.isEmpty()) {
      return null;
    }

    // when parameters is null
    String orderBy, orderType = null;
    Integer page = DEFAULT_PAGE;
    Integer perPageCount = DEFAULT_PER_PAGE_COUNT;
    if (parameters == null) {
      orderBy = DEFAULT_ORDER_TYPE;
      orderType = DEFAULT_ORDER_TYPE;
      page = DEFAULT_PAGE;
      perPageCount = DEFAULT_PER_PAGE_COUNT;
    } else {
      orderBy = parameters.get("orderBy");
      orderType = parameters.get("orderType");
      String pageParam = parameters.get("page");
      if (pageParam != null && pageParam.length() != 0) {
        page = Integer.parseInt(pageParam);
      }
      String pageCountParam = parameters.get("perPageCount");
      if (pageCountParam != null && pageCountParam.length() > 0) {
        perPageCount = Integer.parseInt(pageCountParam);
      }
    }

    // others,such as order
    orderBy = orderBy == null ? DEFAULT_ORDERBY : orderBy;
    orderType = orderType == null ? DEFAULT_ORDER_TYPE : orderType;

    if (!"desc".equals(orderType)) {
      orderType = DEFAULT_ORDER_TYPE;
    }

    // orderby the statData array
    if (orderBy != null && orderBy.trim().length() != 0) {
      Collections.sort(
          array, new MapComparator<String, Object>(orderBy, DEFAULT_ORDER_TYPE.equals(orderType)));
    }

    // page
    int fromIndex = (page - 1) * perPageCount;
    int toIndex = page * perPageCount;
    if (toIndex > array.size()) {
      toIndex = array.size();
    }

    return array.subList(fromIndex, toIndex);
  }

  private List<Map<String, Object>> getSqlStatDataList(Map<String, String> parameters) {
    Integer dataSourceId = null;

    String dataSourceIdParam = parameters.get("dataSourceId");
    if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) {
      dataSourceId = Integer.parseInt(dataSourceIdParam);
    }

    List<Map<String, Object>> array = statManagerFacade.getSqlStatDataList(dataSourceId);
    List<Map<String, Object>> sortedArray = comparatorOrderBy(array, parameters);
    return sortedArray;
  }

  @SuppressWarnings("unchecked")
  public Map<String, Object> getWallStatMap(Map<String, String> parameters) {
    Integer dataSourceId = null;

    String dataSourceIdParam = parameters.get("dataSourceId");
    if (dataSourceIdParam != null && dataSourceIdParam.length() > 0) {
      dataSourceId = Integer.parseInt(dataSourceIdParam);
    }

    Map<String, Object> result = statManagerFacade.getWallStatMap(dataSourceId);

    if (result != null) {
      List<Map<String, Object>> tables = (List<Map<String, Object>>) result.get("tables");
      if (tables != null) {
        List<Map<String, Object>> sortedArray = comparatorOrderBy(tables, parameters);
        result.put("tables", sortedArray);
      }

      List<Map<String, Object>> functions = (List<Map<String, Object>>) result.get("functions");
      if (functions != null) {
        List<Map<String, Object>> sortedArray = comparatorOrderBy(functions, parameters);
        result.put("functions", sortedArray);
      }
    } else {
      result = Collections.emptyMap();
    }

    return result;
  }

  private String getSqlStat(Integer id) {
    Map<String, Object> map = statManagerFacade.getSqlStatData(id);

    if (map == null) {
      return returnJSONResult(RESULT_CODE_ERROR, null);
    }

    String dbType = (String) map.get("DbType");
    String sql = (String) map.get("SQL");

    map.put("formattedSql", SQLUtils.format(sql, dbType));
    List<SQLStatement> statementList = SQLUtils.parseStatements(sql, dbType);

    if (!statementList.isEmpty()) {
      SQLStatement sqlStmt = statementList.get(0);
      SchemaStatVisitor visitor = SQLUtils.createSchemaStatVisitor(dbType);
      sqlStmt.accept(visitor);
      map.put("parsedTable", visitor.getTables().toString());
      map.put("parsedFields", visitor.getColumns().toString());
      map.put("parsedConditions", visitor.getConditions().toString());
      map.put("parsedRelationships", visitor.getRelationships().toString());
      map.put("parsedOrderbycolumns", visitor.getOrderByColumns().toString());
    }

    DateFormat format = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss:SSS");
    Date maxTimespanOccurTime = (Date) map.get("MaxTimespanOccurTime");
    if (maxTimespanOccurTime != null) {
      map.put("MaxTimespanOccurTime", format.format(maxTimespanOccurTime));
    }

    return returnJSONResult(map == null ? RESULT_CODE_ERROR : RESULT_CODE_SUCCESS, map);
  }

  private String returnJSONActiveConnectionStackTrace(Integer id) {
    List<String> result = statManagerFacade.getActiveConnectionStackTraceByDataSourceId(id);

    if (result == null) {
      return returnJSONResult(RESULT_CODE_ERROR, "require set removeAbandoned=true");
    }
    return returnJSONResult(RESULT_CODE_SUCCESS, result);
  }

  public static String returnJSONResult(int resultCode, Object content) {
    Map<String, Object> dataMap = new LinkedHashMap<String, Object>();
    dataMap.put("ResultCode", resultCode);
    dataMap.put("Content", content);
    return JSONUtils.toJSONString(dataMap);
  }

  public static void registerMBean() {
    MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();
    try {

      ObjectName objectName = new ObjectName(MBEAN_NAME);
      if (!mbeanServer.isRegistered(objectName)) {
        mbeanServer.registerMBean(instance, objectName);
      }
    } catch (JMException ex) {
      LOG.error("register mbean error", ex);
    }
  }

  public static void unregisterMBean() {
    MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

    try {
      mbeanServer.unregisterMBean(new ObjectName(MBEAN_NAME));
    } catch (JMException ex) {
      LOG.error("unregister mbean error", ex);
    }
  }

  public static Map<String, String> getParameters(String url) {
    if (url == null || (url = url.trim()).length() == 0) {
      return Collections.<String, String>emptyMap();
    }

    String parametersStr = StringUtils.subString(url, "?", null);
    if (parametersStr == null || parametersStr.length() == 0) {
      return Collections.<String, String>emptyMap();
    }

    String[] parametersArray = parametersStr.split("&");
    Map<String, String> parameters = new LinkedHashMap<String, String>();

    for (String parameterStr : parametersArray) {
      int index = parameterStr.indexOf("=");
      if (index <= 0) {
        continue;
      }

      String name = parameterStr.substring(0, index);
      String value = parameterStr.substring(index + 1);
      parameters.put(name, value);
    }
    return parameters;
  }
}
/** @author wenshao<*****@*****.**> */
public class DruidPooledConnection extends PoolableWrapper
    implements javax.sql.PooledConnection, Connection {

  private static final Log LOG = LogFactory.getLog(DruidPooledConnection.class);

  public static final int MAX_RECORD_SQL_COUNT = 10;

  protected Connection conn;
  protected volatile DruidConnectionHolder holder;
  protected TransactionInfo transactionInfo;
  private final boolean dupCloseLogEnable;
  private volatile boolean traceEnable = false;
  private boolean disable = false;
  private boolean closed = false;
  private final Thread ownerThread;

  private long connectedTimeNano;
  private volatile boolean running = false;

  private volatile boolean abandoned = false;

  private StackTraceElement[] connectStackTrace;

  private Throwable disableError = null;

  public DruidPooledConnection(DruidConnectionHolder holder) {
    super(holder.getConnection());

    this.conn = holder.getConnection();
    this.holder = holder;
    dupCloseLogEnable = holder.getDataSource().isDupCloseLogEnable();
    ownerThread = Thread.currentThread();
  }

  public Thread getOwnerThread() {
    return ownerThread;
  }

  public StackTraceElement[] getConnectStackTrace() {
    return connectStackTrace;
  }

  public void setConnectStackTrace(StackTraceElement[] connectStackTrace) {
    this.connectStackTrace = connectStackTrace;
  }

  public long getConnectedTimeNano() {
    return connectedTimeNano;
  }

  public void setConnectedTimeNano() {
    if (connectedTimeNano <= 0) {
      this.setConnectedTimeNano(System.nanoTime());
    }
  }

  public void setConnectedTimeNano(long connectedTimeNano) {
    this.connectedTimeNano = connectedTimeNano;
  }

  public boolean isTraceEnable() {
    return traceEnable;
  }

  public void setTraceEnable(boolean traceEnable) {
    this.traceEnable = traceEnable;
  }

  public SQLException handleException(Throwable t) throws SQLException {
    final DruidConnectionHolder holder = this.holder;

    //
    if (holder != null) {
      DruidAbstractDataSource dataSource = holder.getDataSource();
      dataSource.handleConnectionException(this, t);
    }

    if (t instanceof SQLException) {
      throw (SQLException) t;
    }

    throw new SQLException("Error", t);
  }

  public boolean isOracle() {
    return holder.getDataSource().isOracle();
  }

  public void closePoolableStatement(DruidPooledPreparedStatement stmt) throws SQLException {
    PreparedStatement rawStatement = stmt.getRawPreparedStatement();

    if (holder == null) {
      return;
    }

    if (stmt.isPooled()) {
      try {
        rawStatement.clearParameters();
      } catch (SQLException ex) {
        this.handleException(ex);
        if (rawStatement.getConnection().isClosed()) {
          return;
        }

        LOG.error("clear parameter error", ex);
      }
    }

    stmt.getPreparedStatementHolder().decrementInUseCount();
    if (stmt.isPooled() && holder.isPoolPreparedStatements()) {
      holder.getStatementPool().put(stmt.getPreparedStatementHolder());

      stmt.clearResultSet();
      holder.removeTrace(stmt);

      stmt.getPreparedStatementHolder().setFetchRowPeak(stmt.getFetchRowPeak());

      stmt.setClosed(true); // soft set close
    } else {
      stmt.closeInternal();
      holder.getDataSource().incrementClosedPreparedStatementCount();
    }
  }

  public DruidConnectionHolder getConnectionHolder() {
    return holder;
  }

  @Override
  public Connection getConnection() {
    return conn;
  }

  public void disable() {
    disable(null);
  }

  public void disable(Throwable error) {
    if (this.holder != null) {
      this.holder.clearStatementCache();
    }

    this.traceEnable = false;
    this.holder = null;
    this.transactionInfo = null;
    this.disable = true;
    this.disableError = error;
  }

  public boolean isDisable() {
    return disable;
  }

  @Override
  public void close() throws SQLException {
    if (this.disable) {
      return;
    }

    DruidConnectionHolder holder = this.holder;
    if (holder == null) {
      if (dupCloseLogEnable) {
        LOG.error("dup close");
      }
      return;
    }

    if (holder.getDataSource().isRemoveAbandoned()) {
      syncClose();
      return;
    }

    for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {
      listener.connectionClosed(new ConnectionEvent(this));
    }

    DruidAbstractDataSource dataSource = holder.getDataSource();
    List<Filter> filters = dataSource.getProxyFilters();
    if (filters.size() > 0) {
      FilterChainImpl filterChain = new FilterChainImpl(dataSource);
      filterChain.dataSource_recycle(this);
    } else {
      recycle();
    }

    this.disable = true;
  }

  public synchronized void syncClose() throws SQLException {
    if (this.disable) {
      return;
    }

    DruidConnectionHolder holder = this.holder;
    if (holder == null) {
      if (dupCloseLogEnable) {
        LOG.error("dup close");
      }
      return;
    }

    for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {
      listener.connectionClosed(new ConnectionEvent(this));
    }

    DruidAbstractDataSource dataSource = holder.getDataSource();
    List<Filter> filters = dataSource.getProxyFilters();
    if (filters.size() > 0) {
      FilterChainImpl filterChain = new FilterChainImpl(dataSource);
      filterChain.dataSource_recycle(this);
    } else {
      recycle();
    }

    this.disable = true;
  }

  public void recycle() throws SQLException {
    if (this.disable) {
      return;
    }

    DruidConnectionHolder holder = this.holder;
    if (holder == null) {
      if (dupCloseLogEnable) {
        LOG.error("dup close");
      }
      return;
    }

    if (!this.abandoned) {
      DruidAbstractDataSource dataSource = holder.getDataSource();
      dataSource.recycle(this);
    }

    this.holder = null;
    conn = null;
    transactionInfo = null;
    closed = true;
  }

  // ////////////////////

  @Override
  public PreparedStatement prepareStatement(String sql) throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.M1);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  private void initStatement(PreparedStatementHolder stmtHolder) throws SQLException {
    stmtHolder.incrementInUseCount();
    holder.getDataSource().initStatement(this, stmtHolder.getStatement());
  }

  @Override
  public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)
      throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key =
        new PreparedStatementKey(
            sql, getCatalog(), MethodType.M2, resultSetType, resultSetConcurrency);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder =
            new PreparedStatementHolder(
                key, conn.prepareStatement(sql, resultSetType, resultSetConcurrency));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public PreparedStatement prepareStatement(
      String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key =
        new PreparedStatementKey(
            sql,
            getCatalog(),
            MethodType.M3,
            resultSetType,
            resultSetConcurrency,
            resultSetHoldability);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder =
            new PreparedStatementHolder(
                key,
                conn.prepareStatement(
                    sql, resultSetType, resultSetConcurrency, resultSetHoldability));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
    checkState();

    PreparedStatementKey key =
        new PreparedStatementKey(sql, getCatalog(), MethodType.M4, columnIndexes);
    PreparedStatementHolder stmtHolder = null;

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnIndexes));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
    checkState();

    PreparedStatementKey key =
        new PreparedStatementKey(sql, getCatalog(), MethodType.M5, columnNames);
    PreparedStatementHolder stmtHolder = null;

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder = new PreparedStatementHolder(key, conn.prepareStatement(sql, columnNames));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
    checkState();

    PreparedStatementKey key =
        new PreparedStatementKey(sql, getCatalog(), MethodType.M6, autoGeneratedKeys);
    PreparedStatementHolder stmtHolder = null;

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder =
            new PreparedStatementHolder(key, conn.prepareStatement(sql, autoGeneratedKeys));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledPreparedStatement rtnVal = new DruidPooledPreparedStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  // ////////////////////

  @Override
  public CallableStatement prepareCall(String sql) throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key = new PreparedStatementKey(sql, getCatalog(), MethodType.Precall_1);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder = new PreparedStatementHolder(key, conn.prepareCall(sql));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public CallableStatement prepareCall(
      String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability)
      throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key =
        new PreparedStatementKey(
            sql,
            getCatalog(),
            MethodType.Precall_2,
            resultSetType,
            resultSetConcurrency,
            resultSetHoldability);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder =
            new PreparedStatementHolder(
                key,
                conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder);

    holder.addTrace(rtnVal);

    return rtnVal;
  }

  @Override
  public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency)
      throws SQLException {
    checkState();

    PreparedStatementHolder stmtHolder = null;
    PreparedStatementKey key =
        new PreparedStatementKey(
            sql, getCatalog(), MethodType.Precall_3, resultSetType, resultSetConcurrency);

    boolean poolPreparedStatements = holder.isPoolPreparedStatements();

    if (poolPreparedStatements) {
      stmtHolder = holder.getStatementPool().get(key);
    }

    if (stmtHolder == null) {
      try {
        stmtHolder =
            new PreparedStatementHolder(
                key, conn.prepareCall(sql, resultSetType, resultSetConcurrency));
        holder.getDataSource().incrementPreparedStatementCount();
      } catch (SQLException ex) {
        handleException(ex);
      }
    }

    initStatement(stmtHolder);

    DruidPooledCallableStatement rtnVal = new DruidPooledCallableStatement(this, stmtHolder);
    holder.addTrace(rtnVal);

    return rtnVal;
  }

  // ////////////////////

  @Override
  public Statement createStatement() throws SQLException {
    checkState();

    Statement stmt = null;
    try {
      stmt = conn.createStatement();
    } catch (SQLException ex) {
      handleException(ex);
    }

    holder.getDataSource().initStatement(this, stmt);

    DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt);
    holder.addTrace(poolableStatement);

    return poolableStatement;
  }

  @Override
  public Statement createStatement(
      int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException {
    checkState();

    Statement stmt = null;
    try {
      stmt = conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
    } catch (SQLException ex) {
      handleException(ex);
    }

    holder.getDataSource().initStatement(this, stmt);

    DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt);
    holder.addTrace(poolableStatement);

    return poolableStatement;
  }

  @Override
  public Statement createStatement(int resultSetType, int resultSetConcurrency)
      throws SQLException {
    checkState();

    Statement stmt = null;
    try {
      stmt = conn.createStatement(resultSetType, resultSetConcurrency);
    } catch (SQLException ex) {
      handleException(ex);
    }

    holder.getDataSource().initStatement(this, stmt);

    DruidPooledStatement poolableStatement = new DruidPooledStatement(this, stmt);
    holder.addTrace(poolableStatement);

    return poolableStatement;
  }

  @Override
  public String nativeSQL(String sql) throws SQLException {
    checkState();

    return conn.nativeSQL(sql);
  }

  @Override
  public void setAutoCommit(boolean autoCommit) throws SQLException {
    checkState();

    boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState();

    if (useLocalSessionState) {
      if (autoCommit == holder.isUnderlyingAutoCommit()) {
        return;
      }
    }

    try {
      conn.setAutoCommit(autoCommit);
      holder.setUnderlyingAutoCommit(autoCommit);
    } catch (SQLException ex) {
      handleException(ex);
    }
  }

  protected void transactionRecord(String sql) throws SQLException {
    if (transactionInfo == null && (!conn.getAutoCommit())) {
      DruidAbstractDataSource dataSource = holder.getDataSource();
      dataSource.incrementStartTransactionCount();
      transactionInfo = new TransactionInfo(dataSource.createTransactionId());
    }

    if (transactionInfo != null) {
      List<String> sqlList = transactionInfo.getSqlList();
      if (sqlList.size() < MAX_RECORD_SQL_COUNT) {
        sqlList.add(sql);
      }
    }
  }

  @Override
  public boolean getAutoCommit() throws SQLException {
    checkState();

    return conn.getAutoCommit();
  }

  @Override
  public void commit() throws SQLException {
    checkState();

    DruidAbstractDataSource dataSource = holder.getDataSource();
    dataSource.incrementCommitCount();

    try {
      conn.commit();
    } catch (SQLException ex) {
      handleException(ex);
    } finally {
      handleEndTransaction(dataSource, null);
    }
  }

  public TransactionInfo getTransactionInfo() {
    return transactionInfo;
  }

  @Override
  public void rollback() throws SQLException {
    if (transactionInfo == null) {
      return;
    }

    if (holder == null) {
      return;
    }

    DruidAbstractDataSource dataSource = holder.getDataSource();
    dataSource.incrementRollbackCount();

    try {
      conn.rollback();
    } catch (SQLException ex) {
      handleException(ex);
    } finally {
      handleEndTransaction(dataSource, null);
    }
  }

  @Override
  public Savepoint setSavepoint(String name) throws SQLException {
    checkState();

    try {
      return conn.setSavepoint(name);
    } catch (SQLException ex) {
      handleException(ex);
      return null; // never arrive
    }
  }

  @Override
  public void rollback(Savepoint savepoint) throws SQLException {
    if (holder == null) {
      return;
    }

    DruidAbstractDataSource dataSource = holder.getDataSource();
    dataSource.incrementRollbackCount();

    try {
      conn.rollback(savepoint);
    } catch (SQLException ex) {
      handleException(ex);
    } finally {
      handleEndTransaction(dataSource, savepoint);
    }
  }

  private void handleEndTransaction(DruidAbstractDataSource dataSource, Savepoint savepoint) {
    if (transactionInfo != null && savepoint == null) {
      transactionInfo.setEndTimeMillis();

      long transactionMillis =
          transactionInfo.getEndTimeMillis() - transactionInfo.getStartTimeMillis();
      dataSource.getTransactionHistogram().record(transactionMillis);

      dataSource.logTransaction(transactionInfo);

      transactionInfo = null;
    }
  }

  @Override
  public void releaseSavepoint(Savepoint savepoint) throws SQLException {
    checkState();
    try {
      conn.releaseSavepoint(savepoint);
    } catch (SQLException ex) {
      handleException(ex);
    }
  }

  @Override
  public Clob createClob() throws SQLException {
    checkState();

    try {
      return conn.createClob();
    } catch (SQLException ex) {
      handleException(ex);
      return null; // never arrive
    }
  }

  @Override
  public boolean isClosed() throws SQLException {
    if (holder == null) {
      return true;
    }

    return conn.isClosed();
  }

  public boolean isAbandonded() {
    return this.abandoned;
  }

  @Override
  public DatabaseMetaData getMetaData() throws SQLException {
    checkState();

    return conn.getMetaData();
  }

  @Override
  public void setReadOnly(boolean readOnly) throws SQLException {
    checkState();

    boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState();
    if (useLocalSessionState) {
      if (readOnly == holder.isUnderlyingReadOnly()) {
        return;
      }
    }

    try {
      conn.setReadOnly(readOnly);
    } catch (SQLException ex) {
      handleException(ex);
    }

    holder.setUnderlyingReadOnly(readOnly);
  }

  @Override
  public boolean isReadOnly() throws SQLException {
    checkState();

    return conn.isReadOnly();
  }

  @Override
  public void setCatalog(String catalog) throws SQLException {
    checkState();

    try {
      conn.setCatalog(catalog);
    } catch (SQLException ex) {
      handleException(ex);
    }
  }

  @Override
  public String getCatalog() throws SQLException {
    checkState();

    return conn.getCatalog();
  }

  @Override
  public void setTransactionIsolation(int level) throws SQLException {
    checkState();

    boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState();
    if (useLocalSessionState) {
      if (level == holder.getUnderlyingTransactionIsolation()) {
        return;
      }
    }

    try {
      conn.setTransactionIsolation(level);
    } catch (SQLException ex) {
      handleException(ex);
    }
    holder.setUnderlyingTransactionIsolation(level);
  }

  @Override
  public int getTransactionIsolation() throws SQLException {
    checkState();

    return holder.getUnderlyingTransactionIsolation();
  }

  @Override
  public SQLWarning getWarnings() throws SQLException {
    checkState();

    return conn.getWarnings();
  }

  @Override
  public void clearWarnings() throws SQLException {
    checkState();
    try {
      conn.clearWarnings();
    } catch (SQLException ex) {
      handleException(ex);
    }
  }

  @Override
  public Map<String, Class<?>> getTypeMap() throws SQLException {
    checkState();

    return conn.getTypeMap();
  }

  @Override
  public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
    checkState();

    conn.setTypeMap(map);
  }

  @Override
  public void setHoldability(int holdability) throws SQLException {
    checkState();

    boolean useLocalSessionState = holder.getDataSource().isUseLocalSessionState();
    if (useLocalSessionState) {
      if (holdability == holder.getUnderlyingHoldability()) {
        return;
      }
    }

    conn.setHoldability(holdability);
    holder.setUnderlyingHoldability(holdability);
  }

  @Override
  public int getHoldability() throws SQLException {
    checkState();

    return conn.getHoldability();
  }

  @Override
  public Savepoint setSavepoint() throws SQLException {
    checkState();

    try {
      return conn.setSavepoint();
    } catch (SQLException ex) {
      handleException(ex);
      return null;
    }
  }

  @Override
  public Blob createBlob() throws SQLException {
    checkState();

    return conn.createBlob();
  }

  @Override
  public NClob createNClob() throws SQLException {
    checkState();

    return conn.createNClob();
  }

  @Override
  public SQLXML createSQLXML() throws SQLException {
    checkState();

    return conn.createSQLXML();
  }

  @Override
  public boolean isValid(int timeout) throws SQLException {
    checkState();

    return conn.isValid(timeout);
  }

  @Override
  public void setClientInfo(String name, String value) throws SQLClientInfoException {
    if (holder == null) {
      throw new SQLClientInfoException();
    }

    conn.setClientInfo(name, value);
  }

  @Override
  public void setClientInfo(Properties properties) throws SQLClientInfoException {
    if (holder == null) {
      throw new SQLClientInfoException();
    }

    conn.setClientInfo(properties);
  }

  @Override
  public String getClientInfo(String name) throws SQLException {
    checkState();

    return conn.getClientInfo(name);
  }

  @Override
  public Properties getClientInfo() throws SQLException {
    checkState();

    return conn.getClientInfo();
  }

  @Override
  public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
    checkState();

    return conn.createArrayOf(typeName, elements);
  }

  @Override
  public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
    checkState();

    return conn.createStruct(typeName, attributes);
  }

  @Override
  public void addConnectionEventListener(ConnectionEventListener listener) {
    if (holder == null) {
      throw new IllegalStateException();
    }

    holder.getConnectionEventListeners().add(listener);
  }

  @Override
  public void removeConnectionEventListener(ConnectionEventListener listener) {
    if (holder == null) {
      throw new IllegalStateException();
    }

    holder.getConnectionEventListeners().remove(listener);
  }

  @Override
  public void addStatementEventListener(StatementEventListener listener) {
    if (holder == null) {
      throw new IllegalStateException();
    }

    holder.getStatementEventListeners().add(listener);
  }

  @Override
  public void removeStatementEventListener(StatementEventListener listener) {
    if (holder == null) {
      throw new IllegalStateException();
    }

    holder.getStatementEventListeners().remove(listener);
  }

  public Throwable getDisableError() {
    return disableError;
  }

  public void checkState() throws SQLException {
    if (holder == null) {
      if (disableError != null) {
        throw new SQLException("connection holder is null", disableError);
      } else {
        throw new SQLException("connection holder is null");
      }
    }

    if (closed) {
      if (disableError != null) {
        throw new SQLException("connection closed", disableError);
      } else {
        throw new SQLException("connection closed");
      }
    }

    if (disable) {
      if (disableError != null) {
        throw new SQLException("connection disabled", disableError);
      } else {
        throw new SQLException("connection disabled");
      }
    }
  }

  public String toString() {
    if (conn != null) {
      return conn.toString();
    } else {
      return "closed-conn-" + System.identityHashCode(this);
    }
  }

  public void setSchema(String schema) throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  public String getSchema() throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  public void abort(Executor executor) throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  public int getNetworkTimeout() throws SQLException {
    throw new SQLFeatureNotSupportedException();
  }

  final void beforeExecute() {
    final DruidConnectionHolder holder = this.holder;
    if (holder != null && holder.getDataSource().isRemoveAbandoned()) {
      running = true;
    }
  }

  final void afterExecute() {
    final DruidConnectionHolder holder = this.holder;
    if (holder != null && holder.getDataSource().isRemoveAbandoned()) {
      running = false;
      holder.setLastActiveTimeMillis(System.currentTimeMillis());
    }
  }

  boolean isRunning() {
    return running;
  }

  public void abandond() {
    this.abandoned = true;
  }
}
public class MySqlValidConnectionChecker extends ValidConnectionCheckerAdapter
    implements ValidConnectionChecker, Serializable {

  public static final int DEFAULT_VALIDATION_QUERY_TIMEOUT = 1000;

  private static final long serialVersionUID = 1L;
  private static final Log LOG = LogFactory.getLog(MySqlValidConnectionChecker.class);

  private Class<?> clazz;
  private Method ping;
  private boolean usePingMethod = false;

  public MySqlValidConnectionChecker() {
    try {
      clazz = Utils.loadClass("com.mysql.jdbc.MySQLConnection");
      ping = clazz.getMethod("pingInternal", boolean.class, int.class);
      if (ping != null) {
        usePingMethod = true;
      }
    } catch (Exception e) {
      LOG.warn(
          "Cannot resolve com.mysq.jdbc.Connection.ping method.  Will use 'SELECT 1' instead.", e);
    }

    configFromProperties(System.getProperties());
  }

  @Override
  public void configFromProperties(Properties properties) {
    String property = properties.getProperty("druid.mysql.usePingMethod");
    if ("true".equals(property)) {
      setUsePingMethod(true);
    } else if ("false".equals(property)) {
      setUsePingMethod(false);
    }
  }

  public boolean isUsePingMethod() {
    return usePingMethod;
  }

  public void setUsePingMethod(boolean usePingMethod) {
    this.usePingMethod = usePingMethod;
  }

  public boolean isValidConnection(
      Connection conn, String validateQuery, int validationQueryTimeout) {
    try {
      if (conn.isClosed()) {
        return false;
      }
    } catch (SQLException ex) {
      // skip
      return false;
    }

    if (usePingMethod) {
      if (conn instanceof DruidPooledConnection) {
        conn = ((DruidPooledConnection) conn).getConnection();
      }

      if (conn instanceof ConnectionProxy) {
        conn = ((ConnectionProxy) conn).getRawObject();
      }

      if (clazz.isAssignableFrom(conn.getClass())) {
        if (validationQueryTimeout < 0) {
          validationQueryTimeout = DEFAULT_VALIDATION_QUERY_TIMEOUT;
        }

        try {
          ping.invoke(conn, true, validationQueryTimeout);
          return true;
        } catch (InvocationTargetException e) {
          Throwable cause = e.getCause();
          if (cause instanceof SQLException) {
            return false;
          }

          LOG.warn("Unexpected error in ping", e);
          return false;
        } catch (Exception e) {
          LOG.warn("Unexpected error in ping", e);
          return false;
        }
      }
    }

    Statement stmt = null;
    ResultSet rs = null;
    try {
      stmt = conn.createStatement();
      if (validationQueryTimeout > 0) {
        stmt.setQueryTimeout(validationQueryTimeout);
      }
      rs = stmt.executeQuery(validateQuery);
      return true;
    } catch (SQLException e) {
      return false;
    } catch (Exception e) {
      LOG.warn("Unexpected error in ping", e);
      return false;
    } finally {
      JdbcUtils.close(rs);
      JdbcUtils.close(stmt);
    }
  }
}
Example #7
0
/** @author wenshao [[email protected]] */
public final class JdbcUtils implements JdbcConstants {

  private static final Log LOG = LogFactory.getLog(JdbcUtils.class);

  private static final Properties DRIVER_URL_MAPPING = new Properties();

  private static Boolean mysql_driver_version_6 = null;

  static {
    try {
      ClassLoader ctxClassLoader = Thread.currentThread().getContextClassLoader();
      if (ctxClassLoader != null) {
        for (Enumeration<URL> e = ctxClassLoader.getResources("META-INF/druid-driver.properties");
            e.hasMoreElements(); ) {
          URL url = e.nextElement();

          Properties property = new Properties();

          InputStream is = null;
          try {
            is = url.openStream();
            property.load(is);
          } finally {
            JdbcUtils.close(is);
          }

          DRIVER_URL_MAPPING.putAll(property);
        }
      }
    } catch (Exception e) {
      LOG.error("load druid-driver.properties error", e);
    }
  }

  public static void close(Connection x) {
    if (x == null) {
      return;
    }
    try {
      x.close();
    } catch (Exception e) {
      LOG.debug("close connection error", e);
    }
  }

  public static void close(Statement x) {
    if (x == null) {
      return;
    }
    try {
      x.close();
    } catch (Exception e) {
      LOG.debug("close statement error", e);
    }
  }

  public static void close(ResultSet x) {
    if (x == null) {
      return;
    }
    try {
      x.close();
    } catch (Exception e) {
      LOG.debug("close result set error", e);
    }
  }

  public static void close(Closeable x) {
    if (x == null) {
      return;
    }

    try {
      x.close();
    } catch (Exception e) {
      LOG.debug("close error", e);
    }
  }

  public static void printResultSet(ResultSet rs) throws SQLException {
    printResultSet(rs, System.out);
  }

  public static void printResultSet(ResultSet rs, PrintStream out) throws SQLException {
    printResultSet(rs, out, true, "\t");
  }

  public static void printResultSet(
      ResultSet rs, PrintStream out, boolean printHeader, String seperator) throws SQLException {
    ResultSetMetaData metadata = rs.getMetaData();
    int columnCount = metadata.getColumnCount();
    if (printHeader) {
      for (int columnIndex = 1; columnIndex <= columnCount; ++columnIndex) {
        if (columnIndex != 1) {
          out.print(seperator);
        }
        out.print(metadata.getColumnName(columnIndex));
      }
    }

    out.println();

    while (rs.next()) {

      for (int columnIndex = 1; columnIndex <= columnCount; ++columnIndex) {
        if (columnIndex != 1) {
          out.print(seperator);
        }

        int type = metadata.getColumnType(columnIndex);

        if (type == Types.VARCHAR
            || type == Types.CHAR
            || type == Types.NVARCHAR
            || type == Types.NCHAR) {
          out.print(rs.getString(columnIndex));
        } else if (type == Types.DATE) {
          Date date = rs.getDate(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(date.toString());
          }
        } else if (type == Types.BIT) {
          boolean value = rs.getBoolean(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Boolean.toString(value));
          }
        } else if (type == Types.BOOLEAN) {
          boolean value = rs.getBoolean(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Boolean.toString(value));
          }
        } else if (type == Types.TINYINT) {
          byte value = rs.getByte(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Byte.toString(value));
          }
        } else if (type == Types.SMALLINT) {
          short value = rs.getShort(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Short.toString(value));
          }
        } else if (type == Types.INTEGER) {
          int value = rs.getInt(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Integer.toString(value));
          }
        } else if (type == Types.BIGINT) {
          long value = rs.getLong(columnIndex);
          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(Long.toString(value));
          }
        } else if (type == Types.TIMESTAMP) {
          out.print(String.valueOf(rs.getTimestamp(columnIndex)));
        } else if (type == Types.DECIMAL) {
          out.print(String.valueOf(rs.getBigDecimal(columnIndex)));
        } else if (type == Types.CLOB) {
          out.print(String.valueOf(rs.getString(columnIndex)));
        } else if (type == Types.JAVA_OBJECT) {
          Object object = rs.getObject(columnIndex);

          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(String.valueOf(object));
          }
        } else if (type == Types.LONGVARCHAR) {
          Object object = rs.getString(columnIndex);

          if (rs.wasNull()) {
            out.print("null");
          } else {
            out.print(String.valueOf(object));
          }
        } else if (type == Types.NULL) {
          out.print("null");
        } else {
          Object object = rs.getObject(columnIndex);

          if (rs.wasNull()) {
            out.print("null");
          } else {
            if (object instanceof byte[]) {
              byte[] bytes = (byte[]) object;
              String text = HexBin.encode(bytes);
              out.print(text);
            } else {
              out.print(String.valueOf(object));
            }
          }
        }
      }
      out.println();
    }
  }

  public static String getTypeName(int sqlType) {
    switch (sqlType) {
      case Types.ARRAY:
        return "ARRAY";

      case Types.BIGINT:
        return "BIGINT";

      case Types.BINARY:
        return "BINARY";

      case Types.BIT:
        return "BIT";

      case Types.BLOB:
        return "BLOB";

      case Types.BOOLEAN:
        return "BOOLEAN";

      case Types.CHAR:
        return "CHAR";

      case Types.CLOB:
        return "CLOB";

      case Types.DATALINK:
        return "DATALINK";

      case Types.DATE:
        return "DATE";

      case Types.DECIMAL:
        return "DECIMAL";

      case Types.DISTINCT:
        return "DISTINCT";

      case Types.DOUBLE:
        return "DOUBLE";

      case Types.FLOAT:
        return "FLOAT";

      case Types.INTEGER:
        return "INTEGER";

      case Types.JAVA_OBJECT:
        return "JAVA_OBJECT";

      case Types.LONGNVARCHAR:
        return "LONGNVARCHAR";

      case Types.LONGVARBINARY:
        return "LONGVARBINARY";

      case Types.NCHAR:
        return "NCHAR";

      case Types.NCLOB:
        return "NCLOB";

      case Types.NULL:
        return "NULL";

      case Types.NUMERIC:
        return "NUMERIC";

      case Types.NVARCHAR:
        return "NVARCHAR";

      case Types.REAL:
        return "REAL";

      case Types.REF:
        return "REF";

      case Types.ROWID:
        return "ROWID";

      case Types.SMALLINT:
        return "SMALLINT";

      case Types.SQLXML:
        return "SQLXML";

      case Types.STRUCT:
        return "STRUCT";

      case Types.TIME:
        return "TIME";

      case Types.TIMESTAMP:
        return "TIMESTAMP";

      case Types.TINYINT:
        return "TINYINT";

      case Types.VARBINARY:
        return "VARBINARY";

      case Types.VARCHAR:
        return "VARCHAR";

      default:
        return "OTHER";
    }
  }

  public static String getDriverClassName(String rawUrl) throws SQLException {
    if (rawUrl == null) {
      return null;
    }

    if (rawUrl.startsWith("jdbc:derby:")) {
      return "org.apache.derby.jdbc.EmbeddedDriver";
    } else if (rawUrl.startsWith("jdbc:mysql:")) {
      if (mysql_driver_version_6 == null) {
        mysql_driver_version_6 = Utils.loadClass("com.mysql.cj.jdbc.Driver") != null;
      }

      if (mysql_driver_version_6) {
        return MYSQL_DRIVER_6;
      } else {
        return MYSQL_DRIVER;
      }
    } else if (rawUrl.startsWith("jdbc:log4jdbc:")) {
      return LOG4JDBC_DRIVER;
    } else if (rawUrl.startsWith("jdbc:mariadb:")) {
      return MARIADB_DRIVER;
    } else if (rawUrl.startsWith("jdbc:oracle:") //
        || rawUrl.startsWith("JDBC:oracle:")) {
      return ORACLE_DRIVER;
    } else if (rawUrl.startsWith("jdbc:alibaba:oracle:")) {
      return ALI_ORACLE_DRIVER;
    } else if (rawUrl.startsWith("jdbc:microsoft:")) {
      return "com.microsoft.jdbc.sqlserver.SQLServerDriver";
    } else if (rawUrl.startsWith("jdbc:sqlserver:")) {
      return "com.microsoft.sqlserver.jdbc.SQLServerDriver";
    } else if (rawUrl.startsWith("jdbc:sybase:Tds:")) {
      return "com.sybase.jdbc2.jdbc.SybDriver";
    } else if (rawUrl.startsWith("jdbc:jtds:")) {
      return "net.sourceforge.jtds.jdbc.Driver";
    } else if (rawUrl.startsWith("jdbc:fake:") || rawUrl.startsWith("jdbc:mock:")) {
      return "com.alibaba.druid.mock.MockDriver";
    } else if (rawUrl.startsWith("jdbc:postgresql:")) {
      return POSTGRESQL_DRIVER;
    } else if (rawUrl.startsWith("jdbc:edb:")) {
      return ENTERPRISEDB_DRIVER;
    } else if (rawUrl.startsWith("jdbc:odps:")) {
      return ODPS_DRIVER;
    } else if (rawUrl.startsWith("jdbc:hsqldb:")) {
      return "org.hsqldb.jdbcDriver";
    } else if (rawUrl.startsWith("jdbc:db2:")) {
      return DB2_DRIVER;
    } else if (rawUrl.startsWith("jdbc:sqlite:")) {
      return "org.sqlite.JDBC";
    } else if (rawUrl.startsWith("jdbc:ingres:")) {
      return "com.ingres.jdbc.IngresDriver";
    } else if (rawUrl.startsWith("jdbc:h2:")) {
      return H2_DRIVER;
    } else if (rawUrl.startsWith("jdbc:mckoi:")) {
      return "com.mckoi.JDBCDriver";
    } else if (rawUrl.startsWith("jdbc:cloudscape:")) {
      return "COM.cloudscape.core.JDBCDriver";
    } else if (rawUrl.startsWith("jdbc:informix-sqli:")) {
      return "com.informix.jdbc.IfxDriver";
    } else if (rawUrl.startsWith("jdbc:timesten:")) {
      return "com.timesten.jdbc.TimesTenDriver";
    } else if (rawUrl.startsWith("jdbc:as400:")) {
      return "com.ibm.as400.access.AS400JDBCDriver";
    } else if (rawUrl.startsWith("jdbc:sapdb:")) {
      return "com.sap.dbtech.jdbc.DriverSapDB";
    } else if (rawUrl.startsWith("jdbc:JSQLConnect:")) {
      return "com.jnetdirect.jsql.JSQLDriver";
    } else if (rawUrl.startsWith("jdbc:JTurbo:")) {
      return "com.newatlanta.jturbo.driver.Driver";
    } else if (rawUrl.startsWith("jdbc:firebirdsql:")) {
      return "org.firebirdsql.jdbc.FBDriver";
    } else if (rawUrl.startsWith("jdbc:interbase:")) {
      return "interbase.interclient.Driver";
    } else if (rawUrl.startsWith("jdbc:pointbase:")) {
      return "com.pointbase.jdbc.jdbcUniversalDriver";
    } else if (rawUrl.startsWith("jdbc:edbc:")) {
      return "ca.edbc.jdbc.EdbcDriver";
    } else if (rawUrl.startsWith("jdbc:mimer:multi1:")) {
      return "com.mimer.jdbc.Driver";
    } else if (rawUrl.startsWith("jdbc:dm:")) {
      return JdbcConstants.DM_DRIVER;
    } else if (rawUrl.startsWith("jdbc:kingbase:")) {
      return JdbcConstants.KINGBASE_DRIVER;
    } else if (rawUrl.startsWith("jdbc:hive:")) {
      return JdbcConstants.HIVE_DRIVER;
    } else if (rawUrl.startsWith("jdbc:hive2:")) {
      return JdbcConstants.HIVE_DRIVER;
    } else if (rawUrl.startsWith("jdbc:phoenix:thin:")) {
      return "org.apache.phoenix.queryserver.client.Driver";
    } else if (rawUrl.startsWith("jdbc:phoenix://")) {
      return JdbcConstants.PHOENIX_DRIVER;
    } else {
      throw new SQLException("unkow jdbc driver : " + rawUrl);
    }
  }

  public static String getDbType(String rawUrl, String driverClassName) {
    if (rawUrl == null) {
      return null;
    }

    if (rawUrl.startsWith("jdbc:derby:") || rawUrl.startsWith("jdbc:log4jdbc:derby:")) {
      return DERBY;
    } else if (rawUrl.startsWith("jdbc:mysql:")
        || rawUrl.startsWith("jdbc:cobar:")
        || rawUrl.startsWith("jdbc:log4jdbc:mysql:")) {
      return MYSQL;
    } else if (rawUrl.startsWith("jdbc:mariadb:")) {
      return MARIADB;
    } else if (rawUrl.startsWith("jdbc:oracle:") || rawUrl.startsWith("jdbc:log4jdbc:oracle:")) {
      return ORACLE;
    } else if (rawUrl.startsWith("jdbc:alibaba:oracle:")) {
      return ALI_ORACLE;
    } else if (rawUrl.startsWith("jdbc:microsoft:")
        || rawUrl.startsWith("jdbc:log4jdbc:microsoft:")) {
      return SQL_SERVER;
    } else if (rawUrl.startsWith("jdbc:sqlserver:")
        || rawUrl.startsWith("jdbc:log4jdbc:sqlserver:")) {
      return SQL_SERVER;
    } else if (rawUrl.startsWith("jdbc:sybase:Tds:")
        || rawUrl.startsWith("jdbc:log4jdbc:sybase:")) {
      return SYBASE;
    } else if (rawUrl.startsWith("jdbc:jtds:") || rawUrl.startsWith("jdbc:log4jdbc:jtds:")) {
      return JTDS;
    } else if (rawUrl.startsWith("jdbc:fake:") || rawUrl.startsWith("jdbc:mock:")) {
      return MOCK;
    } else if (rawUrl.startsWith("jdbc:postgresql:")
        || rawUrl.startsWith("jdbc:log4jdbc:postgresql:")) {
      return POSTGRESQL;
    } else if (rawUrl.startsWith("jdbc:edb:")) {
      return ENTERPRISEDB;
    } else if (rawUrl.startsWith("jdbc:hsqldb:") || rawUrl.startsWith("jdbc:log4jdbc:hsqldb:")) {
      return HSQL;
    } else if (rawUrl.startsWith("jdbc:odps:")) {
      return ODPS;
    } else if (rawUrl.startsWith("jdbc:db2:")) {
      return DB2;
    } else if (rawUrl.startsWith("jdbc:sqlite:")) {
      return "sqlite";
    } else if (rawUrl.startsWith("jdbc:ingres:")) {
      return "ingres";
    } else if (rawUrl.startsWith("jdbc:h2:") || rawUrl.startsWith("jdbc:log4jdbc:h2:")) {
      return H2;
    } else if (rawUrl.startsWith("jdbc:mckoi:")) {
      return "mckoi";
    } else if (rawUrl.startsWith("jdbc:cloudscape:")) {
      return "cloudscape";
    } else if (rawUrl.startsWith("jdbc:informix-sqli:")
        || rawUrl.startsWith("jdbc:log4jdbc:informix-sqli:")) {
      return "informix";
    } else if (rawUrl.startsWith("jdbc:timesten:")) {
      return "timesten";
    } else if (rawUrl.startsWith("jdbc:as400:")) {
      return "as400";
    } else if (rawUrl.startsWith("jdbc:sapdb:")) {
      return "sapdb";
    } else if (rawUrl.startsWith("jdbc:JSQLConnect:")) {
      return "JSQLConnect";
    } else if (rawUrl.startsWith("jdbc:JTurbo:")) {
      return "JTurbo";
    } else if (rawUrl.startsWith("jdbc:firebirdsql:")) {
      return "firebirdsql";
    } else if (rawUrl.startsWith("jdbc:interbase:")) {
      return "interbase";
    } else if (rawUrl.startsWith("jdbc:pointbase:")) {
      return "pointbase";
    } else if (rawUrl.startsWith("jdbc:edbc:")) {
      return "edbc";
    } else if (rawUrl.startsWith("jdbc:mimer:multi1:")) {
      return "mimer";
    } else if (rawUrl.startsWith("jdbc:dm:")) {
      return JdbcConstants.DM;
    } else if (rawUrl.startsWith("jdbc:kingbase:")) {
      return JdbcConstants.KINGBASE;
    } else if (rawUrl.startsWith("jdbc:log4jdbc:")) {
      return LOG4JDBC;
    } else if (rawUrl.startsWith("jdbc:hive:")) {
      return HIVE;
    } else if (rawUrl.startsWith("jdbc:hive2:")) {
      return HIVE;
    } else if (rawUrl.startsWith("jdbc:phoenix:")) {
      return PHOENIX;
    } else {
      return null;
    }
  }

  public static Driver createDriver(String driverClassName) throws SQLException {
    return createDriver(null, driverClassName);
  }

  public static Driver createDriver(ClassLoader classLoader, String driverClassName)
      throws SQLException {
    Class<?> clazz = null;
    if (classLoader != null) {
      try {
        clazz = classLoader.loadClass(driverClassName);
      } catch (ClassNotFoundException e) {
        // skip
      }
    }

    if (clazz == null) {
      try {
        ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
        if (contextLoader != null) {
          clazz = contextLoader.loadClass(driverClassName);
        }
      } catch (ClassNotFoundException e) {
        // skip
      }
    }

    if (clazz == null) {
      try {
        clazz = Class.forName(driverClassName);
      } catch (ClassNotFoundException e) {
        throw new SQLException(e.getMessage(), e);
      }
    }

    try {
      return (Driver) clazz.newInstance();
    } catch (IllegalAccessException e) {
      throw new SQLException(e.getMessage(), e);
    } catch (InstantiationException e) {
      throw new SQLException(e.getMessage(), e);
    }
  }

  public static int executeUpdate(DataSource dataSource, String sql, Object... parameters)
      throws SQLException {
    return executeUpdate(dataSource, sql, Arrays.asList(parameters));
  }

  public static int executeUpdate(DataSource dataSource, String sql, List<Object> parameters)
      throws SQLException {
    Connection conn = null;
    try {
      conn = dataSource.getConnection();
      return executeUpdate(conn, sql, parameters);
    } finally {
      close(conn);
    }
  }

  public static int executeUpdate(Connection conn, String sql, List<Object> parameters)
      throws SQLException {
    PreparedStatement stmt = null;

    int updateCount;
    try {
      stmt = conn.prepareStatement(sql);

      setParameters(stmt, parameters);

      updateCount = stmt.executeUpdate();
    } finally {
      JdbcUtils.close(stmt);
    }

    return updateCount;
  }

  public static void execute(DataSource dataSource, String sql, Object... parameters)
      throws SQLException {
    execute(dataSource, sql, Arrays.asList(parameters));
  }

  public static void execute(DataSource dataSource, String sql, List<Object> parameters)
      throws SQLException {
    Connection conn = null;
    try {
      conn = dataSource.getConnection();
      execute(conn, sql, parameters);
    } finally {
      close(conn);
    }
  }

  public static void execute(Connection conn, String sql, List<Object> parameters)
      throws SQLException {
    PreparedStatement stmt = null;

    try {
      stmt = conn.prepareStatement(sql);

      setParameters(stmt, parameters);

      stmt.executeUpdate();
    } finally {
      JdbcUtils.close(stmt);
    }
  }

  public static List<Map<String, Object>> executeQuery(
      DataSource dataSource, String sql, Object... parameters) throws SQLException {
    return executeQuery(dataSource, sql, Arrays.asList(parameters));
  }

  public static List<Map<String, Object>> executeQuery(
      DataSource dataSource, String sql, List<Object> parameters) throws SQLException {
    Connection conn = null;
    try {
      conn = dataSource.getConnection();
      return executeQuery(conn, sql, parameters);
    } finally {
      close(conn);
    }
  }

  public static List<Map<String, Object>> executeQuery(
      Connection conn, String sql, List<Object> parameters) throws SQLException {
    List<Map<String, Object>> rows = new ArrayList<Map<String, Object>>();

    PreparedStatement stmt = null;
    ResultSet rs = null;
    try {
      stmt = conn.prepareStatement(sql);

      setParameters(stmt, parameters);

      rs = stmt.executeQuery();

      ResultSetMetaData rsMeta = rs.getMetaData();

      while (rs.next()) {
        Map<String, Object> row = new LinkedHashMap<String, Object>();

        for (int i = 0, size = rsMeta.getColumnCount(); i < size; ++i) {
          String columName = rsMeta.getColumnLabel(i + 1);
          Object value = rs.getObject(i + 1);
          row.put(columName, value);
        }

        rows.add(row);
      }
    } finally {
      JdbcUtils.close(rs);
      JdbcUtils.close(stmt);
    }

    return rows;
  }

  private static void setParameters(PreparedStatement stmt, List<Object> parameters)
      throws SQLException {
    for (int i = 0, size = parameters.size(); i < size; ++i) {
      Object param = parameters.get(i);
      stmt.setObject(i + 1, param);
    }
  }

  public static void insertToTable(
      DataSource dataSource, String tableName, Map<String, Object> data) throws SQLException {
    Connection conn = null;
    try {
      conn = dataSource.getConnection();
      insertToTable(conn, tableName, data);
    } finally {
      close(conn);
    }
  }

  public static void insertToTable(Connection conn, String tableName, Map<String, Object> data)
      throws SQLException {
    String sql = makeInsertToTableSql(tableName, data.keySet());
    List<Object> parameters = new ArrayList<Object>(data.values());
    execute(conn, sql, parameters);
  }

  public static String makeInsertToTableSql(String tableName, Collection<String> names) {
    StringBuilder sql =
        new StringBuilder() //
            .append("insert into ") //
            .append(tableName) //
            .append("("); //

    int nameCount = 0;
    for (String name : names) {
      if (nameCount > 0) {
        sql.append(",");
      }
      sql.append(name);
      nameCount++;
    }
    sql.append(") values (");
    for (int i = 0; i < nameCount; ++i) {
      if (i != 0) {
        sql.append(",");
      }
      sql.append("?");
    }
    sql.append(")");

    return sql.toString();
  }
}
/** @author wenshao<*****@*****.**> */
public final class DruidConnectionHolder {

  private static final Log LOG = LogFactory.getLog(DruidConnectionHolder.class);

  private final DruidAbstractDataSource dataSource;
  private final Connection conn;
  private final List<ConnectionEventListener> connectionEventListeners =
      new CopyOnWriteArrayList<ConnectionEventListener>();
  private final List<StatementEventListener> statementEventListeners =
      new CopyOnWriteArrayList<StatementEventListener>();
  private final long connectTimeMillis;
  private transient long lastActiveTimeMillis;
  private long useCount = 0;

  private PreparedStatementPool statementPool;

  private final List<Statement> statementTrace = new ArrayList<Statement>(2);

  private final boolean defaultReadOnly;
  private final int defaultHoldability;
  private final int defaultTransactionIsolation;

  private final boolean defaultAutoCommit;

  private boolean underlyingReadOnly;
  private int underlyingHoldability;
  private int underlyingTransactionIsolation;
  private boolean underlyingAutoCommit;
  private boolean discard = false;

  public static boolean holdabilityUnsupported = false;

  public DruidConnectionHolder(DruidAbstractDataSource dataSource, Connection conn)
      throws SQLException {

    this.dataSource = dataSource;
    this.conn = conn;
    this.connectTimeMillis = System.currentTimeMillis();
    this.lastActiveTimeMillis = connectTimeMillis;

    this.underlyingAutoCommit = conn.getAutoCommit();

    {
      boolean initUnderlyHoldability = !holdabilityUnsupported;
      if (JdbcConstants.SYBASE.equals(dataSource.getDbType()) //
          || JdbcConstants.DB2.equals(dataSource.getDbType()) //
      ) {
        initUnderlyHoldability = false;
      }
      if (initUnderlyHoldability) {
        try {
          this.underlyingHoldability = conn.getHoldability();
        } catch (UnsupportedOperationException e) {
          holdabilityUnsupported = true;
          LOG.warn("getHoldability unsupported", e);
        } catch (SQLFeatureNotSupportedException e) {
          holdabilityUnsupported = true;
          LOG.warn("getHoldability unsupported", e);
        } catch (SQLException e) {
          // bug fixed for hive jdbc-driver
          if ("Method not supported".equals(e.getMessage())) {
            holdabilityUnsupported = true;
          }
          LOG.warn("getHoldability error", e);
        }
      }
    }

    this.underlyingReadOnly = conn.isReadOnly();
    try {
      this.underlyingTransactionIsolation = conn.getTransactionIsolation();
    } catch (SQLException e) {
      // compartible for alibaba corba
      if (!"com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException"
          .equals(e.getClass().getName())) {
        throw e;
      }
    }

    this.defaultHoldability = underlyingHoldability;
    this.defaultTransactionIsolation = underlyingTransactionIsolation;
    this.defaultAutoCommit = underlyingAutoCommit;
    this.defaultReadOnly = underlyingReadOnly;
  }

  public boolean isUnderlyingReadOnly() {
    return underlyingReadOnly;
  }

  public void setUnderlyingReadOnly(boolean underlyingReadOnly) {
    this.underlyingReadOnly = underlyingReadOnly;
  }

  public int getUnderlyingHoldability() {
    return underlyingHoldability;
  }

  public void setUnderlyingHoldability(int underlyingHoldability) {
    this.underlyingHoldability = underlyingHoldability;
  }

  public int getUnderlyingTransactionIsolation() {
    return underlyingTransactionIsolation;
  }

  public void setUnderlyingTransactionIsolation(int underlyingTransactionIsolation) {
    this.underlyingTransactionIsolation = underlyingTransactionIsolation;
  }

  public boolean isUnderlyingAutoCommit() {
    return underlyingAutoCommit;
  }

  public void setUnderlyingAutoCommit(boolean underlyingAutoCommit) {
    this.underlyingAutoCommit = underlyingAutoCommit;
  }

  public long getLastActiveTimeMillis() {
    return lastActiveTimeMillis;
  }

  public void setLastActiveTimeMillis(long lastActiveMillis) {
    this.lastActiveTimeMillis = lastActiveMillis;
  }

  public void addTrace(DruidPooledStatement stmt) {
    statementTrace.add(stmt);
  }

  public void removeTrace(DruidPooledStatement stmt) {
    statementTrace.remove(stmt);
  }

  public List<ConnectionEventListener> getConnectionEventListeners() {
    return connectionEventListeners;
  }

  public List<StatementEventListener> getStatementEventListeners() {
    return statementEventListeners;
  }

  public PreparedStatementPool getStatementPool() {
    if (statementPool == null) {
      statementPool = new PreparedStatementPool(this);
    }
    return statementPool;
  }

  public PreparedStatementPool getStatementPoolDirect() {
    return statementPool;
  }

  public void clearStatementCache() {
    if (this.statementPool == null) {
      return;
    }
    this.statementPool.clear();
  }

  public DruidAbstractDataSource getDataSource() {
    return dataSource;
  }

  public boolean isPoolPreparedStatements() {
    return dataSource.isPoolPreparedStatements();
  }

  public Connection getConnection() {
    return conn;
  }

  public long getTimeMillis() {
    return connectTimeMillis;
  }

  public long getUseCount() {
    return useCount;
  }

  public void incrementUseCount() {
    useCount++;
  }

  public void reset() throws SQLException {
    // reset default settings
    if (underlyingReadOnly != defaultReadOnly) {
      conn.setReadOnly(defaultReadOnly);
      underlyingReadOnly = defaultReadOnly;
    }

    if (underlyingHoldability != defaultHoldability) {
      conn.setHoldability(defaultHoldability);
      underlyingHoldability = defaultHoldability;
    }

    if (underlyingTransactionIsolation != defaultTransactionIsolation) {
      conn.setTransactionIsolation(defaultTransactionIsolation);
      underlyingTransactionIsolation = defaultTransactionIsolation;
    }

    if (underlyingAutoCommit != defaultAutoCommit) {
      conn.setAutoCommit(defaultAutoCommit);
      underlyingAutoCommit = defaultAutoCommit;
    }

    connectionEventListeners.clear();
    statementEventListeners.clear();

    for (Object item : statementTrace.toArray()) {
      Statement stmt = (Statement) item;
      JdbcUtils.close(stmt);
    }
    statementTrace.clear();

    conn.clearWarnings();
  }

  public boolean isDiscard() {
    return discard;
  }

  public void setDiscard(boolean discard) {
    this.discard = discard;
  }

  public String toString() {
    StringBuilder buf = new StringBuilder();

    buf.append("{ID:");
    buf.append(System.identityHashCode(conn));
    buf.append(", ConnectTime:\"");
    buf.append(Utils.toString(new Date(this.connectTimeMillis)));

    buf.append("\", UseCount:");
    buf.append(useCount);

    if (lastActiveTimeMillis > 0) {
      buf.append(", LastActiveTime:\"");
      buf.append(Utils.toString(new Date(this.lastActiveTimeMillis)));
      buf.append("\"");
    }

    if (statementPool != null && statementPool.getMap().size() > 0) {
      buf.append("\", CachedStatementCount:");
      buf.append(statementPool.getMap().size());
    }

    buf.append("}");

    return buf.toString();
  }
}
Example #9
0
/** @author wenshao<*****@*****.**> */
public class DruidDriver implements Driver, DruidDriverMBean {

  private static final Log LOG = LogFactory.getLog(DruidDriver.class);

  private static final DruidDriver instance = new DruidDriver();

  private static final ConcurrentMap<String, DataSourceProxyImpl> proxyDataSources =
      new ConcurrentHashMap<String, DataSourceProxyImpl>();
  private static final AtomicInteger dataSourceIdSeed = new AtomicInteger(0);
  private static final AtomicInteger sqlStatIdSeed = new AtomicInteger(0);

  public static final String DEFAULT_PREFIX = "jdbc:wrap-jdbc:";
  public static final String DRIVER_PREFIX = "driver=";
  public static final String PASSWORD_CALLBACK_PREFIX = "passwordCallback=";
  public static final String NAME_PREFIX = "name=";
  public static final String JMX_PREFIX = "jmx=";
  public static final String FILTERS_PREFIX = "filters=";

  private final AtomicLong connectCount = new AtomicLong(0);

  private String acceptPrefix = DEFAULT_PREFIX;

  private int majorVersion = 4;

  private int minorVersion = 0;

  private static final String MBEAN_NAME = "com.alibaba.druid:type=DruidDriver";

  static {
    registerDriver(instance);
  }

  public static boolean registerDriver(Driver driver) {
    try {
      DriverManager.registerDriver(driver);

      try {
        MBeanServer mbeanServer = ManagementFactory.getPlatformMBeanServer();

        ObjectName objectName = new ObjectName(MBEAN_NAME);
        if (!mbeanServer.isRegistered(objectName)) {
          mbeanServer.registerMBean(instance, objectName);
        }
      } catch (Exception ex) {
        LOG.error("register druid-driver mbean error", ex);
      }

      return true;
    } catch (Exception e) {
      LOG.error("registerDriver error", e);
    }

    return false;
  }

  public DruidDriver() {}

  public static DruidDriver getInstance() {
    return instance;
  }

  public static int createDataSourceId() {
    return dataSourceIdSeed.incrementAndGet();
  }

  public static int createSqlStatId() {
    return sqlStatIdSeed.incrementAndGet();
  }

  @Override
  public boolean acceptsURL(String url) throws SQLException {
    if (url == null) {
      return false;
    }

    if (url.startsWith(acceptPrefix)) {
      return true;
    }

    return false;
  }

  @Override
  public Connection connect(String url, Properties info) throws SQLException {
    if (!acceptsURL(url)) {
      return null;
    }

    connectCount.incrementAndGet();

    DataSourceProxyImpl dataSource = getDataSource(url, info);

    return dataSource.connect(info);
  }

  /**
   * 参数定义: com.alibaba.druid.log.LogFilter=filter com.alibaba.druid.log.LogFilter.p1=prop-value
   * com.alibaba.druid.log.LogFilter.p2=prop-value
   *
   * @param url
   * @return
   * @throws SQLException
   */
  private DataSourceProxyImpl getDataSource(String url, Properties info) throws SQLException {
    DataSourceProxyImpl dataSource = proxyDataSources.get(url);

    if (dataSource == null) {
      DataSourceProxyConfig config = parseConfig(url, info);

      Driver rawDriver = createDriver(config.getRawDriverClassName());

      DataSourceProxyImpl newDataSource = new DataSourceProxyImpl(rawDriver, config);

      {
        String property = System.getProperty("druid.filters");
        if (property != null && property.length() > 0) {
          for (String filterItem : property.split(",")) {
            FilterManager.loadFilter(config.getFilters(), filterItem);
          }
        }
      }
      {
        int dataSourceId = createDataSourceId();
        newDataSource.setId(dataSourceId);

        for (Filter filter : config.getFilters()) {
          filter.init(newDataSource);
        }
      }

      DataSourceProxy oldDataSource = proxyDataSources.putIfAbsent(url, newDataSource);
      if (oldDataSource == null) {
        if (config.isJmxOption()) {
          JMXUtils.register("com.alibaba.druid:type=JdbcStat", JdbcStatManager.getInstance());
        }
      }

      dataSource = proxyDataSources.get(url);
    }
    return dataSource;
  }

  public static DataSourceProxyConfig parseConfig(String url, Properties info) throws SQLException {
    String restUrl = url.substring(DEFAULT_PREFIX.length());

    DataSourceProxyConfig config = new DataSourceProxyConfig();

    if (restUrl.startsWith(DRIVER_PREFIX)) {
      int pos = restUrl.indexOf(':', DRIVER_PREFIX.length());
      String driverText = restUrl.substring(DRIVER_PREFIX.length(), pos);
      if (driverText.length() > 0) {
        config.setRawDriverClassName(driverText.trim());
      }
      restUrl = restUrl.substring(pos + 1);
    }

    if (restUrl.startsWith(FILTERS_PREFIX)) {
      int pos = restUrl.indexOf(':', FILTERS_PREFIX.length());
      String filtersText = restUrl.substring(FILTERS_PREFIX.length(), pos);
      for (String filterItem : filtersText.split(",")) {
        FilterManager.loadFilter(config.getFilters(), filterItem);
      }
      restUrl = restUrl.substring(pos + 1);
    }

    if (restUrl.startsWith(NAME_PREFIX)) {
      int pos = restUrl.indexOf(':', NAME_PREFIX.length());
      String name = restUrl.substring(NAME_PREFIX.length(), pos);
      config.setName(name);
      restUrl = restUrl.substring(pos + 1);
    }

    if (restUrl.startsWith(JMX_PREFIX)) {
      int pos = restUrl.indexOf(':', JMX_PREFIX.length());
      String jmxOption = restUrl.substring(JMX_PREFIX.length(), pos);
      config.setJmxOption(jmxOption);
      restUrl = restUrl.substring(pos + 1);
    }

    String rawUrl = restUrl;
    config.setRawUrl(rawUrl);

    if (config.getRawDriverClassName() == null) {
      String rawDriverClassname = JdbcUtils.getDriverClassName(rawUrl);
      config.setRawDriverClassName(rawDriverClassname);
    }

    config.setUrl(url);
    return config;
  }

  public Driver createDriver(String className) throws SQLException {
    Class<?> rawDriverClass = JdbcUtils.loadDriverClass(className);

    if (rawDriverClass == null) {
      throw new SQLException("jdbc-driver's class not found. '" + className + "'");
    }

    Driver rawDriver;
    try {
      rawDriver = (Driver) rawDriverClass.newInstance();
    } catch (InstantiationException e) {
      throw new SQLException("create driver instance error, driver className '" + className + "'");
    } catch (IllegalAccessException e) {
      throw new SQLException("create driver instance error, driver className '" + className + "'");
    }

    return rawDriver;
  }

  @Override
  public int getMajorVersion() {
    return this.majorVersion;
  }

  @Override
  public int getMinorVersion() {
    return this.minorVersion;
  }

  @Override
  public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException {
    DataSourceProxyImpl dataSource = getDataSource(url, info);
    return dataSource.getRawDriver().getPropertyInfo(dataSource.getConfig().getRawUrl(), info);
  }

  @Override
  public boolean jdbcCompliant() {
    return true;
  }

  @Override
  public long getConnectCount() {
    return connectCount.get();
  }

  public String getAcceptPrefix() {
    return acceptPrefix;
  }

  @Override
  public String[] getDataSourceUrls() {
    return proxyDataSources.keySet().toArray(new String[proxyDataSources.size()]);
  }

  public static ConcurrentMap<String, DataSourceProxyImpl> getProxyDataSources() {
    return proxyDataSources;
  }

  public Logger getParentLogger() throws SQLFeatureNotSupportedException {
    throw new SQLFeatureNotSupportedException();
  }

  @Override
  public void resetStat() {
    connectCount.set(0);
  }

  @Override
  public String getDruidVersion() {
    return VERSION.getVersionNumber();
  }
}
Example #10
0
/**
 * 通过 ID 获取解密器
 *
 * @author Jonas Yang
 */
public class DecrypterFactory {

  private static Log log = LogFactory.getLog(DecrypterFactory.class);

  private static ConcurrentHashMap<String, Decrypter> decrypters =
      new ConcurrentHashMap<String, Decrypter>();

  static {
    RsaDecrypter rsa = new RsaDecrypter();
    AesDecrypter aes = new AesDecrypter();

    decrypters.put(rsa.getId(), rsa);
    decrypters.put(aes.getId(), aes);
  }

  private DecrypterFactory() {}

  //    static void initDecrypters(String resource, ClassLoader classLoader) {
  //        if (resource == null) {
  //            return;
  //        }
  //
  //        InputStream inStream = null;
  //
  //        try {
  //            inStream = classLoader.getResourceAsStream(resource);
  //            if (inStream == null) {
  //                return;
  //            }
  //
  //            Properties p = new Properties();
  //            p.load(inStream);
  //
  //            for (String key : p.stringPropertyNames()) {
  //                String clazzName = p.getProperty(key);
  //                Class clazz = classLoader.loadClass(clazzName);
  //                Decrypter decrypter = (Decrypter) clazz.newInstance();
  //
  //                addDecrypter(decrypter);
  //            }
  //        } catch (Exception e) {
  //            log.warn("Fail to init config loaders.", e);
  //        } finally {
  //            JdbcUtils.close(inStream);
  //        }
  //    }

  /**
   * 通过 ID 获取解密器, 如果没有找到, 返回 <code>null</code>
   *
   * @param id
   * @return
   */
  public static Decrypter getDecrypter(String id) {
    return decrypters.get(id);
  }

  public static void addDecrypter(Decrypter decrypter) {
    Decrypter oldDecrypter = decrypters.putIfAbsent(decrypter.getId(), decrypter);
    if (oldDecrypter != null) {
      log.warn(
          "Replace decrypter ["
              + decrypter.getId()
              + ", "
              + oldDecrypter.getClass()
              + "] with ["
              + decrypter.getClass()
              + "]");
    }
  }

  public static Decrypter[] getDecrypters() {
    return decrypters.values().toArray(new Decrypter[0]);
  }
}