Package ke.go.moh.oec.mpi

Source Code of ke.go.moh.oec.mpi.LoadPersonThread

/* ***** 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.mpi;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import ke.go.moh.oec.Person;
import ke.go.moh.oec.Visit;
import ke.go.moh.oec.lib.Mediator;
import ke.go.moh.oec.mpi.list.FingerprintList;
import ke.go.moh.oec.mpi.list.PersonIdentifierList;
import ke.go.moh.oec.mpi.match.PersonMatch;

/**
* One thread that can be used for concurrent processing to load the person list into memory
*
* @author Jim Grace
*/
public class LoadPersonThread implements Runnable {

    /** The list of person identities in memory against which we will search for candidates. */
    private List<PersonMatch> personMatchList;
    /** Index of this thread (used for debugging and tracing purposes.) */
    private int threadIndex;
    /** The minimum personId we will get from the database. */
    private int minPersonId;
    /** The maximum personId we will get from the database. */
    private int maxPersonId;

    public LoadPersonThread(int threadIndex, int minPersonId, int maxPersonId) {
        this.threadIndex = threadIndex;
        this.minPersonId = minPersonId;
        this.maxPersonId = maxPersonId;
    }

    public List<PersonMatch> getPersonMatchList() {
        return personMatchList;
    }

    /**
     * Do the person matching requested for this thread.
     * <p>
     * Implements java.lang.Runnable.run().
     */
    public void run() {
        long startTime = System.currentTimeMillis();
        Mediator.getLogger(LoadPersonThread.class.getName()).log(Level.FINE,
                "LoadPersonThread {0} starting.", threadIndex);
        personMatchList = new ArrayList<PersonMatch>(); // Our output is collected here, to be retrieved later.
        Connection conn = Sql.connect();
        Calendar cal = Calendar.getInstance(); // Default Calendar, used for getting database date fields.
        String sql = "SELECT p.person_id, p.person_guid, p.sex, p.birthdate, p.deathdate,\n"
                + "       p.first_name, p.middle_name, p.last_name, p.other_name, p.clan_name,\n"
                + "       p.mothers_first_name, p.mothers_middle_name, p.mothers_last_name,\n"
                + "       p.fathers_first_name, p.fathers_middle_name, p.fathers_last_name,\n"
                + "       p.compoundhead_first_name, p.compoundhead_middle_name, p.compoundhead_last_name,\n"
                + "       v.village_name, m.marital_status_name, p.consent_signed,\n"
                + "       MAX(v_reg.visit_date) AS visit_reg_date,\n"
                + "       MAX(v_one.visit_date) AS visit_one_date,\n"
                + "       MID(MAX(CONCAT(v_reg.visit_date, a_reg.address)),20) AS visit_reg_address,\n"
                + "       MID(MAX(CONCAT(v_one.visit_date, a_one.address)),20) AS visit_one_address,\n"
                + "       MID(MAX(CONCAT(v_reg.visit_date, a_reg.facility_name)),20) AS visit_reg_facility\n"
                + "FROM person p\n"
                + "LEFT OUTER JOIN village v ON v.village_id = p.village_id\n"
                + "LEFT OUTER JOIN marital_status_type m ON m.marital_status_type_id = p.marital_status\n"
                + "LEFT OUTER JOIN visit v_reg ON v_reg.person_id = p.person_id and v_reg.visit_type_id = " + Sql.REGULAR_VISIT_TYPE_ID + "\n"
                + "LEFT OUTER JOIN visit v_one ON v_one.person_id = p.person_id and v_one.visit_type_id = " + Sql.ONE_OFF_VISIT_TYPE_ID + "\n"
                + "LEFT OUTER JOIN address a_reg ON a_reg.address_id = v_reg.address_id\n"
                + "LEFT OUTER JOIN address a_one ON a_one.address_id = v_one.address_id\n" //Gitau added to enable passing of facility name to Visit.getvisit
                + "WHERE p.person_id BETWEEN " + minPersonId + " AND " + maxPersonId + " -- Thread " + threadIndex + "\n" // Comment for logging.
                + "GROUP BY p.person_id\n"
                + "ORDER BY p.person_id";
        ResultSet rs = Sql.query(conn, sql);
        int recordCount = 0;
        FingerprintList fingerprintList = new FingerprintList();
        fingerprintList.loadStart(minPersonId, maxPersonId);
        PersonIdentifierList personIdentifierList = new PersonIdentifierList();
        personIdentifierList.loadStart(minPersonId, maxPersonId);
        try {
            // Define ingeger variables to hold column index numbers.
            //
            // When loading the MPI from the database, it is substantially faster to
            // access the recordset by column number than by column name. This was
            // discovered by CPU profiling of the original code which used column name.
            //
            // On the other hand, it would be less code just to refer to the column numbers
            // rather than go through the trouble of defining integers and then looking
            // up the column indices. But this would be more error prone, in the event
            // that the list of columns is ever changed. So we define ingteger variables
            // for all the column indices, and then load them on the first result set.
            int colPersonId = 0, colPersonGuid = 0, colSex = 0, colBirthdate = 0, colDeathdate = 0,
                    colFirstName = 0, colMiddleName = 0, colLastName = 0, colOtherName = 0, colClanName = 0,
                    colMothersFirstName = 0, colMothersMiddleName = 0, colMothersLastName = 0,
                    colFathersFirstName = 0, colFathersMiddleName = 0, colFathersLastName = 0,
                    colCompoundheadFirstName = 0, colCompoundheadMiddleName = 0, colCompoundheadLastName = 0,
                    colVillageName = 0, colMaritalStatusName = 0, colConsentSigned = 0,
                    colVisitRegDate = 0, colVisitOneDate = 0, colVisitRegAddress = 0,colVisitRegFacility = 0, colVisitOneAddress = 0;
            boolean colsFound = false; // Have we found the column numbers yet?
            while (rs.next()) {
                if (!colsFound) {
                    colPersonId = rs.findColumn("person_id");
                    colPersonGuid = rs.findColumn("person_guid");
                    colSex = rs.findColumn("sex");
                    colBirthdate = rs.findColumn("birthdate");
                    colDeathdate = rs.findColumn("deathdate");
                    colFirstName = rs.findColumn("first_name");
                    colMiddleName = rs.findColumn("middle_name");
                    colLastName = rs.findColumn("last_name");
                    colOtherName = rs.findColumn("other_name");
                    colClanName = rs.findColumn("clan_name");
                    colMothersFirstName = rs.findColumn("mothers_first_name");
                    colMothersMiddleName = rs.findColumn("mothers_middle_name");
                    colMothersLastName = rs.findColumn("mothers_last_name");
                    colFathersFirstName = rs.findColumn("fathers_first_name");
                    colFathersMiddleName = rs.findColumn("fathers_middle_name");
                    colFathersLastName = rs.findColumn("fathers_last_name");
                    colCompoundheadFirstName = rs.findColumn("compoundhead_first_name");
                    colCompoundheadMiddleName = rs.findColumn("compoundhead_middle_name");
                    colCompoundheadLastName = rs.findColumn("compoundhead_last_name");
                    colVillageName = rs.findColumn("village_name");
                    colMaritalStatusName = rs.findColumn("marital_status_name");
                    colConsentSigned = rs.findColumn("consent_signed");
                    colVisitRegDate = rs.findColumn("visit_reg_date");
                    colVisitOneDate = rs.findColumn("visit_reg_address");
                    colVisitRegAddress = rs.findColumn("visit_one_date");
                    colVisitOneAddress = rs.findColumn("visit_one_address");
                    colVisitRegFacility = rs.findColumn("visit_reg_facility");
                    colsFound = true;
                }
                Person p = new Person();
                int dbPersonId = rs.getInt(colPersonId);
                p.setPersonGuid(getRsString(rs, colPersonGuid));
                p.setSex((Person.Sex) ValueMap.SEX.getVal().get(getRsString(rs, colSex)));
                p.setBirthdate(rs.getDate(colBirthdate, cal));
                p.setDeathdate(rs.getDate(colDeathdate, cal));
                p.setFirstName(getRsString(rs, colFirstName));
                p.setMiddleName(getRsString(rs, colMiddleName));
                p.setLastName(getRsString(rs, colLastName));
                p.setOtherName(getRsString(rs, colOtherName));
                p.setClanName(getRsString(rs, colClanName));
                p.setMothersFirstName(getRsString(rs, colMothersFirstName));
                p.setMothersMiddleName(getRsString(rs, colMothersMiddleName));
                p.setMothersLastName(getRsString(rs, colMothersLastName));
                p.setFathersFirstName(getRsString(rs, colFathersFirstName));
                p.setFathersMiddleName(getRsString(rs, colFathersMiddleName));
                p.setFathersLastName(getRsString(rs, colFathersLastName));
                p.setCompoundHeadFirstName(getRsString(rs, colCompoundheadFirstName));
                p.setCompoundHeadMiddleName(getRsString(rs, colCompoundheadMiddleName));
                p.setCompoundHeadLastName(getRsString(rs, colCompoundheadLastName));
                p.setVillageName(getRsString(rs, colVillageName));
                p.setMaritalStatus((Person.MaritalStatus) ValueMap.MARITAL_STATUS.getVal().get(getRsString(rs, colMaritalStatusName)));
                p.setPersonIdentifierList(personIdentifierList.loadNext(dbPersonId));
                p.setFingerprintList(fingerprintList.loadNext(dbPersonId));
                p.setConsentSigned((Person.ConsentSigned) ValueMap.CONSENT_SIGNED.getVal().get(getRsString(rs, colConsentSigned)));
                p.setLastRegularVisit(Visit.getVisit(rs.getDate(colVisitRegDate), getRsString(rs, colVisitOneDate),getRsString(rs, colVisitRegFacility)));
                p.setLastOneOffVisit(Visit.getVisit(rs.getDate(colVisitRegAddress), getRsString(rs, colVisitOneAddress),getRsString(rs, colVisitRegFacility)));
                PersonMatch per = new PersonMatch(p);
                per.setDbPersonId(dbPersonId);
                personMatchList.add(per);
                if (++recordCount % 10000 == 0) {
                    double timeInterval = (System.currentTimeMillis() - startTime);
                    Mediator.getLogger(LoadPersonThread.class.getName()).log(Level.FINE,
                            "Thread {0} loaded {1} entries in {2} milliseconds.",
                            new Object[]{threadIndex, recordCount, timeInterval});
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(LoadPersonThread.class.getName()).log(Level.SEVERE, null, ex);
            System.exit(1);
        }
        Sql.close(rs);
        Sql.close(conn);
        fingerprintList.loadEnd();
        personIdentifierList.loadEnd();
                double timeInterval = (System.currentTimeMillis() - startTime);
                Mediator.getLogger(LoadPersonThread.class.getName()).log(Level.FINE,
                        "Thread {0} finished loading {1} entries in {2} milliseconds.",
                        new Object[]{threadIndex, personMatchList.size(), timeInterval});
    }

    /**
     * Does an efficient result set get string, assuming that the byte coding
     * in the database does not need translation into the character coding of
     * the string. This effectively does the same job as rs.getString(), but
     * without the overhead of doing a generalized character coding translation.
     * <p>
     * In CPU profiling, it was discovered that significant time was being
     * spent translating bytes into characters inside the rs.getString() method.
     * So this method was written to replace it for loading the MPI into memory.
     *
     * @param rs ResultSet
     * @param columnIndex index of the column to get
     * @return string value of the column
     * @throws SQLException
     */
    private String getRsString(ResultSet rs, int columnIndex) throws SQLException {
        String s = null;
        byte[] bytes = rs.getBytes(columnIndex);
        if (bytes != null) {
            char[] chars = new char[bytes.length];
            for (int i = 0; i < bytes.length; i++) {
                chars[i] = (char) bytes[i];
            }
            s = new String(chars);
        }
        return s;
    }
}
TOP

Related Classes of ke.go.moh.oec.mpi.LoadPersonThread

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.