jdbcschema.java

来自「数据仓库展示程序」· Java 代码 · 共 1,385 行 · 第 1/3 页

JAVA
1,385
字号
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/JdbcSchema.java#7 $
// This software is subject to the terms of the Common Public License
// Agreement, available at the following URL:
// http://www.opensource.org/licenses/cpl.html.
// Copyright (C) 2005-2005 Julian Hyde and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
*/

package mondrian.rolap.aggmatcher;

import mondrian.olap.MondrianDef;
import mondrian.resource.MondrianResource;
import mondrian.rolap.RolapAggregator;
import mondrian.rolap.RolapStar;
import mondrian.resource.MondrianResource;

import javax.sql.DataSource;

import org.apache.log4j.Logger;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.*;
import java.util.*;

/**
 * This class is used to scrap a database and store information about its
 * tables and columns.
 * A database has tables. A table has columns. A column has one or more usages.
 * A usage might be a column being used as a foreign key or as part of a
 * measure.
 * <p>
 * Tables are created when calling code requests the set of available
 * tables. This call <code>getTables()</code> causes all tables to be loaded.
 * But a table's columns are not loaded until, on a table-by-table basis,
 * a request is made to get the set of columns associated with the table.
 * Since, the AggTableManager first attempts table name matches (recognition)
 * most tables do not match, so why load their columns.
 * Of course, as a result, there are a host of methods that can throw an
 * SQLException, rats.
 *
 * @author <a>Richard M. Emberson</a>
 * @version $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/JdbcSchema.java#7 $
 */
public class JdbcSchema {
    private static final Logger LOGGER =
        Logger.getLogger(JdbcSchema.class);

    private static final MondrianResource mres = MondrianResource.instance();

    /**
     * Get the Logger.
     *
     * @return
     */
    public Logger getLogger() {
        return LOGGER;
    }

    public interface Factory {
        JdbcSchema makeDB(DataSource dataSource);
        void clearDB(DataSource dataSource);
    }

    public static class StdFactory implements Factory {
        private final WeakHashMap dbMap = new WeakHashMap();
        StdFactory() {
        }
        public JdbcSchema makeDB(DataSource dataSource) {
            JdbcSchema db = (JdbcSchema) dbMap.get(dataSource);
            if (db == null) {
                db = new JdbcSchema(dataSource);
                dbMap.put(dataSource, db);
            }
            return db;
        }
        public void clearDB(DataSource dataSource) {
            JdbcSchema db = (JdbcSchema) dbMap.get(dataSource);
            if (db != null) {
                db.clear();
            }
        }
    }

    public static final String FACTORY_CLASS =
                        "mondrian.rolap.aggregates.jdbcFactoryClass";
    private static Factory factory;

    private static void makeFactory() {
        if (factory == null) {
            String classname = System.getProperty(FACTORY_CLASS);
            if (classname == null) {
                factory = new StdFactory();
            } else {
                try {
                    Class clz = Class.forName(classname);
                    factory = (Factory) clz.newInstance();
                } catch (ClassNotFoundException ex) {
                    throw mres.BadJdbcFactoryClassName.ex(classname);
                } catch (InstantiationException ex) {
                    throw mres.BadJdbcFactoryInstantiation.ex(classname);
                } catch (IllegalAccessException ex) {
                    throw mres.BadJdbcFactoryAccess.ex(classname);
                }
            }
        }
    }
    public static synchronized void clearDB(DataSource dataSource) {
        makeFactory();
        factory.clearDB(dataSource);
    }

    public static synchronized JdbcSchema makeDB(DataSource dataSource) {
        makeFactory();
        return factory.makeDB(dataSource);
    }

    //
    // Types of column usages.
    //
    public static final int UNKNOWN_COLUMN_USAGE         = 0x0001;
    public static final int FOREIGN_KEY_COLUMN_USAGE     = 0x0002;
    public static final int MEASURE_COLUMN_USAGE         = 0x0004;
    public static final int LEVEL_COLUMN_USAGE           = 0x0008;
    public static final int FACT_COUNT_COLUMN_USAGE      = 0x0010;
    public static final int IGNORE_COLUMN_USAGE          = 0x0020;

    public static final String UNKNOWN_COLUMN_NAME         = "UNKNOWN";
    public static final String FOREIGN_KEY_COLUMN_NAME     = "FOREIGN_KEY";
    public static final String MEASURE_COLUMN_NAME         = "MEASURE";
    public static final String LEVEL_COLUMN_NAME           = "LEVEL";
    public static final String FACT_COUNT_COLUMN_NAME      = "FACT_COUNT";
    public static final String IGNORE_COLUMN_NAME          = "IGNORE";

    /**
     * Determine if the parameter represents a single column type, i.e., the
     * column only has one usage.
     *
     * @param columnType
     * @return true if column has only one usage.
     */
    public static boolean isUniqueColumnType(int columnType) {
        switch (columnType) {
        case UNKNOWN_COLUMN_USAGE :
            return true;
        case FOREIGN_KEY_COLUMN_USAGE :
            return true;
        case MEASURE_COLUMN_USAGE :
            return true;
        case LEVEL_COLUMN_USAGE :
            return true;
        case FACT_COUNT_COLUMN_USAGE :
            return true;
        case IGNORE_COLUMN_USAGE :
            return true;
        default :
            return false;
        }
    }

    /**
     * Map from column type enum to column type name or list of names if the
     * parameter represents more than on usage.
     *
     * @param columnType
     * @return
     */
    public static String convertColumnTypeToName(int columnType) {
        switch (columnType) {
        case UNKNOWN_COLUMN_USAGE :
            return UNKNOWN_COLUMN_NAME;
        case FOREIGN_KEY_COLUMN_USAGE :
            return FOREIGN_KEY_COLUMN_NAME;
        case MEASURE_COLUMN_USAGE :
            return MEASURE_COLUMN_NAME;
        case LEVEL_COLUMN_USAGE :
            return LEVEL_COLUMN_NAME;
        case FACT_COUNT_COLUMN_USAGE :
            return FACT_COUNT_COLUMN_NAME;
        case IGNORE_COLUMN_USAGE :
            return IGNORE_COLUMN_NAME;
        default :
            // its a multi-purpose column
            StringBuffer buf = new StringBuffer();
            if ((columnType & UNKNOWN_COLUMN_USAGE) != 0) {
                buf.append(UNKNOWN_COLUMN_NAME);
            }
            if ((columnType & FOREIGN_KEY_COLUMN_USAGE) != 0) {
                if (buf.length() != 0) {
                    buf.append('|');
                }
                buf.append(FOREIGN_KEY_COLUMN_NAME);
            }
            if ((columnType & MEASURE_COLUMN_USAGE) != 0) {
                if (buf.length() != 0) {
                    buf.append('|');
                }
                buf.append(MEASURE_COLUMN_NAME);
            }
            if ((columnType & LEVEL_COLUMN_USAGE) != 0) {
                if (buf.length() != 0) {
                    buf.append('|');
                }
                buf.append(LEVEL_COLUMN_NAME);
            }
            if ((columnType & FACT_COUNT_COLUMN_USAGE) != 0) {
                if (buf.length() != 0) {
                    buf.append('|');
                }
                buf.append(FACT_COUNT_COLUMN_NAME);
            }
            if ((columnType & IGNORE_COLUMN_USAGE) != 0) {
                if (buf.length() != 0) {
                    buf.append('|');
                }
                buf.append(IGNORE_COLUMN_NAME);
            }
            return buf.toString();
        }
    }

    /**
     * Returns true if the parameter is a java.sql.Type numeric type.
     *
     * @param javaType
     * @return
     */
    public static boolean isNumeric(int javaType) {
        switch (javaType) {
        case Types.TINYINT :
        case Types.SMALLINT :
        case Types.INTEGER :
        case Types.BIGINT :
        case Types.FLOAT :
        case Types.REAL :
        case Types.DOUBLE :
        case Types.NUMERIC :
        case Types.DECIMAL :
            return true;
        default :
            return false;
        }
    }
    /**
     * Returns true if the parameter is a java.sql.Type text type.
     *
     * @param javaType
     * @return
     */
    public static boolean isText(int javaType) {
        switch (javaType) {
        case Types.CHAR :
        case Types.VARCHAR :
        case Types.LONGVARCHAR :
            return true;
        default :
            return false;
        }
    }

    //
    // Usages of tables.
    //
    public static final int UNKNOWN_TABLE_USAGE         = 10;
    public static final int FACT_TABLE_USAGE            = 11;
    public static final int AGG_TABLE_USAGE             = 12;

    public static final String UNKNOWN_TABLE_USAGE_NAME = "UNKNOWN";
    public static final String FACT_TABLE_USAGE_NAME    = "FACT";
    public static final String AGG_TABLE_USAGE_NAME     = "AGG";

    /**
     * Convert from table usage enum to table usage name.
     *
     * @param tableUsage
     * @return
     */
    public static String convertTableUsageToName(int tableUsage) {
        switch (tableUsage) {
        case UNKNOWN_TABLE_USAGE :
            return UNKNOWN_TABLE_USAGE_NAME;
        case FACT_TABLE_USAGE :
            return FACT_TABLE_USAGE_NAME;
        case AGG_TABLE_USAGE :
            return AGG_TABLE_USAGE_NAME;
        default :
            return UNKNOWN_TABLE_USAGE_NAME;
        }
    }

    //
    // Types of tables.
    //
    public static final String UNKNOWN_TABLE_TYPE       = "UNKNOWN";
    public static final String TABLE_TABLE_TYPE         = "TABLE";
    public static final String VIEW_TYPE                = "VIEW";
    public static final String SYSTEM_TABLE_TABLE_TYPE  = "SYSTEM TABLE";
    public static final String GLOBAL_TEMP_TABLE_TYPE   = "GLOBAL TEMPORARY";
    public static final String LOCAL_TEMP_TABLE_TYPE    = "LOCAL TEMPORARY";
    public static final String ALIAS_TABLE_TYPE         = "ALIAS";
    public static final String SYNONYM_TABLE_TYPE       = "SYNONYM";

    /**
     * A table in a database.
     */
    public class Table {

        /**
         * A column in a table.
         */
        public class Column {

            /**
             * A usage of a column.
             */
            public class Usage {
                private final int columnType;
                private String symbolicName;
                private RolapAggregator aggregator;

                ////////////////////////////////////////////////////
                //
                // These instance variables are used to hold
                // stuff which is determines at one place and
                // then used somewhere else. Generally, a usage
                // is created before all of its "stuff" can be
                // determined, hence, usage is not a set of classes,
                // rather its one class with a bunch of instance
                // variables which may or may not be used.
                //

                // measure stuff
                public RolapStar.Measure rMeasure;

                // hierarchy stuff
                public MondrianDef.Relation relation;
                public MondrianDef.Expression joinExp;
                public String levelColumnName;

                // level
                public RolapStar.Column rColumn;

                // for subtables
                public RolapStar.Table rTable;
                public String rightJoinConditionColumnName;

                // It is used to hold the (possible null) prefix to
                // use during aggregate table generation (See AggGen).
                public String usagePrefix;
                //
                ////////////////////////////////////////////////////

                Usage(final int columnType) {
                    this.columnType = columnType;
                }

                /**
                 * This is the column with which this usage is associated.
                 *
                 * @return the usage's column.
                 */
                public Column getColumn() {
                    return JdbcSchema.Table.Column.this;
                }

                /**
                 * The column usage type.
                 *
                 * @return
                 */
                public int getColumnType() {
                    return columnType;
                }

                /**
                 * Is this usage of this type.
                 *
                 * @param columnType
                 * @return
                 */
                public boolean isColumnType(final int columnType) {
                    return ((this.columnType & columnType) != 0);
                }

                /**
                 * Set the symbolic (logical) name associated with this usage.
                 * For example, this might be the measure's name.
                 *
                 * @param symbolicName
                 */
                public void setSymbolicName(final String symbolicName) {
                    this.symbolicName = symbolicName;
                }

                /**
                 * Get usage's symbolic name.
                 *
                 * @return
                 */
                public String getSymbolicName() {
                    return symbolicName;
                }

                /**
                 * Set the aggregator associated with this usage (if its a
                 * measure usage).
                 *
                 * @param aggregator
                 */
                public void setAggregator(final RolapAggregator aggregator) {
                    this.aggregator = aggregator;
                }
                /**
                 * Get the aggregator associated with this usage (if its a
                 * measure usage, otherwise null).
                 *
                 * @return
                 */
                public RolapAggregator getAggregator() {
                    return aggregator;
                }

                public String toString() {
                    StringWriter sw = new StringWriter(64);
                    PrintWriter pw = new PrintWriter(sw);
                    print(pw, "");
                    pw.flush();
                    return sw.toString();
                }
                public void print(final PrintWriter pw, final String prefix) {
                    if (getSymbolicName() != null) {
                        pw.print("symbolicName=");
                        pw.print(getSymbolicName());
                    }
                    if (getAggregator() != null) {
                        pw.print(", aggregator=");
                        pw.print(getAggregator().getName());
                    }
                    pw.print(", columnType=");
                    pw.print(convertColumnTypeToName(getColumnType()));
                }

            }

            /** This is the name of the column. */
            private final String name;

            /** This is the java.sql.Type enum of the column in the database. */
            private int type;
            /**
             * This is the java.sql.Type name of the column in the database.
             */
            private String typeName;

            /** This is the size of the column in the database. */
            private int columnSize;

            /** The number of fractional digits. */
            private int decimalDigits;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?