From 38e4a07a1cda9b8377dcc116b6661f5f712ef7d5 Mon Sep 17 00:00:00 2001 From: Angshuman Sarkar Date: Fri, 1 Dec 2023 17:39:32 +0530 Subject: [PATCH] BAH-3181 | Enable locale specific concept search and also return FSN in defaultLocale Updated /bahmnicore/observations API to take in optional locale parameter, so that concepts are searched in the locale. Observation.conceptFSN returns the FSN in implementation/default locale --- .../contract/BahmniObservation.java | 9 ++++ .../mapper/OMRSObsToBahmniObsMapper.java | 34 +++++++++++-- .../mapper/ObsRelationshipMapper.java | 6 +-- .../mapper/ObsRelationshipMapperTest.java | 10 ++-- .../bahmnicore/service/impl/BahmniBridge.java | 5 +- .../service/impl/BahmniObsServiceImpl.java | 8 ++-- .../service/impl/BahmniBridgeTest.java | 2 +- .../impl/BahmniObsServiceImplTest.java | 6 +-- .../BahmniObservationsController.java | 48 ++++++++++++++++--- 9 files changed, 99 insertions(+), 29 deletions(-) diff --git a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/contract/BahmniObservation.java b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/contract/BahmniObservation.java index cad649dd35..62f85be997 100644 --- a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/contract/BahmniObservation.java +++ b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/contract/BahmniObservation.java @@ -43,6 +43,7 @@ public class BahmniObservation implements Comparable{ private String interpretation; private String status; private String encounterTypeName; + private String conceptFSN; @JsonIgnore private Serializable complexData; @@ -431,4 +432,12 @@ public String getEncounterTypeName() { public void setEncounterTypeName(String encounterTypeName) { this.encounterTypeName = encounterTypeName; } + + public void setConceptFSN(String conceptFSN) { + this.conceptFSN = conceptFSN; + } + + public String getConceptFSN() { + return this.conceptFSN; + } } diff --git a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/OMRSObsToBahmniObsMapper.java b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/OMRSObsToBahmniObsMapper.java index 512c6ef393..bf4c88fcff 100644 --- a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/OMRSObsToBahmniObsMapper.java +++ b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/OMRSObsToBahmniObsMapper.java @@ -2,13 +2,17 @@ import org.apache.commons.collections.CollectionUtils; import org.openmrs.Concept; +import org.openmrs.ConceptName; import org.openmrs.EncounterProvider; import org.openmrs.Obs; +import org.openmrs.api.ConceptNameType; import org.openmrs.module.bahmniemrapi.drugorder.mapper.BahmniProviderMapper; import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.parameters.AdditionalBahmniObservationFields; import org.openmrs.module.emrapi.encounter.ObservationMapper; import org.openmrs.module.emrapi.encounter.matcher.ObservationTypeMatcher; +import org.openmrs.module.emrapi.utils.HibernateLazyLoader; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -16,6 +20,7 @@ import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.Locale; @Component(value = "omrsObsToBahmniObsMapper") public class OMRSObsToBahmniObsMapper { @@ -33,9 +38,10 @@ public OMRSObsToBahmniObsMapper(ETObsToBahmniObsMapper etObsToBahmniObsMapper, O public Collection map(List obsList, Collection rootConcepts) { Collection bahmniObservations = new ArrayList<>(); + Locale implementationLocale = LocaleUtility.getDefaultLocale(); for (Obs obs : obsList) { if(observationTypeMatcher.getObservationType(obs).equals(ObservationTypeMatcher.ObservationType.OBSERVATION)){ - BahmniObservation bahmniObservation =map(obs); + BahmniObservation bahmniObservation = map(obs, implementationLocale); if(CollectionUtils.isNotEmpty(rootConcepts )){ bahmniObservation.setConceptSortWeight(ConceptSortWeightUtil.getSortWeightFor(bahmniObservation.getConcept().getName(), rootConcepts)); } @@ -45,7 +51,7 @@ public Collection map(List obsList, Collection return bahmniObservations; } - public BahmniObservation map(Obs obs) { + public BahmniObservation map(Obs obs, Locale implementationLocale) { if(obs == null) return null; String obsGroupUuid = obs.getObsGroup() == null? null : obs.getObsGroup().getUuid(); @@ -61,6 +67,28 @@ public BahmniObservation map(Obs obs) { for (EncounterProvider encounterProvider : obs.getEncounter().getEncounterProviders()) { additionalBahmniObservationFields.addProvider(bahmniProviderMapper.map(encounterProvider.getProvider())); } - return etObsToBahmniObsMapper.map(observationMapper.map(obs), additionalBahmniObservationFields, Collections.singletonList(obs.getConcept()), true); + BahmniObservation bahmniObservation = etObsToBahmniObsMapper.map(observationMapper.map(obs), additionalBahmniObservationFields, Collections.singletonList(obs.getConcept()), true); + bahmniObservation.setConceptFSN(getConceptFSNInDefaultLocale(obs, implementationLocale)); + return bahmniObservation; + } + + private String getConceptFSNInDefaultLocale(Obs obs, Locale implementationLocale) { + if (obs.getConcept() == null) { + return null; + } + Concept concept = new HibernateLazyLoader().load(obs.getConcept()); + if (implementationLocale == null) { + return concept.getName().getName(); + } + ConceptName fsn = concept.getName(implementationLocale, ConceptNameType.FULLY_SPECIFIED, null); + if (fsn == null) { + fsn = concept.getNames().stream().filter(name -> !name.getVoided() && name.getLocale().equals(implementationLocale) + && name.getConceptNameType().equals(ConceptNameType.FULLY_SPECIFIED)).findFirst().orElse(null); + } + if (fsn != null) { + return fsn.getName(); + } else { + return concept.getName().getName(); + } } } diff --git a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapper.java b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapper.java index d8eadc662b..b7d37510a4 100644 --- a/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapper.java +++ b/bahmni-emr-api/src/main/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapper.java @@ -34,7 +34,7 @@ public List map(List bahmniObservations, S new org.openmrs.module.bahmniemrapi.obsrelation.contract.ObsRelationship(); targetObsRelation.setRelationshipType(obsRelationship.getObsRelationshipType().getName()); targetObsRelation.setUuid(obsRelationship.getUuid()); - targetObsRelation.setTargetObs(OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs())); + targetObsRelation.setTargetObs(OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs(), null)); bahmniObservation.setTargetObsRelation(targetObsRelation); // bahmniObservation.setProviders(providers); } @@ -47,8 +47,8 @@ public List map(List obsRelationships) { List bahmniObservations = new ArrayList<>(); for (ObsRelationship obsRelationship : obsRelationships) { - BahmniObservation sourceObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getSourceObs()); - BahmniObservation targetObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs()); + BahmniObservation sourceObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getSourceObs(), null); + BahmniObservation targetObservation = OMRSObsToBahmniObsMapper.map(obsRelationship.getTargetObs(), null); sourceObservation.setProviders(encounterProviderMapper.convert(obsRelationship.getSourceObs().getEncounter().getEncounterProviders())); org.openmrs.module.bahmniemrapi.obsrelation.contract.ObsRelationship targetObsRelation = diff --git a/bahmni-emr-api/src/test/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapperTest.java b/bahmni-emr-api/src/test/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapperTest.java index 6ce71e0e0d..350e6abde9 100644 --- a/bahmni-emr-api/src/test/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapperTest.java +++ b/bahmni-emr-api/src/test/java/org/openmrs/module/bahmniemrapi/encountertransaction/mapper/ObsRelationshipMapperTest.java @@ -72,7 +72,7 @@ public void shouldMapObsRelationshipForBahmniObservations() { BahmniObservation sourceObservation = getBahmniObservation(sourceObsUuid); BahmniObservation targetObservation = getBahmniObservation(targetObsUuid); - when(OMRSObsToBahmniObsMapper.map(targetObs)).thenReturn(targetObservation); + when(OMRSObsToBahmniObsMapper.map(targetObs, null)).thenReturn(targetObservation); ArrayList bahmniObservations = new ArrayList<>(); bahmniObservations.add(sourceObservation); @@ -81,7 +81,7 @@ public void shouldMapObsRelationshipForBahmniObservations() { List mappedBahmniObservations = obsRelationshipMapper.map(bahmniObservations, "encounter-uuid"); verify(obsrelationService).getRelationsWhereSourceObsInEncounter("encounter-uuid"); - verify(OMRSObsToBahmniObsMapper, times(1)).map(targetObs); + verify(OMRSObsToBahmniObsMapper, times(1)).map(targetObs, null); assertEquals(2, mappedBahmniObservations.size()); assertEquals(sourceObsUuid, mappedBahmniObservations.get(0).getUuid()); assertEquals(targetObsUuid, mappedBahmniObservations.get(0).getTargetObsRelation().getTargetObs().getUuid()); @@ -112,8 +112,8 @@ public void shouldMapMultipleObsRelationshipForBahmniObservations() { BahmniObservation targetObservation1 = getBahmniObservation(targetObs1Uuid); BahmniObservation targetObservation2 = getBahmniObservation(targetObs2Uuid); - when(OMRSObsToBahmniObsMapper.map(targetObs1)).thenReturn(targetObservation1); - when(OMRSObsToBahmniObsMapper.map(targetObs2)).thenReturn(targetObservation2); + when(OMRSObsToBahmniObsMapper.map(targetObs1, null)).thenReturn(targetObservation1); + when(OMRSObsToBahmniObsMapper.map(targetObs2, null)).thenReturn(targetObservation2); ArrayList bahmniObservations = new ArrayList<>(); bahmniObservations.add(sourceObservation1); @@ -124,7 +124,7 @@ public void shouldMapMultipleObsRelationshipForBahmniObservations() { List mappedBahmniObservations = obsRelationshipMapper.map(bahmniObservations, "encounter-uuid"); verify(obsrelationService).getRelationsWhereSourceObsInEncounter("encounter-uuid"); - verify(OMRSObsToBahmniObsMapper, times(2)).map(any(Obs.class)); + verify(OMRSObsToBahmniObsMapper, times(2)).map(any(Obs.class), any()); assertEquals(4, mappedBahmniObservations.size()); assertEquals(sourceObs1Uuid, mappedBahmniObservations.get(0).getUuid()); assertEquals(targetObs1Uuid, mappedBahmniObservations.get(0).getTargetObsRelation().getTargetObs().getUuid()); diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridge.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridge.java index 695225a196..a875997c7b 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridge.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridge.java @@ -18,7 +18,6 @@ import org.openmrs.api.context.Context; import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.OMRSObsToBahmniObsMapper; -import org.openmrs.module.emrapi.encounter.OrderMapper; import org.openmrs.module.emrapi.encounter.domain.EncounterTransaction; import org.openmrs.module.emrapi.encounter.mapper.OrderMapper1_12; import org.springframework.beans.factory.annotation.Autowired; @@ -240,13 +239,13 @@ else if (o1.getDateActivated().after(o2.getDateActivated())) public BahmniObservation getChildObsFromParentObs(String parentObsGroupUuid, String childConceptName){ Concept childConcept = conceptService.getConceptByName(childConceptName); - return omrsObsToBahmniObsMapper.map(obsDao.getChildObsFromParent(parentObsGroupUuid, childConcept)); + return omrsObsToBahmniObsMapper.map(obsDao.getChildObsFromParent(parentObsGroupUuid, childConcept), null); } public BahmniObservation getLatestBahmniObservationFor(String conceptName){ Obs obs = latestObs(conceptName); if(obs != null) { - return omrsObsToBahmniObsMapper.map(obs); + return omrsObsToBahmniObsMapper.map(obs, null); } return null; } diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java index 5261d0f361..698b3db31a 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImpl.java @@ -21,9 +21,7 @@ import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; import org.openmrs.module.bahmniemrapi.encountertransaction.mapper.OMRSObsToBahmniObsMapper; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.util.*; @@ -93,7 +91,7 @@ private boolean programDoesNotHaveEncounters(String patientProgramUuid, Collecti private List convertToBahmniObservation(List observations) { List bahmniObservations = new ArrayList<>(); for (Obs observation : observations) { - BahmniObservation bahmniObservation = omrsObsToBahmniObsMapper.map(observation); + BahmniObservation bahmniObservation = omrsObsToBahmniObsMapper.map(observation, null); bahmniObservation.setObservationDateTime(observation.getObsDatetime()); bahmniObservations.add(bahmniObservation); } @@ -265,7 +263,7 @@ public Collection getInitialObservationsForPatientProgram(Str @Override public BahmniObservation getBahmniObservationByUuid(String observationUuid) { Obs obs = obsService.getObsByUuid(observationUuid); - return omrsObsToBahmniObsMapper.map(obs); + return omrsObsToBahmniObsMapper.map(obs, null); } @Override @@ -274,7 +272,7 @@ public BahmniObservation getRevisedBahmniObservationByUuid(String observationUui if (obs.getVoided()) { obs = getRevisionObs(obs); } - return omrsObsToBahmniObsMapper.map(obs); + return omrsObsToBahmniObsMapper.map(obs, null); } @Override diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridgeTest.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridgeTest.java index 58bdfad7c3..492d909346 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridgeTest.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniBridgeTest.java @@ -151,7 +151,7 @@ public void shouldGetChildObservationFromParent() throws Exception { bahmniObs.setUuid("observation uuid"); PowerMockito.when(obsDao.getChildObsFromParent("parent obs uuid", vitalsConcept)).thenReturn(obs); - PowerMockito.when(omrsObsToBahmniObsMapper.map(obs)).thenReturn(bahmniObs); + PowerMockito.when(omrsObsToBahmniObsMapper.map(obs, null)).thenReturn(bahmniObs); Assert.assertEquals("observation uuid", bahmniBridge.getChildObsFromParentObs("parent obs uuid", "vital concept name").getUuid()); } diff --git a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImplTest.java b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImplTest.java index d988bcb71e..4cb5f5e368 100644 --- a/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImplTest.java +++ b/bahmnicore-api/src/test/java/org/bahmni/module/bahmnicore/service/impl/BahmniObsServiceImplTest.java @@ -214,12 +214,12 @@ public void shouldGetBahmniObservationByObservationUuid() throws Exception { Obs obs = new Obs(); BahmniObservation expectedBahmniObservation = new BahmniObservation(); when(obsService.getObsByUuid(observationUuid)).thenReturn(obs); - when(omrsObsToBahmniObsMapper.map(obs)).thenReturn(expectedBahmniObservation); + when(omrsObsToBahmniObsMapper.map(obs, null)).thenReturn(expectedBahmniObservation); BahmniObservation actualBahmniObservation = bahmniObsService.getBahmniObservationByUuid(observationUuid); verify(obsService, times(1)).getObsByUuid(observationUuid); - verify(omrsObsToBahmniObsMapper, times(1)).map(obs); + verify(omrsObsToBahmniObsMapper, times(1)).map(obs, null); assertNotNull(actualBahmniObservation); assertEquals(expectedBahmniObservation, actualBahmniObservation); } @@ -262,7 +262,7 @@ public void shouldReturnBahmniObservationWhenGetObsForFormBuilderFormsCalled() { when(visitDao.getVisitIdsFor(patientUuid, numberOfVisits)).thenReturn(visitIds); when(obsDao.getObsForFormBuilderForms(patientUuid, formNames, visitIds, encounters, null, null)) .thenReturn(singletonList(observation)); - when(omrsObsToBahmniObsMapper.map(observation)).thenReturn(bahmniObservation); + when(omrsObsToBahmniObsMapper.map(observation, null)).thenReturn(bahmniObservation); Collection bahmniObservations = bahmniObsService.getObsForFormBuilderForms(patientUuid, formNames, numberOfVisits, null, null, patientProgramUuid); diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/display/controls/BahmniObservationsController.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/display/controls/BahmniObservationsController.java index 137b651df3..0af0d32376 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/display/controls/BahmniObservationsController.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/controller/display/controls/BahmniObservationsController.java @@ -1,17 +1,21 @@ package org.bahmni.module.bahmnicore.web.v1_0.controller.display.controls; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.ObjectUtils; import org.bahmni.module.bahmnicore.extensions.BahmniExtensions; import org.bahmni.module.bahmnicore.obs.ObservationsAdder; import org.bahmni.module.bahmnicore.service.BahmniObsService; import org.bahmni.module.bahmnicore.util.MiscUtils; import org.openmrs.Concept; +import org.openmrs.ConceptSearchResult; import org.openmrs.Visit; +import org.openmrs.api.APIException; import org.openmrs.api.ConceptService; import org.openmrs.api.VisitService; import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.v1_0.controller.BaseRestController; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @@ -21,8 +25,15 @@ import java.text.ParseException; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; +import java.util.Collections; +import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; +import java.util.Optional; +import java.util.Set; +import java.util.stream.Collectors; @Controller @RequestMapping(value = "/rest/" + RestConstants.VERSION_1 + "/bahmnicore/observations") @@ -47,27 +58,52 @@ public BahmniObservationsController(BahmniObsService bahmniObsService, ConceptSe @ResponseBody public Collection get(@RequestParam(value = "patientUuid", required = true) String patientUUID, @RequestParam(value = "concept", required = true) List rootConceptNames, + @RequestParam(value = "locale", required = false) String locale, @RequestParam(value = "scope", required = false) String scope, @RequestParam(value = "numberOfVisits", required = false) Integer numberOfVisits, @RequestParam(value = "obsIgnoreList", required = false) List obsIgnoreList, @RequestParam(value = "filterObsWithOrders", required = false, defaultValue = "true") Boolean filterObsWithOrders ) throws ParseException { - List rootConcepts = MiscUtils.getConceptsForNames(rootConceptNames, conceptService); - + List conceptList = searchConceptsByName(rootConceptNames, identifyLocale(locale)); Collection observations; if (ObjectUtils.equals(scope, LATEST)) { - observations = bahmniObsService.getLatest(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null); + observations = bahmniObsService.getLatest(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null); } else if (ObjectUtils.equals(scope, INITIAL)) { - observations = bahmniObsService.getInitial(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null); + observations = bahmniObsService.getInitial(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null); } else { - observations = bahmniObsService.observationsFor(patientUUID, rootConcepts, numberOfVisits, obsIgnoreList, filterObsWithOrders, null, null, null); + observations = bahmniObsService.observationsFor(patientUUID, conceptList, numberOfVisits, obsIgnoreList, filterObsWithOrders, null, null, null); } - sendObsToGroovyScript(getConceptNames(rootConcepts), observations); + sendObsToGroovyScript(getConceptNames(conceptList), observations); return observations; } + private List searchConceptsByName(List conceptNames, Locale searchLocale) { + Set conceptSet = new LinkedHashSet<>(); + if (CollectionUtils.isNotEmpty(conceptNames)) { + List localeList = Collections.singletonList(searchLocale); + for (String name : conceptNames) { + List conceptsSearchResult = conceptService.getConcepts(name, localeList, false, null, null, null, null, null, 0, null); + List conceptsByName = conceptsSearchResult.stream().map(conceptSearchResult -> conceptSearchResult.getConcept()).collect(Collectors.toList()); + conceptSet.addAll(conceptsByName); + } + } + return new ArrayList<>(conceptSet); + } + + private Locale identifyLocale(String locale) { + if (locale != null && !locale.isEmpty()) { + Locale searchLocale = LocaleUtility.fromSpecification(locale); + if (searchLocale.getLanguage().isEmpty()) { + throw new APIException("Invalid locale: " + locale); + } + return searchLocale; + } else { + return LocaleUtility.getDefaultLocale(); + } + } + @RequestMapping(method = RequestMethod.GET, params = {"visitUuid"}) @ResponseBody public Collection get(@RequestParam(value = "visitUuid", required = true) String visitUuid,