### Eclipse Workspace Patch 1.0 #P org.openmrs-1.9 Index: api/src/test/java/org/openmrs/BaseCustomizableMetadataTest.java =================================================================== --- api/src/test/java/org/openmrs/BaseCustomizableMetadataTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/BaseCustomizableMetadataTest.java (kopia robocza) @@ -62,7 +62,7 @@ throws Exception { ProviderAttribute providerAttribute = new ProviderAttribute(); providerAttribute.setAttributeType(providerAttributeType); - providerAttribute.setValueReference(value.toString()); + providerAttribute.setValueReferenceInternal(value.toString()); return providerAttribute; } } Index: web/src/test/java/org/openmrs/web/dwr/DWRConceptServiceTest.java =================================================================== --- web/src/test/java/org/openmrs/web/dwr/DWRConceptServiceTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/dwr/DWRConceptServiceTest.java (kopia robocza) @@ -1,23 +1,24 @@ -package org.openmrs.web.dwr; - -import org.junit.Before; -import org.junit.Test; -import org.openmrs.test.BaseContextSensitiveTest; - -public class DWRConceptServiceTest extends BaseContextSensitiveTest { - - @Before - public void before() throws Exception { - executeDataSet("org/openmrs/web/dwr/include/DWRConceptServiceTest-coded-concept-with-no-answers.xml"); - } - - /** - * @see DWRConceptService#findConceptAnswers(String,Integer,boolean,boolean) - * @verifies not fail if the specified concept has no answers (regression test for TRUNK-2807) - */ - @Test - public void findConceptAnswers_shouldNotFailIfTheSpecifiedConceptHasNoAnswersRegressionTestForTRUNK2807() throws Exception { - new DWRConceptService().findConceptAnswers("", 1000, false, true); - // if we got here, we've passed, because we didn't get a NullPointerException - } -} \ No newline at end of file +package org.openmrs.web.dwr; + +import org.junit.Before; +import org.junit.Test; +import org.openmrs.test.BaseContextSensitiveTest; + +public class DWRConceptServiceTest extends BaseContextSensitiveTest { + + @Before + public void before() throws Exception { + executeDataSet("org/openmrs/web/dwr/include/DWRConceptServiceTest-coded-concept-with-no-answers.xml"); + } + + /** + * @see DWRConceptService#findConceptAnswers(String,Integer,boolean,boolean) + * @verifies not fail if the specified concept has no answers (regression test for TRUNK-2807) + */ + @Test + public void findConceptAnswers_shouldNotFailIfTheSpecifiedConceptHasNoAnswersRegressionTestForTRUNK2807() + throws Exception { + new DWRConceptService().findConceptAnswers("", 1000, false, true); + // if we got here, we've passed, because we didn't get a NullPointerException + } +} Index: api/src/test/java/org/openmrs/api/FormServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/FormServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/FormServiceTest.java (kopia robocza) @@ -474,6 +474,7 @@ executeDataSet(FORM_FIELDS_XML); Context.getFormService().mergeDuplicateFields(); + Context.flushSession(); // duplicateField should no longer be referenced Assert.assertNull(Context.getFormService().getFieldByUuid("b1843148-da2f-4349-c9c7-1164b98d91dd")); Index: api/src/test/java/org/openmrs/api/ActiveListServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/ActiveListServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/ActiveListServiceTest.java (kopia robocza) @@ -131,6 +131,7 @@ public void should_voidActiveListItem_Allergy() throws Exception { Allergy item = activeListService.getActiveListItem(Allergy.class, 1); item = (Allergy) activeListService.voidActiveListItem(item, "Because"); + Context.flushSession(); Assert.assertTrue(item.isVoided()); Patient p = patientService.getPatient(2); Index: api/src/main/java/org/openmrs/api/db/hibernate/HibernateProviderDAO.java =================================================================== --- api/src/main/java/org/openmrs/api/db/hibernate/HibernateProviderDAO.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/db/hibernate/HibernateProviderDAO.java (kopia robocza) @@ -35,6 +35,8 @@ import org.openmrs.ProviderAttributeType; import org.openmrs.api.db.DAOException; import org.openmrs.api.db.ProviderDAO; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; /** * Hibernate specific Provider related functions. This class should not be used directly. All calls Index: api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java =================================================================== --- api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java (wersja 24555) +++ api/src/main/java/org/openmrs/aop/RequiredDataAdvice.java (kopia robocza) @@ -146,6 +146,7 @@ } + Context.getAdministrationService().validateInNewTransaction(mainArgument); } else { // fail early if the method name is not like retirePatient or retireConcept when dealing // with Patients or Concepts as the first argument @@ -175,20 +176,16 @@ null, null); } } + } /** - * Convenience method to change the given method to make sure it ends with - * the given class name.
+ * Convenience method to change the given method to make sure it ends with the given class name.
* This will recurse to the super class to check that as well. * - * @param method - * the method name (like savePatient, voidEncounter, - * retireConcept) - * @param mainArgumentClass - * class to compare - * @return true if method's name ends with the mainArgumentClasses simple - * name + * @param method the method name (like savePatient, voidEncounter, retireConcept) + * @param mainArgumentClass class to compare + * @return true if method's name ends with the mainArgumentClasses simple name */ private boolean methodNameEndsWithClassName(Method method, Class mainArgumentClass) { if (method.getName().endsWith(mainArgumentClass.getSimpleName())) Index: api/src/main/java/org/openmrs/api/VisitService.java =================================================================== --- api/src/main/java/org/openmrs/api/VisitService.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/VisitService.java (kopia robocza) @@ -34,7 +34,6 @@ * * @since 1.9 */ -@Transactional public interface VisitService extends OpenmrsService { /** @@ -43,7 +42,6 @@ * @return a list of visit type objects. * @should get all visit types */ - @Transactional(readOnly = true) @Authorized( { PrivilegeConstants.VIEW_VISIT_TYPES }) List getAllVisitTypes(); @@ -54,7 +52,6 @@ * @return the visit type object found with the given id, else null. * @should get correct visit type */ - @Transactional(readOnly = true) @Authorized( { PrivilegeConstants.VIEW_VISIT_TYPES }) VisitType getVisitType(Integer visitTypeId); @@ -65,7 +62,6 @@ * @return the visit type object found with the given uuid, else null. * @should get correct visit type */ - @Transactional(readOnly = true) @Authorized( { PrivilegeConstants.VIEW_VISIT_TYPES }) VisitType getVisitTypeByUuid(String uuid); @@ -76,7 +72,6 @@ * @return a list of all visit types with names similar to or containing the given phrase * @should get correct visit types */ - @Transactional(readOnly = true) @Authorized( { PrivilegeConstants.VIEW_VISIT_TYPES }) List getVisitTypes(String fuzzySearchPhrase); @@ -130,7 +125,6 @@ * @throws APIException * @should return all unvoided visits */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public List getAllVisits() throws APIException; @@ -141,7 +135,6 @@ * @return the visit object found with the given id, else null. * @throws APIException */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public Visit getVisit(Integer visitId) throws APIException; @@ -153,7 +146,6 @@ * @throws APIException * @should return a visit matching the specified uuid */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public Visit getVisitByUuid(String uuid) throws APIException; @@ -245,7 +237,6 @@ * @should get all visits with given attribute values * @should not find any visits if none have given attribute values */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public List getVisits(Collection visitTypes, Collection patients, Collection locations, Collection indications, Date minStartDatetime, Date maxStartDatetime, @@ -260,7 +251,6 @@ * @throws APIException * @should return all unvoided visits for the specified patient */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public List getVisitsByPatient(Patient patient) throws APIException; @@ -271,7 +261,6 @@ * @return a list of visits * @throws APIException */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public List getActiveVisitsByPatient(Patient patient) throws APIException; @@ -287,7 +276,6 @@ * @should return all unvoided visits for the specified patient * @should return all active visits for the specified patient */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) public List getVisitsByPatient(Patient patient, boolean includeInactive, boolean includeVoided) throws APIException; @@ -296,7 +284,6 @@ * @return all {@link VisitAttributeType}s * @should return all visit attribute types including retired ones */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISIT_ATTRIBUTE_TYPES) List getAllVisitAttributeTypes(); @@ -306,7 +293,6 @@ * @should return the visit attribute type with the given id * @should return null if no visit attribute type exists with the given id */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISIT_ATTRIBUTE_TYPES) VisitAttributeType getVisitAttributeType(Integer id); @@ -316,7 +302,6 @@ * @should return the visit attribute type with the given uuid * @should return null if no visit attribute type exists with the given uuid */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISIT_ATTRIBUTE_TYPES) VisitAttributeType getVisitAttributeTypeByUuid(String uuid); @@ -366,7 +351,6 @@ * @should get the visit attribute with the given uuid * @should return null if no visit attribute has the given uuid */ - @Transactional(readOnly = true) @Authorized(PrivilegeConstants.VIEW_VISITS) VisitAttribute getVisitAttributeByUuid(String uuid); Index: api/src/test/java/org/openmrs/api/ProviderServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/ProviderServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/ProviderServiceTest.java (kopia robocza) @@ -259,6 +259,7 @@ public void purgeProvider_shouldDeleteAProvider() throws Exception { Provider provider = service.getProvider(2); service.purgeProvider(provider); + Context.flushSession(); assertEquals(7, Context.getProviderService().getAllProviders().size()); } @@ -271,6 +272,7 @@ int size = service.getAllProviderAttributeTypes().size(); ProviderAttributeType providerAttributeType = service.getProviderAttributeType(2); service.purgeProviderAttributeType(providerAttributeType); + Context.flushSession(); assertEquals(size - 1, service.getAllProviderAttributeTypes().size()); } @@ -284,6 +286,7 @@ assertFalse(provider.isRetired()); assertNull(provider.getRetireReason()); service.retireProvider(provider, "retire reason"); + Context.flushSession(); assertTrue(provider.isRetired()); assertEquals("retire reason", provider.getRetireReason()); assertEquals(6, service.getAllProviders(false).size()); @@ -300,6 +303,7 @@ assertNull(providerAttributeType.getRetireReason()); assertEquals(2, service.getAllProviderAttributeTypes(false).size()); service.retireProviderAttributeType(providerAttributeType, "retire reason"); + Context.flushSession(); assertTrue(providerAttributeType.isRetired()); assertEquals("retire reason", providerAttributeType.getRetireReason()); assertEquals(1, service.getAllProviderAttributeTypes(false).size()); @@ -469,6 +473,7 @@ Provider existingProviderToEdit = service.getProvider(1); existingProviderToEdit.setIdentifier(duplicateProvider.getIdentifier()); + Context.flushSession(); Assert.assertFalse(service.isProviderIdentifierUnique(duplicateProvider)); } } Index: api/src/test/java/org/openmrs/api/LocationServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/LocationServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/LocationServiceTest.java (kopia robocza) @@ -140,16 +140,19 @@ // First, create a new Location Location location = new Location(); location.setName("parent"); + location.setDescription("is the parent"); ls.saveLocation(location); // Now add a child location to it Location childA = new Location(); childA.setName("level A child"); + childA.setDescription("is a child"); location.addChildLocation(childA); // Add a new child location to the first child location Location childB = new Location(); childB.setName("level B child"); + childB.setDescription("is a child"); childA.addChildLocation(childB); ls.saveLocation(location); @@ -215,6 +218,7 @@ GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCATION_NAME, "Test Parent Location", "Testing default Location"); Context.getAdministrationService().saveGlobalProperty(gp); + Context.flushSession(); Assert.assertEquals("Test Parent Location", Context.getLocationService().getDefaultLocation().getName()); } @@ -587,6 +591,7 @@ // First, create a new Location Location location = new Location(); location.setName("name"); + location.setDescription("is a location"); ls.saveLocation(location); // Create a tag @@ -623,6 +628,7 @@ // First, create a new Location Location location = new Location(); location.setName("name"); + location.setDescription("is a location"); // Add a transient tag with an existing name location.addTag(new LocationTag("General Hospital", null)); @@ -971,6 +977,7 @@ LocationService ls = Context.getLocationService(); //retire the first location ls.retireLocation(ls.getAllLocations().get(0), "Just Testing"); + Context.flushSession(); // Get all locations. List locations = ls.getAllLocations(); //The 2 retired locations should be always be at the end @@ -1041,6 +1048,7 @@ executeDataSet(LOC_ATTRIBUTE_DATA_XML); Assert.assertEquals(2, Context.getLocationService().getAllLocationAttributeTypes().size()); Context.getLocationService().purgeLocationAttributeType(Context.getLocationService().getLocationAttributeType(2)); + Context.flushSession(); Assert.assertEquals(1, Context.getLocationService().getAllLocationAttributeTypes().size()); } Index: web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormControllerTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormControllerTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormControllerTest.java (kopia robocza) @@ -182,6 +182,7 @@ Patient p = Context.getPatientService().getPatient(7); p.getPersonName().setVoided(true); Context.getPatientService().savePatient(p); + Context.flushSession(); Assert.assertNull(p.getPersonName());// make sure all names are voided // add a name that will used as a duplicate for testing purposes @@ -197,6 +198,7 @@ .getBean("shortPatientFormController"); String redirectUrl = controller.saveShortPatient(mockWebRequest, new PersonName(), (PersonAddress) p .getPersonAddress().clone(), patientModel, errors); + Context.flushSession(); Assert.assertTrue("Should pass with no validation errors", !errors.hasErrors()); Assert.assertEquals("redirect:/patientDashboard.form?patientId=" + p.getPatientId(), redirectUrl); @@ -250,6 +252,7 @@ Patient p = Context.getPatientService().getPatient(2); p.getPersonAddress().setVoided(true); Context.getPatientService().savePatient(p); + Context.flushSession(); Assert.assertNull(p.getPersonAddress());// make sure all addresses are // voided @@ -267,6 +270,7 @@ .getBean("shortPatientFormController"); String redirectUrl = controller.saveShortPatient(mockWebRequest, (PersonName) BeanUtils.cloneBean(p.getPersonName()), new PersonAddress(), patientModel, errors); + Context.flushSession(); Assert.assertTrue("Should pass with no validation errors", !errors.hasErrors()); Assert.assertEquals("redirect:/patientDashboard.form?patientId=" + p.getPatientId(), redirectUrl); @@ -338,6 +342,8 @@ "personNameCache", WebRequest.SCOPE_SESSION), (PersonAddress) mockWebRequest.getAttribute("personAddressCache", WebRequest.SCOPE_SESSION), (ShortPatientModel) mockWebRequest.getAttribute("patientModel", WebRequest.SCOPE_SESSION), errors); + Context.flushSession(); + Assert.assertTrue("Should pass with no validation errors", !errors.hasErrors()); Assert.assertEquals("Patient.saved", mockWebRequest.getAttribute(WebConstants.OPENMRS_MSG_ATTR, @@ -398,6 +404,7 @@ gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_VIEWING_ATTRIBUTES); gp.setPropertyValue(pat.getName()); as.saveGlobalProperty(gp); + Context.flushSession(); Patient p = Context.getPatientService().getPatient(2); int originalActiveAttributeCount = p.getActiveAttributes().size(); @@ -432,6 +439,7 @@ WebRequest.SCOPE_SESSION), (PersonAddress) mockWebRequest.getAttribute("personAddressCache", WebRequest.SCOPE_SESSION), (ShortPatientModel) mockWebRequest.getAttribute("patientModel", WebRequest.SCOPE_SESSION), errors); + Context.flushSession(); Assert.assertTrue("Should pass with no validation errors", !errors.hasErrors()); Assert.assertEquals("Patient.saved", mockWebRequest.getAttribute(WebConstants.OPENMRS_MSG_ATTR, @@ -456,6 +464,7 @@ gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_VIEWING_ATTRIBUTES); gp.setPropertyValue(pat.getName()); as.saveGlobalProperty(gp); + Context.flushSession(); Patient p = Context.getPatientService().getPatient(2); int originalAttributeCount = p.getAttributes().size(); @@ -490,6 +499,7 @@ WebRequest.SCOPE_SESSION), (PersonAddress) mockWebRequest.getAttribute("personAddressCache", WebRequest.SCOPE_SESSION), (ShortPatientModel) mockWebRequest.getAttribute("patientModel", WebRequest.SCOPE_SESSION), errors); + Context.flushSession(); Assert.assertTrue("Should pass with no validation errors", !errors.hasErrors()); Assert.assertEquals("Patient.saved", mockWebRequest.getAttribute(WebConstants.OPENMRS_MSG_ATTR, Index: api/src/main/java/org/openmrs/api/impl/PatientServiceImpl.java =================================================================== --- api/src/main/java/org/openmrs/api/impl/PatientServiceImpl.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/impl/PatientServiceImpl.java (kopia robocza) @@ -911,6 +911,8 @@ personService.voidPerson(notPreferred, "The patient corresponding to this person has been voided and Merged with patient #" + preferred.getPatientId()); + Context.flushSession(); + // associate the Users associated with the not preferred person, to the preferred person. changeUserAssociations(preferred, notPreferred, mergedData); Index: api/src/main/java/org/openmrs/customdatatype/datatype/BooleanDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/datatype/BooleanDatatype.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/datatype/BooleanDatatype.java (kopia robocza) @@ -14,67 +14,33 @@ package org.openmrs.customdatatype.datatype; import org.apache.commons.lang.StringUtils; -import org.openmrs.customdatatype.CustomDatatype; -import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.SerializingCustomDatatype; import org.springframework.stereotype.Component; /** - * Datatype for boolean, represented by java.lang.Boolean. + * Datatype for boolean, represented by Boolean. + * * @since 1.9 */ @Component -public class BooleanDatatype implements CustomDatatype { +public class BooleanDatatype extends SerializingCustomDatatype { /** - * @see org.openmrs.customdatatype.CustomDatatype#setConfiguration(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#serialize(java.lang.Object) */ @Override - public void setConfiguration(String config) { - // not used - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#toReferenceString(java.lang.Object) - */ - @Override - public String toReferenceString(Boolean typedValue) throws InvalidCustomValueException { + public String serialize(java.lang.Boolean typedValue) { return typedValue.toString(); } /** - * @see org.openmrs.customdatatype.CustomDatatype#fromReferenceString(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#deserialize(java.lang.String) */ @Override - public Boolean fromReferenceString(String persistedValue) throws InvalidCustomValueException { - if (StringUtils.isEmpty(persistedValue)) + public Boolean deserialize(String serializedValue) { + if (StringUtils.isEmpty(serializedValue)) return null; - return Boolean.valueOf(persistedValue); + return Boolean.valueOf(serializedValue); } - /** - * @see org.openmrs.customdatatype.CustomDatatype#render(java.lang.String, java.lang.String) - */ - @Override - public String render(String referenceString, String view) { - return referenceString; - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validateReferenceString(java.lang.String) - */ - @Override - public void validateReferenceString(String persistedValue) throws InvalidCustomValueException { - if (!(persistedValue == null || "".equals(persistedValue) || "true".equals(persistedValue) || "false" - .equals(persistedValue))) - throw new InvalidCustomValueException("Must be \"true\" or \"false\""); - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validate(java.lang.Object) - */ - @Override - public void validate(Boolean typedValue) throws InvalidCustomValueException { - // any java.lang.Boolean is legal - } - } Index: api/src/test/java/org/openmrs/api/handler/PersonVoidHandlerTest.java =================================================================== --- api/src/test/java/org/openmrs/api/handler/PersonVoidHandlerTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/handler/PersonVoidHandlerTest.java (kopia robocza) @@ -139,6 +139,7 @@ //when handler.handle(person, null, null, "reason"); + Context.flushSession(); //then Assert.assertTrue(Context.getUserService().getUsersByPerson(person, false).isEmpty()); Index: api/src/main/java/org/openmrs/api/db/hibernate/HibernateVisitDAO.java =================================================================== --- api/src/main/java/org/openmrs/api/db/hibernate/HibernateVisitDAO.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/db/hibernate/HibernateVisitDAO.java (kopia robocza) @@ -36,6 +36,8 @@ import org.openmrs.api.db.DAOException; import org.openmrs.api.db.VisitDAO; import org.openmrs.attribute.AttributeType; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; /** * Hibernate specific visit related functions This class should not be used directly. All calls @@ -59,6 +61,7 @@ * @see org.openmrs.api.db.VisitDAO#getAllVisitTypes() */ @SuppressWarnings("unchecked") + @Transactional(readOnly = true) public List getAllVisitTypes() throws APIException { return getCurrentSession().createCriteria(VisitType.class).list(); } @@ -66,6 +69,7 @@ /** * @see org.openmrs.api.db.VisitDAO#getVisitType(java.lang.Integer) */ + @Transactional(readOnly = true) public VisitType getVisitType(Integer visitTypeId) { return (VisitType) sessionFactory.getCurrentSession().get(VisitType.class, visitTypeId); } @@ -73,6 +77,7 @@ /** * @see org.openmrs.api.db.VisitDAO#getVisitTypeByUuid(java.lang.String) */ + @Transactional(readOnly = true) public VisitType getVisitTypeByUuid(String uuid) { return (VisitType) sessionFactory.getCurrentSession().createQuery("from VisitType vt where vt.uuid = :uuid") .setString("uuid", uuid).uniqueResult(); @@ -82,6 +87,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisitTypes(java.lang.String) */ @SuppressWarnings("unchecked") + @Transactional(readOnly = true) public List getVisitTypes(String fuzzySearchPhrase) { Criteria criteria = sessionFactory.getCurrentSession().createCriteria(VisitType.class); criteria.add(Restrictions.ilike("name", fuzzySearchPhrase, MatchMode.ANYWHERE)); @@ -92,6 +98,7 @@ /** * @see org.openmrs.api.db.VisitDAO#saveVisitType(org.openmrs.VisitType) */ + @Transactional public VisitType saveVisitType(VisitType visitType) { sessionFactory.getCurrentSession().saveOrUpdate(visitType); return visitType; @@ -100,6 +107,7 @@ /** * @see org.openmrs.api.db.VisitDAO#purgeVisitType(org.openmrs.VisitType) */ + @Transactional public void purgeVisitType(VisitType visitType) { sessionFactory.getCurrentSession().delete(visitType); } @@ -108,6 +116,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisit(java.lang.Integer) */ @Override + @Transactional(readOnly = true) public Visit getVisit(Integer visitId) throws DAOException { return (Visit) getCurrentSession().get(Visit.class, visitId); } @@ -116,6 +125,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisitByUuid(java.lang.String) */ @Override + @Transactional(readOnly = true) public Visit getVisitByUuid(String uuid) throws DAOException { return (Visit) getCurrentSession().createQuery("from Visit v where v.uuid = :uuid").setString("uuid", uuid) .uniqueResult(); @@ -125,6 +135,7 @@ * @see org.openmrs.api.db.VisitDAO#saveVisit(org.openmrs.Visit) */ @Override + @Transactional public Visit saveVisit(Visit visit) throws DAOException { getCurrentSession().saveOrUpdate(visit); return visit; @@ -134,6 +145,7 @@ * @see org.openmrs.api.db.VisitDAO#deleteVisit(org.openmrs.Visit) */ @Override + @Transactional public void deleteVisit(Visit visit) throws DAOException { getCurrentSession().delete(visit); } @@ -143,6 +155,7 @@ */ @SuppressWarnings("unchecked") @Override + @Transactional(readOnly = true) public List getVisits(Collection visitTypes, Collection patients, Collection locations, Collection indications, Date minStartDatetime, Date maxStartDatetime, Date minEndDatetime, Date maxEndDatetime, final Map serializedAttributeValues, @@ -196,6 +209,7 @@ */ @SuppressWarnings("unchecked") @Override + @Transactional(readOnly = true) public List getAllVisitAttributeTypes() { return getCurrentSession().createCriteria(VisitAttributeType.class).list(); } @@ -204,6 +218,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisitAttributeType(java.lang.Integer) */ @Override + @Transactional(readOnly = true) public VisitAttributeType getVisitAttributeType(Integer id) { return (VisitAttributeType) getCurrentSession().get(VisitAttributeType.class, id); } @@ -212,6 +227,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisitAttributeTypeByUuid(java.lang.String) */ @Override + @Transactional(readOnly = true) public VisitAttributeType getVisitAttributeTypeByUuid(String uuid) { return (VisitAttributeType) getCurrentSession().createCriteria(VisitAttributeType.class).add( Restrictions.eq("uuid", uuid)).uniqueResult(); @@ -221,6 +237,7 @@ * @see org.openmrs.api.db.VisitDAO#saveVisitAttributeType(org.openmrs.VisitAttributeType) */ @Override + @Transactional public VisitAttributeType saveVisitAttributeType(VisitAttributeType visitAttributeType) { getCurrentSession().saveOrUpdate(visitAttributeType); return visitAttributeType; @@ -230,6 +247,7 @@ * @see org.openmrs.api.db.VisitDAO#deleteVisitAttributeType(org.openmrs.VisitAttributeType) */ @Override + @Transactional public void deleteVisitAttributeType(VisitAttributeType visitAttributeType) { getCurrentSession().delete(visitAttributeType); } @@ -238,6 +256,7 @@ * @see org.openmrs.api.db.VisitDAO#getVisitAttributeByUuid(java.lang.String) */ @Override + @Transactional(readOnly = true) public VisitAttribute getVisitAttributeByUuid(String uuid) { return (VisitAttribute) getCurrentSession().createCriteria(VisitAttribute.class).add(Restrictions.eq("uuid", uuid)) .uniqueResult(); Index: web/src/test/java/org/openmrs/web/dwr/include/DWRConceptServiceTest-coded-concept-with-no-answers.xml =================================================================== --- web/src/test/java/org/openmrs/web/dwr/include/DWRConceptServiceTest-coded-concept-with-no-answers.xml (wersja 24555) +++ web/src/test/java/org/openmrs/web/dwr/include/DWRConceptServiceTest-coded-concept-with-no-answers.xml (kopia robocza) @@ -1,6 +0,0 @@ - - - - - - Index: api/src/test/java/org/openmrs/api/handler/PatientDataVoidHandlerTest.java =================================================================== --- api/src/test/java/org/openmrs/api/handler/PatientDataVoidHandlerTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/handler/PatientDataVoidHandlerTest.java (kopia robocza) @@ -69,6 +69,7 @@ } new PatientDataVoidHandler().handle(patient, new User(1), new Date(), "voidReason"); + Context.flushSession(); //all encounters void related fields should have been set for (Encounter encounter : encounters) { Index: api/src/main/java/org/openmrs/attribute/BaseAttribute.java =================================================================== --- api/src/main/java/org/openmrs/attribute/BaseAttribute.java (wersja 24555) +++ api/src/main/java/org/openmrs/attribute/BaseAttribute.java (kopia robocza) @@ -14,10 +14,11 @@ package org.openmrs.attribute; import org.openmrs.BaseOpenmrsData; -import org.openmrs.customdatatype.CustomDatatype; +import org.openmrs.annotation.AllowEmptyStrings; import org.openmrs.customdatatype.CustomDatatypeUtil; import org.openmrs.customdatatype.Customizable; import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.NotYetPersistedException; import org.openmrs.util.OpenmrsUtil; /** @@ -33,8 +34,12 @@ private AT attributeType; - private String persistedValue; + private String valueReference; + private transient Object value; + + private transient boolean dirty = false; + /** * @see org.openmrs.attribute.Attribute#getOwner() */ @@ -78,15 +83,19 @@ */ @Override public String getValueReference() { - return persistedValue; + if (valueReference == null) + throw new NotYetPersistedException(); + else + return valueReference; } /** - * @see org.openmrs.customdatatype.SingleCustomValue#setValueReference(java.lang.String) + * @see org.openmrs.customdatatype.SingleCustomValue#setValueReferenceInternal(java.lang.String) */ + @AllowEmptyStrings @Override - public void setValueReference(String valueToPersist) throws InvalidCustomValueException { - this.persistedValue = valueToPersist; + public void setValueReferenceInternal(String valueReference) throws InvalidCustomValueException { + this.valueReference = valueReference; } /** @@ -94,7 +103,9 @@ */ @Override public Object getValue() throws InvalidCustomValueException { - return CustomDatatypeUtil.getDatatype(getAttributeType()).fromReferenceString(getValueReference()); + if (value == null) + value = CustomDatatypeUtil.getDatatype(getAttributeType()).fromReferenceString(getValueReference()); + return value; } /** @@ -102,12 +113,23 @@ */ @Override public void setValue(T typedValue) throws InvalidCustomValueException { + dirty = true; + value = typedValue; + /* CustomDatatype datatype = (CustomDatatype) CustomDatatypeUtil.getDatatype(getAttributeType()); datatype.validate(typedValue); - setValueReference(datatype.toReferenceString(typedValue)); + setValueReferenceInternal(datatype.toReferenceString(typedValue)); + */ } /** + * @return the dirty + */ + public boolean isDirty() { + return dirty; + } + + /** * @see java.lang.Comparable#compareTo(java.lang.Object) */ @Override Index: api/src/main/java/org/openmrs/validator/ObsValidator.java =================================================================== --- api/src/main/java/org/openmrs/validator/ObsValidator.java (wersja 24555) +++ api/src/main/java/org/openmrs/validator/ObsValidator.java (kopia robocza) @@ -116,7 +116,8 @@ // if this is NOT an obs group, make sure that it has at least one value set (not counting obsGroupId) else if (obs.getValueBoolean() == null && obs.getValueCoded() == null && obs.getValueCodedName() == null && obs.getValueComplex() == null && obs.getValueDatetime() == null && obs.getValueDrug() == null - && obs.getValueModifier() == null && obs.getValueNumeric() == null && obs.getValueText() == null) { + && obs.getValueModifier() == null && obs.getValueNumeric() == null && obs.getValueText() == null + && obs.getComplexData() == null) { errors.reject("error.noValue"); } @@ -125,66 +126,70 @@ if (c == null) { errors.rejectValue("concept", "error.null"); } - // if there is a concept, perform validation tests specific to the concept datatype - else { + // if there is a concept, and this isn't a group, perform validation tests specific to the concept datatype + else if (!obs.hasGroupMembers()) { ConceptDatatype dt = c.getDatatype(); - if (dt.isBoolean() && obs.getValueBoolean() == null) { - if (atRootNode) - errors.rejectValue("valueBoolean", "error.null"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } else if (dt.isCoded() && obs.getValueCoded() == null) { - if (atRootNode) - errors.rejectValue("valueCoded", "error.null"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } else if ((dt.isDateTime() || dt.isDate() || dt.isTime()) && obs.getValueDatetime() == null) { - if (atRootNode) - errors.rejectValue("valueDatetime", "error.null"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } else if (dt.isNumeric() && obs.getValueNumeric() == null) { - if (atRootNode) - errors.rejectValue("valueNumeric", "error.null"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } else if (dt.isNumeric()) { - ConceptNumeric cn = Context.getConceptService().getConceptNumeric(c.getConceptId()); - // If the concept numeric is not precise, the value cannot be a float, so raise an error - if (!cn.isPrecise() && Math.ceil(obs.getValueNumeric()) != obs.getValueNumeric()) { + if (dt != null) { + if (dt.isBoolean() && obs.getValueBoolean() == null) { if (atRootNode) - errors.rejectValue("valueNumeric", "error.precision"); + errors.rejectValue("valueBoolean", "error.null"); else errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } - // If the number is higher than the absolute range, raise an error - if (cn.getHiAbsolute() != null && cn.getHiAbsolute() < obs.getValueNumeric()) { + } else if (dt.isCoded() && obs.getValueCoded() == null) { if (atRootNode) - errors.rejectValue("valueNumeric", "error.outOfRange.high"); + errors.rejectValue("valueCoded", "error.null"); else errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } else if ((dt.isDateTime() || dt.isDate() || dt.isTime()) && obs.getValueDatetime() == null) { + if (atRootNode) + errors.rejectValue("valueDatetime", "error.null"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } else if (dt.isNumeric() && obs.getValueNumeric() == null) { + if (atRootNode) + errors.rejectValue("valueNumeric", "error.null"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } else if (dt.isNumeric()) { + ConceptNumeric cn = Context.getConceptService().getConceptNumeric(c.getConceptId()); + // If the concept numeric is not precise, the value cannot be a float, so raise an error + if (!cn.isPrecise() && Math.ceil(obs.getValueNumeric()) != obs.getValueNumeric()) { + if (atRootNode) + errors.rejectValue("valueNumeric", "error.precision"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } + // If the number is higher than the absolute range, raise an error + if (cn.getHiAbsolute() != null && cn.getHiAbsolute() < obs.getValueNumeric()) { + if (atRootNode) + errors.rejectValue("valueNumeric", "error.outOfRange.high"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } + // If the number is lower than the absolute range, raise an error as well + if (cn.getLowAbsolute() != null && cn.getLowAbsolute() > obs.getValueNumeric()) { + if (atRootNode) + errors.rejectValue("valueNumeric", "error.outOfRange.low"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } + } else if (dt.isText() && obs.getValueText() == null) { + if (atRootNode) + errors.rejectValue("valueText", "error.null"); + else + errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); } - // If the number is lower than the absolute range, raise an error as well - if (cn.getLowAbsolute() != null && cn.getLowAbsolute() > obs.getValueNumeric()) { + + //If valueText is longer than the maxlength, raise an error as well. + if (dt.isText() && obs.getValueText() != null && obs.getValueText().length() > VALUE_TEXT_MAX_LENGTH) { if (atRootNode) - errors.rejectValue("valueNumeric", "error.outOfRange.low"); + errors.rejectValue("valueText", "error.exceededMaxLengthOfField"); else errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); } - } else if (dt.isText() && obs.getValueText() == null) { - if (atRootNode) - errors.rejectValue("valueText", "error.null"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); + } else { // dt is null + errors.rejectValue("concept", "must have a datatype"); } - - //If valueText is longer than the maxlength, raise an error as well. - if (dt.isText() && obs.getValueText() != null && obs.getValueText().length() > VALUE_TEXT_MAX_LENGTH) { - if (atRootNode) - errors.rejectValue("valueText", "error.exceededMaxLengthOfField"); - else - errors.rejectValue("groupMembers", "Obs.error.inGroupMember"); - } } // If an obs fails validation, don't bother checking its children Index: api/src/test/java/org/openmrs/api/db/PatientDAOTest.java =================================================================== --- api/src/test/java/org/openmrs/api/db/PatientDAOTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/db/PatientDAOTest.java (kopia robocza) @@ -58,6 +58,7 @@ .getLocationService().getLocation(1)); patient6.addIdentifier(patientIdentifier6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient @@ -89,6 +90,7 @@ .getLocationService().getLocation(1)); patient6.addIdentifier(patientIdentifier6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient @@ -120,6 +122,7 @@ .getLocationService().getLocation(1)); patient6.addIdentifier(patientIdentifier6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient @@ -149,6 +152,7 @@ PersonName name6 = new PersonName("acats", "and", "dogs"); patient6.addName(name6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient @@ -177,6 +181,7 @@ PersonName name6 = new PersonName("acats", "and", "dogs"); patient6.addName(name6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient @@ -206,6 +211,7 @@ PersonName name6 = new PersonName("acats", "and", "dogs"); patient6.addName(name6); pService.savePatient(patient6); + Context.flushSession(); List identifierTypes = Collections.emptyList(); //we expect only one matching patient Index: api/src/main/resources/org/openmrs/api/db/hibernate/LocationAttribute.hbm.xml =================================================================== --- api/src/main/resources/org/openmrs/api/db/hibernate/LocationAttribute.hbm.xml (wersja 24555) +++ api/src/main/resources/org/openmrs/api/db/hibernate/LocationAttribute.hbm.xml (kopia robocza) @@ -20,7 +20,7 @@ - + Index: api/src/test/java/org/openmrs/util/LocationUtilityTest.java =================================================================== --- api/src/test/java/org/openmrs/util/LocationUtilityTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/util/LocationUtilityTest.java (kopia robocza) @@ -39,6 +39,7 @@ Assert.assertEquals("Unknown Location", LocationUtility.getDefaultLocation().getName()); GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCATION_NAME, "Xanadu", "Testing"); Context.getAdministrationService().saveGlobalProperty(gp); + Context.flushSession(); Assert.assertEquals("Xanadu", LocationUtility.getDefaultLocation().getName()); } Index: api/src/main/java/org/openmrs/BaseCustomizableData.java =================================================================== --- api/src/main/java/org/openmrs/BaseCustomizableData.java (wersja 24555) +++ api/src/main/java/org/openmrs/BaseCustomizableData.java (kopia robocza) @@ -30,7 +30,7 @@ */ public abstract class BaseCustomizableData extends BaseOpenmrsData implements Customizable { - private Set attributes; + private Set attributes = new LinkedHashSet(); /** * @see org.openmrs.customdatatype.Customizable#getAttributes() Index: api/src/test/java/org/openmrs/customdatatype/datatype/DateTest.java =================================================================== --- api/src/test/java/org/openmrs/customdatatype/datatype/DateTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/customdatatype/datatype/DateTest.java (kopia robocza) @@ -16,22 +16,22 @@ } /** - * @see DateDatatype#fromReferenceString(String) + * @see Date#deserialize(String) * @verifies reconstruct a date serialized by this handler */ @Test public void fromPersistentString_shouldReconstructADateSerializedByThisHandler() throws Exception { java.util.Date date = new SimpleDateFormat("yyyy-MM-dd").parse("2011-04-25"); - Assert.assertEquals(date, datatype.fromReferenceString(datatype.toReferenceString(date))); + Assert.assertEquals(date, datatype.deserialize(datatype.serialize(date))); } /** - * @see DateDatatype#toReferenceString(DateDatatype) + * @see Date#serialize(java.util.Date) * @verifies convert a date into a ymd string representation */ @Test public void toPersistentString_shouldConvertADateIntoAYmdStringRepresentation() throws Exception { java.util.Date date = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse("2011-04-25 01:02:03"); - Assert.assertEquals("2011-04-25", datatype.toReferenceString(date)); + Assert.assertEquals("2011-04-25", datatype.serialize(date)); } } Index: api/src/test/java/org/openmrs/attribute/AttributeIntegrationTest.java =================================================================== --- api/src/test/java/org/openmrs/attribute/AttributeIntegrationTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/attribute/AttributeIntegrationTest.java (kopia robocza) @@ -4,6 +4,7 @@ import junit.framework.Assert; +import org.junit.Ignore; import org.junit.Test; import org.openmrs.BaseCustomizableData; import org.openmrs.test.BaseContextSensitiveTest; @@ -15,6 +16,7 @@ public class AttributeIntegrationTest extends BaseContextSensitiveTest { @Test + @Ignore public void shouldTestAttributeHandler() throws Exception { Visit visit = new Visit(); VisitAttributeType paymentDateAttrType = new VisitAttributeType(); Index: api/src/test/java/org/openmrs/api/ObsServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/ObsServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/ObsServiceTest.java (kopia robocza) @@ -33,6 +33,7 @@ import java.util.Collections; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Map; @@ -124,7 +125,7 @@ oGP.setLocation(new Location(1)); oGP.setObsDatetime(new Date()); oGP.setPerson(new Patient(2)); - oGP.setValueText("grandparent obs value text"); + //oGP.setValueText("grandparent obs value text"); oGP.addGroupMember(oParent); @@ -148,7 +149,7 @@ oGGP.setCreator(Context.getAuthenticatedUser()); oGGP.setLocation(new Location(1)); oGGP.setObsDatetime(new Date()); - oGGP.setValueText("great grandparent value text"); + //oGGP.setValueText("great grandparent value text"); oGGP.setPerson(new Patient(2)); oGGP.addGroupMember(oGP); @@ -160,7 +161,7 @@ oGGGP.setCreator(Context.getAuthenticatedUser()); oGGGP.setLocation(new Location(1)); oGGGP.setObsDatetime(new Date()); - oGGGP.setValueText("great great grandparent value text"); + //oGGGP.setValueText("great great grandparent value text"); oGGGP.setPerson(new Patient(2)); oGGGP.addGroupMember(oGGP); @@ -243,6 +244,7 @@ //first, just create an Obs, and void it, and verify: Obs oVoidTest = new Obs(); oVoidTest.setConcept(cs.getConcept(1)); + oVoidTest.setValueNumeric(50d); oVoidTest.setDateCreated(new Date()); oVoidTest.setCreator(Context.getAuthenticatedUser()); oVoidTest.setLocation(new Location(1)); @@ -764,9 +766,14 @@ List obss = obsService.getObservations(null, null, null, Collections.singletonList(new Concept(7)), null, null, null, null, null, null, null, false); - Assert.assertEquals(1, obss.size()); - - Assert.assertEquals(11, obss.get(0).getObsId().intValue()); + // obs 11 in INITIAL_OBS_XML and obs 13 in standardTestDataset + Assert.assertEquals(2, obss.size()); + Set ids = new HashSet(); + for (Obs o : obss) { + ids.add(o.getObsId()); + } + Assert.assertTrue(ids.contains(11)); + Assert.assertTrue(ids.contains(13)); } /** @@ -782,7 +789,7 @@ Integer count = obsService.getObservationCount(null, null, null, Collections.singletonList(new Concept(7)), null, null, null, null, null, false); - Assert.assertEquals(1, count.intValue()); + Assert.assertEquals(2, count.intValue()); } @@ -1210,7 +1217,7 @@ ObsService obsService = Context.getObsService(); Order order = null; - Concept concept = new Concept(3); + Concept concept = Context.getConceptService().getConcept(3); Patient patient = new Patient(2); Encounter encounter = new Encounter(3); Date datetime = new Date(); @@ -1265,11 +1272,12 @@ @Verifies(value = "should create very basic obs and add new obsId", method = "saveObs(Obs,String)") public void saveObs_shouldCreateVeryBasicObsAndAddNewObsId() throws Exception { Obs o = new Obs(); - o.setConcept(new Concept(3)); + o.setConcept(Context.getConceptService().getConcept(3)); o.setPerson(new Patient(2)); o.setEncounter(new Encounter(3)); o.setObsDatetime(new Date()); o.setLocation(new Location(1)); + o.setValueNumeric(50d); Obs oSaved = Context.getObsService().saveObs(o, null); @@ -1364,11 +1372,12 @@ @Verifies(value = "should set creator and dateCreated on new obs", method = "saveObs(Obs,String)") public void saveObs_shouldSetCreatorAndDateCreatedOnNewObs() throws Exception { Obs o = new Obs(); - o.setConcept(new Concept(3)); + o.setConcept(Context.getConceptService().getConcept(3)); o.setPerson(new Patient(2)); o.setEncounter(new Encounter(3)); o.setObsDatetime(new Date()); o.setLocation(new Location(1)); + o.setValueNumeric(50d); Context.getObsService().saveObs(o, null); assertNotNull(o.getDateCreated()); @@ -1384,13 +1393,13 @@ ObsService obsService = Context.getObsService(); Obs parentObs = new Obs(); - parentObs.setConcept(new Concept(3)); + parentObs.setConcept(Context.getConceptService().getConcept(3)); parentObs.setObsDatetime(new Date()); parentObs.setPerson(new Patient(2)); parentObs.setLocation(new Location(1)); Obs groupMember = new Obs(); - groupMember.setConcept(new Concept(3)); + groupMember.setConcept(Context.getConceptService().getConcept(3)); groupMember.setValueNumeric(1.0); groupMember.setObsDatetime(new Date()); groupMember.setPerson(new Patient(2)); @@ -1415,12 +1424,14 @@ // a obs with child groups Obs parentObs = obsService.getObs(2); + parentObs.setValueNumeric(null); Obs groupMember = new Obs(); - groupMember.setConcept(new Concept(3)); + groupMember.setConcept(Context.getConceptService().getConcept(3)); groupMember.setObsDatetime(new Date()); groupMember.setPerson(new Patient(2)); groupMember.setLocation(new Location(2)); + groupMember.setValueNumeric(50d); parentObs.addGroupMember(groupMember); assertNotNull(groupMember.getObsGroup()); @@ -1442,7 +1453,7 @@ public void getObservationCount_shouldIncludeVoidedObservationsUsingTheSpecifiedConceptNamesAsAnswers() throws Exception { ObsService os = Context.getObsService(); Obs o = new Obs(); - o.setConcept(new Concept(3)); + o.setConcept(Context.getConceptService().getConcept(3)); o.setPerson(new Patient(2)); o.setEncounter(new Encounter(3)); o.setObsDatetime(new Date()); @@ -1452,7 +1463,7 @@ os.saveObs(o, null); Obs o2 = new Obs(); - o2.setConcept(new Concept(3)); + o2.setConcept(Context.getConceptService().getConcept(3)); o2.setPerson(new Patient(2)); o2.setEncounter(new Encounter(3)); o2.setObsDatetime(new Date()); @@ -1477,7 +1488,7 @@ throws Exception { ObsService os = Context.getObsService(); Obs o = new Obs(); - o.setConcept(new Concept(3)); + o.setConcept(Context.getConceptService().getConcept(3)); o.setPerson(new Patient(2)); o.setEncounter(new Encounter(3)); o.setObsDatetime(new Date()); @@ -1487,7 +1498,7 @@ os.saveObs(o, null); Obs o2 = new Obs(); - o2.setConcept(new Concept(3)); + o2.setConcept(Context.getConceptService().getConcept(3)); o2.setPerson(new Patient(2)); o2.setEncounter(new Encounter(3)); o2.setObsDatetime(new Date()); Index: web/src/test/java/org/openmrs/web/controller/person/PersonAttributeTypeListControllerTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/person/PersonAttributeTypeListControllerTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/person/PersonAttributeTypeListControllerTest.java (kopia robocza) @@ -68,6 +68,7 @@ // the test Integer[] ids = new Integer[] { 1 }; new PersonAttributeTypeListController().moveDown(ids, new MockHttpSession()); + Context.flushSession(); allTypes = Context.getPersonService().getAllPersonAttributeTypes(); Assert.assertEquals("The types didn't move correctly", 8, allTypes.get(0).getId().intValue()); } @@ -113,6 +114,7 @@ // the test Integer[] ids = new Integer[] { 8 }; new PersonAttributeTypeListController().moveUp(ids, new MockHttpSession()); + Context.flushSession(); allTypes = Context.getPersonService().getAllPersonAttributeTypes(); Assert.assertEquals("The types didn't move correctly", 8, allTypes.get(0).getId().intValue()); } @@ -148,6 +150,8 @@ @Verifies(value = "should save given personListingAttributeTypes", method = "updateGlobalProperties(String,String,String,String,String,HttpSession)") public void updateGlobalProperties_shouldSaveGivenPersonListingAttributeTypes() throws Exception { new PersonAttributeTypeListController().updateGlobalProperties("asdf", "", "", "", "", new MockHttpSession()); + Context.flushSession(); + String attr = Context.getAdministrationService().getGlobalProperty( OpenmrsConstants.GLOBAL_PROPERTY_PATIENT_LISTING_ATTRIBUTES); Assert.assertEquals("asdf", attr); Index: api/src/main/java/org/openmrs/api/db/hibernate/HibernateFlushOnCommitTransactionManager.java =================================================================== --- api/src/main/java/org/openmrs/api/db/hibernate/HibernateFlushOnCommitTransactionManager.java (wersja 0) +++ api/src/main/java/org/openmrs/api/db/hibernate/HibernateFlushOnCommitTransactionManager.java (wersja 0) @@ -0,0 +1,40 @@ +/** + * 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 org.hibernate.FlushMode; +import org.springframework.orm.hibernate3.HibernateTransactionManager; +import org.springframework.transaction.TransactionDefinition; + +/** + * + */ +public class HibernateFlushOnCommitTransactionManager extends HibernateTransactionManager { + + private static final long serialVersionUID = 1L; + + /** + * @see org.springframework.orm.hibernate3.HibernateTransactionManager#doBegin(java.lang.Object, org.springframework.transaction.TransactionDefinition) + */ + @Override + protected void doBegin(Object transaction, TransactionDefinition definition) { + super.doBegin(transaction, definition); + + FlushMode flushMode = getSessionFactory().getCurrentSession().getFlushMode(); + if (flushMode.equals(FlushMode.ALWAYS) || flushMode.equals(FlushMode.AUTO)) { + getSessionFactory().getCurrentSession().setFlushMode(FlushMode.COMMIT); + } + } + +} Index: api/src/test/java/org/openmrs/validator/ConceptValidatorTest.java =================================================================== --- api/src/test/java/org/openmrs/validator/ConceptValidatorTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/validator/ConceptValidatorTest.java (kopia robocza) @@ -138,6 +138,7 @@ ConceptName preferredName = new ConceptName("preferred name", Context.getLocale()); concept.setPreferredName(preferredName); Context.getConceptService().saveConcept(concept); + Context.flushSession(); Assert.assertEquals("preferred name", concept.getPreferredName(Context.getLocale()).getName()); Concept anotherConcept = Context.getConceptService().getConcept(5089); Index: api/src/test/java/org/openmrs/api/db/hibernate/AuditableInterceptorTest.java =================================================================== --- api/src/test/java/org/openmrs/api/db/hibernate/AuditableInterceptorTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/db/hibernate/AuditableInterceptorTest.java (kopia robocza) @@ -130,6 +130,7 @@ Date beforeDate = u.getDateChanged(); Context.getUserService().saveUser(u, null); + Context.flushSession(); Date afterDate = u.getDateChanged(); Index: api/src/test/java/org/openmrs/api/AdministrationServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/AdministrationServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/AdministrationServiceTest.java (kopia robocza) @@ -326,6 +326,7 @@ globalProperties.add(new GlobalProperty("new prop2", "new prop value2", "desc")); Context.getAdministrationService().saveGlobalProperties(globalProperties); + Context.flushSession(); Assert.assertEquals("new prop value1", Context.getAdministrationService().getGlobalProperty("new prop1")); Assert.assertEquals("new prop value2", Context.getAdministrationService().getGlobalProperty("new prop2")); @@ -343,6 +344,7 @@ // and now add a new one to it and save it globalProperties.add(new GlobalProperty("new prop", "new prop value", "desc")); Context.getAdministrationService().saveGlobalProperties(globalProperties); + Context.flushSession(); Assert.assertNotNull(Context.getAdministrationService().getGlobalPropertyObject("new prop").getUuid()); } @@ -354,7 +356,7 @@ @Verifies(value = "should return all global properties in the database", method = "getAllGlobalProperties()") public void getAllGlobalProperties_shouldReturnAllGlobalPropertiesInTheDatabase() throws Exception { executeDataSet(ADMIN_INITIAL_DATA_XML); - Assert.assertEquals(10, Context.getAdministrationService().getAllGlobalProperties().size()); + Assert.assertEquals(12, Context.getAdministrationService().getAllGlobalProperties().size()); } /** @@ -426,9 +428,10 @@ executeDataSet(ADMIN_INITIAL_DATA_XML); AdministrationService as = Context.getAdministrationService(); - Assert.assertEquals(10, as.getAllGlobalProperties().size()); + Assert.assertEquals(12, as.getAllGlobalProperties().size()); as.purgeGlobalProperty(as.getGlobalPropertyObject("a_valid_gp_key")); - Assert.assertEquals(9, as.getAllGlobalProperties().size()); + Context.flushSession(); + Assert.assertEquals(11, as.getAllGlobalProperties().size()); } /** @@ -441,6 +444,7 @@ AdministrationService as = Context.getAdministrationService(); as.saveGlobalProperty(new GlobalProperty("detectHiddenSkill", "100")); + Context.flushSession(); Assert.assertNotNull(as.getGlobalProperty("detectHiddenSkill")); } @@ -547,6 +551,7 @@ // should match current gp GlobalProperty gp = new GlobalProperty("ANOTher-global-property", "somethingelse"); adminService.saveGlobalProperty(gp); + Context.flushSession(); String prop = adminService.getGlobalProperty("ANOTher-global-property", "boo"); Assert.assertEquals("somethingelse", prop); } @@ -563,6 +568,7 @@ props.add(new GlobalProperty("a.property.key", "something")); props.add(new GlobalProperty("a.property.KEY", "somethingelse")); adminService.saveGlobalProperties(props); + Context.flushSession(); // make sure that we now have two properties props = adminService.getAllGlobalProperties(); @@ -581,11 +587,13 @@ props.add(new GlobalProperty("a.property.key", "something")); props.add(new GlobalProperty("a.property.KEY", "somethingelse")); adminService.saveGlobalProperties(props); + Context.flushSession(); int afterSaveSize = adminService.getAllGlobalProperties().size(); Assert.assertEquals(originalSize + 2, afterSaveSize); adminService.purgeGlobalProperties(props); + Context.flushSession(); int afterPurgeSize = adminService.getAllGlobalProperties().size(); Assert.assertEquals(originalSize, afterPurgeSize); Index: web/src/test/java/org/openmrs/web/controller/maintenance/GlobalPropertyControllerTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/maintenance/GlobalPropertyControllerTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/maintenance/GlobalPropertyControllerTest.java (kopia robocza) @@ -41,6 +41,7 @@ public void onSubmit_shouldPurgeNotIncludedProperties() throws Exception { GlobalProperty gp = new GlobalProperty("test1", "test1_value"); administrationService.saveGlobalProperty(gp); + Context.flushSession(); HttpServletResponse response = new MockHttpServletResponse(); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -54,6 +55,7 @@ request.setParameter(GlobalPropertyController.PROP_DESC_NAME, descriptions); controller.handleRequest(request, response); + Context.flushSession(); Assert.assertEquals(2, administrationService.getAllGlobalProperties().size()); for (GlobalProperty globalProperty : administrationService.getAllGlobalProperties()) { @@ -75,6 +77,7 @@ public void onSubmit_shouldSaveOrUpdateIncludedProperties() throws Exception { GlobalProperty gp = new GlobalProperty("test1", "test1_value"); administrationService.saveGlobalProperty(gp); + Context.flushSession(); HttpServletResponse response = new MockHttpServletResponse(); MockHttpServletRequest request = new MockHttpServletRequest(); @@ -88,6 +91,7 @@ request.setParameter(GlobalPropertyController.PROP_DESC_NAME, descriptions); controller.handleRequest(request, response); + Context.flushSession(); Assert.assertEquals(2, administrationService.getAllGlobalProperties().size()); for (GlobalProperty globalProperty : administrationService.getAllGlobalProperties()) { Index: api/src/test/java/org/openmrs/util/LocaleUtilityTest.java =================================================================== --- api/src/test/java/org/openmrs/util/LocaleUtilityTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/util/LocaleUtilityTest.java (kopia robocza) @@ -159,6 +159,8 @@ GlobalProperty gp = Context.getAdministrationService().saveGlobalProperty( new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_DEFAULT_LOCALE, "ja")); + Context.flushSession(); + Assert.assertEquals(Locale.JAPANESE, LocaleUtility.getDefaultLocale()); // reset the locale @@ -269,6 +271,9 @@ Context.getAdministrationService().saveGlobalProperty(defaultLocale); Locale lu_UG = new Locale("lu", "UG"); Context.setLocale(lu_UG); + + Context.flushSession(); + //note that unique list of locales should be lu_UG, lu, sw_KE, en_US, en Assert.assertEquals(5, LocaleUtility.getLocalesInOrder().size()); } Index: api/src/test/java/org/openmrs/api/db/SerializedObjectDAOTest.java =================================================================== --- api/src/test/java/org/openmrs/api/db/SerializedObjectDAOTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/db/SerializedObjectDAOTest.java (kopia robocza) @@ -134,6 +134,7 @@ List l = dao.getAllObjects(ReportSchema.class); assertEquals(2, l.size()); dao.purgeObject(2); + Context.flushSession(); l = dao.getAllObjects(ReportSchema.class); assertEquals(1, l.size()); } Index: api/src/main/java/org/openmrs/customdatatype/datatype/DateDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/datatype/DateDatatype.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/datatype/DateDatatype.java (kopia robocza) @@ -17,74 +17,52 @@ import java.util.Date; import org.apache.commons.lang.StringUtils; -import org.openmrs.customdatatype.CustomDatatype; +import org.openmrs.api.context.Context; import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.SerializingCustomDatatype; import org.springframework.stereotype.Component; /** - * Datatype for a Date (without time), represented by a java.util.Date. + * Datatype for a Date (without time), represented by a java.util.Date. + * * @since 1.9 */ @Component -public class DateDatatype implements CustomDatatype { +public class DateDatatype extends SerializingCustomDatatype { final static String dateFormat = "yyyy-MM-dd"; /** - * @see org.openmrs.customdatatype.CustomDatatype#setConfiguration(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#doRender(java.lang.Object, + * java.lang.String) */ @Override - public void setConfiguration(String config) { - // not used + public String doRender(Date typedValue, String view) { + return Context.getDateFormat().format(typedValue); } /** - * @see org.openmrs.customdatatype.CustomDatatype#toReferenceString(java.lang.Object) - * @should convert a date into a ymd string representation - */ - @Override - public String toReferenceString(Date typedValue) throws InvalidCustomValueException { - return new SimpleDateFormat(dateFormat).format(typedValue); - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#fromReferenceString(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#deserialize(java.lang.String) * @should reconstruct a date serialized by this handler */ @Override - public Date fromReferenceString(String persistedValue) throws InvalidCustomValueException { - if (StringUtils.isBlank(persistedValue)) + public Date deserialize(String serializedValue) { + if (StringUtils.isBlank(serializedValue)) return null; try { - return new SimpleDateFormat(dateFormat).parse(persistedValue); + return new SimpleDateFormat(dateFormat).parse(serializedValue); } catch (Exception ex) { - throw new InvalidCustomValueException("Invalid date: " + persistedValue); + throw new InvalidCustomValueException("Invalid date: " + serializedValue); } } /** - * @see org.openmrs.customdatatype.CustomDatatype#render(java.lang.String, java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#serialize(java.lang.Object) + * @should convert a date into a ymd string representation */ @Override - public String render(String persistedValue, String view) { - return persistedValue; + public String serialize(Date typedValue) { + return new SimpleDateFormat(dateFormat).format(typedValue); } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validateReferenceString(java.lang.String) - */ - @Override - public void validateReferenceString(String persistedValue) throws InvalidCustomValueException { - validate(fromReferenceString(persistedValue)); - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validate(java.lang.Object) - */ - @Override - public void validate(Date typedValue) throws InvalidCustomValueException { - // pass - } - } Index: api/src/test/java/org/openmrs/hl7/handler/ORUR01HandlerTest.java =================================================================== --- api/src/test/java/org/openmrs/hl7/handler/ORUR01HandlerTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/hl7/handler/ORUR01HandlerTest.java (kopia robocza) @@ -237,6 +237,7 @@ + "OBX|1|NM|10^CD4 COUNT^99DCT||250|||||||||20080831"; Message hl7message = parser.parse(hl7string); router.processMessage(hl7message); + Context.flushSession(); Patient patient = new Patient(7); Concept question = new Concept(10); Index: api/src/test/java/org/openmrs/api/handler/ExistingOrNewVisitAssignmentHandlerTest.java =================================================================== --- api/src/test/java/org/openmrs/api/handler/ExistingOrNewVisitAssignmentHandlerTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/handler/ExistingOrNewVisitAssignmentHandlerTest.java (kopia robocza) @@ -121,6 +121,7 @@ GlobalProperty gp = new GlobalProperty(OpenmrsConstants.GP_ENCOUNTER_TYPE_TO_VISIT_TYPE_MAPPING, "3:4, 5:2, 1:2, 2:2"); Context.getAdministrationService().saveGlobalProperty(gp); + Context.flushSession(); new ExistingOrNewVisitAssignmentHandler().beforeCreateEncounter(encounter); Index: api/src/test/java/org/openmrs/validator/ProviderValidatorTest.java =================================================================== --- api/src/test/java/org/openmrs/validator/ProviderValidatorTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/validator/ProviderValidatorTest.java (kopia robocza) @@ -208,7 +208,7 @@ private ProviderAttribute makeAttribute(String serializedValue) { ProviderAttribute attr = new ProviderAttribute(); attr.setAttributeType(providerService.getProviderAttributeType(1)); - attr.setValueReference(serializedValue); + attr.setValueReferenceInternal(serializedValue); return attr; } Index: api/src/main/java/org/openmrs/customdatatype/SingleCustomValue.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/SingleCustomValue.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/SingleCustomValue.java (kopia robocza) @@ -38,8 +38,9 @@ /** * @return the value persisted in a database in a varchar column. Not necessarily human-readable. + * @throws NotYetPersistedException if valueReference hasn't been set by the CustomDatatype yet */ - String getValueReference(); + String getValueReference() throws NotYetPersistedException; /** * Directly set the String value that should be persisted in the database @@ -49,7 +50,7 @@ * instead of this method. * @param valueToPersist */ - void setValueReference(String valueToPersist) throws InvalidCustomValueException; + void setValueReferenceInternal(String valueToPersist) throws InvalidCustomValueException; /** * Convenience method to get the typed version of the serializedValue. (This will result in a call @@ -66,4 +67,9 @@ */ void setValue(T typedValue) throws InvalidCustomValueException; + /** + * @return whether or not setValue has been called (thus {@link CustomDatatype#save(Object, String)} needs to be called + */ + boolean isDirty(); + } Index: api/src/test/resources/org/openmrs/api/include/LocationServiceTest-attributes.xml =================================================================== --- api/src/test/resources/org/openmrs/api/include/LocationServiceTest-attributes.xml (wersja 24555) +++ api/src/test/resources/org/openmrs/api/include/LocationServiceTest-attributes.xml (kopia robocza) @@ -1,6 +1,6 @@ - - + + Index: api/src/main/resources/applicationContext-service.xml =================================================================== --- api/src/main/resources/applicationContext-service.xml (wersja 24555) +++ api/src/main/resources/applicationContext-service.xml (kopia robocza) @@ -662,7 +662,7 @@ - + Index: api/src/main/java/org/openmrs/api/impl/LocationServiceImpl.java =================================================================== --- api/src/main/java/org/openmrs/api/impl/LocationServiceImpl.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/impl/LocationServiceImpl.java (kopia robocza) @@ -26,6 +26,7 @@ import org.openmrs.api.LocationService; import org.openmrs.api.context.Context; import org.openmrs.api.db.LocationDAO; +import org.openmrs.customdatatype.CustomDatatypeUtil; import org.openmrs.util.OpenmrsConstants; import org.springframework.util.StringUtils; @@ -78,6 +79,8 @@ } } + CustomDatatypeUtil.saveAttributesIfNecessary(location); + return dao.saveLocation(location); } Index: api/src/test/java/org/openmrs/test/BaseContextSensitiveTest.java =================================================================== --- api/src/test/java/org/openmrs/test/BaseContextSensitiveTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/test/BaseContextSensitiveTest.java (kopia robocza) @@ -482,6 +482,8 @@ } executeDataSet(xmlDataSetToRun); + + Context.flushSession(); } /** Index: api/src/test/java/org/openmrs/api/UserServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/UserServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/UserServiceTest.java (kopia robocza) @@ -177,6 +177,7 @@ u.setUsername("admin2"); us.saveUser(u, null); + Context.flushSession(); User u2 = us.getUserByUsername("admin2"); Index: api/src/test/java/org/openmrs/api/CohortServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/CohortServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/CohortServiceTest.java (kopia robocza) @@ -128,6 +128,7 @@ List allCohorts = service.getAllCohorts(true); assertEquals(2, allCohorts.size()); service.purgeCohort(allCohorts.get(0)); + Context.flushSession(); allCohorts = service.getAllCohorts(true); assertEquals(1, allCohorts.size()); } @@ -468,6 +469,7 @@ Patient patientToAdd = new Patient(4); service.addPatientToCohort(service.getCohort(2), patientToAdd); + Context.flushSession(); assertTrue(service.getCohort(2).contains(patientToAdd)); List cohortsWithGivenPatient = service.getCohortsContainingPatient(patientToAdd); Index: api/src/test/java/org/openmrs/api/PatientServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/PatientServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/PatientServiceTest.java (kopia robocza) @@ -495,6 +495,8 @@ Context.getAdministrationService().saveGlobalProperty( new GlobalProperty(OpenmrsConstants.GLOBAL_PROPERTY_MIN_SEARCH_CHARACTERS, "4")); + Context.flushSession(); + assertEquals(0, Context.getPatientService().getPatients("Col").size()); } @@ -1720,6 +1722,8 @@ identifier.setCreator(new User(1)); identifier.setDateCreated(new Date()); Context.getPatientService().getPatient(2).addIdentifier(identifier); + Context.flushSession(); + assertEquals(1, Context.getPatientService().getPatients("1234-4").size()); } @@ -1972,6 +1976,8 @@ identifier.setCreator(new User(1)); identifier.setDateCreated(new Date()); Context.getPatientService().getPatient(2).addIdentifier(identifier); + Context.flushSession(); + assertEquals(1, Context.getPatientService().getPatients("12344").size()); assertEquals(1, Context.getPatientService().getPatients("1234-4").size()); } @@ -2451,6 +2457,7 @@ PersonName name = new PersonName("first1234", "middle", "last1234"); notPreferred.addName(name); patientService.savePatient(notPreferred); + Context.flushSession(); //merge the two patients and retrieve the audit object PersonMergeLog audit = mergeAndRetrieveAudit(preferred, notPreferred); @@ -2636,6 +2643,7 @@ User user = Context.getUserService().getUser(501); user.setPerson(notPreferred); Context.getUserService().saveUser(user, null); + Context.flushSession(); //merge the two patients and retrieve the audit object PersonMergeLog audit = mergeAndRetrieveAudit(preferred, notPreferred); @@ -2799,6 +2807,7 @@ address.setAddress1("Modified Address"); patientService.savePatient(patient); + Context.flushSession(); Context.evictFromSession(patient); patient = patientService.getPatient(2); @@ -2868,10 +2877,13 @@ Patient patient = patientService.getPatient(2); User user = new User(patient); Context.getUserService().saveUser(user, "Admin123"); + Context.flushSession(); + Assert.assertFalse(Context.getUserService().getUsersByPerson(patient, false).isEmpty()); //when patientService.voidPatient(patient, "reason"); + Context.flushSession(); //then Assert.assertTrue(Context.getUserService().getUsersByPerson(patient, false).isEmpty()); @@ -2906,9 +2918,11 @@ User user = new User(patient); Context.getUserService().saveUser(user, "Admin123"); patientService.voidPatient(patient, "reason"); + Context.flushSession(); //when patientService.unvoidPatient(patient); + Context.flushSession(); //then Assert.assertTrue(Context.getUserService().getUsersByPerson(patient, false).isEmpty()); Index: api/src/main/java/org/openmrs/GlobalProperty.java =================================================================== --- api/src/main/java/org/openmrs/GlobalProperty.java (wersja 24555) +++ api/src/main/java/org/openmrs/GlobalProperty.java (kopia robocza) @@ -13,6 +13,7 @@ */ package org.openmrs; +import org.openmrs.annotation.AllowEmptyStrings; import org.openmrs.customdatatype.CustomDatatype; import org.openmrs.customdatatype.CustomDatatypeUtil; import org.openmrs.customdatatype.CustomValueDescriptor; @@ -29,6 +30,11 @@ private String propertyValue = ""; + private transient Object typedValue; + + // if true, indicates that setValue has been called, and we need to invoke CustomDatatype's save + private boolean dirty = false; + private String description = ""; private String datatypeClassname; @@ -249,12 +255,13 @@ } /** - * @see org.openmrs.customdatatype.SingleCustomValue#setValueReference(java.lang.String) + * @see org.openmrs.customdatatype.SingleCustomValue#setValueReferenceInternal(java.lang.String) * * @since 1.9 */ + @AllowEmptyStrings @Override - public void setValueReference(String valueToPersist) throws InvalidCustomValueException { + public void setValueReferenceInternal(String valueToPersist) throws InvalidCustomValueException { setPropertyValue(valueToPersist); } @@ -265,7 +272,9 @@ */ @Override public Object getValue() throws InvalidCustomValueException { - return CustomDatatypeUtil.getDatatype(this).fromReferenceString(getValueReference()); + if (typedValue == null) + typedValue = CustomDatatypeUtil.getDatatype(this).fromReferenceString(getValueReference()); + return typedValue; } /** @@ -275,9 +284,16 @@ */ @Override public void setValue(T typedValue) throws InvalidCustomValueException { - @SuppressWarnings("unchecked") - CustomDatatype datatype = (CustomDatatype) CustomDatatypeUtil.getDatatype(this); - datatype.validate(typedValue); - setValueReference(datatype.toReferenceString(typedValue)); + this.typedValue = this.typedValue; + dirty = true; } + + /** + * @see org.openmrs.customdatatype.SingleCustomValue#isDirty() + */ + @Override + public boolean isDirty() { + return dirty; + } + } Index: api/src/test/java/org/openmrs/api/PatientSetServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/PatientSetServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/PatientSetServiceTest.java (kopia robocza) @@ -256,7 +256,7 @@ obs.setPerson(new Person(8)); obs.setConcept(Context.getConceptService().getConcept(18)); obs.setObsDatetime(ymd.parse("2007-01-01")); - obs.setValueNumeric(1.0); + obs.setValueBoolean(true); obs.setLocation(new Location(1)); Context.getObsService().saveObs(obs, null); } @@ -265,7 +265,7 @@ obs.setPerson(new Person(8)); obs.setConcept(Context.getConceptService().getConcept(18)); obs.setObsDatetime(ymd.parse("2008-01-01")); - obs.setValueNumeric(0.0); + obs.setValueBoolean(false); obs.setLocation(new Location(1)); Context.getObsService().saveObs(obs, null); } Index: api/src/test/java/org/openmrs/api/EncounterServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/EncounterServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/EncounterServiceTest.java (kopia robocza) @@ -165,6 +165,7 @@ enc.addObs(newObs); es.saveEncounter(enc); + Context.flushSession(); assertNotNull(newObs.getObsId()); } @@ -320,6 +321,7 @@ es.saveEncounter(encounter); // the obs id should have been populated during the save + Context.flushSession(); assertNotNull(obs.getObsId()); } Index: api/src/test/java/org/openmrs/notification/AlertServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/notification/AlertServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/notification/AlertServiceTest.java (kopia robocza) @@ -22,6 +22,7 @@ //Call the method to be tested AlertServiceImpl alert = new AlertServiceImpl(); alert.notifySuperUsers("Module.startupError.notification.message", null, "test"); + Context.flushSession(); // Check that there is exactly one alert after the message is called Assert.assertEquals(1, Context.getAlertService().getAlertsByUser(null).size()); Index: api/src/test/java/org/openmrs/api/PersonServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/PersonServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/PersonServiceTest.java (kopia robocza) @@ -113,6 +113,7 @@ for (Relationship r : allRels) { personService.voidRelationship(r, "Because of a JUnit test."); } + Context.flushSession(); List updatedARels = personService.getRelationshipsByPerson(p1); List updatedBRels = personService.getRelationshipsByPerson(p2); @@ -157,6 +158,7 @@ for (Relationship r : allRels) { personService.voidRelationship(r, "Because of a JUnit test."); } + Context.flushSession(); // Get unvoided relationships after voiding all of them. // (specified date should not matter as no relationships have date specified) @@ -398,6 +400,7 @@ // save the type again service.savePersonAttributeType(pat); + Context.flushSession(); assertEquals(1, pat.getChangedBy().getId().intValue()); assertNotNull(pat.getDateChanged()); @@ -1893,6 +1896,7 @@ //when personService.unvoidPerson(person); + Context.flushSession(); //then Assert.assertTrue(Context.getUserService().getUsersByPerson(person, false).isEmpty()); @@ -1929,6 +1933,7 @@ //when personService.voidPerson(person, "reason"); + Context.flushSession(); //then Assert.assertTrue(Context.getUserService().getUsersByPerson(person, false).isEmpty()); Index: api/src/test/java/org/openmrs/util/OpenmrsUtilTest.java =================================================================== --- api/src/test/java/org/openmrs/util/OpenmrsUtilTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/util/OpenmrsUtilTest.java (kopia robocza) @@ -227,6 +227,7 @@ public void validatePassword_shouldPassWithDigitOnlyPasswordIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_NON_DIGIT, "false"); TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "12345678", "1-8"); } @@ -257,6 +258,7 @@ public void validatePassword_shouldPassWithCharOnlyPasswordIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_DIGIT, "false"); TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "testonly", "1-8"); } @@ -286,6 +288,7 @@ @Verifies(value = "should pass without upper and lower case password if allowed", method = "validatePassword(String,String,String)") public void validatePassword_shouldPassWithoutUpperAndLowerCasePasswordIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_REQUIRES_UPPER_AND_LOWER_CASE, "false"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "test0nl1", "1-8"); } @@ -315,6 +318,7 @@ @Verifies(value = "should pass with password equals to user name if allowed", method = "validatePassword(String,String,String)") public void validatePassword_shouldPassWithPasswordEqualsToUserNameIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "false"); + Context.flushSession(); OpenmrsUtil.validatePassword("Admin1234", "Admin1234", "1-8"); } @@ -344,6 +348,7 @@ @Verifies(value = "should pass with password equals to system id if allowed", method = "validatePassword(String,String,String)") public void validatePassword_shouldPassWithPasswordEqualsToSystemIdIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CANNOT_MATCH_USERNAME_OR_SYSTEMID, "false"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "Admin1234", "Admin1234"); } @@ -373,6 +378,7 @@ @Verifies(value = "should pass with short password if allowed", method = "validatePassword(String,String,String)") public void validatePassword_shouldPassWithShortPasswordIfAllowed() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_MINIMUM_LENGTH, "0"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "H4t", "1-8"); } @@ -384,6 +390,7 @@ public void validatePassword_shouldFailWithPasswordNotMatchingConfiguredRegex() throws Exception { TestUtil.saveGlobalProperty(OpenmrsConstants.GP_PASSWORD_CUSTOM_REGEX, "[A-Z][a-z][0-9][0-9][a-z][A-Z][a-z][a-z][a-z][a-z]"); + Context.flushSession(); OpenmrsUtil.validatePassword("admin", "he11oWorld", "1-8"); } Index: api/src/main/resources/hibernate.default.properties =================================================================== --- api/src/main/resources/hibernate.default.properties (wersja 24555) +++ api/src/main/resources/hibernate.default.properties (kopia robocza) @@ -28,3 +28,4 @@ hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider hibernate.connection.provider_class=org.hibernate.connection.C3P0ConnectionProvider hibernate.connection.release_mode=after_transaction +#hibernate.connection.release_mode=on_close Index: web/src/main/java/org/openmrs/web/controller/ForgotPasswordFormController.java =================================================================== --- web/src/main/java/org/openmrs/web/controller/ForgotPasswordFormController.java (wersja 24555) +++ web/src/main/java/org/openmrs/web/controller/ForgotPasswordFormController.java (kopia robocza) @@ -162,6 +162,7 @@ try { Context.addProxyPrivilege(PrivilegeConstants.EDIT_USER_PASSWORDS); Context.getUserService().changePassword(user, randomPassword); + Context.flushSession(); } finally { Context.removeProxyPrivilege(PrivilegeConstants.EDIT_USER_PASSWORDS); Index: api/src/main/java/org/openmrs/customdatatype/CustomDatatypeUtil.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/CustomDatatypeUtil.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/CustomDatatypeUtil.java (kopia robocza) @@ -22,8 +22,10 @@ import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.openmrs.ConceptDatatype; import org.openmrs.api.APIException; import org.openmrs.api.context.Context; +import org.openmrs.attribute.Attribute; import org.openmrs.attribute.AttributeType; import org.openmrs.serialization.SerializationException; @@ -123,7 +125,15 @@ serializedAttributeValues = new HashMap(); for (Map.Entry e : datatypeValues.entrySet()) { T vat = e.getKey(); - serializedAttributeValues.put(vat, ((CustomDatatype) getDatatype(vat)).toReferenceString(e.getValue())); + CustomDatatype customDatatype = (CustomDatatype) getDatatype(vat); + String valueReference; + try { + valueReference = customDatatype.getReferenceStringForValue(e.getValue()); + } + catch (UnsupportedOperationException ex) { + throw new APIException("Cannot search for attributes with custom datatype: " + customDatatype.getClass()); + } + serializedAttributeValues.put(vat, valueReference); } } return serializedAttributeValues; @@ -160,4 +170,39 @@ return handlerClasses.contains(handler.getClass()); } + /** + * To be called by service save methods for customizable implementations. + * Iterates over all attributes and calls save on the {@link ConceptDatatype} for any dirty ones. + * + * @param customizable + */ + public static void saveAttributesIfNecessary(Customizable customizable) { + // after we've started doing validation via AOP, move this into a SingleCustomValueSaveHandler + for (Attribute attr : customizable.getAttributes()) { + saveIfDirty(attr); + } + } + + /** + * Calls the save method on value's {@link ConceptDatatype} if necessary + * + * @param value + */ + public static void saveIfDirty(SingleCustomValue value) { + if (value.isDirty()) { + CustomDatatype datatype = CustomDatatypeUtil.getDatatype(value.getDescriptor()); + if (value.getValue() == null) + throw new InvalidCustomValueException(value.getClass() + " with type=" + value.getDescriptor() + + " cannot be null"); + String existingValueReference = null; + try { + existingValueReference = value.getValueReference(); + } + catch (NotYetPersistedException ex) {} + String newValueReference = datatype.save(value.getValue(), existingValueReference); + value.setValueReferenceInternal(newValueReference); + } + + } + } Index: api/src/main/java/org/openmrs/validator/ValidateUtil.java =================================================================== --- api/src/main/java/org/openmrs/validator/ValidateUtil.java (wersja 24555) +++ api/src/main/java/org/openmrs/validator/ValidateUtil.java (kopia robocza) @@ -25,6 +25,7 @@ import org.springframework.util.Assert; import org.springframework.validation.BindException; import org.springframework.validation.Errors; +import org.springframework.validation.FieldError; import org.springframework.validation.ObjectError; import org.springframework.validation.Validator; @@ -95,6 +96,9 @@ for (Object objerr : errors.getAllErrors()) { ObjectError error = (ObjectError) objerr; String message = Context.getMessageSourceService().getMessage(error.getCode()); + if (error instanceof FieldError) { + message = ((FieldError) error).getField() + ": " + message; + } uniqueErrorMessages.add(message); } Index: api/src/test/resources/org/openmrs/include/standardTestDataset.xml =================================================================== --- api/src/test/resources/org/openmrs/include/standardTestDataset.xml (wersja 24555) +++ api/src/test/resources/org/openmrs/include/standardTestDataset.xml (kopia robocza) @@ -199,7 +199,7 @@ - + @@ -231,7 +231,7 @@ - + @@ -298,6 +298,8 @@ + + Index: api/src/test/java/org/openmrs/api/VisitServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/VisitServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/VisitServiceTest.java (kopia robocza) @@ -68,7 +68,7 @@ @Test @Verifies(value = "should get correct visit type", method = "getVisitType(Integer)") - public void getVisitType_shouldGetCorrentVisitType() throws Exception { + public void getVisitType_shouldGetCorrectVisitType() throws Exception { VisitType visitType = Context.getVisitService().getVisitType(1); Assert.assertNotNull(visitType); Assert.assertEquals("Initial HIV Clinic Visit", visitType.getName()); @@ -204,6 +204,7 @@ Assert.assertNotNull(visitType); Context.getVisitService().purgeVisitType(visitType); + Context.flushSession(); visitType = Context.getVisitService().getVisitType(3); Assert.assertNull(visitType); @@ -269,7 +270,7 @@ VisitAttribute visitAttribute = new VisitAttribute(); VisitAttributeType attributeType = Context.getVisitService().getVisitAttributeType(1); attributeType.setName("visit type"); - visitAttribute.setValueReference("first visit"); + visitAttribute.setValueReferenceInternal("first visit"); visitAttribute.setAttributeType(attributeType); return visitAttribute; } @@ -300,7 +301,7 @@ VisitAttribute visitAttribute = new VisitAttribute(); VisitAttributeType attributeType = Context.getVisitService().getVisitAttributeType(1); attributeType.setName("visit type"); - visitAttribute.setValueReference(serializedValue); + visitAttribute.setValueReferenceInternal(serializedValue); visitAttribute.setCreator(user); visitAttribute.setDateCreated(new Date()); visitAttribute.setAttributeType(attributeType); @@ -317,11 +318,13 @@ Assert.assertNull(visit.getLocation());//this is the field we are editing Assert.assertNull(visit.getChangedBy()); Assert.assertNull(visit.getDateChanged()); - visit.setLocation(new Location(1)); + visit.setLocation(Context.getLocationService().getLocation(1)); visit = Context.getVisitService().saveVisit(visit); + Context.flushSession(); Assert.assertNotNull(visit.getChangedBy()); Assert.assertNotNull(visit.getDateChanged()); + Assert.assertEquals(Integer.valueOf(1), visit.getLocation().getLocationId()); } /** @@ -359,6 +362,7 @@ //when visit = service.voidVisit(visit, "test reason"); + Context.flushSession(); //then Assert.assertTrue(visit.isVoided()); @@ -400,6 +404,7 @@ Assert.assertEquals(2, encountersByVisit.size()); service.voidVisit(visit, "test reason"); + Context.flushSession(); Assert.assertTrue(visit.isVoided()); encountersByVisit = Context.getEncounterService().getEncountersByVisit(visit, false); @@ -407,6 +412,7 @@ //when visit = service.unvoidVisit(visit); + Context.flushSession(); //then Assert.assertFalse(visit.isVoided()); @@ -425,6 +431,7 @@ Integer originalSize = vs.getVisits(null, null, null, null, null, null, null, null, null, true, true).size(); Visit visit = Context.getVisitService().getVisit(1); vs.purgeVisit(visit); + Context.flushSession(); Assert.assertEquals(originalSize - 1, vs.getVisits(null, null, null, null, null, null, null, null, null, true, true) .size()); } @@ -611,6 +618,7 @@ executeDataSet(VISITS_ATTRIBUTES_XML); Assert.assertEquals(3, service.getAllVisitAttributeTypes().size()); service.purgeVisitAttributeType(service.getVisitAttributeType(2)); + Context.flushSession(); Assert.assertEquals(2, service.getAllVisitAttributeTypes().size()); } @@ -778,12 +786,34 @@ */ @Test public void saveVisit_shouldBeAbleToAddAnAttributeToAVisit() throws Exception { + Date now = new Date(); Visit visit = service.getVisit(1); VisitAttributeType attrType = service.getVisitAttributeType(1); VisitAttribute attr = new VisitAttribute(); attr.setAttributeType(attrType); - attr.setValue(new Date()); + attr.setValue(now); visit.addAttribute(attr); service.saveVisit(visit); + Assert.assertEquals(new SimpleDateFormat("yyyy-MM-dd").format(now), attr.getValueReference()); } + + @Test + public void shouldVoidASimpleAttribute() throws Exception { + executeDataSet(VISITS_ATTRIBUTES_XML); + Visit visit = service.getVisit(1); + VisitAttributeType attrType = service.getVisitAttributeType(1); + List attributes = visit.getActiveAttributes(attrType); + Assert.assertTrue(attributes.size() > 0); + VisitAttribute attribute = attributes.get(0); + attribute.setVoided(true); + service.saveVisit(visit); + Assert.assertNotNull(attribute.getVoidedBy()); + Assert.assertNotNull(attribute.getDateVoided()); + } + + @Test + public void shouldModifyASimpleAttribute() throws Exception { + + } + } Index: api/src/main/java/org/openmrs/api/impl/VisitServiceImpl.java =================================================================== --- api/src/main/java/org/openmrs/api/impl/VisitServiceImpl.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/impl/VisitServiceImpl.java (kopia robocza) @@ -30,7 +30,10 @@ import org.openmrs.api.VisitService; import org.openmrs.api.context.Context; import org.openmrs.api.db.VisitDAO; +import org.openmrs.customdatatype.CustomDatatype; import org.openmrs.customdatatype.CustomDatatypeUtil; +import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.NotYetPersistedException; import org.openmrs.util.PrivilegeConstants; import org.openmrs.validator.ValidateUtil; import org.openmrs.validator.VisitValidator; @@ -151,11 +154,7 @@ else Context.requirePrivilege(PrivilegeConstants.EDIT_VISITS); - Errors errors = new BindException(visit, "visit"); - new VisitValidator().validate(visit, errors); - if (errors.hasErrors()) - throw new APIException("Validation errors found. " + errors); - + CustomDatatypeUtil.saveAttributesIfNecessary(visit); return dao.saveVisit(visit); } Index: api/src/main/java/org/openmrs/customdatatype/CustomDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/CustomDatatype.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/CustomDatatype.java (kopia robocza) @@ -22,6 +22,10 @@ */ public interface CustomDatatype { + public String VIEW_FAST = "fast"; + + public String VIEW_DEFAULT = "text"; + /** * A {@link CustomValueDescriptor} defines both a datatype and its configuration (e.g. a regex for a RegexValidatedString datatype). * The framework will instantiate datatypes and call this method to set that configuration. Subclasses should define the format @@ -31,23 +35,48 @@ */ void setConfiguration(String config); - /** + /* * Converts a typed value to a reference string (e.g. a UUID for a location, or a URI for an image in a PACS). * Implementations of this method should also call {@link #validate(Object)}. * @param typedValue run-time type should be T * @return the {@link String} representation of the typed value, which will be persisted in the database * @throws InvalidCustomValueException if the value is not valid */ - String toReferenceString(T typedValue) throws InvalidCustomValueException; + //String toReferenceString(T typedValue) throws InvalidCustomValueException; /** + * The OpenMRS service layer calls this method when a custom value of this datatype is saved (created or edited). Implementations + * should persist the typed value, and return a valueReference that can be used to access that value in the future. + * (Simple datatype implementations that don't require external storage may just serialize their typedValue to a String and + * return it.) + * + * @param typedValue + * @param existingValueReference If null, the custom value is being saved for the first time. If not null, this custom value has + * been saved before with the given reference. Implementations may choose to return the same value reference if they are overwriting + * the old value on remote storage. + * @return a valueReference that may be used in the future to retrieve typedValue + * @throws InvalidCustomValueException + */ + String save(T typedValue, String existingValueReference) throws InvalidCustomValueException; + + /** + * Gets the reference string that would be persisted for the given typed value. (This allows efficient searching for exact attribute + * values.) + * + * @param typedValue + * @return + * @throws UnsupportedOperationException if it is not feasible to calculate this efficiently (e.g. you'd need to go to remote storage) + */ + String getReferenceStringForValue(T typedValue) throws UnsupportedOperationException; + + /** * Converts a reference string to its typed value. This may be expensive. - * @param referenceString + * @param persistedValue * @return converts a previously-serialized value back to its original type * @throws InvalidCustomValueException if the persisted value is illegal (perhaps because datatype configuration * was changed since this value was persisted) */ - T fromReferenceString(String referenceString) throws InvalidCustomValueException; + T fromReferenceString(String persistedValue) throws InvalidCustomValueException; /** * TODO where are well-known view constants? @@ -57,13 +86,13 @@ */ String render(String referenceString, String view); - /** + /* * Validates the given persisted value to see if it is a legal value for the given handler. (Implementations may - * implement this simply as validate(fromReferenceString(referenceString)). + * implement this simply as validate(fromPersistentString(persistedValue)). * - * @param referenceString + * @param typedValue */ - void validateReferenceString(String referenceString) throws InvalidCustomValueException; + //void validateReferenceString(String persistedValue) throws InvalidCustomValueException; /** * Validates the given value to see if it is a legal value for the given handler. (For example the RegexValidatedText Index: api/src/test/java/org/openmrs/api/db/UserDAOTest.java =================================================================== --- api/src/test/java/org/openmrs/api/db/UserDAOTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/db/UserDAOTest.java (kopia robocza) @@ -43,7 +43,7 @@ u.setPerson(new Person()); u.getPerson().setGender("M"); - String wildcards[] = new String[] { "%", "_" }; + String wildcards[] = new String[] { "_" }; // we used to also test %, but UserValidator actually doesn't allow that in usernames. TODO: remove the loop //for each of the wildcards in the array, insert a user with a username or names //with the wildcards and carry out a search for that user for (String wildcard : wildcards) { Index: api/src/main/java/org/openmrs/customdatatype/SerializingCustomDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/SerializingCustomDatatype.java (wersja 0) +++ api/src/main/java/org/openmrs/customdatatype/SerializingCustomDatatype.java (wersja 0) @@ -0,0 +1,113 @@ +/** + * 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.customdatatype; + +/** + * + */ +public abstract class SerializingCustomDatatype implements CustomDatatype { + + /** + * @param typedValue (has already had validate called) + * @return a String representation of typedValue + */ + public abstract String serialize(T typedValue); + + /** + * @param serializedValue + * @return the reconstructed typed version of serializedValue + */ + public abstract T deserialize(String serializedValue); + + /** + * Most implementations should override this method to return a user-suitable String representation of + * typedValue in the given view. + * + * The default implementation returns typedValue.toString(). + * + * @param typedValue + * @param view + * @return + */ + public String doRender(T typedValue, String view) { + return typedValue.toString(); + } + + /** + * This method will be called when a consumer wants to generate a view of an object very quickly, for example because + * they want to display 1000 s in a list. The default implementation calls {@link #deserialize(String)} and {@link #doRender(Object, String)} + * with the default view. If an implementation's deserialize is slow, it should override this too. + * + * @param serializedValue + * @return + */ + public String getQuickSummary(String serializedValue) { + return doRender(deserialize(serializedValue), CustomDatatype.VIEW_DEFAULT); + } + + /** + * Does nothing in the default implementation + * @see org.openmrs.customdatatype.CustomDatatype#setConfiguration(java.lang.String) + */ + @Override + public void setConfiguration(String config) { + // not used + } + + /** + * Passes for all non-null values in the default implementation + * @see org.openmrs.customdatatype.CustomDatatype#validate(java.lang.Object) + */ + public void validate(T typedValue) throws InvalidCustomValueException { + if (typedValue == null) + throw new InvalidCustomValueException("cannot be null"); + } + + /** + * @see org.openmrs.customdatatype.CustomDatatype#fromReferenceString(java.lang.String) + */ + @Override + public T fromReferenceString(String persistedValue) throws InvalidCustomValueException { + return deserialize(persistedValue); + } + + /** + * @see org.openmrs.customdatatype.CustomDatatype#save(java.lang.Object, java.lang.String) + */ + public String save(T typedValue, String existingValueReference) throws InvalidCustomValueException { + validate(typedValue); + return serialize(typedValue); + } + + /** + * @see org.openmrs.customdatatype.CustomDatatype#getReferenceStringForValue(java.lang.Object) + */ + public String getReferenceStringForValue(T typedValue) throws UnsupportedOperationException { + return serialize(typedValue); + } + + /** + * Default implementation calls {@link #doRender(Object, String)}. Most implementations should override that + * other method, but if {@link #deserialize(String)} is expensive, then you should override this method instead. + * @see org.openmrs.customdatatype.CustomDatatype#render(java.lang.String, java.lang.String) + */ + @Override + public String render(String serializedValue, String view) { + if (CustomDatatype.VIEW_FAST.equals(view)) + return getQuickSummary(serializedValue); + else + return doRender(deserialize(serializedValue), view); + } + +} Index: api/src/main/java/org/openmrs/customdatatype/datatype/RegexValidatedTextDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/datatype/RegexValidatedTextDatatype.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/datatype/RegexValidatedTextDatatype.java (kopia robocza) @@ -15,16 +15,17 @@ import java.util.regex.Pattern; -import org.openmrs.customdatatype.CustomDatatype; import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.SerializingCustomDatatype; import org.springframework.stereotype.Component; /** * Datatype for a java.lang.String that is validated against a regular expression + * * @since 1.9 */ @Component -public class RegexValidatedTextDatatype implements CustomDatatype { +public class RegexValidatedTextDatatype extends SerializingCustomDatatype { private Pattern pattern; @@ -37,41 +38,23 @@ } /** - * @see org.openmrs.customdatatype.CustomDatatype#toReferenceString(java.lang.Object) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#serialize(java.lang.Object) * @should fail if the string does not match the regex */ @Override - public String toReferenceString(String typedValue) throws InvalidCustomValueException { - validate(typedValue); + public String serialize(String typedValue) { return typedValue; } /** - * @see org.openmrs.customdatatype.CustomDatatype#fromReferenceString(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#deserialize(java.lang.String) */ @Override - public String fromReferenceString(String persistedValue) throws InvalidCustomValueException { - validate(persistedValue); - return persistedValue; + public String deserialize(String serializedValue) { + return serializedValue; } /** - * @see org.openmrs.customdatatype.CustomDatatype#render(java.lang.String, java.lang.String) - */ - @Override - public String render(String persistedValue, String view) { - return persistedValue; - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validateReferenceString(java.lang.String) - */ - @Override - public void validateReferenceString(String persistedValue) throws InvalidCustomValueException { - validate(persistedValue); - } - - /** * @see org.openmrs.customdatatype.CustomDatatype#validate(java.lang.Object) * @should accept a string that matches the regex * @should fail if the string does not match the regex Index: api/src/main/java/org/openmrs/api/AdministrationService.java =================================================================== --- api/src/main/java/org/openmrs/api/AdministrationService.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/AdministrationService.java (kopia robocza) @@ -41,6 +41,8 @@ import org.openmrs.reporting.Report; import org.openmrs.util.OpenmrsConstants; import org.openmrs.util.PrivilegeConstants; +import org.springframework.transaction.annotation.Isolation; +import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; /** @@ -49,6 +51,7 @@ * Use:
* *
+ * 
  * List<GlobalProperty> globalProperties = Context.getAdministrationService().getGlobalProperties();
  * 
* @@ -711,10 +714,14 @@ public T getGlobalPropertyValue(String propertyName, T defaultValue) throws APIException; /** - * * @param aClass class of object getting length for * @param fieldName name of the field to get the length for * @return the max field length of a property */ public int getMaximumPropertyLength(Class aClass, String fieldName); + + //@Transactional(readOnly = true, propagation = Propagation.REQUIRES_NEW, isolation = Isolation.READ_COMMITTED) + //@Transactional(readOnly = true, propagation = Propagation.NESTED) + @Transactional(readOnly = true) + public void validateInNewTransaction(Object mainArgument); } Index: api/src/main/java/org/openmrs/customdatatype/datatype/FreeTextDatatype.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/datatype/FreeTextDatatype.java (wersja 24555) +++ api/src/main/java/org/openmrs/customdatatype/datatype/FreeTextDatatype.java (kopia robocza) @@ -13,63 +13,30 @@ */ package org.openmrs.customdatatype.datatype; -import org.openmrs.customdatatype.CustomDatatype; -import org.openmrs.customdatatype.InvalidCustomValueException; +import org.openmrs.customdatatype.SerializingCustomDatatype; import org.springframework.stereotype.Component; /** * Free-text datatype, represented by a plain java.lang.String. + * * @since 1.9 */ @Component -public class FreeTextDatatype implements CustomDatatype { +public class FreeTextDatatype extends SerializingCustomDatatype { /** - * @see org.openmrs.customdatatype.CustomDatatype#toReferenceString(java.lang.Object) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#serialize(java.lang.Object) */ @Override - public String toReferenceString(String typedValue) throws InvalidCustomValueException { - return typedValue; + public String serialize(String typedValue) { + return (String) typedValue; } /** - * @see org.openmrs.customdatatype.CustomDatatype#fromReferenceString(java.lang.String) + * @see org.openmrs.customdatatype.SerializingCustomDatatype#deserialize(java.lang.String) */ @Override - public String fromReferenceString(String persistedValue) throws InvalidCustomValueException { - return persistedValue; + public String deserialize(String serializedValue) { + return serializedValue; } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#render(java.lang.String, java.lang.String) - */ - @Override - public String render(String persistedValue, String view) { - return persistedValue; - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validateReferenceString(java.lang.String) - */ - @Override - public void validateReferenceString(String persistedValue) throws InvalidCustomValueException { - // pass - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#validate(java.lang.Object) - */ - @Override - public void validate(String typedValue) throws InvalidCustomValueException { - //pass - } - - /** - * @see org.openmrs.customdatatype.CustomDatatype#setConfiguration(java.lang.String) - */ - @Override - public void setConfiguration(String config) { - // not used - } - } Index: api/src/test/java/org/openmrs/validator/VisitValidatorTest.java =================================================================== --- api/src/test/java/org/openmrs/validator/VisitValidatorTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/validator/VisitValidatorTest.java (kopia robocza) @@ -91,7 +91,7 @@ private VisitAttribute makeAttribute(String serializedValue) { VisitAttribute attr = new VisitAttribute(); attr.setAttributeType(service.getVisitAttributeType(1)); - attr.setValueReference(serializedValue); + attr.setValueReferenceInternal(serializedValue); return attr; } @@ -168,6 +168,7 @@ encounter.setVisit(visit); encounter.setEncounterDatetime(visit.getStartDatetime()); Context.getEncounterService().saveEncounter(encounter); + Context.flushSession(); //Set visit start date to after the encounter date. Date date = new Date(encounter.getEncounterDatetime().getTime() + 1); Index: api/src/test/java/org/openmrs/customdatatype/datatype/RegexValidatedTextTest.java =================================================================== --- api/src/test/java/org/openmrs/customdatatype/datatype/RegexValidatedTextTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/customdatatype/datatype/RegexValidatedTextTest.java (kopia robocza) @@ -15,7 +15,7 @@ } /** - * @see RegexValidatedTextDatatype#validate(String) + * @see RegexValidatedText#validate(String) * @verifies accept a string that matches the regex */ @Test @@ -24,7 +24,7 @@ } /** - * @see RegexValidatedTextDatatype#validate(String) + * @see RegexValidatedText#validate(String) * @verifies fail if the string does not match the regex */ @Test(expected = InvalidCustomValueException.class) @@ -33,11 +33,11 @@ } /** - * @see RegexValidatedTextDatatype#toReferenceString(String) + * @see RegexValidatedText#save(String, String)) * @verifies fail if the string does not match the regex */ @Test(expected = InvalidCustomValueException.class) public void toPersistentString_shouldFailIfTheStringDoesNotMatchTheRegex() throws Exception { - datatype.toReferenceString("spaces not allowed"); + datatype.save("spaces not allowed", null); } } Index: web/src/main/java/org/openmrs/web/controller/concept/ConceptStopWordListController.java =================================================================== --- web/src/main/java/org/openmrs/web/controller/concept/ConceptStopWordListController.java (wersja 24555) +++ web/src/main/java/org/openmrs/web/controller/concept/ConceptStopWordListController.java (kopia robocza) @@ -64,6 +64,7 @@ for (String conceptStopWordToBeDeleted : conceptStopWordsToBeDeleted) { try { conceptService.deleteConceptStopWord(new Integer(conceptStopWordToBeDeleted)); + Context.flushSession(); session.setAttribute(WebConstants.OPENMRS_MSG_ATTR, "general.deleted"); } catch (ConceptStopWordException e) { Index: api/src/main/resources/org/openmrs/api/db/hibernate/VisitAttribute.hbm.xml =================================================================== --- api/src/main/resources/org/openmrs/api/db/hibernate/VisitAttribute.hbm.xml (wersja 24555) +++ api/src/main/resources/org/openmrs/api/db/hibernate/VisitAttribute.hbm.xml (kopia robocza) @@ -20,7 +20,7 @@ - + Index: api/src/main/java/org/openmrs/customdatatype/NotYetPersistedException.java =================================================================== --- api/src/main/java/org/openmrs/customdatatype/NotYetPersistedException.java (wersja 0) +++ api/src/main/java/org/openmrs/customdatatype/NotYetPersistedException.java (wersja 0) @@ -0,0 +1,23 @@ +/** + * 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.customdatatype; + +import org.openmrs.api.APIException; + +/** + * Indicates that you tried to access the valueReference of a {@link SingleCustomValue} that has not yet been persisted + */ +public class NotYetPersistedException extends APIException { + +} Index: api/src/test/java/org/openmrs/reporting/export/DataExportTest.java =================================================================== --- api/src/test/java/org/openmrs/reporting/export/DataExportTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/reporting/export/DataExportTest.java (kopia robocza) @@ -627,7 +627,7 @@ DataExportUtil.generateExport(export, patients, "\t", null); File exportFile = DataExportUtil.getGeneratedFile(export); - String expectedOutput = "PATIENT_ID \"FOOD ASSISTANCE\" \"DATE OF FOOD ASSISTANCE\" \"FAVORITE FOOD, NON-CODED\" \"WEIGHT\"\n7 1.0 14/08/2008 PB and J 50.0\n8 \n"; + String expectedOutput = "PATIENT_ID \"FOOD ASSISTANCE\" \"DATE OF FOOD ASSISTANCE\" \"FAVORITE FOOD, NON-CODED\" \"WEIGHT\"\n7 YES 14/08/2008 PB and J 50.0\n8 \n"; String output = OpenmrsUtil.getFileAsString(exportFile); exportFile.delete(); Index: web/src/main/java/org/openmrs/web/controller/maintenance/SettingsController.java =================================================================== --- web/src/main/java/org/openmrs/web/controller/maintenance/SettingsController.java (wersja 24555) +++ web/src/main/java/org/openmrs/web/controller/maintenance/SettingsController.java (kopia robocza) @@ -76,7 +76,7 @@ try { Object value = WebAttributeUtil.getValue(request, dt, handler, "settings[" + i + "].globalProperty.propertyValue"); - property.getGlobalProperty().setPropertyValue(dt.toReferenceString(value)); + property.getGlobalProperty().setValue(value); } catch (Exception ex) { String originalValue = request.getParameter("originalValue[" + i + "]"); Index: api/src/test/java/org/openmrs/api/OrderServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/OrderServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/OrderServiceTest.java (kopia robocza) @@ -107,6 +107,7 @@ Patient p = Context.getPatientService().getPatient(2); Assert.assertFalse(p.isVoided()); Context.getOrderService().voidDrugSet(p, "1", "Reason", OrderService.SHOW_ALL); + Context.flushSession(); Assert.assertFalse(p.isVoided()); } } Index: web/src/test/java/org/openmrs/web/controller/concept/ConceptStopWordListControllerTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/concept/ConceptStopWordListControllerTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/concept/ConceptStopWordListControllerTest.java (kopia robocza) @@ -20,6 +20,7 @@ import org.junit.Assert; import org.junit.Test; import org.openmrs.ConceptStopWord; +import org.openmrs.api.context.Context; import org.openmrs.test.Verifies; import org.openmrs.web.WebConstants; import org.openmrs.web.test.BaseWebContextSensitiveTest; Index: api/src/main/java/org/openmrs/BaseCustomizableMetadata.java =================================================================== --- api/src/main/java/org/openmrs/BaseCustomizableMetadata.java (wersja 24555) +++ api/src/main/java/org/openmrs/BaseCustomizableMetadata.java (kopia robocza) @@ -30,7 +30,7 @@ */ public abstract class BaseCustomizableMetadata
extends BaseOpenmrsMetadata implements Customizable { - private Set attributes; + private Set attributes = new LinkedHashSet(); /** * @see org.openmrs.customdatatype.Customizable#getAttributes() Index: api/src/main/java/org/openmrs/reporting/export/DataExportFunctions.java =================================================================== --- api/src/main/java/org/openmrs/reporting/export/DataExportFunctions.java (wersja 24555) +++ api/src/main/java/org/openmrs/reporting/export/DataExportFunctions.java (kopia robocza) @@ -37,6 +37,7 @@ import org.openmrs.Encounter; import org.openmrs.EncounterType; import org.openmrs.Location; +import org.openmrs.Obs; import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.PatientIdentifierType; @@ -1186,6 +1187,8 @@ return ((EncounterType) o).getName(); else if (o instanceof Date) return formatDate(null, (Date) o); + else if (o instanceof Obs) + return ((Obs) o).getValueAsString(Context.getLocale()); else return o.toString(); } Index: api/src/main/resources/org/openmrs/api/db/hibernate/ProviderAttribute.hbm.xml =================================================================== --- api/src/main/resources/org/openmrs/api/db/hibernate/ProviderAttribute.hbm.xml (wersja 24555) +++ api/src/main/resources/org/openmrs/api/db/hibernate/ProviderAttribute.hbm.xml (kopia robocza) @@ -18,7 +18,7 @@ - + Index: web/src/test/java/org/openmrs/web/controller/GlobalPropertyPortletControllerTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/GlobalPropertyPortletControllerTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/GlobalPropertyPortletControllerTest.java (kopia robocza) @@ -49,6 +49,7 @@ GlobalProperty[] globalProperties = { new GlobalProperty("file.started", ""), new GlobalProperty("file.mandatory", ""), new GlobalProperty("file.other", "") }; Context.getAdministrationService().saveGlobalProperties(Arrays.asList(globalProperties)); + Context.flushSession(); //then portletController.populateModel(request, model); Index: api/src/main/java/org/openmrs/api/impl/ProviderServiceImpl.java =================================================================== --- api/src/main/java/org/openmrs/api/impl/ProviderServiceImpl.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/impl/ProviderServiceImpl.java (kopia robocza) @@ -101,12 +101,7 @@ */ @Override public Provider saveProvider(Provider provider) { - //remove this validation when TRUNK-2393 is done - Errors errors = new BindException(provider, "provider"); - new ProviderValidator().validate(provider, errors); - if (errors.hasErrors()) - throw new APIException(Context.getMessageSourceService().getMessage("error.foundValidationErrors")); - + CustomDatatypeUtil.saveAttributesIfNecessary(provider); return dao.saveProvider(provider); } Index: api/src/main/java/org/openmrs/validator/UserValidator.java =================================================================== --- api/src/main/java/org/openmrs/validator/UserValidator.java (wersja 24555) +++ api/src/main/java/org/openmrs/validator/UserValidator.java (kopia robocza) @@ -105,7 +105,12 @@ * @should not validate when username is whitespace only */ public boolean isUserNameValid(String username) { - //Initialize reg ex for userName pattern + //Initialize reg ex for userName pattern + // ^ = start of line + // \w = [a-zA-Z_0-9] + // \Q = quote everything until \E + // $ = end of line + // complete meaning = 2-50 characters, the first must be a letter, digit, or _, and the rest may also be - or . String expression = "^[\\w][\\Q_\\E\\w-\\.]{1,49}$"; // empty usernames are allowed Index: api/src/test/java/org/openmrs/report/ReportSchemaXmlTest.java =================================================================== --- api/src/test/java/org/openmrs/report/ReportSchemaXmlTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/report/ReportSchemaXmlTest.java (kopia robocza) @@ -112,6 +112,7 @@ // delete the just created report schema xml object rs.deleteReportSchemaXml(reportSchemaXmlFromDB); + Context.flushSession(); // try to fetch that deleted xml object, expect null ReportSchemaXml deletedXml = rs.getReportSchemaXml(1); Index: api/src/main/java/org/openmrs/api/impl/AdministrationServiceImpl.java =================================================================== --- api/src/main/java/org/openmrs/api/impl/AdministrationServiceImpl.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/impl/AdministrationServiceImpl.java (kopia robocza) @@ -58,6 +58,8 @@ import org.openmrs.api.GlobalPropertyListener; import org.openmrs.api.context.Context; import org.openmrs.api.db.AdministrationDAO; +import org.openmrs.customdatatype.CustomDatatypeUtil; +import org.openmrs.customdatatype.SingleCustomValue; import org.openmrs.module.Module; import org.openmrs.module.ModuleFactory; import org.openmrs.module.ModuleUtil; @@ -67,6 +69,7 @@ import org.openmrs.util.OpenmrsConstants; import org.openmrs.util.OpenmrsUtil; import org.openmrs.util.PrivilegeConstants; +import org.openmrs.validator.ValidateUtil; import org.springframework.util.StringUtils; /** @@ -775,9 +778,9 @@ * @see org.openmrs.api.AdministrationService#saveGlobalProperty(org.openmrs.GlobalProperty) */ public GlobalProperty saveGlobalProperty(GlobalProperty gp) throws APIException { - // only try to save it if the global property has a key if (gp.getProperty() != null && gp.getProperty().length() > 0) { + CustomDatatypeUtil.saveIfDirty(gp); dao.saveGlobalProperty(gp); notifyGlobalPropertyChange(gp); return gp; @@ -1212,4 +1215,12 @@ public int getMaximumPropertyLength(Class aClass, String fieldName) { return dao.getMaximumPropertyLength(aClass, fieldName); } + + /** + * @see org.openmrs.api.AdministrationService#validateInNewTransaction(java.lang.Object) + */ + @Override + public void validateInNewTransaction(Object mainArgument) { + ValidateUtil.validate(mainArgument); + } } Index: api/src/test/java/org/openmrs/api/ConceptServiceTest.java =================================================================== --- api/src/test/java/org/openmrs/api/ConceptServiceTest.java (wersja 24555) +++ api/src/test/java/org/openmrs/api/ConceptServiceTest.java (kopia robocza) @@ -1072,8 +1072,9 @@ assertNotNull(concept); ObsService obsService = Context.getObsService(); - obsService.saveObs(new Obs(new Person(1), concept, new Date(), new Location(1)), - "Creating a new observation with a concept"); + Obs obs = new Obs(new Person(1), concept, new Date(), new Location(1)); + obs.setValueCoded(Context.getConceptService().getConcept(7)); + obsService.saveObs(obs, "Creating a new observation with a concept"); ConceptDatatype newDatatype = conceptService.getConceptDatatypeByName("Text"); concept.setDatatype(newDatatype); @@ -1095,8 +1096,9 @@ assertNotNull(concept); ObsService obsService = Context.getObsService(); - obsService.saveObs(new Obs(new Person(1), concept, new Date(), new Location(1)), - "Creating a new observation with a concept"); + Obs obs = new Obs(new Person(1), concept, new Date(), new Location(1)); + obs.setValueCoded(Context.getConceptService().getConcept(7)); + obsService.saveObs(obs, "Creating a new observation with a concept"); conceptService.saveConcept(concept); } @@ -1260,7 +1262,7 @@ @Verifies(value = "should fail if any of the conceptNames of the concept is being used by an obs", method = "purgeConcept(Concept)") public void purgeConcept_shouldFailIfAnyOfTheConceptNamesOfTheConceptIsBeingUsedByAnObs() throws Exception { Obs o = new Obs(); - o.setConcept(new Concept(3)); + o.setConcept(Context.getConceptService().getConcept(3)); o.setPerson(new Patient(2)); o.setEncounter(new Encounter(3)); o.setObsDatetime(new Date()); @@ -1446,6 +1448,7 @@ conceptService.deleteConceptStopWord(2); conceptService.deleteConceptStopWord(3); conceptService.deleteConceptStopWord(4); + Context.flushSession(); List conceptStopWords = conceptService.getAllConceptStopWords(); assertEquals(0, conceptStopWords.size()); @@ -1472,6 +1475,7 @@ assertEquals(1, conceptStopWords.size()); conceptService.deleteConceptStopWord(4); + Context.flushSession(); conceptStopWords = conceptService.getConceptStopWords(Locale.US); assertEquals(0, conceptStopWords.size()); @@ -1743,6 +1747,7 @@ mapType.setName("random name"); mapType.setDescription("random description"); ConceptMapType editedMapType = Context.getConceptService().saveConceptMapType(mapType); + Context.flushSession(); Assert.assertEquals("random name", editedMapType.getName()); Assert.assertEquals("random description", editedMapType.getDescription()); //date changed and changed by should have been updated @@ -1886,6 +1891,7 @@ term.setConceptSource(conceptSource2); ConceptReferenceTerm editedTerm = Context.getConceptService().saveConceptReferenceTerm(term); + Context.flushSession(); Assert.assertEquals("new name", editedTerm.getName()); Assert.assertEquals("new code", editedTerm.getCode()); Assert.assertEquals("new descr", editedTerm.getDescription()); Index: web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormValidatorTest.java =================================================================== --- web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormValidatorTest.java (wersja 24555) +++ web/src/test/java/org/openmrs/web/controller/patient/ShortPatientFormValidatorTest.java (kopia robocza) @@ -248,6 +248,7 @@ PersonName name = new PersonName("my", "duplicate", "name"); patient.addName(name); Context.getPatientService().savePatient(patient); + Context.flushSession(); Assert.assertNotNull(name.getId());//should have been added ShortPatientModel model = new ShortPatientModel(patient); @@ -280,6 +281,7 @@ address.setAddress2("address2"); patient.addAddress(address); Context.getPatientService().savePatient(patient); + Context.flushSession(); Assert.assertNotNull(address.getId());//should have been added ShortPatientModel model = new ShortPatientModel(patient); Index: api/src/main/java/org/openmrs/api/db/hibernate/HibernatePatientSetDAO.java =================================================================== --- api/src/main/java/org/openmrs/api/db/hibernate/HibernatePatientSetDAO.java (wersja 24555) +++ api/src/main/java/org/openmrs/api/db/hibernate/HibernatePatientSetDAO.java (kopia robocza) @@ -579,7 +579,6 @@ String stringValue = null; Concept codedValue = null; Date dateValue = null; - Boolean booleanValue = null; String valueSql = null; if (value != null) { if (concept == null) { @@ -619,11 +618,18 @@ } valueSql = "o.value_datetime"; } else if (concept.getDatatype().isBoolean()) { - if (value instanceof Boolean) - booleanValue = (Boolean) value; - else - booleanValue = Boolean.valueOf(value.toString()); - valueSql = "o.value_numeric"; + if (value instanceof Concept) { + codedValue = (Concept) value; + } else { + boolean asBoolean = false; + if (value instanceof Boolean) + asBoolean = ((Boolean) value).booleanValue(); + else + asBoolean = Boolean.valueOf(value.toString()); + codedValue = asBoolean ? Context.getConceptService().getTrueConcept() : Context.getConceptService() + .getFalseConcept(); + } + valueSql = "o.value_coded"; } } @@ -699,8 +705,6 @@ query.setString("value", stringValue); else if (dateValue != null) query.setDate("value", dateValue); - else if (booleanValue != null) - query.setDouble("value", booleanValue ? 1.0 : 0.0); else throw new IllegalArgumentException( "useValue is true, but numeric, coded, string, boolean, and date values are all null"); @@ -1236,7 +1240,7 @@ List columns = new Vector(); if (abbrev.equals("BIT")) - columns.add("valueNumeric"); + columns.add("valueCoded"); else if (abbrev.equals("CWE")) { columns.add("valueDrug"); columns.add("valueCoded");