org.openmrs.module.metadatasharing.api.db.hibernate.HibernateMetadataDAO.java Source code

Java tutorial

Introduction

Here is the source code for org.openmrs.module.metadatasharing.api.db.hibernate.HibernateMetadataDAO.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.metadatasharing.api.db.hibernate;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Disjunction;
import org.hibernate.criterion.MatchMode;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.Subqueries;
import org.hibernate.type.StringType;
import org.openmrs.Concept;
import org.openmrs.ConceptWord;
import org.openmrs.OpenmrsMetadata;
import org.openmrs.Privilege;
import org.openmrs.RelationshipType;
import org.openmrs.Role;
import org.openmrs.api.context.Context;
import org.openmrs.api.db.DAOException;
import org.openmrs.module.metadatasharing.api.db.MetadataDAO;
import org.openmrs.module.metadatasharing.reflection.ClassUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

/**
 * Hibernate specific database methods for {@link MetadataDAO}
 */
@Repository
public class HibernateMetadataDAO implements MetadataDAO {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public <T> List<T> getItems(Class<? extends T> type, boolean includeRetired, String filter, Integer first,
            Integer max) throws DAOException {
        Criteria criteria = sessionFactory.getCurrentSession().createCriteria(type);

        if (first != null) {
            criteria.setFirstResult(first);
        }

        if (max != null) {
            criteria.setMaxResults(max);
        }

        filter(type, criteria, includeRetired, filter);

        criteria.addOrder(Order.asc("uuid"));

        @SuppressWarnings("unchecked")
        List<T> list = criteria.list();
        return list;
    }

    @Override
    public <T> int getItemsCount(Class<? extends T> type, boolean includeRetired, String filter)
            throws DAOException {
        Criteria criteria = sessionFactory.getCurrentSession().createCriteria(type);

        filter(type, criteria, includeRetired, filter);

        criteria.setProjection(Projections.rowCount());

        return ((Number) criteria.uniqueResult()).intValue();
    }

    @Override
    public <T> T getItemByUuid(Class<? extends T> type, String uuid) {
        Criteria criteria = sessionFactory.getCurrentSession().createCriteria(type);
        criteria.add(Restrictions.eq("uuid", uuid));

        @SuppressWarnings("unchecked")
        T result = (T) criteria.uniqueResult();
        return result;
    }

    @Override
    public <T> T getItemById(Class<? extends T> type, String id) {
        Criteria criteria = sessionFactory.getCurrentSession().createCriteria(type);
        criteria.add(Restrictions.idEq(id));

        @SuppressWarnings("unchecked")
        T result = (T) criteria.uniqueResult();
        return result;
    }

    private void filter(Class<?> type, Criteria criteria, boolean includeRetired, String filter) {
        if (!includeRetired) {
            criteria.add(Restrictions.eq("retired", includeRetired));
        }

        if (filter != null && !filter.isEmpty()) {
            Disjunction or = Restrictions.disjunction();
            criteria.add(or);

            or.add(Restrictions.like("uuid", filter, MatchMode.START));

            or.add(Restrictions.idEq(asItemId(filter)));

            type = ClassUtil.getDeproxiedClass(type);

            if (Role.class.isAssignableFrom(type)) {
                or.add(Restrictions.ilike("role", filter, MatchMode.START));

            } else if (Privilege.class.isAssignableFrom(type)) {
                or.add(Restrictions.ilike("privilege", filter, MatchMode.START));

            } else if (RelationshipType.class.isAssignableFrom(type)) {
                or.add(Restrictions.sqlRestriction("CONCAT(a_Is_To_B, CONCAT('/', b_Is_To_A)) like (?)",
                        "%" + filter, new StringType()));
            } else if (type.getSimpleName().equals("HtmlForm")) {
                criteria.createAlias("form", "form");
                or.add(Restrictions.ilike("form.name", filter, MatchMode.START));
            } else if (OpenmrsMetadata.class.isAssignableFrom(type)) {
                //It may happen that the name property is not defined for the specific metadata type so we need to test it.
                String[] propertyNames = sessionFactory.getClassMetadata(type).getPropertyNames();
                if (Arrays.asList(propertyNames).contains("name")) {
                    or.add(Restrictions.ilike("name", filter, MatchMode.START));
                }
            }
        }
    }

    /**
     * @see org.openmrs.module.metadatasharing.api.db.MetadataDAO#getConcepts(boolean,
     *      java.lang.String, java.lang.Integer, java.lang.Integer)
     */
    @Override
    public List<Concept> getConcepts(boolean includeRetired, String filter, Integer firstResult,
            Integer maxResults) {
        List<Concept> result = new ArrayList<Concept>();
        if (!StringUtils.isEmpty(filter)) {
            Concept concept = Context.getConceptService().getConceptByUuid(filter);
            if (concept != null) {
                return Arrays.asList(concept);
            }
            concept = filterById(filter);
            if (concept != null) {
                // if the first page with concepts was requested, we just add found concept 
                if (firstResult == 0) {
                    result.add(concept);
                    maxResults -= 1;
                } else {
                    // otherwise, we need to shift down the lower bound of concepts
                    firstResult -= 1;
                }
            }
        }

        Criteria criteria = null;
        if (StringUtils.isEmpty(filter)) {
            criteria = sessionFactory.getCurrentSession().createCriteria(Concept.class);

            if (!includeRetired) {
                criteria.add(Restrictions.eq("retired", includeRetired));
            }

            criteria.addOrder(Order.asc("conceptId"));
        } else {
            criteria = sessionFactory.getCurrentSession().createCriteria(ConceptWord.class, "conceptWord");

            filterConceptWords(criteria, includeRetired, filter);

            criteria.addOrder(Order.asc("concept"));
            criteria.setProjection(Projections.distinct(Projections.property("concept")));
        }

        if (firstResult != null) {
            criteria.setFirstResult(firstResult);
        }

        if (maxResults != null) {
            criteria.setMaxResults(maxResults);
        }

        @SuppressWarnings("unchecked")
        List<Concept> concepts = criteria.list();

        if (concepts != null && !concepts.isEmpty()) {
            result.addAll(concepts);
        }

        return result;
    }

    /**
     * @see org.openmrs.module.metadatasharing.api.db.MetadataDAO#getConceptsCount(boolean,
     *      java.lang.String)
     */
    @Override
    public int getConceptsCount(boolean includeRetired, String filter) {
        if (StringUtils.isEmpty(filter)) {
            Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Concept.class);

            if (!includeRetired) {
                criteria.add(Restrictions.eq("retired", includeRetired));
            }

            criteria.setProjection(Projections.rowCount());

            return ((Number) criteria.uniqueResult()).intValue();
        }

        boolean incrementNeeded = false;
        if (!StringUtils.isEmpty(filter)) {
            Concept concept = Context.getConceptService().getConceptByUuid(filter);
            if (concept != null) {
                if (concept.isRetired() && includeRetired) {
                    return 1;
                } else {
                    return 0;
                }
            }
            concept = filterById(filter);
            if (concept != null) {
                incrementNeeded = true;
            }
        }

        Criteria criteria = sessionFactory.getCurrentSession().createCriteria(ConceptWord.class, "conceptWord");

        filterConceptWords(criteria, includeRetired, filter);

        criteria.setProjection(Projections.countDistinct("concept"));

        Integer resultsCount = ((Number) criteria.uniqueResult()).intValue();
        if (incrementNeeded) {
            return resultsCount + 1;
        } else {
            return resultsCount;
        }
    }

    private void filterConceptWords(Criteria criteria, boolean includeRetired, String filter) {
        criteria.createAlias("concept", "concept");
        if (!includeRetired) {
            criteria.add(Restrictions.eq("concept.retired", includeRetired));
        }

        if (!StringUtils.isEmpty(filter)) {
            Iterator<String> words = ConceptWord.getUniqueWords(filter).iterator();
            if (words.hasNext()) {
                criteria.add(Restrictions.like("word", words.next(), MatchMode.START));
                while (words.hasNext()) {
                    DetachedCriteria crit = DetachedCriteria.forClass(ConceptWord.class)
                            .setProjection(Property.forName("concept"))
                            .add(Restrictions.eqProperty("concept", "conceptWord.concept"))
                            .add(Restrictions.like("word", words.next(), MatchMode.START));

                    criteria.add(Subqueries.exists(crit));
                }
            }
        }
    }

    /**
     * @see org.openmrs.module.metadatasharing.api.db.MetadataDAO#getItemById(Class, Integer)
     */
    @SuppressWarnings("unchecked")
    @Override
    public <T> T getItemById(Class<? extends T> type, Integer id) {
        return (T) sessionFactory.getCurrentSession().get(type, id);
    }

    /**
     * Tries to filter concept by given string, assuming that it's an ID
     * 
     * @param filter the filtering string for concept
     * @return concept object if there is matching item for given filter or null otherwise
     */
    private Concept filterById(String filter) {
        Concept concept = null;
        Integer conceptId = asItemId(filter);
        if (conceptId != null) {
            concept = (Concept) getItemById(Concept.class, conceptId);
        }
        return concept;
    }

    /**
     * Represents given filter as meta-data item's id
     * 
     * @param filter the filtering string to cast to
     * @return integer value of given filter if it can be cast to otherwise null
     */
    private Integer asItemId(String filter) {
        Integer itemId = null;
        try {
            itemId = Integer.parseInt(filter);
        } catch (NumberFormatException e) {
            // do nothing
        }
        return itemId;
    }
}