edu.ku.brc.af.core.db.DBTableIdMgr.java Source code

Java tutorial

Introduction

Here is the source code for edu.ku.brc.af.core.db.DBTableIdMgr.java

Source

/* Copyright (C) 2015, University of Kansas Center for Research
 * 
 * Specify Software Project, specify@ku.edu, Biodiversity Institute,
 * 1345 Jayhawk Boulevard, Lawrence, Kansas, 66045, USA
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
package edu.ku.brc.af.core.db;

import static edu.ku.brc.helpers.XMLHelper.getAttr;
import static org.apache.commons.lang.StringUtils.isNotEmpty;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.AccessController;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import edu.ku.brc.af.core.expresssearch.QueryAdjusterForDomain;
import edu.ku.brc.af.ui.forms.BusinessRulesIFace;
import edu.ku.brc.af.ui.forms.GenericBusRules;
import edu.ku.brc.af.ui.forms.formatters.UIFieldFormatterIFace;
import edu.ku.brc.dbsupport.RecordSetIFace;
import edu.ku.brc.dbsupport.RecordSetItemIFace;
import edu.ku.brc.helpers.XMLHelper;
import edu.ku.brc.ui.UIRegistry;
import edu.ku.brc.util.DatamodelHelper;

/**
 * This manages all the tables and maps names to ids and can create queries for
 * recordsets. (This needs to be updated for all the tables. XXX - Meg??????).
 * <br>
 * TODO Many of the searches are linear and should be converted to bininary searches.
 * 
 * @code_status Betra
 * 
 * @author rods
 * 
 */
public class DBTableIdMgr {
    public static final String factoryName = "edu.ku.brc.dbsupport.DBTableIdMgr"; //$NON-NLS-1$

    // Static Data Members
    protected static final Logger log = Logger.getLogger(DBTableIdMgr.class);

    protected static DBTableIdMgr instance = null;

    // Data Members
    protected Hashtable<Integer, DBTableInfo> hash = new Hashtable<Integer, DBTableInfo>();
    protected Hashtable<String, DBTableInfo> byClassNameHash = new Hashtable<String, DBTableInfo>();
    protected Hashtable<String, DBTableInfo> byShortClassNameHash = new Hashtable<String, DBTableInfo>();

    protected Vector<DBTableInfo> tables = new Vector<DBTableInfo>();
    protected boolean isFullSchema = true;

    /**
     * Can now be created as a standalone class to read in other types of Schema Definitions (i.e. Workbench Schema).
     */
    public DBTableIdMgr(final boolean isFullSchema) {
        this.isFullSchema = isFullSchema;
    }

    /**
     * Returns the singleton.
     * @return the singleton.
     */
    public static DBTableIdMgr getInstance() {
        if (instance != null) {
            return instance;
        }

        // else
        String factoryNameStr = AccessController.doPrivileged(new java.security.PrivilegedAction<String>() {
            public String run() {
                return System.getProperty(factoryName);
            }
        });

        if (isNotEmpty(factoryNameStr)) {
            try {
                instance = (DBTableIdMgr) Class.forName(factoryNameStr).newInstance();
                instance.initialize();
                return instance;

            } catch (Exception e) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DBTableIdMgr.class, e);
                InternalError error = new InternalError("Can't instantiate WebLink factory " + factoryNameStr); //$NON-NLS-1$
                error.initCause(e);
                throw error;
            }
        }
        instance = new DBTableIdMgr(true);
        instance.initialize();
        return instance;
    }

    /**
     * Reads in datamodel input file and populates the hashtable of the
     * DBTableMgr with DBTableInfo.
     */
    public void initialize() {
        initialize(DatamodelHelper.getDatamodelFilePath());
    }

    /**
     * Reads in datamodel input file and populates the Hashtable of the DBTableMgr with DBTableInfo
     * @param inputFile the input file.
     */
    public void initialize(final File inputFile) {
        log.debug(
                "Reading in datamodel file: " + inputFile.getAbsolutePath() + " to create and populate DBTableMgr"); //$NON-NLS-1$ //$NON-NLS-2$
        String classname = null;
        try {
            SAXReader reader = new SAXReader();
            reader.setValidation(false);

            Element databaseNode = XMLHelper.readFileToDOM4J(inputFile);

            if (databaseNode != null) {
                for (Iterator<?> i = databaseNode.elementIterator("table"); i.hasNext();) //$NON-NLS-1$
                {
                    Element tableNode = (Element) i.next();
                    classname = tableNode.attributeValue("classname"); //$NON-NLS-1$

                    String tablename = tableNode.attributeValue("table"); //$NON-NLS-1$
                    int tableId = Integer.parseInt(tableNode.attributeValue("tableid")); //$NON-NLS-1$
                    boolean isSearchable = XMLHelper.getAttr(tableNode, "searchable", false); //$NON-NLS-1$

                    String primaryKeyField = null;

                    // iterate through child elements of id nodes, there should only be 1
                    for (Iterator<?> i2 = tableNode.elementIterator("id"); i2.hasNext();) //$NON-NLS-1$
                    {
                        Element idNode = (Element) i2.next();
                        primaryKeyField = idNode.attributeValue("name"); //$NON-NLS-1$
                    }

                    if (classname == null) {
                        log.error("classname is null; check input file"); //$NON-NLS-1$
                    }
                    if (tablename == null) {
                        log.error("tablename is null; check input file"); //$NON-NLS-1$
                    }
                    if (isFullSchema && primaryKeyField == null) {
                        log.error("primaryKeyField is null; check input file table[" + tablename + "]"); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    //log.debug("Populating hashtable ID["+tableId+"]for class: " + classname+" "+ inputFile.getName());

                    DBTableInfo tblInfo = new DBTableInfo(tableId, classname, tablename, primaryKeyField,
                            tableNode.attributeValue("abbrv")); //$NON-NLS-1$
                    tblInfo.setSearchable(isSearchable);
                    tblInfo.setBusinessRuleName(XMLHelper.getAttr(tableNode, "businessrule", null)); //$NON-NLS-1$

                    if (hash.get(tableId) != null) {
                        log.error("Table ID used twice[" + tableId + "]"); //$NON-NLS-1$ //$NON-NLS-2$
                    }
                    hash.put(tableId, tblInfo);
                    byClassNameHash.put(classname.toLowerCase(), tblInfo);
                    byShortClassNameHash.put(tblInfo.getShortClassName().toLowerCase(), tblInfo);
                    tables.add(tblInfo);

                    Element idElement = (Element) tableNode.selectSingleNode("id"); //$NON-NLS-1$
                    if (idElement != null) {
                        tblInfo.setIdColumnName(getAttr(idElement, "column", null)); //$NON-NLS-1$
                        tblInfo.setIdFieldName(getAttr(idElement, "name", null)); //$NON-NLS-1$
                        tblInfo.setIdType(getAttr(idElement, "type", null)); //$NON-NLS-1$
                    }

                    for (Iterator<?> ir = tableNode.elementIterator("tableindex"); ir.hasNext();) //$NON-NLS-1$
                    {
                        Element irNode = (Element) ir.next();
                        String inxName = getAttr(irNode, "indexName", null);
                        String inxColNames = getAttr(irNode, "columnNames", null);
                        tblInfo.addTableIndex(inxName, inxColNames);
                    }

                    Element displayElement = (Element) tableNode.selectSingleNode("display"); //$NON-NLS-1$
                    if (displayElement != null) {
                        tblInfo.setDefaultFormName(getAttr(displayElement, "view", null)); //$NON-NLS-1$
                        tblInfo.setUiFormatter(getAttr(displayElement, "uiformatter", null)); //$NON-NLS-1$
                        tblInfo.setDataObjFormatter(getAttr(displayElement, "dataobjformatter", null)); //$NON-NLS-1$
                        tblInfo.setSearchDialog(getAttr(displayElement, "searchdlg", null)); //$NON-NLS-1$
                        tblInfo.setNewObjDialog(getAttr(displayElement, "newobjdlg", null)); //$NON-NLS-1$

                    } else {
                        tblInfo.setDefaultFormName(""); //$NON-NLS-1$
                        tblInfo.setUiFormatter(""); //$NON-NLS-1$
                        tblInfo.setDataObjFormatter(""); //$NON-NLS-1$
                        tblInfo.setSearchDialog(""); //$NON-NLS-1$
                        tblInfo.setNewObjDialog(""); //$NON-NLS-1$
                    }

                    for (Iterator<?> ir = tableNode.elementIterator("relationship"); ir.hasNext();) //$NON-NLS-1$
                    {
                        Element irNode = (Element) ir.next();
                        DBRelationshipInfo tblRel = new DBRelationshipInfo(
                                irNode.attributeValue("relationshipname"), //$NON-NLS-1$
                                getRelationshipType(irNode.attributeValue("type")), //$NON-NLS-1$
                                irNode.attributeValue("classname"), //$NON-NLS-1$
                                irNode.attributeValue("columnname"), //$NON-NLS-1$
                                irNode.attributeValue("othersidename"), //$NON-NLS-1$
                                irNode.attributeValue("jointable"), //$NON-NLS-1$
                                getAttr(irNode, "required", false), //$NON-NLS-1$
                                getAttr(irNode, "updatable", false), //$NON-NLS-1$
                                getAttr(irNode, "save", false), //$NON-NLS-1$
                                getAttr(irNode, "likemanytoone", false)); //$NON-NLS-1$
                        tblInfo.getRelationships().add(tblRel);
                    }

                    for (Iterator<?> ir = tableNode.elementIterator("field"); ir.hasNext();) //$NON-NLS-1$
                    {
                        Element irNode = (Element) ir.next();

                        int len = -1;
                        String lenStr = irNode.attributeValue("length"); //$NON-NLS-1$
                        if (StringUtils.isNotEmpty(lenStr) && StringUtils.isNumeric(lenStr)) {
                            len = Integer.parseInt(lenStr);
                            //                            if (!UIRegistry.isMobile() && len > 256) // length over 255 are memo/text fields in MySQL and do not need to be constrained
                            //                            {
                            //                                len = 32767;
                            //                            }
                        }
                        DBFieldInfo fieldInfo = new DBFieldInfo(tblInfo, irNode.attributeValue("column"), //$NON-NLS-1$
                                irNode.attributeValue("name"), //$NON-NLS-1$
                                irNode.attributeValue("type"), //$NON-NLS-1$
                                len, getAttr(irNode, "required", false), //$NON-NLS-1$
                                getAttr(irNode, "updatable", false), //$NON-NLS-1$
                                getAttr(irNode, "unique", false), //$NON-NLS-1$
                                getAttr(irNode, "indexed", false), //$NON-NLS-1$
                                getAttr(irNode, "partialDate", false), //$NON-NLS-1$
                                getAttr(irNode, "datePrecisionName", null)); //$NON-NLS-1$
                        // This done to cache the original setting.
                        fieldInfo.setRequiredInSchema(fieldInfo.isRequired());
                        tblInfo.addField(fieldInfo);
                    }

                    for (Iterator<?> faIter = tableNode.elementIterator("fieldalias"); faIter.hasNext();) //$NON-NLS-1$
                    {
                        Element faNode = (Element) faIter.next();
                        String vName = getAttr(faNode, "vname", null);//$NON-NLS-1$
                        String aName = getAttr(faNode, "aname", null);//$NON-NLS-1$
                        if (vName != null && aName != null) {
                            tblInfo.addFieldAlias(vName, aName);
                        }
                    }

                    //Collections.sort(tblInfo.getFields());
                }
            } else {
                log.error("Reading in datamodel file.  SAX parser got null for the root of the document."); //$NON-NLS-1$
            }

        } catch (java.lang.NumberFormatException numEx) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DBTableIdMgr.class, numEx);
            log.error("Specify datamodel input file: " + inputFile.getAbsolutePath() //$NON-NLS-1$
                    + " failed to provide valid table id for class/table:" + classname); //$NON-NLS-1$
            log.error(numEx);
        } catch (Exception ex) {
            edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
            edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DBTableIdMgr.class, ex);
            log.error(ex);
            ex.printStackTrace();
        }
        Collections.sort(tables);
        log.debug("Done Reading in datamodel file: " + inputFile.getAbsolutePath()); //$NON-NLS-1$
    }

    /**
     * Clears (resets) all the permissions so they are re-read.
     */
    public void clearPermissions() {
        for (DBTableInfo ti : hash.values()) {
            ti.setPermissions(null);
        }
    }

    /**
     * Cleanups internal state.
     */
    public void cleanUp() {
        for (DBTableInfo ti : hash.values()) {
            ti.cleanUp();
        }
        hash.clear();
        byClassNameHash.clear();
        byShortClassNameHash.clear();
    }

    /**
     * Gets the localized title for a table. 
     * @param tableId the table id
     * @return the localized title for a table by id, returns "" if in error
     */
    public String getTitleForId(final int tableId) {
        DBTableInfo ti = getInfoById(tableId);
        if (ti != null) {
            return ti.getTitle();
        }
        return "";
    }

    /**
     * Gets the localized title for a field in a table. 
     * @param tableId the table id
     * @param fieldName POJO field name, NOT column name
     * @return the localized title for a table by id, returns "" if in error
     */
    public String getTitleForField(final int tableId, final String fieldName) {
        DBTableInfo ti = getInfoById(tableId);
        if (ti != null) {
            DBFieldInfo fi = ti.getFieldByName(fieldName);
            if (fi != null) {
                return fi.getTitle();
            }
        }
        return "";
    }

    /**
     * Returns the full collection of Tables. 
     * @return a collection of DBTableInfo objects
     */
    public Vector<DBTableInfo> getTables() {
        return tables;
    }

    /**
     * Returns the defualt form name for a given table ID.
     * @param id the ID of a table
     * @return the default form name
     */
    public String getDefaultFormNameById(final int id) {
        // for now the default name will
        DBTableInfo tableInfo = hash.get(id);
        if (tableInfo != null) {
            String defaultFormName = tableInfo.getDefaultFormName();
            if (StringUtils.isEmpty(defaultFormName)) {
                return tableInfo.getClassObj().getSimpleName();
            }
            return defaultFormName;
        }
        return null;
    }

    /**
     * This looks it up by table name (not Object name) the look up is case
     * insensitive.
     * @param name the name
     * @return the id of the table
     */
    public int getIdByShortName(final String name) {
        for (DBTableInfo tableInfo : hash.values()) {
            String tableName = tableInfo.getName();
            int inx = tableName.lastIndexOf('.');

            tableName = inx > -1 ? tableName.substring(inx + 1) : tableName;
            if (tableName.equalsIgnoreCase(name)) {
                return tableInfo.getTableId();
            }
        }
        throw new RuntimeException("Couldn't find table id for table name[" + name + "]"); //$NON-NLS-1$ //$NON-NLS-2$
    }

    /**
     * This looks it up by fully specified class name the look up is case
     * sensitive.
     * 
     * @param className the full class name
     * @return the id of the table
     */
    public int getIdByClassName(final String className) {
        DBTableInfo tableInfo = getByClassName(className);
        if (tableInfo != null) {
            return tableInfo.getTableId();
        }
        log.error("Couldn't find table id for table name[" + className + "]"); //$NON-NLS-1$ //$NON-NLS-2$
        return -1;
    }

    /**
     * This looks it up by fully specified class name the look up is case
     * sensitive.
     * 
     * @param className the full class name
     * @return the id of the table
     */
    public DBTableInfo getByClassName(final String className) {
        if (className != null) {
            return byClassNameHash.get(className.toLowerCase());
        }
        log.error("Couldn't find table id for table name[" + className + "]"); //$NON-NLS-1$ //$NON-NLS-2$
        return null;
    }

    /**
     * This looks it up by specified class (no path) name the look up is case sensitive.
     * 
     * @param className the full class name
     * @return the id of the table
     */
    public DBTableInfo getByShortClassName(final String shortClassName) {
        if (shortClassName != null) {
            return byShortClassNameHash.get(shortClassName.toLowerCase());
        }
        log.error("Couldn't find table id for table name[" + shortClassName + "]"); //$NON-NLS-1$ //$NON-NLS-2$
        return null;
    }

    /**
     * @return a list of the tables the users deal with, it excludes all System tables.
     */
    public Vector<DBTableInfo> getTablesForUserDisplay() {
        Vector<DBTableInfo> list = new Vector<DBTableInfo>();

        for (DBTableInfo ti : tables) {
            String tblName = ti.getName();

            if (!(tblName.startsWith("sp") || tblName.startsWith("attachment") || tblName.startsWith("autonum")
                    || tblName.equals("picklist") || tblName.equals("attributedef") || tblName.equals("recordset")
                    ||
                    //tblName.equals("inforequest") || 
                    tblName.startsWith("workbench") || tblName.endsWith("treedef")
                    || tblName.endsWith("treedefitem") || tblName.endsWith("attachment") || tblName.endsWith("attr")
                    || tblName.endsWith("reltype"))) {
                list.add(ti);
            }
        }
        return list;
    }

    /**
     * Returns the Info Object By Id.
     * @param tableId the id to look up
     * @return the table info object
     */
    public DBTableInfo getInfoById(final String tableId) {
        return getInfoById(Integer.parseInt(tableId));
    }

    /**
     * Returns the Info Object By Id.
     * @param tableId the id to look up
     * @return the table info object
     */
    public DBTableInfo getInfoById(final int tableId) {
        if (hash.get(tableId) == null) {
            log.error("Couldn't find tableId[" + tableId + "]"); //$NON-NLS-1$ //$NON-NLS-2$
        }
        return hash.get(tableId);
    }

    /**
     * Returns the Info Object By table name (the all lowercase name of the table).
     * @param tableName the name of the table
     * @return the table info object
     */
    public DBTableInfo getInfoByTableName(final String tableName) {
        // for now just use a brute force linear search
        for (DBTableInfo tblInfo : hash.values()) {
            if (tblInfo.getName().equals(tableName)) {
                return tblInfo;
            }
        }
        return null;
    }

    /**
     * Creates a Query object for a table from a recordset, it uses an "in" clause.
     * @param recordSet the recordset containing the record ids
     * @return a query object
     */
    public String getQueryForTable(final RecordSetIFace recordSet) {
        DBTableInfo tableInfo = hash.get(recordSet.getDbTableId());
        if (tableInfo != null) {
            String joins = QueryAdjusterForDomain.getInstance().getJoinClause(tableInfo, true, null, false);
            String specCols = QueryAdjusterForDomain.getInstance().getSpecialColumns(tableInfo, true);

            StringBuffer strBuf = new StringBuffer("from "); //$NON-NLS-1$
            strBuf.append(tableInfo.getName());
            strBuf.append(" IN CLASS "); //$NON-NLS-1$
            strBuf.append(tableInfo.getShortClassName());
            if (joins != null) {
                strBuf.append(joins);
            }
            strBuf.append(" WHERE "); //$NON-NLS-1$
            strBuf.append(tableInfo.getName());
            strBuf.append('.');
            strBuf.append(tableInfo.getPrimaryKeyName());
            strBuf.append(getInClause(recordSet));
            if (specCols != null) {
                strBuf.append(" AND ");
                strBuf.append(specCols);
            }
            log.debug(strBuf.toString());
            return strBuf.toString();
        }
        return null;
    }

    /**
     * Creates a Query object for a table from a single Record ID.
     * @param recordId a single Record Id
     * @return a query object
     */
    public String getQueryForTable(final int tableId, final long recordId) {
        DBTableInfo tableInfo = hash.get(tableId);
        if (tableInfo != null) {
            StringBuffer strBuf = new StringBuffer("from "); //$NON-NLS-1$
            strBuf.append(tableInfo.getName());
            strBuf.append(" in class "); //$NON-NLS-1$
            strBuf.append(tableInfo.getShortClassName());
            strBuf.append(" where "); //$NON-NLS-1$
            strBuf.append(tableInfo.getName());
            strBuf.append('.');
            strBuf.append(tableInfo.getPrimaryKeyName());
            strBuf.append(" = " + recordId); //$NON-NLS-1$
            log.debug(strBuf.toString());
            return strBuf.toString();
        }
        return null;
    }

    /**
     * Returns an "in" clause for a recordset
     * 
     * @param recordSet the recordset of ids
     * @return a string "in" clause
     */
    public String getInClause(final RecordSetIFace recordSet) {
        if (recordSet != null) {
            StringBuffer strBuf = new StringBuffer(" in ("); //$NON-NLS-1$
            List<RecordSetItemIFace> items = recordSet.getOrderedItems();
            if (items == null) {
                throw new RuntimeException("RecordSet items is null!"); //$NON-NLS-1$
            }
            int i = 0;
            for (RecordSetItemIFace rsi : items) {
                if (i > 0) {
                    strBuf.append(","); //$NON-NLS-1$
                }
                strBuf.append(rsi.getRecordId());
                i++;
            }
            strBuf.append(")"); //$NON-NLS-1$
            return strBuf.toString();
        }
        // else
        return ""; //$NON-NLS-1$
    }

    /**
     * Converts a String to an Enum for Relationship Type
     * @param relTypeStr the string
     * @return the relationship type
     */
    public static DBRelationshipInfo.RelationshipType getRelationshipType(final String relTypeStr) {
        if (relTypeStr.equals("one-to-many")) //$NON-NLS-1$
        {
            return DBRelationshipInfo.RelationshipType.OneToMany;

        } else if (relTypeStr.equals("many-to-one")) //$NON-NLS-1$
        {
            return DBRelationshipInfo.RelationshipType.ManyToOne;

        } else if (relTypeStr.equals("many-to-many")) //$NON-NLS-1$
        {
            return DBRelationshipInfo.RelationshipType.ManyToMany;

        } else if (relTypeStr.equals("one-to-one")) //$NON-NLS-1$
        {
            return DBRelationshipInfo.RelationshipType.OneToOne;

        } else if (relTypeStr.equals("zero-to-one")) //$NON-NLS-1$
        {
            return DBRelationshipInfo.RelationshipType.ZeroOrOne;
        }
        return null;
    }

    /**
     * Returns a business rule object for a given class.
     * @param data the data that might have a business rule class
     * @return the business rule object or null
     */
    public BusinessRulesIFace getBusinessRule(Object data) {
        if (data != null) {
            return getBusinessRule(data.getClass());
        }
        return null;
    }

    /**
     * Returns a business rule object for a given class name.
     * @param classOfObj the class to look up
     * @return the business rule object or null
     */
    public BusinessRulesIFace getBusinessRule(String className) {
        if (StringUtils.isNotEmpty(className)) {
            try {
                return getBusinessRule(Class.forName(className));

            } catch (Exception ex) {
                edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DBTableIdMgr.class, ex);
                //log.error(ex); // this isn't an error
            }
        } else {
            log.warn("Class Name was empty.");
        }
        return null;
    }

    /**
     * Returns a business rule object for a given class.
     * @param classOfObj the class to look up
     * @return the business rule object or null
     */
    public BusinessRulesIFace getBusinessRule(Class<?> classOfObj) {
        DBTableInfo ti = getByClassName(classOfObj.getName());
        if (ti != null) {
            String br = ti.getBusinessRuleName();
            if (StringUtils.isNotEmpty(br)) {
                try {
                    return (BusinessRulesIFace) Class.forName(br).newInstance();

                } catch (Exception ex) {
                    edu.ku.brc.af.core.UsageTracker.incrHandledUsageCount();
                    edu.ku.brc.exceptions.ExceptionTracker.getInstance().capture(DBTableIdMgr.class, ex);
                    log.error("Bad Business Rule class name[" + br + "]"); //$NON-NLS-1$ //$NON-NLS-2$
                    log.error(ex);
                }
            }
        }
        return new GenericBusRules();
    }

    /**
     * @return an iterator for Tables that only returns 'visible ones'
     */
    public DBInfoVisibleIterator<DBTableInfo> getVisableTabless() {
        return new DBInfoVisibleIterator<DBTableInfo>(tables);
    }

    /**
     * Returns the UIFieldFormatterIFace for a given Table Class and field Name.
     * @param tableClass the name of the class to look up
     * @param fieldName the field name
     * @return null or the formatter
     */
    public static UIFieldFormatterIFace getFieldFormatterFor(final Class<?> tableClass, final String fieldName) {
        DBTableInfo ti = DBTableIdMgr.getInstance().getByShortClassName(tableClass.getSimpleName());
        if (ti != null) {
            DBFieldInfo fi = ti.getFieldByName(fieldName);
            if (fi != null) {
                return fi.getFormatter();
            }
        }
        return null;
    }

    /**
     * Returns the list of fields that a tree table supports. 
     * @param tableInfo the main table definition.
     * @return the list from the highest (root) to the lower (leaf) or null if it isn't a tree.
     */
    public List<String> getTreeFieldNames(final DBTableInfo tableInfo) {
        return null;
    }

    /**
     * 
     */
    public void dumpTablesAsCSV() {
        boolean checkMM = true;
        try {
            PrintWriter pw = new PrintWriter("TablesAndField.csv");
            for (DBTableInfo ti : getTables()) {
                pw.write("\"" + ti.getName() + "\",,\"" + ti.getTitle() + "\",\"" + ti.getDescription() + "\","
                        + (checkMM ? "Mismatch" : "") + "\n");
                for (DBFieldInfo fi : ti.getFields()) {
                    pw.write(",\"" + fi.getName() + "\",\"" + fi.getTitle() + "\",\""
                            + (StringUtils.isNotEmpty(fi.getDescription()) ? fi.getDescription() : "") + "\",\""
                            + fi.getType() + "\"");
                    if (checkMM) {
                        if (fi.getColumn().startsWith("Number")) {
                            if (StringUtils.contains(fi.getType(), "Byte")
                                    || StringUtils.contains(fi.getType(), "Short")
                                    || StringUtils.contains(fi.getType(), "Integer")
                                    || StringUtils.contains(fi.getType(), "Long")
                                    || StringUtils.contains(fi.getType(), "Float")
                                    || StringUtils.contains(fi.getType(), "Double")) {
                                //pw.write(", OK");
                            } else {
                                pw.write(",*");
                            }
                        } else if (fi.getColumn().startsWith("Text")) {
                            if (StringUtils.contains(fi.getType(), "String")) {
                                //pw.write(", OK");
                            } else {
                                pw.write(",*");
                            }
                        } else if (fi.getColumn().startsWith("Yes")) {
                            if (StringUtils.contains(fi.getType(), "Boolean")) {
                                //pw.write(", OK");
                            } else {
                                pw.write(",*");
                            }
                        } else if (fi.getColumn().startsWith("Remark")) {
                            if (StringUtils.contains(fi.getType(), "text")) {
                                //pw.write(", OK");
                            } else {
                                pw.write(",*");
                            }
                        }
                    }
                    pw.write("\n");
                }
                for (DBRelationshipInfo ri : ti.getRelationships()) {
                    pw.write(",\"" + ri.getName() + "\",\"" + ri.getTitle() + "\",\""
                            + (StringUtils.isNotEmpty(ri.getDescription()) ? ri.getDescription() : "") + "\",\""
                            + ri.getType() + "\"\n");
                }
            }

            pw.close();

        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}