org.openmrs.module.emrapi.concept.HibernateEmrConceptDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.emrapi.concept.HibernateEmrConceptDAO.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.emrapi.concept;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.Vector;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.openmrs.api.db.hibernate.DbSessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.openmrs.Concept;
import org.openmrs.ConceptClass;
import org.openmrs.ConceptMap;
import org.openmrs.ConceptMapType;
import org.openmrs.ConceptName;
import org.openmrs.ConceptReferenceTerm;
import org.openmrs.ConceptSearchResult;
import org.openmrs.ConceptSet;
import org.openmrs.ConceptSource;
import org.openmrs.api.ConceptService;
import org.openmrs.api.context.Context;
import org.openmrs.module.ModuleUtil;
import org.openmrs.util.OpenmrsConstants;
import org.springframework.transaction.annotation.Transactional;

/**
 *
 */
public class HibernateEmrConceptDAO implements EmrConceptDAO {

    DbSessionFactory sessionFactory;

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

    @Override
    public List<Concept> getConceptsMappedTo(Collection<ConceptMapType> mapTypes, ConceptReferenceTerm term) {
        Criteria crit = sessionFactory.getCurrentSession().createCriteria(Concept.class);
        crit.createCriteria("conceptMappings").add(Restrictions.in("conceptMapType", mapTypes))
                .add(Restrictions.eq("conceptReferenceTerm", term));
        return crit.list();
    }

    @Override
    @Transactional(readOnly = true)
    public List<ConceptSearchResult> conceptSearch(String query, Locale locale, Collection<ConceptClass> classes,
            Collection<Concept> inSets, Collection<ConceptSource> sources, Integer limit) {
        List<String> uniqueWords = getUniqueWords(query, locale);
        if (uniqueWords.size() == 0) {
            return Collections.emptyList();
        }

        List<ConceptSearchResult> results = new ArrayList<ConceptSearchResult>();

        // find matches based on name
        {
            Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ConceptName.class, "cn");
            criteria.add(Restrictions.eq("voided", false));
            if (StringUtils.isNotBlank(locale.getCountry()) || StringUtils.isNotBlank(locale.getVariant())) {
                Locale[] locales = new Locale[] { locale, new Locale(locale.getLanguage()) };
                criteria.add(Restrictions.in("locale", locales));
            } else {
                criteria.add(Restrictions.eq("locale", locale));
            }
            criteria.setMaxResults(limit);

            Criteria conceptCriteria = criteria.createCriteria("concept");
            conceptCriteria.add(Restrictions.eq("retired", false));
            if (classes != null) {
                conceptCriteria.add(Restrictions.in("conceptClass", classes));
            }
            if (inSets != null) {
                DetachedCriteria allowedSetMembers = DetachedCriteria.forClass(ConceptSet.class);
                allowedSetMembers.add(Restrictions.in("conceptSet", inSets));
                allowedSetMembers.setProjection(Projections.property("concept"));
                criteria.add(Subqueries.propertyIn("concept", allowedSetMembers));
            }

            for (String word : uniqueWords) {
                criteria.add(Restrictions.ilike("name", word, MatchMode.ANYWHERE));
            }

            Set<Concept> conceptsMatchedByPreferredName = new HashSet<Concept>();
            for (ConceptName matchedName : (List<ConceptName>) criteria.list()) {
                results.add(new ConceptSearchResult(null, matchedName.getConcept(), matchedName,
                        calculateMatchScore(query, uniqueWords, matchedName)));
                if (matchedName.isLocalePreferred()) {
                    conceptsMatchedByPreferredName.add(matchedName.getConcept());
                }
            }

            // don't display synonym matches if the preferred name matches too
            for (Iterator<ConceptSearchResult> i = results.iterator(); i.hasNext();) {
                ConceptSearchResult candidate = i.next();
                if (!candidate.getConceptName().isLocalePreferred()
                        && conceptsMatchedByPreferredName.contains(candidate.getConcept())) {
                    i.remove();
                }
            }
        }

        // find matches based on mapping
        if (sources != null) {
            Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ConceptMap.class);
            criteria.setMaxResults(limit);

            Criteria conceptCriteria = criteria.createCriteria("concept");
            conceptCriteria.add(Restrictions.eq("retired", false));
            if (classes != null) {
                conceptCriteria.add(Restrictions.in("conceptClass", classes));
            }

            Criteria mappedTerm = criteria.createCriteria("conceptReferenceTerm");
            mappedTerm.add(Restrictions.eq("retired", false));
            mappedTerm.add(Restrictions.in("conceptSource", sources));
            mappedTerm.add(Restrictions.ilike("code", query, MatchMode.EXACT));

            for (ConceptMap mapping : (List<ConceptMap>) criteria.list()) {
                results.add(new ConceptSearchResult(null, mapping.getConcept(), null,
                        calculateMatchScore(query, mapping)));
            }
        }

        Collections.sort(results, new Comparator<ConceptSearchResult>() {
            @Override
            public int compare(ConceptSearchResult left, ConceptSearchResult right) {
                return right.getTransientWeight().compareTo(left.getTransientWeight());
            }
        });

        if (results.size() > limit) {
            results = results.subList(0, limit);
        }
        return results;
    }

    /**
     * Copied over from OpenMRS 1.9.8 to provide backwards compatibility.
     * 
     * It's no longer available in 1.11.
     * 
     * @param phrase
     * @param locale
     * @return
     */
    public static List<String> getUniqueWords(String phrase, Locale locale) {
        String[] parts = splitPhrase(phrase);
        List<String> uniqueParts = new Vector<String>();

        if (parts != null) {
            List<String> conceptStopWords = Context.getConceptService().getConceptStopWords(locale);
            for (String part : parts) {
                if (!StringUtils.isBlank(part)) {
                    String upper = part.trim().toUpperCase();
                    if (!conceptStopWords.contains(upper) && !uniqueParts.contains(upper))
                        uniqueParts.add(upper);
                }
            }
        }

        return uniqueParts;
    }

    /**
     * Copied over from OpenMRS 1.9.8 to provide backwards compatibility.
     * 
     * It's no longer available in 1.11.
     * 
     * @param phrase
     * @return
     */
    public static String[] splitPhrase(String phrase) {
        if (StringUtils.isBlank(phrase)) {
            return null;
        }
        if (phrase.length() > 2) {
            phrase = phrase.replaceAll(OpenmrsConstants.REGEX_LARGE, " ");
        } else {
            phrase = phrase.replaceAll(OpenmrsConstants.REGEX_SMALL, " ");
        }

        return phrase.trim().replace('\n', ' ').split(" ");
    }

    private Double calculateMatchScore(String query, ConceptMap matchedMapping) {
        // eventually consider weighting this by map type (e.g. same-as > narrower-than > others)
        return 10000d;
    }

    private Double calculateMatchScore(String query, List<String> uniqueWords, ConceptName matchedName) {
        double score = 0d;
        if (query.equalsIgnoreCase(matchedName.getName())) {
            score += 1000d;
        }
        if (matchedName.isLocalePreferred()) {
            score += 500d;
        }
        score -= matchedName.getName().length();
        return score;
    }
}