Package ke.go.moh.oec.adt.controller

Source Code of ke.go.moh.oec.adt.controller.TransactionMiner

/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (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.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is OpenEMRConnect.
*
* The Initial Developer of the Original Code is International Training &
* Education Center for Health (I-TECH) <http://www.go2itech.org/>
*
* Portions created by the Initial Developer are Copyright (C) 2011
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* ***** END LICENSE BLOCK ***** */
package ke.go.moh.oec.adt.controller;

import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Date;
import java.util.logging.Level;
import ke.go.moh.oec.adt.data.Column;
import ke.go.moh.oec.adt.data.RecordSource;
import ke.go.moh.oec.adt.data.Transaction;
import ke.go.moh.oec.adt.data.TransactionType;
import ke.go.moh.oec.adt.exceptions.BadRecordSourceException;
import ke.go.moh.oec.lib.Mediator;

/**
* @date Apr 25, 2012
*
* @author Gitahi Ng'ang'a
*/
public class TransactionMiner {

    private int lastTransactionId = -1;

    public Map<RecordSource, Map<Integer, Transaction>> mine(List<RecordSource> recordSourceList, Date since) throws SQLException,
            BadRecordSourceException {
        Map<RecordSource, Map<Integer, Transaction>> transactionMap =
                new LinkedHashMap<RecordSource, Map<Integer, Transaction>>();
        for (RecordSource recordSource : recordSourceList) {
            validatePrimaryKeys(recordSource);
            transactionMap.put(recordSource, mine(recordSource, since));
        }
        return transactionMap;
    }

    public void saveLastTransactionId() throws SQLException {
        if (lastTransactionId != -1) {
            Statement statement = null;
            String query;
            int lastTxId = retrieveLastTransactionId();
            if (lastTxId == -1) {
                query = "INSERT INTO `destination`(`name`, `last_received_transaction_id`, `last_processed_transaction_id`)\n"
                        + "VALUES('" + ResourceManager.getSetting("Instance.Name") + "', " + lastTransactionId + ", " + lastTransactionId + ")";
            } else {
                query = "UPDATE `destination`\n"
                        + "SET `last_received_transaction_id` = " + lastTransactionId
                        + ", `last_processed_transaction_id` = " + lastTransactionId + "\n"
                        + "WHERE `name` = '" + ResourceManager.getSetting("Instance.Name") + "'";
            }
            try {
                statement = getConnection().createStatement();
                statement.executeUpdate(query);
                Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINER, query);
                Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINE, "Saved last_transaction_id = {0}.", lastTransactionId);
            } catch (SQLException ex) {
                throw ex;
            } finally {
                if (statement != null) {
                    statement.close();
                }
            }
        }
    }

    private Map<Integer, Transaction> mine(RecordSource recordSource, Date since) throws SQLException {
        Map<Integer, Transaction> transactionMap = new LinkedHashMap<Integer, Transaction>();
        Statement statement = null;
        ResultSet resultSet = null;
        String query = "SELECT t.`id`, t.`type`, b.`name` AS `table_name`, b.`primary_keys`\n"
                + "FROM `transaction` t\n"
                + "JOIN `table` b ON b.`id` = t.`table_id`\n"
                + "WHERE (`type` = 'INSERT' OR `type` = 'UPDATE')\n"
                + "AND b.`name` = '" + recordSource.getTableName() + "'\n"
                + "AND t.`id` > " + retrieveLastTransactionId() + "\n";
        if (since != null) {
            query += "AND created_datetime > '" + new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(since) + "'\n";
        }
        query += "ORDER BY t.`id` DESC\n";
        if (recordSource.getLimit() >= 0) {
            query += "LIMIT " + recordSource.getLimit();
        }
        try {
            statement = getConnection().createStatement();
            resultSet = statement.executeQuery(query);
            Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINER, query);
            while (resultSet.next()) {
                Transaction transaction = new Transaction(resultSet.getInt("id"), resultSet.getString("table_name"),
                        TransactionType.valueOf(resultSet.getString("type")));
                transactionMap.put(transaction.getId(), transaction);
            }
        } catch (SQLException ex) {
            throw ex;
        } finally {
            if (statement != null) {
                statement.close();
            }
            if (resultSet != null) {
                resultSet.close();
            }
        }
        setPrimaryKeyMaps(recordSource, transactionMap);
        return coalesceSameRecordTransactions(transactionMap);
    }

private void setPrimaryKeyMaps(RecordSource recordSource, Map<Integer, Transaction> transactionMap) throws SQLException {
        if (transactionMap != null && !transactionMap.isEmpty()) {
            List<Integer> keyList = new ArrayList<Integer>(transactionMap.keySet());
            int firstId = keyList.get(keyList.size() - 1);
            int lastId = keyList.get(0);
            lastTransactionId = (lastTransactionId > lastId ? lastTransactionId : lastId);
            Statement statement = null;
            ResultSet resultSet = null;
            String query = "SELECT c.`name` AS `column_name`, t.`data` AS `column_value`, t.`transaction_id`, t.`transaction_id`, b.`name`\n"
                    + "FROM `transaction_data` t\n"
                    + "JOIN `column` c ON c.`id` = t.`column_id`\n"
                    + "JOIN `table` b ON b.`id` = c.`table_id`\n"
                    + "WHERE t.`transaction_id`\n"
                    + "BETWEEN " + firstId + " AND " + lastId + "\n"
                    + "AND c.`name`IN (" + concatenatePkColumns(recordSource.getPrimaryKeyColumnMap().keySet()) + ")\n"
                    + "AND b.`name` = '" + recordSource.getTableName() + "'\n"
                    + "ORDER BY t.`transaction_id`";
            try {
                statement = getConnection().createStatement();
                resultSet = statement.executeQuery(query);
                Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINER, query);
                Transaction transaction = null;
                if (resultSet.next()) {
                    int transactionId = resultSet.getInt("transaction_id");
                    String primaryKeyColumnName = resultSet.getString("column_name");
                    String primaryKeyColumnValue = resultSet.getString("column_value");
                    while (resultSet.next()) {
                        int txId = resultSet.getInt("transaction_id");
                        if (txId != transactionId) {//211691//185730
                            transaction = transactionMap.get(transactionId);
                            if (transaction == null) {
                                transaction = transactionMap.get(txId);
                            }
                            addPrimaryKey(transaction, recordSource, primaryKeyColumnName, primaryKeyColumnValue);
                            primaryKeyColumnName = resultSet.getString("column_name");
                            primaryKeyColumnValue = resultSet.getString("column_value");
                            transactionId = txId;
                        } else {
                            primaryKeyColumnName = resultSet.getString("column_name");
                            primaryKeyColumnValue = resultSet.getString("column_value");
                            addPrimaryKey(transaction, recordSource, primaryKeyColumnName, primaryKeyColumnValue);
                        }
                    }
                    transaction = transactionMap.get(transactionId);
                    addPrimaryKey(transaction, recordSource, primaryKeyColumnName, primaryKeyColumnValue);
                }
            } finally {
                if (statement != null) {
                    statement.close();
                }
                if (resultSet != null) {
                    resultSet.close();
                }
            }
        }
    }

    private void addPrimaryKey(Transaction transaction, RecordSource recordSource, String primaryKeyColumnName, String primaryKeyColumnValue) {
        Column column = recordSource.getPrimaryKeyColumnMap().get(primaryKeyColumnName);
        if (column != null) {
            if (transaction.getPrimaryKey() == null) {
                transaction.setPrimaryKey(new LinkedHashMap<Column, String>());
            }
            transaction.getPrimaryKey().put(column, primaryKeyColumnValue);
        }
    }

    private Map<Integer, Transaction> coalesceSameRecordTransactions(Map<Integer, Transaction> txMap) {
        List<String> compositePrimaryKeyList = new ArrayList<String>();
        Map<Integer, Transaction> transactionMap = new LinkedHashMap<Integer, Transaction>();
        for (Integer id : txMap.keySet()) {
            String compositePrimaryKey = createCompositePrimaryKey(txMap.get(id));
            if (!compositePrimaryKeyList.contains(compositePrimaryKey)) {
                compositePrimaryKeyList.add(compositePrimaryKey);
                transactionMap.put(id, txMap.get(id));
            }
        }
        return transactionMap;
    }

    private String createCompositePrimaryKey(Transaction transaction) {
        String compositePrimaryKey = "";
        for (Column column : transaction.getPrimaryKey().keySet()) {
            compositePrimaryKey += transaction.getPrimaryKey().get(column) + "#";
        }
        compositePrimaryKey += transaction.getTableName();
        return compositePrimaryKey;
    }

    private int retrieveLastTransactionId() throws SQLException {
        int lastTxId = -1;
        Statement statement = null;
        ResultSet resultSet = null;
        String query = "SELECT `last_processed_transaction_id`\n"
                + "FROM `destination`\n"
                + "WHERE `name` = '" + ResourceManager.getSetting("Instance.Name") + "'";
        try {
            statement = getConnection().createStatement();
            resultSet = statement.executeQuery(query);
            Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINER, query);
            if (resultSet.next()) {
                lastTxId = resultSet.getInt("last_processed_transaction_id");
            }
        } catch (SQLException ex) {
            throw ex;
        } finally {
            if (statement != null) {
                statement.close();
            }
            if (resultSet != null) {
                resultSet.close();
            }
        }
        return lastTxId;
    }

    private void validatePrimaryKeys(RecordSource recordSource) throws SQLException, BadRecordSourceException {
        Statement statement = null;
        ResultSet resultSet = null;
        String query = "SELECT t.`primary_keys`\n"
                + "FROM `column` c, `table` t\n"
                + "WHERE t.`name` = '" + recordSource.getTableName() + "'\n"
                + "LIMIT 1";
        try {
            statement = getConnection().createStatement();
            resultSet = statement.executeQuery(query);
            Mediator.getLogger(TransactionMiner.class.getName()).log(Level.FINER, query);
            if (resultSet.next()) {
                List<String> truePrimaryKeyList = Arrays.asList(resultSet.getString("primary_keys").split(","));
                int configuredPkCount = recordSource.getPrimaryKeyColumnMap().size();
                int truePkCount = truePrimaryKeyList.size();
                if (configuredPkCount != truePkCount) {
                    throw new BadRecordSourceException("The number of configured primary key columns (" + configuredPkCount
                            + ") does not match the number of true primary key columns (" + truePkCount + ")");
                }
                for (Column column : recordSource.getPrimaryKeyColumnMap().values()) {
                    if (!truePrimaryKeyList.contains(column.getName())) {
                        throw new BadRecordSourceException("The column " + column.getName()
                                + " is configured as a primary key for the table " + recordSource.getTableName()
                                + " but it is not actually a primary key.");
                    }
                }
            }
        } finally {
            if (statement != null) {
                statement.close();
            }
            if (resultSet != null) {
                resultSet.close();
            }
        }
    }

    private String concatenatePkColumns(Collection<String> pkColumnNameCollection) {
        String concatenatedPkColumns = "";
        int index = 0;
        int count = pkColumnNameCollection.size();
        for (String pkColumnName : pkColumnNameCollection) {
            concatenatedPkColumns += "'" + pkColumnName + "'";
            if (index < (count - 1)) {
                concatenatedPkColumns += ", ";
            }
            index++;
        }
        return concatenatedPkColumns;
    }

    /*
     * Returns a usable database connection based on the settings specified in
     * the properties file.
     */
    private Connection getConnection() throws SQLException {
        return ResourceManager.getDatabaseConnection("shadow");
    }
}
TOP

Related Classes of ke.go.moh.oec.adt.controller.TransactionMiner

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.