Package org.adbcj.jdbc

Source Code of org.adbcj.jdbc.JdbcConnection$CallableRequestWrapper

/*
*   Copyright (c) 2007 Mike Heath.  All rights reserved.
*
*   Licensed under the Apache License, Version 2.0 (the "License");
*   you may not use this file except in compliance with the License.
*   You may obtain a copy of the License at
*
*       http://www.apache.org/licenses/LICENSE-2.0
*
*   Unless required by applicable law or agreed to in writing, software
*   distributed under the License is distributed on an "AS IS" BASIS,
*   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*   See the License for the specific language governing permissions and
*   limitations under the License.
*
*/
package org.adbcj.jdbc;

import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;

import org.adbcj.Connection;
import org.adbcj.ConnectionManager;
import org.adbcj.DbException;
import org.adbcj.DbFuture;
import org.adbcj.DbSessionClosedException;
import org.adbcj.DbSessionFuture;
import org.adbcj.Field;
import org.adbcj.PreparedStatement;
import org.adbcj.Result;
import org.adbcj.ResultEventHandler;
import org.adbcj.Type;
import org.adbcj.support.AbstractDbSession;
import org.adbcj.support.DefaultDbSessionFuture;
import org.adbcj.support.DefaultField;
import org.adbcj.support.DefaultResult;
import org.adbcj.support.DefaultValue;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JdbcConnection extends AbstractDbSession implements Connection {
 
  private final Logger logger = LoggerFactory.getLogger(JdbcConnection.class);
 
  private final JdbcConnectionManager connectionManager;
  private final java.sql.Connection jdbcConnection;
 
  private DbSessionFuture<Void> closeFuture;
 
  public JdbcConnection(JdbcConnectionManager connectionManager, java.sql.Connection jdbcConnection) {
    super(false);
    this.connectionManager = connectionManager;
    this.jdbcConnection = jdbcConnection;
  }

  public ConnectionManager getConnectionManager() {
    return connectionManager;
  }

  public synchronized DbSessionFuture<Void> close(boolean immediate) throws DbException {
    if (!isClosed()) {
      if (immediate) {
        cancelPendingRequests(true);
        DefaultDbSessionFuture<Void> future = new DefaultDbSessionFuture<Void>(this);
        try {
          jdbcConnection.close();
          future.setResult(null);
        } catch (SQLException e) {
          future.setException(e);
        }
        closeFuture = future;
      } else {
        CallableRequest<Void> closeRequest = new CallableRequest<Void>() {
          private boolean started = false;
          private boolean cancelled = false;
          public synchronized Void doCall() throws Exception {
            if (cancelled) {
              return null;
            }
            started = true;
            jdbcConnection.close();
            return null;
          }
          @Override
          public synchronized boolean cancelRequest(boolean mayInterruptIfRunning) {
            if (started) {
              return false;
            }
            cancelled = true;
            unclose();
            return true;
          }
          @Override
          public boolean isPipelinable() {
            return false;
          }
        };
        enqueueRequest(closeRequest);
        closeFuture = closeRequest;
      }
    }
    return closeFuture;
  }

  private synchronized void unclose() {
    this.closeFuture = null;
  }
 
  public boolean isClosed() {
    try {
      return closeFuture != null || jdbcConnection.isClosed();
    } catch (SQLException e) {
      throw new DbException(this, e);
    }
  }

  public <T> DbSessionFuture<T> executeQuery(final String sql, final ResultEventHandler<T> eventHandler, final T accumulator) {
    checkClosed();
    logger.trace("Scheduling query '{}'", sql);
    return enqueueTransactionalRequest(new CallableRequest<T>() {
      @Override
      protected T doCall() throws Exception {
        logger.debug("Executing query '{}'", sql);
        Statement jdbcStatement = jdbcConnection.createStatement();
        java.sql.ResultSet jdbcResultSet = null;
        try {
          // Execute query
          jdbcResultSet = jdbcStatement.executeQuery(sql);
         
          // Fetch meta data
          ResultSetMetaData metaData = jdbcResultSet.getMetaData();
          int columnCount = metaData.getColumnCount();
          List<Field> fields = new ArrayList<Field>(columnCount);
          eventHandler.startFields(accumulator);
         
          for (int i = 1; i <= columnCount; i++) {
            Field field = new DefaultField(
                i - 1,
                metaData.getCatalogName(i),
                metaData.getSchemaName(i),
                metaData.getTableName(i),
                metaData.getTableName(i),
                Type.fromJdbcType(metaData.getColumnType(i)),
                metaData.getColumnLabel(i),
                metaData.getCatalogName(i),
                metaData.getPrecision(i),
                metaData.getScale(i),
                metaData.isAutoIncrement(i),
                metaData.isCaseSensitive(i),
                metaData.isCurrency(i),
                metaData.isDefinitelyWritable(i),
                metaData.isNullable(i) == 1,
                metaData.isReadOnly(i),
                metaData.isSearchable(i),
                metaData.isSigned(i),
                metaData.isWritable(i),
                metaData.getColumnClassName(i)
                );
            fields.add(field);
            eventHandler.field(field, accumulator);
          }
         
          eventHandler.endFields(accumulator);
         
          eventHandler.startResults(accumulator);
          while (jdbcResultSet.next()) {
            eventHandler.startRow(accumulator);
            for (int i = 1; i <= columnCount; i++) {
              Field field = fields.get(i - 1);
              Object value = null;
              switch (field.getColumnType()) {
              case BIGINT:
                value = jdbcResultSet.getLong(i);
                break;
              case INTEGER:
                value = jdbcResultSet.getInt(i);
                break;
              case VARCHAR:
                value = jdbcResultSet.getString(i);
                break;
              default:
                throw new IllegalStateException("Don't know how to handle field to type " + field.getColumnType());
              }
              if (jdbcResultSet.wasNull()) {
                value = null;
              }
              eventHandler.value(new DefaultValue(field, value), accumulator);
            }
            eventHandler.endRow(accumulator);
          }
          eventHandler.endResults(accumulator);
         
          return accumulator;
        } finally {
          if (jdbcResultSet != null) {
            jdbcResultSet.close();
          }
          if (jdbcStatement != null) {
            jdbcStatement.close();
          }
        }
      }
    });
  }
 
  public DbSessionFuture<Result> executeUpdate(final String sql) {
    checkClosed();
    return enqueueTransactionalRequest(new CallableRequest<Result>() {
      public Result doCall() throws Exception {
        Statement statement = jdbcConnection.createStatement();
        try {
          statement.execute(sql);
          List<String> warnings = new LinkedList<String>();
          SQLWarning sqlWarnings = statement.getWarnings();
          while (sqlWarnings != null) {
            warnings.add(sqlWarnings.getLocalizedMessage());
            sqlWarnings = sqlWarnings.getNextWarning();
          }
          return new DefaultResult((long)statement.getUpdateCount(), warnings);
        } finally {
          statement.close();
        }
      }
    });
  }
 
  public DbSessionFuture<PreparedStatement> prepareStatement(String sql) {
    checkClosed();
    // TODO Implement JDBC prepareStatement(String sql)
    throw new IllegalStateException("Not yet implemented");
  }
 
  public DbSessionFuture<PreparedStatement> prepareStatement(Object key, String sql) {
    checkClosed();
    // TODO Implement JDBC prepareStatement(Object key, String sql)
    throw new IllegalStateException("Not yet implemented");
  }

  public DbFuture<Void> ping() {
    checkClosed();
    // TODO Implement JDBC ping()
    throw new IllegalStateException("Not yet implemented");
  }
 
  /*
   *
   * End of API methods
   *
   */
 
  // *********** Transaction method implementations **************************
 
  @Override
  protected void sendBegin() throws SQLException {
    logger.trace("Sending begin");
    jdbcConnection.setAutoCommit(false);
  }
 
  @Override
  protected Request<Void> createBeginRequest(Transaction transaction) {
    logger.trace("Creating begin request");
    return new CallableRequestWrapper(super.createBeginRequest(transaction));
  }
 
  @Override
  protected void sendCommit() throws SQLException {
    logger.trace("Sending commit");
    jdbcConnection.commit();
  }
 
  @Override
  protected Request<Void> createCommitRequest(Transaction transaction) {
    logger.trace("Creating commit request");
    return new CallableRequestWrapper(super.createCommitRequest(transaction));
  }
 
  @Override
  protected void sendRollback() throws SQLException {
    logger.trace("Sending rollback");
    jdbcConnection.rollback();
  }
 
  @Override
  protected Request<Void> createRollbackRequest() {
    logger.trace("Creating rollback request");
    return new CallableRequestWrapper(super.createRollbackRequest());
  }
 
  // *********** JDBC Specific method implementations ************************
 
  @Override
  protected void checkClosed() {
    if (isClosed()) {
      throw new DbSessionClosedException(this, "Connection is closed");
    }
  }

  private abstract class CallableRequest<E> extends Request<E> implements Callable<E> {
    private Future<E> future = null;
   
    @Override
    public boolean cancelRequest(boolean mayInterruptIfRunning) {
      if (future == null) {
        return true;
      }
      return future.cancel(mayInterruptIfRunning);
    }
    @Override
    final public void execute() {
      logger.trace("In CallableRequest.execute() processing request {}", this);
      this.future = connectionManager.getExecutorService().submit(this);
    }
   
    final public E call() throws Exception {
      if (isCancelled()) {
        return null;
      }
      try {
        E value = doCall();
        complete(value);
        return value;
      } catch (Exception e) {
        error(DbException.wrap(JdbcConnection.this, e));
        if (jdbcConnection.isClosed()) {
          connectionManager.removeConnection(JdbcConnection.this);
        }
        throw e;
      }
    }

    protected abstract E doCall() throws Exception;
   
    @Override
    public boolean isPipelinable() {
      return false;
    }
   
  }

  private class CallableRequestWrapper extends CallableRequest<Void> {

    private final Request<Void> request;
   
    public CallableRequestWrapper(Request<Void> request) {
      this.request = request;
    }
   
    @Override
    public synchronized boolean cancelRequest(boolean mayInterruptIfRunning) {
      if (super.cancel(mayInterruptIfRunning)) {
        return request.cancel(mayInterruptIfRunning);
      }
      return false;
    }
   
    @Override
    protected Void doCall() throws Exception {
      request.invokeExecute();
      return null;
    }
   
    @Override
    public boolean canRemove() {
      return request.canRemove();
    }
   
    @Override
    public boolean isPipelinable() {
      return request.isPipelinable();
    }
  }
}
TOP

Related Classes of org.adbcj.jdbc.JdbcConnection$CallableRequestWrapper

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.