Package org.jtester.module.database.environment

Source Code of org.jtester.module.database.environment.AbstractDBEnvironment

package org.jtester.module.database.environment;

import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.sql.DataSource;

import org.jtester.bytecode.reflector.helper.ClazzConst;
import org.jtester.bytecode.reflector.helper.ClazzHelper;
import org.jtester.core.TestedObject;
import org.jtester.core.context.DbFitContext;
import org.jtester.core.context.DbFitContext.RunIn;
import org.jtester.exception.ExceptionWrapper;
import org.jtester.fit.util.SymbolUtil;
import org.jtester.module.database.JTesterDataSource;
import org.jtester.module.database.environment.typesmap.AbstractTypeMap;
import org.jtester.module.database.util.DataSourceType;
import org.jtester.module.dbfit.db.model.BigDecimalParseDelegate;
import org.jtester.module.dbfit.db.model.DbParameterAccessor;
import org.jtester.module.dbfit.db.model.SqlDateParseDelegate;
import org.jtester.module.dbfit.db.model.SqlTimestampParseDelegate;
import org.jtester.utility.JTesterLogger;
import org.springframework.jdbc.datasource.DataSourceUtils;
import org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy;

import fit.TypeAdapter;

public abstract class AbstractDBEnvironment implements DBEnvironment {

  protected Connection connection;

  protected final String dataSourceName;

  protected final String dataSourceFrom;

  protected DataSourceType dataSourceType;

  private JTesterDataSource jtesterDataSource;

  private DataSource dataSourceProxy = null;

  protected AbstractTypeMap typeMap;

  /**
   * 是否使用spring来管理事务
   */
  private boolean hasTransaction;

  protected AbstractDBEnvironment(DataSourceType dataSourceType, String dataSourceName, String dataSourceFrom) {
    TypeAdapter.registerParseDelegate(BigDecimal.class, BigDecimalParseDelegate.class);
    TypeAdapter.registerParseDelegate(java.sql.Date.class, SqlDateParseDelegate.class);
    TypeAdapter.registerParseDelegate(java.sql.Timestamp.class, SqlTimestampParseDelegate.class);

    this.dataSourceName = dataSourceName;
    this.dataSourceFrom = dataSourceFrom;
    this.dataSourceType = dataSourceType;
  }

  public void setDataSource(String driver, String url, String schemas, String username, String password) {
    this.jtesterDataSource = new JTesterDataSource(dataSourceType, driver, url, schemas, username, password);
  }

  public DataSource getDataSource(boolean withTransactionManager) {
    this.dataSourceProxy = this.jtesterDataSource;
    if (withTransactionManager) {
      this.dataSourceProxy = new TransactionAwareDataSourceProxy(jtesterDataSource);
    }
    return this.dataSourceProxy;
  }

  public void close() {
    try {
      if (connection != null && connection.isClosed() == false) {
        commit();
        DataSourceUtils.doReleaseConnection(connection, this.dataSourceProxy);
        connection = null;
      }
    } catch (SQLException e) {
      throw new RuntimeException(String.format("close datasource[%s] connection error.",
          this.jtesterDataSource.toString()), e);
    }
  }

  /**
   * 连接当前数据源
   *
   * @return
   */
  public Connection connect() throws SQLException {
    this.hasTransaction = false;
    RunIn runIn = DbFitContext.getRunIn();
    if (runIn == RunIn.TestCase) {
      boolean springAvailable = ClazzHelper.isClassAvailable(ClazzConst.Spring_DataSourceUtils);
      hasTransaction = springAvailable && TestedObject.isTransactionsEnabled();
    }
    this.dataSourceProxy = getDataSource(hasTransaction);

    connection = DataSourceUtils.doGetConnection(this.dataSourceProxy);
    if (connection == null || connection.isClosed()) {
      System.out.println();
    }

    connection.setAutoCommit(false);
    return connection;
  }

  public final void teardown() throws SQLException {
    boolean isDefaultDbEnv = isDefaultDBEnvironment();

    if (!(isDefaultDbEnv && this.hasTransaction && connection != null)) {
      commit();

      DataSourceUtils.doReleaseConnection(connection, this.dataSourceProxy);
      connection = null;
    }
  }

  /**
   * 是否是默认的数据源
   *
   * @return
   */
  private boolean isDefaultDBEnvironment() {
    boolean isDefault = DEFAULT_DATASOURCE_NAME.equals(this.dataSourceName)
        && DEFAULT_DATASOURCE_FROM.equals(dataSourceFrom);
    return isDefault;
  }

  /**
   * any processing required to turn a string into something jdbc driver can
   * process, can be used to clean up CRLF, externalise parameters if required
   * etc.
   */
  protected String parseCommandText(String commandText, String[] vars) {
    return commandText;
  }

  public final PreparedStatement createStatementWithBoundFixtureSymbols(String commandText) throws SQLException {
    String text = SymbolUtil.replacedBySymbols(commandText);
    String paramNames[] = extractParamNames(text);

    String sql = parseCommandText(text, paramNames);

    PreparedStatement cs = connection.prepareStatement(sql);
    for (int i = 0; i < paramNames.length; i++) {
      Object value = org.jtester.fit.util.SymbolUtil.getSymbol(paramNames[i]);
      cs.setObject(i + 1, value);
    }
    return cs;
  }

  public void commit() throws SQLException {
    if (connection != null && connection.isClosed() == false) {
      connection.commit();
      connection.setAutoCommit(false);
    }
  }

  public void rollback() throws SQLException {
    if (connection != null && connection.isClosed() == false) {
      connection.rollback();
    }
  }

  public Connection getConnection() {
    return connection;
  }

  public int getExceptionCode(SQLException dbException) {
    return dbException.getErrorCode();
  }

  /**
   * MUST RETURN PARAMETER NAMES IN EXACT ORDER AS IN STATEMENT. IF SINGLE
   * PARAMETER APPEARS MULTIPLE TIMES, MUST BE LISTED MULTIPLE TIMES IN THE
   * ARRAY ALSO
   */
  public String[] extractParamNames(String commandText) {
    ArrayList<String> hs = new ArrayList<String>();
    Matcher mc = getParameterPattern().matcher(commandText);
    while (mc.find()) {
      String var = mc.group(1);
      if (SymbolUtil.hasSymbol(var)) {
        hs.add(var);
      }

    }
    String[] array = new String[hs.size()];
    return hs.toArray(array);
  }

  protected abstract Pattern getParameterPattern();

  /**
   * by default, this will support retrieving a single autogenerated key via
   * JDBC. DB environments which support automated column retrieval after
   * insert, like oracle, should override this and put in parameters for OUT
   * accessors
   */
  public String buildInsertCommand(String tableName, DbParameterAccessor[] accessors) {
    StringBuilder sb = new StringBuilder("insert into ");
    sb.append(tableName).append("(");
    String comma = "";

    StringBuilder values = new StringBuilder();

    for (DbParameterAccessor accessor : accessors) {
      if (accessor.getDirection() == DbParameterAccessor.INPUT) {
        sb.append(comma);
        values.append(comma);
        sb.append(this.getFieldQuato()).append(accessor.getName()).append(this.getFieldQuato());
        // values.append(":").append(accessor.getName());
        values.append("?");
        comma = ",";
      }
    }
    sb.append(") values (");
    sb.append(values);
    sb.append(")");
    return sb.toString();
  }

  public String buildDeleteCommand(String tableName, DbParameterAccessor[] accessors) {
    StringBuilder sb = new StringBuilder("delete from " + tableName + " where ");
    String comma = "";
    for (DbParameterAccessor accessor : accessors) {
      if (accessor.getDirection() == DbParameterAccessor.INPUT) {
        sb.append(comma);
        sb.append(accessor.getName());
        sb.append("=?");
        comma = ",";
      }
    }
    return sb.toString();
  }

  /**
   * by default, this is set to false.
   *
   * @see org.jtester.module.database.environment.DBEnvironment#supportsOuputOnInsert()
   */
  public boolean supportsOuputOnInsert() {
    return false;
  }

  /** Check the validity of the supplied connection. */
  public static void checkConnectionValid(final Connection conn) throws SQLException {
    if (conn == null || conn.isClosed()) {
      throw new IllegalArgumentException("No open connection to a database is available. "
          + "Make sure your database is running and that you have connected before performing any queries.");
    }
  }

  /**
   * 连接数据源,如果先前没有建立过连接的话
   *
   * @param environment
   * @return 返回数据源连接
   * @throws SQLException
   */
  public Connection connectIfNeeded() {
    try {
      Connection conn = this.getConnection();
      if (conn == null || conn.isClosed()) {
        conn = this.connect();
      }
      return conn;
    } catch (Exception e) {
      throw ExceptionWrapper.getUndeclaredThrowableExceptionCaused(e);
    }
  }

  private Map<String, TableMeta> metas = new HashMap<String, TableMeta>();

  /**
   * 获得数据表的元信息
   *
   * @param table
   * @return
   * @throws Exception
   */
  public TableMeta getTableMetaData(String table) {
    TableMeta meta = metas.get(table);
    if (meta == null) {
      try {
        this.connectIfNeeded();
        String query = "select * from " + table + " where 1!=1";
        PreparedStatement st = this.createStatementWithBoundFixtureSymbols(query);
        ResultSet rs = st.executeQuery();

        meta = new TableMeta(table, rs.getMetaData(), this);
        metas.put(table, meta);
      } catch (Exception e) {
        throw ExceptionWrapper.getUndeclaredThrowableExceptionCaused(e);
      }
    }
    return meta;
  }

  public Object getDefaultValue(String javaType) {
    Object value = this.typeMap.getDefaultValue(javaType);
    return value;
  }

  public Object toObjectValue(String input, String javaType) {
    try {
      Object value = this.typeMap.toObjectByType(input, javaType);
      return value;
    } catch (Exception e) {
      JTesterLogger.info("convert input[" + input + "] to type[" + javaType + "] error, so return input value.\n"
          + e.getMessage());
      return input;
    }
  }
}
TOP

Related Classes of org.jtester.module.database.environment.AbstractDBEnvironment

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