/**
* 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.api.db.hibernate;
import java.util.Date;
import java.util.List;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Expression;
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.openmrs.Concept;
import org.openmrs.ConceptName;
import org.openmrs.Encounter;
import org.openmrs.Location;
import org.openmrs.MimeType;
import org.openmrs.Obs;
import org.openmrs.Patient;
import org.openmrs.Person;
import org.openmrs.User;
import org.openmrs.api.db.DAOException;
import org.openmrs.api.db.ObsDAO;
import org.openmrs.util.OpenmrsConstants.PERSON_TYPE;
/**
* Hibernate specific Observation related functions This class should not be used directly. All
* calls should go through the {@link org.openmrs.api.ObsService} methods.
*
* @see org.openmrs.api.db.ObsDAO
* @see org.openmrs.api.ObsService
*/
public class HibernateObsDAO implements ObsDAO {
protected final Log log = LogFactory.getLog(getClass());
protected SessionFactory sessionFactory;
/**
* Set session factory that allows us to connect to the database that Hibernate knows about.
*
* @param sessionFactory
*/
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
/**
* @see org.openmrs.api.ObsService#deleteObs(org.openmrs.Obs)
*/
public void deleteObs(Obs obs) throws DAOException {
sessionFactory.getCurrentSession().delete(obs);
}
/**
* @see org.openmrs.api.ObsService#getObs(java.lang.Integer)
*/
public Obs getObs(Integer obsId) throws DAOException {
return (Obs) sessionFactory.getCurrentSession().get(Obs.class, obsId);
}
/**
* @see org.openmrs.api.db.ObsDAO#getMimeType(java.lang.Integer)
* @deprecated
*/
@Deprecated
public MimeType getMimeType(Integer mimeTypeId) throws DAOException {
return (MimeType) sessionFactory.getCurrentSession().get(MimeType.class, mimeTypeId);
}
/**
* @see org.openmrs.api.db.ObsDAO#getAllMimeTypes(boolean)
* @deprecated
*/
@Deprecated
@SuppressWarnings("unchecked")
public List<MimeType> getAllMimeTypes(boolean includeRetired) throws DAOException {
Criteria crit = sessionFactory.getCurrentSession().createCriteria(MimeType.class);
if (includeRetired == false)
crit.add(Expression.eq("retired", Boolean.FALSE));
return crit.list();
}
/**
* @see org.openmrs.api.db.ObsDAO#saveMimeType(org.openmrs.MimeType)
* @deprecated
*/
@Deprecated
public MimeType saveMimeType(MimeType mimeType) throws DAOException {
sessionFactory.getCurrentSession().saveOrUpdate(mimeType);
return mimeType;
}
/**
* @see org.openmrs.api.db.ObsDAO#deleteMimeType(org.openmrs.MimeType)
* @deprecated
*/
@Deprecated
public void deleteMimeType(MimeType mimeType) throws DAOException {
sessionFactory.getCurrentSession().delete(mimeType);
}
/**
* @see org.openmrs.api.db.ObsDAO#saveObs(org.openmrs.Obs)
*/
public Obs saveObs(Obs obs) throws DAOException {
if (obs.hasGroupMembers() && obs.getObsId() != null) {
// hibernate has a problem updating child collections
// if the parent object was already saved so we do it
// explicitly here
for (Obs member : obs.getGroupMembers())
if (member.getObsId() == null)
saveObs(member);
}
sessionFactory.getCurrentSession().saveOrUpdate(obs);
return obs;
}
/**
* @see org.openmrs.api.db.ObsDAO#getObservations(List, List, List, List, List, List, List,
* Integer, Integer, Date, Date, boolean)
*/
@SuppressWarnings("unchecked")
public List<Obs> getObservations(List<Person> whom, List<Encounter> encounters, List<Concept> questions,
List<Concept> answers, List<PERSON_TYPE> personTypes, List<Location> locations, List<String> sortList,
Integer mostRecentN, Integer obsGroupId, Date fromDate, Date toDate, boolean includeVoidedObs)
throws DAOException {
Criteria criteria = createGetObservationsCriteria(whom, encounters, questions, answers, personTypes, locations,
sortList, mostRecentN, obsGroupId, fromDate, toDate, null, includeVoidedObs);
return criteria.list();
}
/**
* @see org.openmrs.api.db.ObsDAO#getObservationCount(java.util.List, java.util.List,
* java.util.List, java.util.List, java.util.List, java.util.List, java.lang.Integer,
* java.util.Date, java.util.Date, boolean)
*/
public Long getObservationCount(List<Person> whom, List<Encounter> encounters, List<Concept> questions,
List<Concept> answers, List<PERSON_TYPE> personTypes, List<Location> locations, Integer obsGroupId,
Date fromDate, Date toDate, List<ConceptName> valueCodedNameAnswers, boolean includeVoidedObs)
throws DAOException {
Criteria criteria = createGetObservationsCriteria(whom, encounters, questions, answers, personTypes, locations,
null, null, obsGroupId, fromDate, toDate, valueCodedNameAnswers, includeVoidedObs);
criteria.setProjection(Projections.rowCount());
return (Long) criteria.list().get(0);
}
/**
* A utility method for creating a criteria based on parameters (which are optional)
*
* @param whom
* @param encounters
* @param questions
* @param answers
* @param personTypes
* @param locations
* @param sortList
* @param mostRecentN
* @param obsGroupId
* @param fromDate
* @param toDate
* @param includeVoidedObs
* @return
*/
private Criteria createGetObservationsCriteria(List<Person> whom, List<Encounter> encounters, List<Concept> questions,
List<Concept> answers, List<PERSON_TYPE> personTypes, List<Location> locations, List<String> sortList,
Integer mostRecentN, Integer obsGroupId, Date fromDate, Date toDate, List<ConceptName> valueCodedNameAnswers,
boolean includeVoidedObs) {
Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Obs.class, "obs");
if (CollectionUtils.isNotEmpty(whom))
criteria.add(Restrictions.in("person", whom));
if (CollectionUtils.isNotEmpty(encounters))
criteria.add(Restrictions.in("encounter", encounters));
if (CollectionUtils.isNotEmpty(questions))
criteria.add(Restrictions.in("concept", questions));
if (CollectionUtils.isNotEmpty(answers))
criteria.add(Restrictions.in("valueCoded", answers));
if (CollectionUtils.isNotEmpty(personTypes))
getCriteriaPersonModifier(criteria, personTypes);
if (CollectionUtils.isNotEmpty(locations))
criteria.add(Restrictions.in("location", locations));
// TODO add an option for each sort item to be asc/desc
if (CollectionUtils.isNotEmpty(sortList)) {
for (String sort : sortList) {
if (sort != null && !"".equals(sort))
criteria.addOrder(Order.desc(sort));
}
}
if (mostRecentN != null && mostRecentN > 0)
criteria.setMaxResults(mostRecentN);
if (obsGroupId != null) {
criteria.createAlias("obsGroup", "og");
criteria.add(Restrictions.eq("og.obsId", obsGroupId));
}
if (fromDate != null)
criteria.add(Restrictions.ge("obsDatetime", fromDate));
if (toDate != null)
criteria.add(Restrictions.le("obsDatetime", toDate));
if (CollectionUtils.isNotEmpty(valueCodedNameAnswers))
criteria.add(Restrictions.in("valueCodedName", valueCodedNameAnswers));
if (includeVoidedObs == false)
criteria.add(Restrictions.eq("voided", false));
return criteria;
}
/**
* Convenience method that adds an expression to the given <code>criteria</code> according to
* what types of person objects is wanted
*
* @param criteria
* @param personType
* @return the given criteria (for chaining)
*/
private Criteria getCriteriaPersonModifier(Criteria criteria, List<PERSON_TYPE> personTypes) {
if (personTypes.contains(PERSON_TYPE.PATIENT)) {
DetachedCriteria crit = DetachedCriteria.forClass(Patient.class, "patient").setProjection(
Property.forName("patientId"));
criteria.add(Subqueries.propertyIn("person.personId", crit));
}
if (personTypes.contains(PERSON_TYPE.USER)) {
DetachedCriteria crit = DetachedCriteria.forClass(User.class, "user").setProjection(Property.forName("userId"));
criteria.add(Subqueries.propertyIn("person.personId", crit));
}
if (personTypes.contains(PERSON_TYPE.PERSON)) {
// all observations are already on person's. Limit to non-patient and non-users here?
//criteria.createAlias("Person", "person");
//criteria.add(Restrictions.eqProperty("obs.person.personId", "person.personId"));
}
return criteria;
}
/**
* @see org.openmrs.api.db.ObsDAO#getObsByUuid(java.lang.String)
*/
public Obs getObsByUuid(String uuid) {
return (Obs) sessionFactory.getCurrentSession().createQuery("from Obs o where o.uuid = :uuid").setString("uuid",
uuid).uniqueResult();
}
}