org.openmrs.module.patientregistration.service.db.HibernatePatientRegistrationDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.patientregistration.service.db.HibernatePatientRegistrationDAO.java

Source

/**
 * The contents of this file are subject to the OpenMRS Public License
 * Version 1.0 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License at
 * http://license.openmrs.org
 *
 * 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.
 *
 * Copyright (C) OpenMRS, LLC.  All Rights Reserved.
 */
package org.openmrs.module.patientregistration.service.db;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.CacheMode;
import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.openmrs.*;
import org.openmrs.api.context.Context;
import org.openmrs.module.patientregistration.PatientRegistrationConstants;
import org.openmrs.module.patientregistration.PatientRegistrationGlobalProperties;
import org.openmrs.module.patientregistration.PatientRegistrationUtil;
import org.openmrs.module.patientregistration.UserActivity;
import org.openmrs.module.patientregistration.util.DuplicatePatient;

/**
 * Core implementation of the DAO
 */
public class HibernatePatientRegistrationDAO implements PatientRegistrationDAO {

    protected final Log log = LogFactory.getLog(getClass());
    //***** PROPERTIES *****

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    /**
     * @see PatientRegistrationDAO#getNumberOfEncountersByAddress(Map, String, EncounterType, Location)
     */
    public Map<String, Integer> getNumberOfRegistrationsByAddress(Map<String, String> filterCriteria,
            String addressField, EncounterType encounterType, Location location, boolean groupByPatient) {
        Map<String, Integer> m = new TreeMap<String, Integer>();
        List<String> keys = PatientRegistrationUtil.getAddressHierarchyValues(addressField, filterCriteria);
        for (String key : keys) {
            m.put(key, new Integer(0));
        }
        m.put("other", new Integer(0));
        m.put("unspecified", new Integer(0));

        // First we'll get a Map of encounterId -> patientId, and get a list of all patients to aggregate
        Map<Integer, Integer> encounterToPatient = getEncounterToPatientMap(encounterType, location);
        List<Integer> patientIds = new ArrayList<Integer>();
        if (groupByPatient) {
            patientIds.addAll(new HashSet<Integer>(encounterToPatient.values()));
        } else {
            patientIds.addAll(encounterToPatient.values());
        }

        // Now we can get the unique address entries
        Map<Integer, String> addressValues = getAddressValuesForCohort(new Cohort(encounterToPatient.values()),
                addressField, filterCriteria);

        for (Integer patientId : patientIds) {
            String addressValue = addressValues.get(patientId);
            if (addressValue != null) {
                String keyToAdd = StringUtils.isBlank(addressValue) ? "unspecified"
                        : (keys.contains(addressValue) ? addressValue : "other");
                m.put(keyToAdd, m.get(keyToAdd) + 1);
            }
        }

        return m;
    }

    /**
     * @return a Map of encounterId to patientId for the matching encounterType and location.
     * If encounterType or location are null, it will restrict to the supported encounter types and locations if defined
     */
    public Map<Integer, Integer> getEncounterToPatientMap(EncounterType encounterType, Location location) {
        StringBuilder sb = new StringBuilder();
        sb.append("select e.encounter_id, p.patient_id from encounter e, patient p ");
        sb.append("where e.patient_id = p.patient_id and e.voided = 0 and p.voided = 0 ");
        if (encounterType != null) {
            sb.append("and e.encounter_type = " + encounterType.getId() + " ");
        } else {
            List<EncounterType> types = PatientRegistrationGlobalProperties
                    .GLOBAL_PROPERTY_REGISTRATION_ENCOUNTER_TYPES();
            if (!types.isEmpty()) {
                sb.append("and e.encounter_type in (");
                for (Iterator<EncounterType> iter = types.iterator(); iter.hasNext();) {
                    sb.append(iter.next().getId() + (iter.hasNext() ? "," : ""));
                }
                sb.append(") ");
            }
        }
        if (location != null) {
            sb.append("and e.location_id = " + location.getId() + " ");
        } else {
            List<Location> locations = PatientRegistrationGlobalProperties.GLOBAL_PROPERTY_REGISTRATION_LOCATIONS();
            if (!locations.isEmpty()) {
                sb.append("and e.location_id in (");
                for (Iterator<Location> iter = locations.iterator(); iter.hasNext();) {
                    sb.append(iter.next().getId() + (iter.hasNext() ? "," : ""));
                }
                sb.append(") ");
            }
        }

        List<List<Object>> queryResults = Context.getAdministrationService().executeSQL(sb.toString(), true);
        Map<Integer, Integer> ret = new HashMap<Integer, Integer>();
        for (List<Object> row : queryResults) {
            ret.put(Integer.parseInt(row.get(0).toString()), Integer.parseInt(row.get(1).toString()));
        }
        return ret;
    }

    /**
     * @return the relevant person address value for each patient in the passed cohort if they have a person address, limited by the
     * passed filter criteria
     */
    @SuppressWarnings("unchecked")
    public Map<Integer, String> getAddressValuesForCohort(Cohort c, String addressField,
            Map<String, String> filterCriteria) {
        Map<Integer, String> ret = new HashMap<Integer, String>();
        if (!c.isEmpty()) {
            StringBuilder sql = new StringBuilder();
            sql.append("select p.personId, a." + addressField + " from Person p, PersonAddress a ");
            sql.append("where p.personId = a.person.personId and p.voided = false and a.voided = false ");
            // NOTE: Removed 'and a.preferred = true ' since many/most addresses didn't have this set properly (MS)
            sql.append("and p.personId in (" + c.getCommaSeparatedPatientIds() + ") ");
            for (String filterKey : filterCriteria.keySet()) {
                sql.append("and a." + filterKey + " = :" + filterKey + " ");
            }
            Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
            for (String filterKey : filterCriteria.keySet()) {
                query.setParameter(filterKey, filterCriteria.get(filterKey));
            }
            query.setCacheMode(CacheMode.IGNORE);
            List<Object[]> queryResults = query.list();
            for (Object[] row : queryResults) {
                ret.put(Integer.valueOf(row[0].toString()), row[1] == null ? "" : row[1].toString());
            }
        }
        return ret;
    }

    public Set<Integer> getDistinctDuplicateObs(Integer conceptId) {
        Set<Integer> distinctDuplicates = null;
        if (conceptId != null) {
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT distinct(o.person_id) ");
            sql.append("FROM obs o ");
            sql.append("WHERE  o.concept_id=").append(conceptId.toString());
            sql.append(" ORDER BY o.obs_datetime desc, o.person_id");
            List<List<Object>> queryResults = Context.getAdministrationService().executeSQL(sql.toString(), true);
            if (queryResults != null && queryResults.size() > 0) {
                distinctDuplicates = new HashSet<Integer>();
                for (List<Object> row : queryResults) {
                    Integer patientId = Integer.parseInt(row.get(0).toString());
                    if (patientId != null) {
                        distinctDuplicates.add(patientId);
                    }
                }
            } else {
                log.debug("we got not duplicates");
            }
        }

        return distinctDuplicates;
    }

    public List<DuplicatePatient> getDuplicatePatients(Patient patient) {
        List<DuplicatePatient> duplicatePatients = null;
        if (patient != null && patient.getId() != null && (patient.getBirthdate() != null)) {
            Calendar birthdate = Calendar.getInstance();
            birthdate.setTime(patient.getBirthdate());
            Integer birthYear = new Integer(birthdate.get(Calendar.YEAR));
            Integer intervalYear = PatientRegistrationGlobalProperties.GLOBAL_PROPERTY_BIRTH_YEAR_INTERVAL();
            Integer minYear = new Integer(birthYear.intValue() - intervalYear.intValue());
            if (minYear.intValue() < 0) {
                minYear = 0;
            }
            PatientIdentifierType zlIdentifierType = PatientRegistrationGlobalProperties
                    .GLOBAL_PROPERTY_PRIMARY_IDENTIFIER_TYPE();
            PatientIdentifierType dossierType = PatientRegistrationGlobalProperties
                    .GLOBAL_PROPERTY_NUMERO_DOSSIER();
            StringBuilder sql = new StringBuilder();
            sql.append("SELECT s.person_id as PatientId, ");
            sql.append("n.given_name as FirstName, n.family_name as LastName, ");
            sql.append("s.gender as Gender, s.birthdate as Birthdate, ");
            sql.append("a.address1 as Address1, ");
            sql.append("a.city_village as Commune, s.date_created as PersonDateCreated, ");
            if (zlIdentifierType != null) {
                sql.append("id1.identifier as ZLEMRID, ");
            }
            if (dossierType != null) {
                sql.append("id3.identifier as NimewoDosye, ");
            }
            sql.append("Min(e.date_created) as FirstEncounterDate ");
            sql.append("FROM person as s JOIN person_name as n ON (s.person_id=n.person_id) ");
            sql.append("LEFT JOIN person_address as a ON (s.person_id = a.person_id) ");
            if (zlIdentifierType != null) {
                sql.append(
                        "LEFT JOIN patient_identifier as id1 ON (s.person_id = id1.patient_id and id1.identifier_type=")
                        .append(zlIdentifierType.getId().intValue()).append(") ");
            }
            if (dossierType != null) {
                sql.append(
                        "LEFT JOIN patient_identifier as id3 ON (s.person_id = id3.patient_id and id3.identifier_type=")
                        .append(dossierType.getId().intValue()).append(") ");
            }
            sql.append("LEFT outer JOIN encounter as e ON (s.person_id = e.patient_id) ");
            sql.append("WHERE s.voided=0 and n.voided=0 and n.given_name=\"").append(patient.getGivenName())
                    .append("\" ");
            sql.append("AND n.family_name=\"").append(patient.getFamilyName()).append("\" ");
            sql.append("AND YEAR(s.birthdate) BETWEEN ").append(minYear.toString()).append(" AND ")
                    .append(birthYear.intValue() + intervalYear.intValue()).append(" ");
            if (patient.getPersonAddress() != null) {
                String cityVillage = patient.getPersonAddress().getCityVillage();
                if (StringUtils.isNotBlank(cityVillage)) {
                    sql.append("AND ((a.city_village is null) OR TRIM(a.city_village)='' OR (a.city_village=\"")
                            .append(cityVillage).append("\")) ");
                }
            }
            sql.append("GROUP BY PatientId ");
            sql.append("ORDER BY PatientId, PersonDateCreated, FirstEncounterDate");

            List<List<Object>> queryResults = Context.getAdministrationService().executeSQL(sql.toString(), true);
            if (queryResults != null && queryResults.size() > 0) {
                duplicatePatients = new ArrayList<DuplicatePatient>();
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                SimpleDateFormat bdf = new SimpleDateFormat("yyyy-MM-dd");
                Date date = null;
                Object fieldValue = null;
                for (List<Object> row : queryResults) {
                    Integer patientId = Integer.parseInt(row.get(0).toString());
                    if (patientId.compareTo(patient.getId()) == 0) {
                        continue;
                    }

                    DuplicatePatient duplicatePatient = new DuplicatePatient();
                    duplicatePatient.setPatientId(patientId);
                    duplicatePatient.setFirstName(row.get(1).toString());
                    duplicatePatient.setLastName(row.get(2).toString());
                    duplicatePatient.setGender(row.get(3).toString());
                    try {
                        date = bdf.parse(row.get(4).toString());
                        if (date != null) {
                            duplicatePatient.setBirthdate(date);
                        }
                    } catch (ParseException e) {
                        log.error("failed to parse date", e);
                    }
                    fieldValue = row.get(5);
                    if (fieldValue != null) {
                        duplicatePatient.setAddress1(fieldValue.toString());
                    }
                    fieldValue = row.get(6);
                    if (fieldValue != null) {
                        duplicatePatient.setCityVillage(fieldValue.toString());
                    }
                    fieldValue = row.get(7);
                    if (fieldValue != null) {
                        try {
                            date = sdf.parse(fieldValue.toString());
                            if (date != null) {
                                duplicatePatient.setPersonDateCreated(date);
                            }
                        } catch (ParseException e) {
                            log.error("failed to parse date", e);
                        }
                    }
                    fieldValue = row.get(8);
                    if (fieldValue != null) {
                        duplicatePatient.setZlEmrId(fieldValue.toString());
                    }
                    fieldValue = row.get(9);
                    if (fieldValue != null) {
                        duplicatePatient.setDossierNumber(fieldValue.toString());
                    }
                    fieldValue = row.get(10);
                    if (fieldValue != null) {
                        try {
                            date = sdf.parse(fieldValue.toString());
                            if (date != null) {
                                duplicatePatient.setFirstEncounterDate(date);
                            }
                        } catch (ParseException e) {
                            log.error("failed to parse date", e);
                        }
                    }

                    duplicatePatients.add(duplicatePatient);
                }
            }

        }
        return duplicatePatients;
    }

    public Set<String> searchNames(String name, String nameField) {
        Set<String> firstNames = null;
        if (StringUtils.isNotBlank(name)) {
            StringBuilder sql = new StringBuilder();
            sql.append("select distinct(n.").append(nameField).append(") ");
            sql.append("from PersonName n ");
            sql.append("where n.").append(nameField).append(" like '%").append(name).append("%' ");
            sql.append("group by n.").append(nameField).append(" ");
            sql.append("order by n.").append(nameField).append(" ");
            try {
                Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
                query.setCacheMode(CacheMode.IGNORE);
                List<String> queryResults = (List<String>) query.list();
                if (queryResults != null && queryResults.size() > 0) {
                    firstNames = new HashSet<String>();
                    for (String personName : queryResults) {
                        firstNames.add(personName);
                    }
                }
            } catch (Exception e) {
                log.error("error retrieving patient names", e);
            }
        }
        return firstNames;
    }

    public Map<String, Integer> searchNamesByOccurence(String name, String nameField) {
        Map<String, Integer> nameOccurences = new HashMap<String, Integer>();
        if (StringUtils.isNotBlank(name)) {
            String escapedName = StringEscapeUtils.escapeSql(name);
            StringBuilder sql = new StringBuilder();
            sql.append("select distinct(n.").append(nameField).append("), count(*) ");
            sql.append("from PersonName n ");
            sql.append("where n.").append(nameField).append(" like '%").append(escapedName).append("%' ");
            sql.append("and person.personId not in (");
            sql.append("select pa.person.personId ");
            sql.append("from PersonAttribute pa ");
            sql.append("where pa.attributeType.name='");
            sql.append(PatientRegistrationConstants.UNKNOWN_PATIENT_PERSON_ATTRIBUTE_TYPE_NAME);
            sql.append("' and pa.value='true' ");
            sql.append(")");

            sql.append("group by n.").append(nameField).append(" ");
            sql.append("order by count(*) desc, n.").append(nameField).append(" ");
            try {
                Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
                query.setCacheMode(CacheMode.IGNORE);

                List<Object[]> queryResults = query.list();
                for (Object[] row : queryResults) {
                    nameOccurences.put(row[0] == null ? "" : row[0].toString(), Integer.valueOf(row[1].toString()));
                }
            } catch (Exception e) {
                log.error("error retrieving patient names", e);
            }
        }
        return nameOccurences;
    }

    @Override
    public List<Patient> getPatientsByName(PersonName personName) {
        List<Patient> patients = null;
        if (personName != null) {
            String firstName = personName.getGivenName();
            String lastName = personName.getFamilyName();
            if (StringUtils.isNotBlank(firstName) && StringUtils.isNotBlank(lastName)) {
                try {
                    Query query = sessionFactory.getCurrentSession()
                            .createQuery("from Patient as p" + " left outer join p.names as n"
                                    + " where (n.givenName= :firstName and n.familyName= :lastName) or"
                                    + " (n.givenName= :lastName and n.familyName= :firstName)");

                    query.setParameter("firstName", firstName);
                    query.setParameter("lastName", lastName);

                    query.setCacheMode(CacheMode.IGNORE);
                    List<Object[]> results = query.list();
                    if (results != null && results.size() > 0) {
                        patients = new ArrayList<Patient>();
                        for (Object[] result : results) {
                            Patient patient = (Patient) result[0];
                            patients.add(patient);
                        }
                        return patients;
                    }
                } catch (Exception e) {
                    log.error("error finding patients", e);
                }
            }
        }
        return new ArrayList<Patient>();
    }

    public List<Patient> getPatientsByNameId(List<Integer> nameIds) {
        List<Patient> patients = null;
        if (nameIds == null || (nameIds != null && nameIds.size() < 1)) {
            return null;
        }
        try {
            Query query = sessionFactory.getCurrentSession()
                    .createQuery("from Patient as p where p.personId in (:nameIds)");
            query.setParameterList("nameIds", nameIds);
            query.setCacheMode(CacheMode.IGNORE);
            patients = query.list();
            if (patients != null && patients.size() > 0) {
                return patients;

            }

        } catch (Exception e) {
            log.error("error retrieving name phonetics", e);
        }
        return patients;

    }

    public List<Integer> getUnknownPersonId() {
        List<Integer> queryResults = null;
        StringBuilder sql = new StringBuilder();
        sql.append("select distinct pa.person.personId ");
        sql.append("from PersonAttribute pa ");
        sql.append("where pa.attributeType.name='");
        sql.append(PatientRegistrationConstants.UNKNOWN_PATIENT_PERSON_ATTRIBUTE_TYPE_NAME);
        sql.append("' and pa.value='true' ");
        try {
            Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
            query.setCacheMode(CacheMode.IGNORE);
            queryResults = query.list();
            if (queryResults != null && queryResults.size() > 0) {
                return queryResults;
            }

        } catch (Exception e) {
            log.error("error retrieving the IDs of the unknown persons", e);
        }
        return queryResults;
    }

    public List<Integer> getPhoneticsPersonId(String firstName, String lastName) {

        List<Integer> queryResults = null;
        if (StringUtils.isBlank(firstName) || (StringUtils.isBlank(lastName))) {
            return queryResults;
        }
        StringBuilder sql = new StringBuilder();
        sql.append("select distinct np1.personName.person.personId ");
        sql.append("from NamePhonetic np1 ");
        sql.append("where np1.renderedString like '").append(firstName).append("%' ");
        sql.append("and np1.nameField=1 ");
        sql.append("and np1.personName.personNameId in ");
        sql.append("(select np2.personName.personNameId from NamePhonetic np2 ");
        sql.append("where np2.renderedString like '").append(lastName).append("%' ");
        sql.append("and np2.nameField=3) ");
        try {
            Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
            query.setCacheMode(CacheMode.IGNORE);

            queryResults = query.list();
            if (queryResults != null && queryResults.size() > 0) {
                return queryResults;

            }

        } catch (Exception e) {
            log.error("error retrieving name phonetics", e);
        }

        return queryResults;
    }

    public List<String> getDistinctObs(Integer conceptId) {
        List<String> distinctObs = null;
        if (conceptId == null) {
            return distinctObs;
        }

        StringBuilder sql = new StringBuilder();
        sql.append("select distinct(trim(value_text)) as NonCodedDiagnoses");
        sql.append(" from Obs where voided=0 and concept_id=").append(conceptId.toString());
        sql.append(" order by value_text");
        try {
            Query query = sessionFactory.getCurrentSession().createQuery(sql.toString());
            query.setCacheMode(CacheMode.IGNORE);
            distinctObs = query.list();
            if (distinctObs != null && distinctObs.size() > 0) {
                List<String> cleanObs = new ArrayList<String>();
                for (String obs : distinctObs) {
                    cleanObs.add(obs.replace("\\", " "));
                }
                return cleanObs;
            }
        } catch (Exception e) {
            log.error("error retrieving distinct obs", e);
        }
        return distinctObs;
    }

    /**
     * @see PatientRegistrationDAO#saveUserActivity(UserActivity)
     */
    public UserActivity saveUserActivity(UserActivity userActivity) {
        sessionFactory.getCurrentSession().saveOrUpdate(userActivity);
        return userActivity;
    }
}