org.seasar.dbflute.logic.jdbc.metadata.basic.DfColumnExtractor.java Source code

Java tutorial

Introduction

Here is the source code for org.seasar.dbflute.logic.jdbc.metadata.basic.DfColumnExtractor.java

Source

/*
 * Copyright 2004-2011 the Seasar Foundation and the Others.
 *
 * 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.seasar.dbflute.logic.jdbc.metadata.basic;

import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.torque.engine.database.model.UnifiedSchema;
import org.seasar.dbflute.helper.StringSet;
import org.seasar.dbflute.logic.jdbc.mapping.DfJdbcTypeMapper;
import org.seasar.dbflute.logic.jdbc.mapping.DfJdbcTypeMapper.Resource;
import org.seasar.dbflute.logic.jdbc.metadata.info.DfColumnMeta;
import org.seasar.dbflute.logic.jdbc.metadata.info.DfTableMeta;
import org.seasar.dbflute.properties.DfTypeMappingProperties;
import org.seasar.dbflute.util.DfCollectionUtil;

/**
 * @author jflute
 */
public class DfColumnExtractor extends DfAbstractMetaDataBasicExtractor {

    // ===================================================================================
    //                                                                          Definition
    //                                                                          ==========
    private static final Log _log = LogFactory.getLog(DfColumnExtractor.class);

    // ===================================================================================
    //                                                                           Attribute
    //                                                                           =========
    protected DfJdbcTypeMapper _jdbcTypeMapper;

    // ===================================================================================
    //                                                                        Meta Getting
    //                                                                        ============
    /**
     * Get the list of column meta information.
     * @param metaData The meta data of database. (NotNull)
     * @param tableInfo The meta information of table. (NotNull, CaseInsensitive)
     * @return The list of column meta information. (NotNull)
     */
    public List<DfColumnMeta> getColumnList(DatabaseMetaData metaData, DfTableMeta tableInfo) throws SQLException {
        final UnifiedSchema unifiedSchema = tableInfo.getUnifiedSchema();
        final String tableName = tableInfo.getTableName();
        return getColumnList(metaData, unifiedSchema, tableName);
    }

    /**
     * Get the list of column meta information.
     * @param metaData The meta data of database. (NotNull)
     * @param unifiedSchema The unified schema that can contain catalog name and no-name mark. (NullAllowed)
     * @param tableName The name of table. (NotNull, CaseInsensitive)
     * @return The list of column meta information. (NotNull)
     */
    public List<DfColumnMeta> getColumnList(DatabaseMetaData metaData, UnifiedSchema unifiedSchema,
            String tableName) throws SQLException {
        List<DfColumnMeta> ls = doGetColumnList(metaData, unifiedSchema, tableName, false);
        if (canRetryCaseInsensitive()) {
            if (ls.isEmpty()) { // retry by lower case
                ls = doGetColumnList(metaData, unifiedSchema, tableName.toLowerCase(), true);
            }
            if (ls.isEmpty()) { // retry by upper case
                ls = doGetColumnList(metaData, unifiedSchema, tableName.toUpperCase(), true);
            }
        }
        return ls;
    }

    protected List<DfColumnMeta> doGetColumnList(DatabaseMetaData metaData, UnifiedSchema unifiedSchema,
            String tableName, boolean retry) throws SQLException {
        final List<DfColumnMeta> columnList = DfCollectionUtil.newArrayList();

        // Column names for duplicate check
        final StringSet columnNameSet = StringSet.createAsFlexible();

        // Duplicate objects for warning log
        final StringSet duplicateTableNameSet = StringSet.createAsFlexible();
        final StringSet duplicateColumnNameSet = StringSet.createAsFlexible();

        ResultSet rs = null;
        try {
            rs = extractColumnMetaData(metaData, unifiedSchema, tableName, retry);
            if (rs == null) {
                return DfCollectionUtil.newArrayList();
            }
            while (rs.next()) {
                // /- - - - - - - - - - - - - - - - - - - - - - - - - - -
                // same policy of table process (see DfTableHandler.java)
                // - - - - - - - - - -/

                final String columnName = rs.getString(4);
                if (isColumnExcept(unifiedSchema, tableName, columnName)) {
                    continue;
                }

                final String metaTableName = rs.getString(3);
                if (checkMetaTableDiffIfNeeds(tableName, metaTableName)) {
                    continue;
                }

                // Filter duplicate objects
                if (columnNameSet.contains(columnName)) {
                    duplicateTableNameSet.add(metaTableName);
                    duplicateColumnNameSet.add(columnName);
                    continue; // ignored with warning
                }
                columnNameSet.add(columnName);

                final Integer jdbcTypeCode = Integer.valueOf(rs.getString(5));
                final String dbTypeName = rs.getString(6);
                final Integer columnSize = Integer.valueOf(rs.getInt(7));
                final Integer decimalDigits = rs.getInt(9);
                final Integer nullType = Integer.valueOf(rs.getInt(11));
                final String columnComment = rs.getString(12);
                final String defaultValue = rs.getString(13);

                final DfColumnMeta columnMetaInfo = new DfColumnMeta();
                columnMetaInfo.setColumnName(columnName);
                columnMetaInfo.setJdbcDefValue(jdbcTypeCode);
                columnMetaInfo.setDbTypeName(dbTypeName);
                columnMetaInfo.setColumnSize(columnSize);
                columnMetaInfo.setDecimalDigits(decimalDigits);
                columnMetaInfo.setRequired(nullType == 0);
                columnMetaInfo.setColumnComment(columnComment);

                // default value as meta data may have illegal characters
                //  e.g. Oracle, MySQL
                columnMetaInfo.setDefaultValue(defaultValue != null ? defaultValue.trim() : null);

                columnList.add(columnMetaInfo);
            }
        } finally {
            if (rs != null) {
                rs.close();
            }
        }

        // Show duplicate objects if exists
        if (!duplicateColumnNameSet.isEmpty()) {
            String msg = "*Duplicate meta data was found:";
            msg = msg + "\n[" + tableName + "]";
            msg = msg + "\n  duplicate tables = " + duplicateTableNameSet;
            msg = msg + "\n  duplicate columns = " + duplicateColumnNameSet;
            _log.info(msg);
        }

        // /= = = = = = = = = = = = = = = = = = = = = = = = = = = 
        // The duplication handling is mainly for Oracle Synonym.
        // = = = = = = = = = =/

        return columnList;
    }

    protected ResultSet extractColumnMetaData(DatabaseMetaData metaData, UnifiedSchema unifiedSchema,
            String tableName, boolean retry) throws SQLException {
        final String catalogName = unifiedSchema.getPureCatalog();
        final String schemaName = unifiedSchema.getPureSchema();
        try {
            return metaData.getColumns(catalogName, schemaName, tableName, null);
        } catch (SQLException e) {
            if (retry) {
                // because the exception may be thrown when the table is not found
                return null;
            } else {
                throw e;
            }
        }
    }

    public Map<String, DfColumnMeta> getColumnMap(DatabaseMetaData metaData, DfTableMeta tableInfo)
            throws SQLException {
        final List<DfColumnMeta> columnList = getColumnList(metaData, tableInfo);
        final Map<String, DfColumnMeta> map = new LinkedHashMap<String, DfColumnMeta>();
        for (DfColumnMeta columnInfo : columnList) {
            map.put(columnInfo.getColumnName(), columnInfo);
        }
        return map;
    }

    // ===================================================================================
    //                                                                 Torque Type Getting
    //                                                                 ===================
    /**
     * Get the JDBC type of the column. <br /> 
     * Look at the java-doc of overload method if you want to know the priority of mapping.
     * @param columnMetaInfo The meta information of column. (NotNull)
     * @return The JDBC type of the column. (NotNull)
     */
    public String getColumnJdbcType(DfColumnMeta columnMetaInfo) {
        return getColumnJdbcType(columnMetaInfo.getJdbcDefValue(), columnMetaInfo.getDbTypeName());
    }

    /**
     * Get the JDBC type of the column. 
     * @param jdbcDefType The JDBC definition value.
     * @param dbTypeName The name of DB data type. (NullAllowed: If null, the mapping using this is invalid)
     * @return The JDBC type of the column. (NotNull)
     */
    public String getColumnJdbcType(int jdbcDefType, String dbTypeName) {
        return getJdbcTypeMapper().getColumnJdbcType(jdbcDefType, dbTypeName);
    }

    /**
     * Does it have a mapping about the type?
     * @param columnMetaInfo The meta information of column. (NotNull)
     * @return The JDBC type of the column. (NotNull)
     */
    public boolean hasMappingJdbcType(DfColumnMeta columnMetaInfo) {
        return hasMappingJdbcType(columnMetaInfo.getJdbcDefValue(), columnMetaInfo.getDbTypeName());
    }

    /**
     * Does it have a mapping about the type?
     * @param jdbcDefType The definition type of JDBC.
     * @param dbTypeName The name of DB data type. (NullAllowed: If null, the mapping using this is invalid)
     * @return The JDBC type of the column. (NotNull)
     */
    public boolean hasMappingJdbcType(int jdbcDefType, String dbTypeName) {
        return getJdbcTypeMapper().hasMappingJdbcType(jdbcDefType, dbTypeName);
    }

    protected DfJdbcTypeMapper getJdbcTypeMapper() {
        if (_jdbcTypeMapper == null) {
            _jdbcTypeMapper = newJdbcTypeMapper();
        }
        return _jdbcTypeMapper;
    }

    protected DfJdbcTypeMapper newJdbcTypeMapper() { // only once
        final DfTypeMappingProperties typeMappingProperties = getProperties().getTypeMappingProperties();
        final Map<String, String> nameToJdbcTypeMap = typeMappingProperties.getNameToJdbcTypeMap();
        final DfJdbcTypeMapper mapper = new DfJdbcTypeMapper(nameToJdbcTypeMap, new Resource() {
            public boolean isLangJava() {
                return getLanguageTypeFacadeProp().isTargetLanguageJava();
            }

            public boolean isDbmsPostgreSQL() {
                return isDatabasePostgreSQL();
            }

            public boolean isDbmsOracle() {
                return isDatabaseOracle();
            }

            public boolean isDbmsSQLServer() {
                return isDatabaseSQLServer();
            }

            @Override
            public String toString() {
                return "{" + isLangJava() + ", " + isDbmsOracle() + ", " + isDbmsPostgreSQL() + "}";
            }

        });
        return mapper;
    }

    // -----------------------------------------------------
    //                                          Concept Type
    //                                          ------------
    public boolean isConceptTypeUUID(final String dbTypeName) {
        return getJdbcTypeMapper().isConceptTypeUUID(dbTypeName);
    }

    public boolean isConceptTypeStringClob(final String dbTypeName) {
        return getJdbcTypeMapper().isConceptTypeStringClob(dbTypeName);
    }

    public boolean isConceptTypeBytesOid(final String dbTypeName) {
        return getJdbcTypeMapper().isConceptTypeBytesOid(dbTypeName);
    }

    public boolean isConceptTypeFixedLengthString(final String dbTypeName) {
        return getJdbcTypeMapper().isConceptTypeFixedLengthString(dbTypeName);
    }

    public boolean isConceptTypeObjectBindingBigDecimal(final String dbTypeName) {
        return getJdbcTypeMapper().isConceptTypeObjectBindingBigDecimal(dbTypeName);
    }

    // -----------------------------------------------------
    //                                         Pinpoint Type
    //                                         -------------
    public boolean isPostgreSQLBpChar(final String dbTypeName) {
        return getJdbcTypeMapper().isPostgreSQLBpChar(dbTypeName);
    }

    public boolean isPostgreSQLNumeric(final String dbTypeName) {
        return getJdbcTypeMapper().isPostgreSQLNumeric(dbTypeName);
    }

    public boolean isPostgreSQLUuid(final String dbTypeName) {
        return getJdbcTypeMapper().isPostgreSQLUuid(dbTypeName);
    }

    public boolean isPostgreSQLOid(final String dbTypeName) {
        return getJdbcTypeMapper().isPostgreSQLOid(dbTypeName);
    }

    public boolean isPostgreSQLCursor(final String dbTypeName) {
        return getJdbcTypeMapper().isPostgreSQLCursor(dbTypeName);
    }

    public boolean isOracleNCharOrNVarchar(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleNCharOrNVarchar(dbTypeName);
    }

    public boolean isOracleNumber(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleNumber(dbTypeName);
    }

    public boolean isOracleDate(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleDate(dbTypeName);
    }

    public boolean isOracleCursor(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleCursor(dbTypeName);
    }

    public boolean isOracleTreatedAsArray(final String dbTypeName) {
        return isOracleTable(dbTypeName) || isOracleVArray(dbTypeName);
    }

    public boolean isOracleTable(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleTable(dbTypeName);
    }

    public boolean isOracleVArray(final String dbTypeName) {
        return getJdbcTypeMapper().isOracleVArray(dbTypeName);
    }

    public boolean isSQLServerUniqueIdentifier(final String dbTypeName) {
        return getJdbcTypeMapper().isSQLServerUniqueIdentifier(dbTypeName);
    }

    // ===================================================================================
    //                                                                Column Size Handling
    //                                                                ====================
    public static boolean isColumnSizeValid(Integer columnSize) {
        return columnSize != null && columnSize > 0;
    }

    public static boolean isDecimalDigitsValid(Integer decimalDigits) {
        return decimalDigits != null && decimalDigits > 0;
    }
}