com.sam.moca.server.db.translate.BaseDialect.java Source code

Java tutorial

Introduction

Here is the source code for com.sam.moca.server.db.translate.BaseDialect.java

Source

/*
 *  $URL$
 *  $Revision$
 *  $Author$
 *  $Date$
 *  
 *  $Copyright-Start$
 *
 *  Copyright (c) 2016
 *  Sam Corporation
 *  All Rights Reserved
 *
 *  This software is furnished under a corporate license for use on a
 *  single computer system and can be copied (with inclusion of the
 *  above copyright) only for use on such a system.
 *
 *  The information in this document is subject to change without notice
 *  and should not be construed as a commitment by Sam Corporation.
 *
 *  Sam Corporation assumes no responsibility for the use of the
 *  software described in this document on equipment which has not been
 *  supplied or approved by Sam Corporation.
 *
 *  $Copyright-End$
 */

package com.sam.moca.server.db.translate;

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.joda.time.DateTime;

import com.sam.moca.MocaType;
import com.sam.moca.pool.Validator;
import com.sam.moca.server.db.BindList;
import com.sam.moca.server.db.DBType;
import com.sam.moca.server.db.MissingVariableException;
import com.sam.moca.server.db.SQLBinder;
import com.sam.moca.server.db.jdbc.ConnectionValidators;
import com.sam.moca.server.db.jdbc.ConnectionValidator;
import com.sam.moca.server.db.jdbc.DefaultDbValidator;
import com.sam.moca.server.db.jdbc.PropertyProvider;

/**
 * Abstract class describing a SQL translator that takes a string and a list
 * of bind variables and returns another string.  If necessary, the bind
 * list can be modified by the translator.
 * 
 * <b><pre>
 * Copyright (c) 2016 Sam Corporation
 * All Rights Reserved
 * </pre></b>
 * 
 * @author dinksett
 * @version $Revision$
 */
public abstract class BaseDialect implements SQLDialect {

    public static final String NOCONV_INDICATOR = "/*NOCONV*/";
    public static final int STD_DEADLOCK_CODE = -60;
    public static final int STD_LOCK_TIMEOUT_CODE = -54;
    public static final int STD_UNIQUE_CONS_CODE = -1;

    /**
     * Constructor that takes an array of filters to be applied in order.
     * The given filters will be applied to the SQL statement in order. 
     * @param filters
     */
    public BaseDialect(DBType dbType) {
        _dbType = dbType;
    }

    // @see com.sam.moca.server.db.translate.SQLDialect#translateStatement(java.lang.String, com.sam.moca.server.db.BindList, com.sam.moca.server.db.translate.TranslationOptions)
    @Override
    public String translateStatement(String sql, BindList args, TranslationOptions options)
            throws TranslationException {
        return sql;
    }

    // @see com.sam.moca.server.db.translate.SQLDialect#translateSQLException(java.sql.SQLException)
    @Override
    public SQLException translateSQLException(SQLException e) {
        return e;
    }

    // @see com.sam.moca.server.db.translate.SQLDialect#getDBType()
    @Override
    public DBType getDBType() {
        return _dbType;
    }

    // @see com.sam.moca.server.db.translate.SQLDialect#getPoolListener()
    @Override
    public Validator<Connection> getValidator(String levelString) {
        return new DefaultDbValidator(getConnectionValidator(), getTransactionIsolation(levelString));
    }

    // @see com.sam.moca.server.db.translate.SQLDialect#getPropertyProvider()
    @Override
    public PropertyProvider getPropertyProvider() {
        return new DefaultPropertyProvider();
    }

    @Override
    public PreparedStatement prepareStatement(Connection conn, SQLBinder binder, BindList bindList)
            throws SQLException, MissingVariableException {
        PreparedStatement pstmt;
        CallableStatement call = null;

        if (!bindList.hasReferences()) {
            pstmt = conn.prepareStatement(binder.getBoundStatement(), ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_READ_ONLY);
        } else {
            call = conn.prepareCall(binder.getBoundStatement(), ResultSet.TYPE_FORWARD_ONLY,
                    ResultSet.CONCUR_READ_ONLY);
            pstmt = call;
        }

        // Go through the passed-in bound variables. If it's a
        // reference type, register it as an in/out parameter.
        // Otherwise, just set its value on the CallableStatement.
        List<String> bindNames = binder.getNames();
        for (int i = 0; i < bindNames.size(); i++) {
            String name = bindNames.get(i);
            Object value = bindList.getValue(name);
            MocaType type = bindList.getType(name);

            // If the variable is not present but used, it's
            // an error.
            if (type == null) {
                throw new MissingVariableException(name);
            }

            // Handle reference types
            if (type.equals(MocaType.INTEGER_REF)) {
                call.registerOutParameter(i + 1, Types.INTEGER);
            } else if (type.equals(MocaType.DOUBLE_REF)) {
                call.registerOutParameter(i + 1, Types.DOUBLE);
            } else if (type.equals(MocaType.STRING_REF)) {
                call.registerOutParameter(i + 1, Types.VARCHAR);
            }

            // Set input variables
            if (value == null) {
                pstmt.setNull(i + 1, type.getSQLType());
            } else if (type == MocaType.DATETIME) {
                if (value instanceof Date) {
                    // For now we have to bind date times as strings
                    // so that we don't have issues with oracle to_date
                    // and to keep people from having to change all their
                    // to_date calls
                    Date timestamp = (Date) value;
                    DateTime dateTime = new DateTime(timestamp.getTime());
                    pstmt.setString(i + 1, dateTime.toString("YYYYMMddHHmmss"));
                } else {
                    pstmt.setString(i + 1, String.valueOf(value));
                }
            } else {
                pstmt.setObject(i + 1, value);
            }
        }

        return pstmt;
    }

    @Override
    public void updateOutVariables(CallableStatement call, SQLBinder binder, BindList bindList)
            throws SQLException {
        // Now, spin through the bind variables again, and re-assign
        // the value for the reference variables.
        if (bindList.hasReferences()) {
            List<String> bindNames = binder.getNames();
            for (int i = 0; i < bindNames.size(); i++) {
                String name = bindNames.get(i);
                MocaType type = bindList.getType(name);

                // Handle reference types coming out of a
                // stored procedure call.
                if (type.equals(MocaType.INTEGER_REF) || type.equals(MocaType.DOUBLE_REF)
                        || type.equals(MocaType.STRING_REF)) {
                    Object value = call.getObject(i + 1);
                    bindList.setValue(name, value);
                }
            }
        }
    }

    /**
     * Default NooopLimitHandler which indicates limit handling is not supported.
     * Subclasses should override this with their LimitHandler implementation.
     */
    @Override
    public LimitHandler getLimitHandler() {
        return NoopLimitHandler.getInstance();
    }

    @Override
    public ConnectionValidator getConnectionValidator() {
        return DEFAULT_CONNECTION_VALIDATOR;
    }

    //
    // Subclass interface
    //
    protected int getTransactionIsolation(String levelName) {
        if (levelName == null) {
            return DefaultDbValidator.UNSPECIFIED_TRANSACTION_ISOLATION;
        }

        Integer level = ISOLATION_LEVELS.get(levelName);

        if (level == null) {
            return DefaultDbValidator.UNSPECIFIED_TRANSACTION_ISOLATION;
        } else {
            return level;
        }
    }

    //
    // Implementation
    //
    private DBType _dbType;

    private static final ConnectionValidator DEFAULT_CONNECTION_VALIDATOR = ConnectionValidators
            .newQueryTestValidator("select 'x' from dual where 1=0");

    private static final Map<String, Integer> ISOLATION_LEVELS = new HashMap<String, Integer>();
    static {
        ISOLATION_LEVELS.put("read_committed", Connection.TRANSACTION_READ_COMMITTED);
        ISOLATION_LEVELS.put("read_uncommitted", Connection.TRANSACTION_READ_UNCOMMITTED);
        ISOLATION_LEVELS.put("repeatable_read", Connection.TRANSACTION_REPEATABLE_READ);
        ISOLATION_LEVELS.put("serializable", Connection.TRANSACTION_SERIALIZABLE);
        ISOLATION_LEVELS.put("snapshot", 4096);
        ISOLATION_LEVELS.put("default", DefaultDbValidator.UNSPECIFIED_TRANSACTION_ISOLATION);
    }
}