/** * This Source Code Form is subject to the terms of the Mozilla Public License, * v. 2.0. If a copy of the MPL was not distributed with this file, You can * obtain one at http://mozilla.org/MPL/2.0/. OpenMRS is also distributed under * the terms of the Healthcare Disclaimer located at http://openmrs.org/license. * * Copyright (C) OpenMRS Inc. OpenMRS is a registered trademark and the OpenMRS * graphic logo is a trademark of OpenMRS Inc. */ package org.openmrs.module.webservices.rest.web.v1_0.resource.openmrs1_8; import java.util.Arrays; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.openmrs.Patient; import org.openmrs.PatientIdentifier; import org.openmrs.Person; import org.openmrs.api.PatientService; import org.openmrs.api.context.Context; import org.openmrs.module.webservices.rest.SimpleObject; import org.openmrs.module.webservices.rest.web.ConversionUtil; import org.openmrs.module.webservices.rest.web.RequestContext; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.annotation.PropertyGetter; import org.openmrs.module.webservices.rest.web.annotation.PropertySetter; import org.openmrs.module.webservices.rest.web.annotation.Resource; import org.openmrs.module.webservices.rest.web.api.RestService; import org.openmrs.module.webservices.rest.web.representation.DefaultRepresentation; import org.openmrs.module.webservices.rest.web.representation.FullRepresentation; import org.openmrs.module.webservices.rest.web.representation.Representation; import org.openmrs.module.webservices.rest.web.resource.impl.AlreadyPaged; import org.openmrs.module.webservices.rest.web.resource.impl.DataDelegatingCrudResource; import org.openmrs.module.webservices.rest.web.resource.impl.DelegatingResourceDescription; import org.openmrs.module.webservices.rest.web.resource.impl.ServiceSearcher; import org.openmrs.module.webservices.rest.web.response.ConversionException; import org.openmrs.module.webservices.rest.web.response.ResourceDoesNotSupportOperationException; import org.openmrs.module.webservices.rest.web.response.ResponseException; import org.openmrs.module.webservices.validation.ValidateUtil; /** * {@link Resource} for Patients, supporting standard CRUD operations */ @Resource(name = RestConstants.VERSION_1 + "/patient", supportedClass = Patient.class, supportedOpenmrsVersions = { "1.8.*" }) public class PatientResource1_8 extends DataDelegatingCrudResource<Patient> { public PatientResource1_8() { } @PropertyGetter("person") public static Person getPerson(Patient instance) { return new Person(instance); //Must be a Person instead of Patient to prevent infinite recursion RESTWS-273 } /** * It is empty, because we set that already in the create method. * <p> * It takes String instead of Person so that the uuid is not resolved to a person, which leads * to the Hibernate exception: the object is already associated with the session. * * @param instance * @param personUuid */ @PropertySetter("person") public static void setPerson(Patient instance, String personUuid) { } @PropertyGetter("identifiers") public static Set<PatientIdentifier> getIdentifiers(Patient instance) { return new LinkedHashSet<PatientIdentifier>(instance.getActiveIdentifiers()); } @PropertySetter("identifiers") public static void setIdentifiers(Patient instance, List<PatientIdentifier> identifiers) throws ResourceDoesNotSupportOperationException { if (instance.getIdentifiers() != null && instance.getIdentifiers().containsAll(identifiers)) { return; } if (instance.getIdentifiers() != null && !instance.getIdentifiers().isEmpty()) { throw new ResourceDoesNotSupportOperationException("Identifiers can only be set for newly created objects!"); } if (identifiers == null || identifiers.isEmpty()) { throw new ResourceDoesNotSupportOperationException("At least one identifier required"); } boolean hasPreferred = false; for (PatientIdentifier identifier : identifiers) { if (identifier.isPreferred()) { if (!hasPreferred) { hasPreferred = true; } else { throw new ResourceDoesNotSupportOperationException("Only one preferred identifier allowed"); } } } if (!hasPreferred) { //Mark the first one as preferred if none marked identifiers.iterator().next().setPreferred(true); } instance.getIdentifiers().clear(); for (PatientIdentifier identifier : identifiers) { instance.addIdentifier(identifier); } } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#getRepresentationDescription(org.openmrs.module.webservices.rest.web.representation.Representation) */ @Override public DelegatingResourceDescription getRepresentationDescription(Representation rep) { if (rep instanceof DefaultRepresentation) { DelegatingResourceDescription description = new DelegatingResourceDescription(); description.addProperty("uuid"); description.addProperty("display"); description.addProperty("identifiers", Representation.REF); description.addProperty("person", Representation.DEFAULT); description.addProperty("voided"); description.addSelfLink(); description.addLink("full", ".?v=" + RestConstants.REPRESENTATION_FULL); return description; } else if (rep instanceof FullRepresentation) { DelegatingResourceDescription description = new DelegatingResourceDescription(); description.addProperty("uuid"); description.addProperty("display"); description.addProperty("identifiers", Representation.DEFAULT); description.addProperty("person", Representation.FULL); description.addProperty("voided"); description.addProperty("auditInfo"); description.addSelfLink(); return description; } return null; } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#getCreatableProperties() */ @Override public DelegatingResourceDescription getCreatableProperties() { DelegatingResourceDescription description = new DelegatingResourceDescription(); description.addRequiredProperty("person"); description.addRequiredProperty("identifiers"); return description; } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.BaseDelegatingResource#getUpdatableProperties() */ @Override public DelegatingResourceDescription getUpdatableProperties() { DelegatingResourceDescription description = new DelegatingResourceDescription(); description.addRequiredProperty("person"); return description; } /** * The method is overwritten, because we need to create a patient from an existing person. In * the POST body only person and identifiers are provided and other properties must come from * the existing person. We need to promote the existing person to be a patient by overwriting it * and at the same time preserving all person properties. * * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#create(org.openmrs.module.webservices.rest.SimpleObject, * org.openmrs.module.webservices.rest.web.RequestContext) */ @Override public Object create(SimpleObject propertiesToCreate, RequestContext context) throws ResponseException { Patient delegate = getPatient(propertiesToCreate); ValidateUtil.validate(delegate); delegate = save(delegate); return ConversionUtil.convertToRepresentation(delegate, Representation.DEFAULT); } public Patient getPatient(SimpleObject propertiesToCreate) { Object personProperty = propertiesToCreate.get("person"); Person person = null; if (personProperty == null) { throw new ConversionException("The person property is missing"); } else if (personProperty instanceof String) { person = Context.getPersonService().getPersonByUuid((String) personProperty); Context.evictFromSession(person); } else if (personProperty instanceof Map) { person = (Person) ConversionUtil.convert(personProperty, Person.class); propertiesToCreate.put("person", ""); } Patient delegate = new Patient(person); setConvertedProperties(delegate, propertiesToCreate, getCreatableProperties(), true); return delegate; } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#newDelegate() */ @Override public Patient newDelegate() { return new Patient(); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#save(java.lang.Object) */ @Override public Patient save(Patient patient) { return Context.getPatientService().savePatient(patient); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#getByUniqueId(java.lang.String) */ @Override public Patient getByUniqueId(String uuid) { return Context.getPatientService().getPatientByUuid(uuid); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#delete(java.lang.Object, * java.lang.String, org.openmrs.module.webservices.rest.web.RequestContext) */ @Override public void delete(Patient patient, String reason, RequestContext context) throws ResponseException { if (patient.isVoided()) { // DELETE is idempotent, so we return success here return; } Context.getPatientService().voidPatient(patient, reason); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#purge(java.lang.Object, * org.openmrs.module.webservices.rest.web.RequestContext) */ @Override public void purge(Patient patient, RequestContext context) throws ResponseException { if (patient == null) { // DELETE is idempotent, so we return success here return; } Context.getPatientService().purgePatient(patient); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#doSearch(org.openmrs.module.webservices.rest.web.RequestContext) */ @Override protected AlreadyPaged<Patient> doSearch(RequestContext context) { return new ServiceSearcher<Patient>(PatientService.class, "getPatients", "getCountOfPatients").search( context.getParameter("q"), context); } /** * @see org.openmrs.module.webservices.rest.web.resource.impl.DelegatingCrudResource#getPropertiesToExposeAsSubResources() */ @Override public List<String> getPropertiesToExposeAsSubResources() { return Arrays.asList("identifiers"); } /** * @param patient * @return identifier + name (for concise display purposes) */ @PropertyGetter("display") public String getDisplayString(Patient patient) { if (patient.getPatientIdentifier() == null) return ""; return patient.getPatientIdentifier().getIdentifier() + " - " + patient.getPersonName().getFullName(); } @Override public Object update(String uuid, SimpleObject propertiesToUpdate, RequestContext context) throws ResponseException { if (propertiesToUpdate.get("person") == null) { return super.update(uuid, propertiesToUpdate, context); } Patient patient = getPatientForUpdate(uuid, propertiesToUpdate); ValidateUtil.validate(patient); patient = save(patient); return ConversionUtil.convertToRepresentation(patient, Representation.DEFAULT); } public Patient getPatientForUpdate(String uuid, Map<String, Object> propertiesToUpdate) { Patient patient = getByUniqueId(uuid); PersonResource1_8 personResource = (PersonResource1_8) Context.getService(RestService.class) .getResourceBySupportedClass(Person.class); personResource.setConvertedProperties(patient, (Map<String, Object>) propertiesToUpdate.get("person"), personResource.getUpdatableProperties(), false); return patient; } }