edu.wustl.geneconnect.postwork.MetadataManager.java Source code

Java tutorial

Introduction

Here is the source code for edu.wustl.geneconnect.postwork.MetadataManager.java

Source

/*L
 * Copyright Washington University at St. Louis
 *
 * Distributed under the OSI-approved BSD 3-Clause License.
 * See http://ncip.github.com/geneconnect/LICENSE.txt for details.
 */

/**
 *<p>ClassName: java edu.wustl.geneconnect.postwork.MetadataManager</p> 
 */

package edu.wustl.geneconnect.postwork;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.MultiMap;
import org.apache.commons.collections.map.MultiValueMap;

import com.dataminer.server.database.DBManager;
import com.dataminer.server.exception.FatalException;
import com.dataminer.server.jobmanager.BaseBuilder;
import com.dataminer.server.log.Logger;

import edu.wustl.geneconnect.GeneConnectServerConstants;
import edu.wustl.geneconnect.metadata.domain.BaseTable;
import edu.wustl.geneconnect.metadata.domain.DataSource;
import edu.wustl.geneconnect.metadata.domain.Path;
import edu.wustl.geneconnect.metadata.domain.TableColumn;
import edu.wustl.geneconnect.metadata.domain.TableJoinInformation;

/**
 * This class will implement all business logic to provide geneconnect metadata.
 * It caches all the metdata when it is invoked first time in order to avoid database queries every time. 
 * @author mahesh_nalkande
 * @version 1.0
 */
public class MetadataManager implements GeneConnectServerConstants {

    /** MetadataManager as a singleton class */
    private static MetadataManager metadataManagerInstance;

    /** 
     * Method to return instance of this class
     * @return MetadataManager Returns object of this class
     */
    public static MetadataManager getInstance() {
        if (metadataManagerInstance == null) {
            metadataManagerInstance = new MetadataManager();
            //Cache all metadata required 
            metadataManagerInstance.cacheMetadata();
        }
        return metadataManagerInstance;
    }

    /**
     * Default constructor, not accessible to all as it is a singleton class
     */
    private MetadataManager() {
        super();
    }

    /**
     * Data Base Manager instance used for all database operations
     */
    private DBManager dbManager = DBManager.getInstance();

    /**
     * Map to store cached Data Source Information
     */
    private Map dataSources = new HashMap();
    /**
     * Map to store cached base table metadata
     */
    private Map baseTableMetaData = new HashMap();
    /**
     * Map to store cached column metadata
     */
    private Map columnMetaData = new HashMap();
    /**
     * Map to store cached table join metadata
     */
    private List tableJoinMetaData = new ArrayList();
    /**
     * Map to store cached Path Information
     */
    private Map paths = new HashMap();
    /**
     * Contains multimaps, one each for a source node
     */
    private List masterPathList = new ArrayList();
    /**
     * List of subPath Ids for every path.
     * n th element in the list contains subPath Ids (delimited by '_') of the path Id n.
     */
    private List subPathIds = new ArrayList();
    /**
     * List of Ont Ids for every path.
     * n th element in the list contains ont Ids (delimited by '_') of the path Id n.
     */
    private List ontIds = new ArrayList();
    /**
     * Caches Link types (delimited by '_') for every ont.
     * Key : Ont Id
     * Value : Link types (delimited by '_') 
     */
    private Map ontLinkTypes = new HashMap();

    /**
     * This method caches all metadata required during summary table genration, 
     * in order to avoid data base server queries. 
     */
    private void cacheMetadata() {
        Logger.log("Caching MetaData...", Logger.DEBUG);
        Logger.log("Total memory available : " + Runtime.getRuntime().totalMemory(), Logger.DEBUG);
        Logger.log("Free memory available : " + Runtime.getRuntime().freeMemory(), Logger.DEBUG);

        /** set up Data Base connection object*/
        connectToDB();
        cacheDataSourceInformation();
        cacheBaseTableMetaData();
        cacheColumnMetaData();
        cacheTableJoinInformation();
        cachePaths();
        cachePathSubPathsMapping();
        cachePathOntMapping();
        cacheOntLinkTypes();
        Logger.log("Metadata has been cached.", Logger.DEBUG);
        Logger.log("Free memory available after caching : " + Runtime.getRuntime().freeMemory(), Logger.DEBUG);
    }

    private void cacheDataSourceInformation() {
        DataSource dataSource = null;
        String sqlQuery = "SELECT DATASOURCE_ID, DATASOURCE_NAME, GENOMIC_IDENTIFIER_CLASS, CLASS, ATTRIBUTE, ATTRIBUTE_TYPE, "
                + "TABLE_NAME, COLUMN_NAME, OUTPUT_ATTRIBUTE FROM DATASOURCE ORDER BY DATASOURCE_ID";
        //execute query to get all the data from the BASETABLE_METADATA table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        try {
            while (resultSet.next()) {
                //Prepae base tabel object
                dataSource = new DataSource(new Long(resultSet.getString(1)), resultSet.getString(2),
                        resultSet.getString(3), resultSet.getString(4), resultSet.getString(5),
                        resultSet.getString(6), resultSet.getString(7), resultSet.getString(8),
                        resultSet.getString(9));

                //put it into the Map, which will be refered later on
                dataSources.put(new Long(resultSet.getString(1)), dataSource);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    /**
     * This method cahces all base table metadata. 
     */
    private void cacheBaseTableMetaData() {
        BaseTable baseTable = null;
        String sqlQuery = "select TABLE_ID,TABLE_NAME,SOURCE_DATASOURCE_ID,TARGET_DATASOURCE_ID "
                + " from BASETABLE_METADATA";
        //execute query to get all the data from the BASETABLE_METADATA table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        try {
            while (resultSet.next()) {
                //Prepae base tabel object
                baseTable = new BaseTable(new Long(resultSet.getString(1)), resultSet.getString(2),
                        new Long(resultSet.getString(3)), new Long(resultSet.getString(4)));
                //put it into the Map, which will be refered later on
                baseTableMetaData.put(new Long(resultSet.getString(1)), baseTable);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    /**
     * This method cahces all column metadata. 
     */
    private void cacheColumnMetaData() {
        TableColumn columnInfo = null;
        String sqlQuery = "select COLUMN_ID,COLUMN_NAME,TABLE_ID,DATASOURCE_ID from COLUMN_METADATA";

        //execute query to get all the data from the COLUMN_METADATA table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        try {
            while (resultSet.next()) {
                //Prepae table column object
                columnInfo = new TableColumn(new Long(resultSet.getString(1)), resultSet.getString(2),
                        new Long(resultSet.getString(3)), null);
                if (resultSet.getString(4) != null) {
                    columnInfo.setDataSourceId(new Long(resultSet.getString(4)));
                }
                //put it into the Map, which will be refered later on
                columnMetaData.put(new Long(resultSet.getString(1)), columnInfo);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    /**
     * This method cahces all Table Join metadata. 
     */
    private void cacheTableJoinInformation() {
        TableJoinInformation tableJoinInfo = null;
        String sqlQuery = "select SOURCE_TABLE_ID,TARGET_TABLE_ID,SOURCE_COLUMN_ID,TARGET_COLUMN_ID "
                + "from TABLEJOIN_METADATA";

        //execute query to get all the data from the TABLEJOIN_METADATA table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        try {
            while (resultSet.next()) {
                //Prepae table column object
                tableJoinInfo = new TableJoinInformation(new Long(resultSet.getString(1)),
                        new Long(resultSet.getString(2)), new Long(resultSet.getString(3)),
                        new Long(resultSet.getString(4)));
                //put it into the Map, which will be refered later on
                tableJoinMetaData.add(tableJoinInfo);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    private void cachePaths() {
        for (int i = 0; i < dataSources.size(); ++i) {
            MultiMap pathMap = new MultiValueMap();
            masterPathList.add(pathMap);
        }

        Path currentPath = null;
        String sqlQuery = "select PATH_ID, SOURCE_DATASOURCE_ID, TARGET_DATASOURCE_ID, PATH FROM PATH";
        //execute query to get all the data from the BASETABLE_METADATA table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        try {
            while (resultSet.next()) {
                //Prepae base tabel object
                currentPath = new Path(new Long(resultSet.getString(1)), new Long(resultSet.getString(2)),
                        new Long(resultSet.getString(3)), resultSet.getString(4));

                //put it into the Map, which will be refered later on
                paths.put(new Long(resultSet.getString(1)), currentPath);

                MultiMap pathMap = (MultiMap) masterPathList.get(currentPath.getSourceDataSourceId().intValue());
                pathMap.put(currentPath.getTargetDataSourceId(), currentPath);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    private void cachePathSubPathsMapping() {
        for (int i = 0; i <= paths.size(); i++) {
            subPathIds.add(i, new String());
        }
        String sqlQuery = "select PATH_ID,SUBPATH_ID from SUBPATH order by PATH_ID";
        //execute query to get all the data from the SUBPATH table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        String currentSubPathIds, subPathId;
        int pathId;
        try {
            while (resultSet.next()) {
                pathId = resultSet.getInt(1);
                subPathId = resultSet.getString(2);
                currentSubPathIds = (String) subPathIds.get(pathId);
                if (currentSubPathIds.equals("")) {
                    currentSubPathIds = subPathId;
                } else {
                    currentSubPathIds = currentSubPathIds + SUBPATH_IDS_DELIMITER + subPathId;
                }
                subPathIds.remove(pathId);
                subPathIds.add(pathId, currentSubPathIds);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    private void cachePathOntMapping() {
        for (int i = 0; i <= paths.size(); i++) {
            ontIds.add(i, new String());
        }
        String sqlQuery = "select PATH_ID,ONT_ID from PATH_ONT order by PATH_ID";
        //execute query to get all the data from the PATH_ONT table
        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        String currentOntIds, ontId;
        int pathId;
        try {
            while (resultSet.next()) {
                pathId = resultSet.getInt(1);
                ontId = resultSet.getString(2);
                currentOntIds = (String) ontIds.get(pathId);
                if (currentOntIds.equals("")) {
                    currentOntIds = ontId;
                } else {
                    currentOntIds = currentOntIds + ONT_IDS_DELIMITER + ontId;
                }
                ontIds.remove(pathId);
                ontIds.add(pathId, currentOntIds);
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }
    }

    private void cacheOntLinkTypes() {
        String sqlQuery = "select PATH_ID,LINKTYPE_ID,NEXT_PATH_ID,PREV_PATH_ID from ONT order by PATH_ID";
        //execute query to get all the data from the ONT table

        ResultSet resultSet = dbManager.executeSQLQuery(sqlQuery);
        String currentOntLinkTypes = "";
        long prevPathId = 0, nextPathId = 0, currentOntId = 0;
        try {
            while (resultSet.next()) {
                prevPathId = resultSet.getLong(4);
                nextPathId = resultSet.getLong(3);

                if (prevPathId == 0) //Begining of new Ont Definition
                {
                    currentOntId = resultSet.getLong(1);
                    currentOntLinkTypes = resultSet.getString(2);
                } else if (nextPathId == 0) //End of of Ont Definition
                {
                    //put it into the Map, which will be refered later on
                    ontLinkTypes.put(new Long(currentOntId), currentOntLinkTypes);
                } else
                //intermediate node of the ONT
                {
                    currentOntLinkTypes = currentOntLinkTypes + LINK_TYPES_DELIMITER + resultSet.getString(2);
                }
            }
        } catch (SQLException e) {
            Logger.log("SQLException occured while fetching the metadata from the database", Logger.FATAL);
            SummaryExceptionHandler.handleException(e);
        }

    }

    public Path getPath(Long pathId) {
        return (Path) paths.get(pathId);
    }

    public String getSubPaths(Long pathId) {
        return subPathIds.get(pathId.intValue()).toString();
    }

    public String getOnts(Long pathId) {
        return ontIds.get(pathId.intValue()).toString();
    }

    public String getOntLinkTypes(Long ontId) {
        return ontLinkTypes.get(ontId).toString();
    }

    public Path getPath(String path) {
        String[] pathNodes = path.split(PATH_NODES_DELIMITER);
        Long sourceNodeId = new Long(pathNodes[0]);
        Long destinationNodeId = new Long(pathNodes[pathNodes.length - 1]);
        MultiMap pathMap = (MultiMap) masterPathList.get(sourceNodeId.intValue());
        Collection possiblePathsFromSrcToDest = (Collection) pathMap.get(destinationNodeId);

        if (possiblePathsFromSrcToDest != null) {
            Path currentPath = null;
            for (Iterator iter = possiblePathsFromSrcToDest.iterator(); iter.hasNext();) {
                currentPath = (Path) iter.next();
                if (path.equals(currentPath.getCompletePath())) {
                    return currentPath;
                }
            }
        }
        return null;
    }

    public List getPaths(Long sourceId, Long destinationId) {
        return null;
    }

    /**
     * This method gives base table information given a data source Ids of source and destination
     * @param sourceDataSourceId Id of the source datasource
     * @param destinationDataSourceId Id of the destination datasource
     * @return BaseTable base table information object 
     */
    public BaseTable getBaseTableInformation(Long sourceDataSourceId, Long destinationDataSourceId) {
        BaseTable baseTable = null;
        Iterator iterator = baseTableMetaData.values().iterator();
        while (iterator.hasNext()) {
            baseTable = (BaseTable) iterator.next();
            if (sourceDataSourceId.equals(baseTable.getSourceDataSourceId())
                    && destinationDataSourceId.equals(baseTable.getDestinationDataSourceId())) {
                return baseTable;
            }
        }
        Logger.log("ERROR : Base Table Information for data sources " + sourceDataSourceId + " - "
                + destinationDataSourceId + " is not available.", Logger.FATAL);
        Logger.log("Please check the GC graph configuration file and GCMetadataPopulation.sql "
                + "in script folder and rerun the server.", Logger.FATAL);
        return null;
    }

    /**
     * Names of columns which can be used to join given 2 tables.
     * @param sourceTableId source table to be joined
     * @param targetTableId destination table to be joined
     * @return
     */
    public String[] getJoiningColumnNames(Long sourceTableId, Long targetTableId) {
        TableJoinInformation tableJoinInformation = null;
        Iterator iterator = tableJoinMetaData.iterator();
        while (iterator.hasNext()) {
            tableJoinInformation = (TableJoinInformation) iterator.next();
            if (sourceTableId.equals(tableJoinInformation.getSourceTableId())
                    && targetTableId.equals(tableJoinInformation.getDestinationTableId())) {
                String[] joinColumnNames = {
                        getColumnInformation(tableJoinInformation.getSourceColumnId()).getName(),
                        getColumnInformation(tableJoinInformation.getDestinationColumnId()).getName() };
                return joinColumnNames;
            }
        }
        Logger.log(
                "ERROR : Joining Column Information for tables " + getBaseTableInformation(sourceTableId).getName()
                        + " - " + getBaseTableInformation(targetTableId).getName() + " is not available.",
                Logger.FATAL);
        Logger.log("Please check the GC graph configuration file and GCMetadataPopulation.sql "
                + "in script folder and rerun the server.", Logger.FATAL);
        return null;
    }

    /**
     * Gives Base Table Information based on given Name of the table 
     * @param tableName Name of the base table
     * @return BaseTable object - describes the base table which stores mapping Ids among 2 adjucent data sources
     */
    public BaseTable getBaseTableInformation(String tableName) {
        BaseTable baseTable = null;
        Iterator iterator = baseTableMetaData.values().iterator();
        while (iterator.hasNext()) {
            baseTable = (BaseTable) iterator.next();
            if (tableName.equals(baseTable.getName())) {
                return baseTable;
            }
        }
        Logger.log("ERROR : Table Information for table " + tableName + " is not available.", Logger.FATAL);
        Logger.log("Please check the GC graph configuration file and GCMetadataPopulation.sql "
                + "in script folder and re-run the server.", Logger.FATAL);
        return null;
    }

    /**
     * Gives Base Table Information based on given Id of the table 
     * @param tableId Id of the base table
     * @return BaseTable object - describes the base table which stores mapping Ids among 2 adjucent data sources
     */
    public BaseTable getBaseTableInformation(Long tableId) {
        BaseTable baseTable = null;
        baseTable = (BaseTable) baseTableMetaData.get(tableId);
        if (baseTable != null) {
            return baseTable;
        }
        Logger.log("ERROR : Table Information for table " + tableId + " is not available.", Logger.FATAL);
        Logger.log("Please check the GC graph configuration file and GCMetadataPopulation.sql "
                + "in script folder and re-run the server.", Logger.FATAL);
        return null;
    }

    /**
     * Gives information about the requsted base table column.
     * @param columnId Id of the column whose information is required.
     * @return TableColumn object which describes coulmn in the base table. 
     */
    public TableColumn getColumnInformation(Long columnId) {
        TableColumn columnInformation = null;
        Iterator iterator = columnMetaData.values().iterator();
        while (iterator.hasNext()) {
            columnInformation = (TableColumn) iterator.next();
            if (columnId.equals(columnInformation.getId())) {
                return columnInformation;
            }
        }
        Logger.log("ERROR : Column Information for columnId " + columnId + " is not available.", Logger.FATAL);
        Logger.log("Please check the GC graph configuration file and GCMetadataPopulation.sql "
                + "in script folder and re-run the server.", Logger.FATAL);
        return null;
    }

    /**
     * List of column infromation objects describing all columns in the requsted base table. 
     * @param tableId Id of the base table 
     * @return List of TableColumn objects. Each object describes single column in the requestes base table.
     */
    public List getAllColumns(Long tableId) {
        List columns = new ArrayList();
        TableColumn columnInformation = null;

        Iterator iterator = columnMetaData.values().iterator();
        while (iterator.hasNext()) {
            columnInformation = (TableColumn) iterator.next();
            if (tableId.equals(columnInformation.getTableId())) {
                columns.add(columnInformation);
            }
        }
        return columns;
    }

    public DataSource getDataSource(Long dataSourceId) {
        return (DataSource) dataSources.get(dataSourceId);
    }

    public Map getDataSources() {
        return dataSources;
    }

    public Map getBaseTableMetaData() {
        return baseTableMetaData;
    }

    public Map getColumnMetaData() {
        return columnMetaData;
    }

    /**
     * Establish data base connection using db properties specified in server.properties
     */
    private void connectToDB() {
        /** set up Data Base connection object*/
        try {
            Logger.log("Connecting to DB server...", Logger.DEBUG);
            dbManager.connect();
            Logger.log("Connected.", Logger.DEBUG);
        } catch (FatalException fatal) {
            /** If database connection can not be established successfully it will throw 
             * FatalException which will cause the program to terminate  */
            Logger.log("Fatal Exception occured while connecting to database", Logger.FATAL);
            Logger.log("Reason : " + fatal.getMessage(), Logger.FATAL);
            fatal.printStackTrace();
            fatal.printException();
            BaseBuilder.getInstance("edu.wustl.geneconnect.builder.GCBuilder").handleFatalException();
        }
    }
}