/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.api.db.hibernate; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.apache.commons.lang.StringUtils; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.MatchMode; import org.hibernate.criterion.Order; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.hibernate.criterion.Subqueries; import org.openmrs.Concept; import org.openmrs.EncounterType; import org.openmrs.Field; import org.openmrs.FieldAnswer; import org.openmrs.FieldType; import org.openmrs.Form; import org.openmrs.FormField; import org.openmrs.FormResource; import org.openmrs.api.APIException; import org.openmrs.api.db.DAOException; import org.openmrs.api.db.FormDAO; import org.openmrs.util.OpenmrsUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Hibernate-specific Form-related functions. This class should not be used directly. All calls * should go through the {@link org.openmrs.api.FormService} methods. * * @see org.openmrs.api.db.FormDAO * @see org.openmrs.api.FormService */ public class HibernateFormDAO implements FormDAO { protected final Logger log = LoggerFactory.getLogger(getClass()); /** * Hibernate session factory */ private SessionFactory sessionFactory; /** * Set session factory * * @param sessionFactory */ public void setSessionFactory(SessionFactory sessionFactory) { this.sessionFactory = sessionFactory; } /** * Returns the form object originally passed in, which will have been persisted. * * @see org.openmrs.api.FormService#createForm(org.openmrs.Form) */ @Override public Form saveForm(Form form) throws DAOException { sessionFactory.getCurrentSession().saveOrUpdate(form); return form; } /** * @see org.openmrs.api.FormService#duplicateForm(org.openmrs.Form) */ @Override public Form duplicateForm(Form form) throws DAOException { return (Form) sessionFactory.getCurrentSession().merge(form); } /** * @see org.openmrs.api.FormService#deleteForm(org.openmrs.Form) */ @Override public void deleteForm(Form form) throws DAOException { sessionFactory.getCurrentSession().delete(form); } /** * @see org.openmrs.api.FormService#getForm(java.lang.Integer) */ @Override public Form getForm(Integer formId) throws DAOException { return (Form) sessionFactory.getCurrentSession().get(Form.class, formId); } /** * @see org.openmrs.api.FormService#getFormFields(Form) */ @SuppressWarnings("unchecked") public List<FormField> getFormFields(Form form) throws DAOException { return sessionFactory.getCurrentSession().createCriteria(FormField.class, "ff") .add(Restrictions.eq("ff.form", form)).list(); } /** * @see org.openmrs.api.db.FormDAO#getFields(java.lang.String) */ @Override @SuppressWarnings("unchecked") public List<Field> getFields(String search) throws DAOException { Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Field.class); criteria.add(Restrictions.like("name", search, MatchMode.ANYWHERE)); criteria.addOrder(Order.asc("name")); return criteria.list(); } /** * @see org.openmrs.api.FormService#getFieldsByConcept(org.openmrs.Concept) */ @SuppressWarnings("unchecked") public List<Field> getFieldsByConcept(Concept concept) throws DAOException { Criteria criteria = sessionFactory.getCurrentSession().createCriteria(Field.class); criteria.add(Restrictions.eq("concept", concept)); criteria.addOrder(Order.asc("name")); return criteria.list(); } /** * @see org.openmrs.api.FormService#getField(java.lang.Integer) * @see org.openmrs.api.db.FormDAO#getField(java.lang.Integer) */ @Override public Field getField(Integer fieldId) throws DAOException { return (Field) sessionFactory.getCurrentSession().get(Field.class, fieldId); } /** * @see org.openmrs.api.FormService#getAllFields(boolean) * @see org.openmrs.api.db.FormDAO#getAllFields(boolean) */ @Override @SuppressWarnings("unchecked") public List<Field> getAllFields(boolean includeRetired) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Field.class); if (!includeRetired) { crit.add(Restrictions.eq("retired", false)); } return crit.list(); } /** * @see org.openmrs.api.FormService#getFieldType(java.lang.Integer) * @see org.openmrs.api.db.FormDAO#getFieldType(java.lang.Integer) */ @Override public FieldType getFieldType(Integer fieldTypeId) throws DAOException { return (FieldType) sessionFactory.getCurrentSession().get(FieldType.class, fieldTypeId); } /** * @see org.openmrs.api.FormService#getFieldTypes() * @see org.openmrs.api.db.FormDAO#getAllFieldTypes(boolean) */ @Override @SuppressWarnings("unchecked") public List<FieldType> getAllFieldTypes(boolean includeRetired) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(FieldType.class); if (!includeRetired) { crit.add(Restrictions.eq("retired", false)); } return crit.list(); } /** * @see org.openmrs.api.FormService#getFormField(java.lang.Integer) * @see org.openmrs.api.db.FormDAO#getFormField(java.lang.Integer) */ @Override public FormField getFormField(Integer formFieldId) throws DAOException { return (FormField) sessionFactory.getCurrentSession().get(FormField.class, formFieldId); } /** * @see org.openmrs.api.FormService#getFormField(org.openmrs.Form, org.openmrs.Concept, * java.util.Collection, boolean) * @see org.openmrs.api.db.FormDAO#getFormField(org.openmrs.Form, org.openmrs.Concept, * java.util.Collection, boolean) */ @Override @SuppressWarnings("unchecked") public FormField getFormField(Form form, Concept concept, Collection<FormField> ignoreFormFields, boolean force) throws DAOException { if (form == null) { log.debug("form is null, no fields will be matched"); return null; } Criteria crit = sessionFactory.getCurrentSession().createCriteria(FormField.class, "ff").createAlias("field", "field").add(Restrictions.eq("field.concept", concept)).add(Restrictions.eq("form", form)); // get the list of all formfields with this concept for this form List<FormField> formFields = crit.list(); String err = "FormField warning. No FormField matching concept '" + concept + "' for form '" + form + "'"; if (formFields.isEmpty()) { log.debug(err); return null; } // save the first formfield in case we're not a in a "force" situation FormField backupPlan = formFields.get(0); // remove the formfields we're supposed to ignore from the return list formFields.removeAll(ignoreFormFields); // if we ended up removing all of the formfields, check to see if we're // in a "force" situation if (formFields.isEmpty()) { if (!force) { return backupPlan; } else { log.debug(err); return null; } } else { // if formFields.size() is still greater than 0 FormField ff = (FormField) formFields.get(0); return ff; } } /** * @see org.openmrs.api.FormService#getForms() */ @Override @SuppressWarnings("unchecked") public List<Form> getAllForms(boolean includeRetired) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Form.class); if (!includeRetired) { crit.add(Restrictions.eq("retired", false)); } crit.addOrder(Order.asc("name")); crit.addOrder(Order.asc("formId")); return crit.list(); } /** * @see org.openmrs.api.db.FormDAO#getFormsContainingConcept(org.openmrs.Concept) */ @Override @SuppressWarnings("unchecked") public List<Form> getFormsContainingConcept(Concept c) throws DAOException { String q = "select distinct ff.form from FormField ff where ff.field.concept = :concept"; Query query = sessionFactory.getCurrentSession().createQuery(q); query.setEntity("concept", c); return query.list(); } /** * @see org.openmrs.api.FormService#saveField(org.openmrs.Field) * @see org.openmrs.api.db.FormDAO#saveField(org.openmrs.Field) */ @Override public Field saveField(Field field) throws DAOException { sessionFactory.getCurrentSession().saveOrUpdate(field); return field; } /** * @see org.openmrs.api.FormService#deleteField(org.openmrs.Field) * @see org.openmrs.api.db.FormDAO#deleteField(org.openmrs.Field) */ @Override public void deleteField(Field field) throws DAOException { sessionFactory.getCurrentSession().delete(field); } /** * @see org.openmrs.api.FormService#createFormField(org.openmrs.FormField) */ @Override public FormField saveFormField(FormField formField) throws DAOException { sessionFactory.getCurrentSession().saveOrUpdate(formField); return formField; } /** * @see org.openmrs.api.FormService#deleteFormField(org.openmrs.FormField) * @see org.openmrs.api.db.FormDAO#deleteFormField(org.openmrs.FormField) */ @Override public void deleteFormField(FormField formField) throws DAOException { sessionFactory.getCurrentSession().delete(formField); } /** * @see org.openmrs.api.db.FormDAO#getAllFormFields() */ @Override @SuppressWarnings("unchecked") public List<FormField> getAllFormFields() throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(FormField.class); return crit.list(); } /** * @see org.openmrs.api.db.FormDAO#getFields(java.util.Collection, java.util.Collection, * java.util.Collection, java.util.Collection, java.util.Collection, java.lang.Boolean, * java.util.Collection, java.util.Collection, java.lang.Boolean) */ @Override @SuppressWarnings("unchecked") public List<Field> getFields(Collection<Form> forms, Collection<FieldType> fieldTypes, Collection<Concept> concepts, Collection<String> tableNames, Collection<String> attributeNames, Boolean selectMultiple, Collection<FieldAnswer> containsAllAnswers, Collection<FieldAnswer> containsAnyAnswer, Boolean retired) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Field.class); if (!forms.isEmpty()) { crit.add(Restrictions.in("form", forms)); } if (!fieldTypes.isEmpty()) { crit.add(Restrictions.in("fieldType", fieldTypes)); } if (!concepts.isEmpty()) { crit.add(Restrictions.in("concept", concepts)); } if (!tableNames.isEmpty()) { crit.add(Restrictions.in("tableName", tableNames)); } if (!attributeNames.isEmpty()) { crit.add(Restrictions.in("attributeName", attributeNames)); } if (selectMultiple != null) { crit.add(Restrictions.eq("selectMultiple", selectMultiple)); } if (!containsAllAnswers.isEmpty()) { throw new APIException("Form.getFields.error", new Object[] { "containsAllAnswers" }); } if (!containsAnyAnswer.isEmpty()) { throw new APIException("Form.getFields.error", new Object[] { "containsAnyAnswer" }); } if (retired != null) { crit.add(Restrictions.eq("retired", retired)); } return crit.list(); } /** * @see org.openmrs.api.db.FormDAO#getForm(java.lang.String, java.lang.String) */ @Override public Form getForm(String name, String version) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Form.class); crit.add(Restrictions.eq("name", name)); crit.add(Restrictions.eq("version", version)); return (Form) crit.uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getForms(java.lang.String, java.lang.Boolean, * java.util.Collection, java.lang.Boolean, java.util.Collection, java.util.Collection, * java.util.Collection) */ @Override @SuppressWarnings("unchecked") public List<Form> getForms(String partialName, Boolean published, Collection<EncounterType> encounterTypes, Boolean retired, Collection<FormField> containingAnyFormField, Collection<FormField> containingAllFormFields, Collection<Field> fields) throws DAOException { Criteria crit = getFormCriteria(partialName, published, encounterTypes, retired, containingAnyFormField, containingAllFormFields, fields); return crit.list(); } /** * @see org.openmrs.api.db.FormDAO#getFormCount(java.lang.String, java.lang.Boolean, * java.util.Collection, java.lang.Boolean, java.util.Collection, java.util.Collection, * java.util.Collection) */ @Override public Integer getFormCount(String partialName, Boolean published, Collection<EncounterType> encounterTypes, Boolean retired, Collection<FormField> containingAnyFormField, Collection<FormField> containingAllFormFields, Collection<Field> fields) throws DAOException { Criteria crit = getFormCriteria(partialName, published, encounterTypes, retired, containingAnyFormField, containingAllFormFields, fields); crit.setProjection(Projections.count("formId")); return OpenmrsUtil.convertToInteger((Long) crit.uniqueResult()); } /** * Convenience method to create the same hibernate criteria object for both getForms and * getFormCount * * @param partialName * @param published * @param encounterTypes * @param retired * @param containingAnyFormField * @param containingAllFormFields * @param fields * @return */ private Criteria getFormCriteria(String partialName, Boolean published, Collection<EncounterType> encounterTypes, Boolean retired, Collection<FormField> containingAnyFormField, Collection<FormField> containingAllFormFields, Collection<Field> fields) { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Form.class, "form"); if (StringUtils.isNotEmpty(partialName)) { crit.add(Restrictions.or(Restrictions.like("name", partialName, MatchMode.START), Restrictions.like("name", " " + partialName, MatchMode.ANYWHERE))); } if (published != null) { crit.add(Restrictions.eq("published", published)); } if (!encounterTypes.isEmpty()) { crit.add(Restrictions.in("encounterType", encounterTypes)); } if (retired != null) { crit.add(Restrictions.eq("retired", retired)); } // TODO junit test if (!containingAnyFormField.isEmpty()) { // Convert form field persistents to integers Set<Integer> anyFormFieldIds = new HashSet<Integer>(); for (FormField ff : containingAnyFormField) { anyFormFieldIds.add(ff.getFormFieldId()); } DetachedCriteria subquery = DetachedCriteria.forClass(FormField.class, "ff"); subquery.setProjection(Projections.property("ff.form.formId")); subquery.add(Restrictions.in("ff.formFieldId", anyFormFieldIds)); crit.add(Subqueries.propertyIn("form.formId", subquery)); } //select * from form where len(containingallformfields) = (select count(*) from form_field ff where ff.form_id = form_id and form_field_id in (containingallformfields); if (!containingAllFormFields.isEmpty()) { // Convert form field persistents to integers Set<Integer> allFormFieldIds = new HashSet<Integer>(); for (FormField ff : containingAllFormFields) { allFormFieldIds.add(ff.getFormFieldId()); } DetachedCriteria subquery = DetachedCriteria.forClass(FormField.class, "ff"); subquery.setProjection(Projections.count("ff.formFieldId")); subquery.add(Restrictions.eqProperty("ff.form", "form")); subquery.add(Restrictions.in("ff.formFieldId", allFormFieldIds)); crit.add(Subqueries.eq(Long.valueOf(containingAllFormFields.size()), subquery)); } // get all forms (dupes included) that have this field on them if (!fields.isEmpty()) { Criteria crit2 = crit.createCriteria("formFields", "ff"); crit2.add(Restrictions.eqProperty("ff.form.formId", "form.formId")); crit2.add(Restrictions.in("ff.field", fields)); } return crit; } /** * @see org.openmrs.api.db.FormDAO#getFieldByUuid(java.lang.String) */ @Override public Field getFieldByUuid(String uuid) { return (Field) sessionFactory.getCurrentSession().createQuery("from Field f where f.uuid = :uuid").setString("uuid", uuid).uniqueResult(); } @Override public FieldAnswer getFieldAnswerByUuid(String uuid) { return (FieldAnswer) sessionFactory.getCurrentSession().createQuery("from FieldAnswer f where f.uuid = :uuid") .setString("uuid", uuid).uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFieldTypeByUuid(java.lang.String) */ @Override public FieldType getFieldTypeByUuid(String uuid) { return (FieldType) sessionFactory.getCurrentSession().createQuery("from FieldType ft where ft.uuid = :uuid") .setString("uuid", uuid).uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFieldTypeByName(java.lang.String) */ @Override public FieldType getFieldTypeByName(String name) { return (FieldType) sessionFactory.getCurrentSession().createQuery("from FieldType ft where ft.name = :name") .setString("name", name).uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFormByUuid(java.lang.String) */ @Override public Form getFormByUuid(String uuid) { return (Form) sessionFactory.getCurrentSession().createQuery("from Form f where f.uuid = :uuid").setString("uuid", uuid).uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFormFieldByUuid(java.lang.String) */ @Override public FormField getFormFieldByUuid(String uuid) { return (FormField) sessionFactory.getCurrentSession().createQuery("from FormField ff where ff.uuid = :uuid") .setString("uuid", uuid).uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFormsByName(java.lang.String) */ @Override @SuppressWarnings("unchecked") public List<Form> getFormsByName(String name) throws DAOException { Criteria crit = sessionFactory.getCurrentSession().createCriteria(Form.class); crit.add(Restrictions.eq("name", name)); crit.add(Restrictions.eq("retired", false)); crit.addOrder(Order.desc("version")); return crit.list(); } /** * @see org.openmrs.api.db.FormDAO#deleteFieldType(org.openmrs.FieldType) */ @Override public void deleteFieldType(FieldType fieldType) throws DAOException { sessionFactory.getCurrentSession().delete(fieldType); } /** * @see org.openmrs.api.db.FormDAO#saveFieldType(org.openmrs.FieldType) */ @Override public FieldType saveFieldType(FieldType fieldType) throws DAOException { sessionFactory.getCurrentSession().saveOrUpdate(fieldType); return fieldType; } /** * @see org.openmrs.api.db.FormDAO#getFormFieldsByField(Field) */ @Override @SuppressWarnings("unchecked") public List<FormField> getFormFieldsByField(Field field) { return sessionFactory.getCurrentSession().createQuery("from FormField f where f.field = :field").setEntity("field", field).list(); } /** * @see org.openmrs.api.db.FormDAO#getFormResource(java.lang.Integer) */ @Override public FormResource getFormResource(Integer formResourceId) { return (FormResource) sessionFactory.getCurrentSession().get(FormResource.class, formResourceId); } /** * @see org.openmrs.api.db.FormDAO#getFormResourceByUuid(java.lang.String) */ @Override public FormResource getFormResourceByUuid(String uuid) { Criteria crit = sessionFactory.getCurrentSession().createCriteria(FormResource.class).add( Restrictions.eq("uuid", uuid)); return (FormResource) crit.uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#getFormResource(org.openmrs.Form, java.lang.String) */ @Override public FormResource getFormResource(Form form, String name) { Criteria crit = sessionFactory.getCurrentSession().createCriteria(FormResource.class).add( Restrictions.and(Restrictions.eq("form", form), Restrictions.eq("name", name))); return (FormResource) crit.uniqueResult(); } /** * @see org.openmrs.api.db.FormDAO#saveFormResource(org.openmrs.FormResource) */ @Override public FormResource saveFormResource(FormResource formResource) { sessionFactory.getCurrentSession().saveOrUpdate(formResource); return formResource; } /** * @see org.openmrs.api.db.FormDAO#deleteFormResource(org.openmrs.FormResource) */ @Override public void deleteFormResource(FormResource formResource) { sessionFactory.getCurrentSession().delete(formResource); } /** * @see org.openmrs.api.db.FormDAO#getFormResourcesForForm(org.openmrs.Form) */ @Override public Collection<FormResource> getFormResourcesForForm(Form form) { Criteria crit = sessionFactory.getCurrentSession().createCriteria(FormResource.class).add( Restrictions.eq("form", form)); return crit.list(); } }