⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 recognizer.java

📁 数据仓库展示程序
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
/*
// $Id: //open/mondrian/src/main/mondrian/rolap/aggmatcher/Recognizer.java#9 $
// 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) 2001-2005 Kana Software, Inc. and others.
// All Rights Reserved.
// You must accept the terms of that agreement to use this software.
//
// jhyde, 30 August, 2001
*/

package mondrian.rolap.aggmatcher;

import mondrian.olap.Hierarchy;
import mondrian.olap.Dimension;
import mondrian.olap.MondrianDef;
import mondrian.resource.MondrianResource;
import mondrian.recorder.MessageRecorder;
import mondrian.rolap.RolapStar;
import mondrian.rolap.RolapLevel;
import mondrian.rolap.RolapSchema;
import mondrian.rolap.RolapCube;
import mondrian.rolap.RolapAggregator;
import mondrian.rolap.HierarchyUsage;
import mondrian.rolap.sql.SqlQuery;
import mondrian.resource.MondrianResource;

import java.util.*;

import org.apache.log4j.Logger;

/**
 * Abstract Recognizer class used to determine if a candidate aggregate table
 * has the column categories: "fact_count" column, measure columns, foreign key
 * and level columns.
 * Derived classes use either the default or explicit column descriptions in
 * matching column categories. The basic matching algorithm is in this class
 * while some specific column category matching and column building must be
 * specified in derived classes.
 * <p>
 * A Recognizer is created per candidate aggregate table. The tables columns are
 * then categorized. All errors and warnings are added to a MessageRecorder.
 * <p>
 * This class is less about defining a type and more about code sharing.
 *
 * @author <a>Richard M. Emberson</a>
 * @version
 */
abstract class Recognizer {

    private static final MondrianResource mres = MondrianResource.instance();
    private static final Logger LOGGER = Logger.getLogger(Recognizer.class);
    /**
     * This is used to wrap column name matching rules.
     */
    public interface Matcher {

        /**
         * Return true it the name matches and false otherwise.
         *
         * @param name
         * @return
         */
        boolean matches(String name);
    }

    protected final RolapStar star;
    protected final JdbcSchema.Table dbFactTable;
    protected final JdbcSchema.Table aggTable;
    protected final MessageRecorder msgRecorder;
    protected boolean returnValue;

    protected Recognizer(final RolapStar star,
                         final JdbcSchema.Table dbFactTable,
                         final JdbcSchema.Table aggTable,
                         final MessageRecorder msgRecorder) {
        this.star = star;
        this.dbFactTable = dbFactTable;
        this.aggTable = aggTable;
        this.msgRecorder = msgRecorder;

        returnValue = true;
    }

    /**
     * Return true if the candidate aggregate table was successfully mapped into
     * the fact table. This is the top-level checking method.
     * <p>
     * It first checks the ignore columns.
     * <p>
     * Next, the existence of a fact count column is checked.
     * <p>
     * Then the measures are checked. First the specified (defined,
     * explicit) measures are all determined. There must be at least one such
     * measure. This if followed by checking for implied measures (e.g., if base
     * fact table as both sum and average of a column and the aggregate has a
     * sum measure, the there is an implied average measure in the aggregate).
     * <p>
     * Now the levels are checked. This is in two parts. First, foreign keys are
     * checked followed by level columns (for collapsed dimension aggregates).
     * <p>
     * If eveything checks out, then true is returned.
     *
     * @return
     */
    public boolean check() {
        checkIgnores();
        checkFactCount();

        // Check measures
        int nosMeasures = checkMeasures();
        // There must be at least one measure
        checkNosMeasures(nosMeasures);
        generateImpliedMeasures();

        // Check levels
        List notSeenForeignKeys = checkForeignKeys();
//printNotSeenForeignKeys(notSeenForeignKeys);
        checkLevels(notSeenForeignKeys);

        if (returnValue) {
            // Add all unused columns as warning to the MessageRecorder
            checkUnusedColumns();
        }

        return returnValue;
    }

    /**
     * Return the ignore column Matcher.
     *
     * @return
     */
    protected abstract Matcher getIgnoreMatcher();

    /**
     * Check all columns to be marked as ignore.
     */
    protected void checkIgnores() {
        Matcher ignoreMatcher = getIgnoreMatcher();

        for (Iterator it = aggTable.getColumns(); it.hasNext(); ) {
            JdbcSchema.Table.Column aggColumn =
                (JdbcSchema.Table.Column) it.next();
            if (ignoreMatcher.matches(aggColumn.getName())) {
                makeIgnore(aggColumn);
            }
        }
    }

    /**
     * Create an ignore usage for the aggColumn.
     *
     * @param aggColumn
     */
    protected void makeIgnore(final JdbcSchema.Table.Column aggColumn) {
        JdbcSchema.Table.Column.Usage usage =
                aggColumn.newUsage(JdbcSchema.IGNORE_COLUMN_USAGE);
        usage.setSymbolicName("Ignore");
    }



    /**
     * Return the fact count column Matcher.
     *
     * @return
     */
    protected abstract Matcher getFactCountMatcher();

    /**
     * Make sure that the aggregate table has one fact count column and that its
     * type is numeric.
     */
    protected void checkFactCount() {
        msgRecorder.pushContextName("Recognizer.checkFactCount");

        try {

            Matcher factCountMatcher = getFactCountMatcher();

            int nosOfFactCounts = 0;
            for (Iterator it = aggTable.getColumns(); it.hasNext(); ) {
                JdbcSchema.Table.Column aggColumn =
                    (JdbcSchema.Table.Column) it.next();

                // if marked as ignore, then do not consider
                if (aggColumn.hasUsage(JdbcSchema.IGNORE_COLUMN_USAGE)) {
                    continue;
                }
                if (factCountMatcher.matches(aggColumn.getName())) {
                    if (! aggColumn.isNumeric()) {
                        String msg = mres.NonNumericFactCountColumn.str(
                                aggTable.getName(),
                                dbFactTable.getName(),
                                aggColumn.getName(),
                                aggColumn.getTypeName());
                        msgRecorder.reportError(msg);

                        returnValue = false;
                    } else {
                        makeFactCount(aggColumn);
                        nosOfFactCounts++;
                    }
                }

            }
            if (nosOfFactCounts == 0) {
                String msg = mres.NoFactCountColumns.str(
                        aggTable.getName(),
                        dbFactTable.getName());
                msgRecorder.reportError(msg);

                returnValue = false;

            } else if (nosOfFactCounts > 1) {
                String msg = mres.TooManyFactCountColumns.str(
                        aggTable.getName(),
                        dbFactTable.getName(),
                        new Integer(nosOfFactCounts));
                msgRecorder.reportError(msg);

                returnValue = false;
            }

        } finally {
            msgRecorder.popContextName();
        }
    }


    /**
     * Check all measure columns returning the number of measure columns.
     *
     * @return
     */
    protected abstract int checkMeasures();

    /**
     * Create a fact count usage for the aggColumn.
     *
     * @param aggColumn
     */
    protected void makeFactCount(final JdbcSchema.Table.Column aggColumn) {
        JdbcSchema.Table.Column.Usage usage =
                aggColumn.newUsage(JdbcSchema.FACT_COUNT_COLUMN_USAGE);
        usage.setSymbolicName("Fact Count");
    }


    /**
     * Make sure there was at least one measure column identified.
     *
     * @param nosMeasures
     */
    protected void checkNosMeasures(int nosMeasures) {
        msgRecorder.pushContextName("Recognizer.checkNosMeasures");

        try {
            if (nosMeasures == 0) {
                String msg = mres.NoMeasureColumns.str(
                        aggTable.getName(),
                        dbFactTable.getName()
                    );
                msgRecorder.reportError(msg);

                returnValue = false;
            }

        } finally {
            msgRecorder.popContextName();
        }
    }

    /**
     * An implied measure in an aggregate table is one where there is both a sum
     * and average measures in the base fact table and the aggregate table has
     * either a sum or average, the other measure is implied and can be
     * generated from the measure and the fact_count column.
     * <p>
     * For each column in the fact table, get its measure usages. If there is
     * both an average and sum aggregator associated with the column, then
     * iterator over all of the column usage of type measure of the aggregator
     * table. If only one aggregate column usage measure is found and this
     * RolapStar.Measure measure instance variable is the same as the
     * the fact table's usage's instance variable, then the other measure is
     * implied and the measure is created for the aggregate table.
     */
    protected void generateImpliedMeasures() {
        for (Iterator it = dbFactTable.getColumns(); it.hasNext(); ) {
            JdbcSchema.Table.Column factColumn =
                (JdbcSchema.Table.Column) it.next();

            JdbcSchema.Table.Column.Usage sumFactUsage = null;
            JdbcSchema.Table.Column.Usage avgFactUsage = null;

            for (Iterator mit =
                    factColumn.getUsages(JdbcSchema.MEASURE_COLUMN_USAGE);
                    mit.hasNext(); ) {
                JdbcSchema.Table.Column.Usage factUsage =
                    (JdbcSchema.Table.Column.Usage) mit.next();

                if (factUsage.getAggregator() == RolapAggregator.Avg) {
                    avgFactUsage = factUsage;
                } else if (factUsage.getAggregator() == RolapAggregator.Sum) {
                    sumFactUsage = factUsage;
                }
            }

            if ((avgFactUsage != null) && (sumFactUsage != null)) {
                JdbcSchema.Table.Column.Usage sumAggUsage = null;
                JdbcSchema.Table.Column.Usage avgAggUsage = null;
                int nosSeen = 0;
                for (Iterator mit =
                    aggTable.getColumnUsages(JdbcSchema.MEASURE_COLUMN_USAGE);
                        mit.hasNext(); ) {

                    JdbcSchema.Table.Column.Usage aggUsage =
                        (JdbcSchema.Table.Column.Usage) mit.next();

                    if (aggUsage.rMeasure == avgFactUsage.rMeasure) {
                        avgAggUsage = aggUsage;
                        nosSeen++;
                    } else if (aggUsage.rMeasure == sumFactUsage.rMeasure) {
                        sumAggUsage = aggUsage;
                        nosSeen++;
                    }
                }
                if (nosSeen == 1) {

⌨️ 快捷键说明

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