From 9693e249af803f87db4df4d5dff60f48188e1fa0 Mon Sep 17 00:00:00 2001 From: Siva Reddy Date: Mon, 20 Nov 2023 11:55:42 +0530 Subject: [PATCH 1/2] BAH-3266 | Siva Reddy | Fetching concepts from default locale if no concepts in requested locale --- .../bahmnicore/dao/impl/ObsDaoImpl.java | 11 +- .../module/bahmnicore/util/MiscUtils.java | 19 ++++ .../search/BahmniConceptSearchHandler.java | 27 ++++- .../BahmniConceptSearchHandlerTest.java | 102 ++++++++++++++++++ 4 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java index 474d564a60..15a276bee0 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/dao/impl/ObsDaoImpl.java @@ -15,6 +15,7 @@ import org.openmrs.Person; import org.openmrs.api.ConceptNameType; import org.openmrs.api.context.Context; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Repository; @@ -24,6 +25,7 @@ import java.util.Collection; import java.util.Date; import java.util.List; +import java.util.Locale; import static java.util.Objects.nonNull; @@ -77,7 +79,7 @@ public List getObsByPatientAndVisit(String patientUuid, List concep " where obs.person.uuid = :patientUuid " + " and cn.concept = obs.concept.conceptId " + " and cn.name in (:conceptNames) " + - " and cn.locale = :locale " + + " and cn.locale in (:locale) " + " and cn.conceptNameType = :conceptNameType " + " and cn.voided = false and obs.voided = false "); @@ -106,13 +108,18 @@ public List getObsByPatientAndVisit(String patientUuid, List concep query.append(" order by obs.obsDatetime desc "); } + List localeList = new ArrayList<>(); + localeList.add(Context.getLocale()); + if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + localeList.add(LocaleUtility.getDefaultLocale()); + } Query queryToGetObservations = sessionFactory.getCurrentSession().createQuery(query.toString()); queryToGetObservations.setMaxResults(limit); queryToGetObservations.setString("patientUuid", patientUuid); queryToGetObservations.setParameterList("conceptNames", conceptNames); queryToGetObservations.setParameter("conceptNameType", ConceptNameType.FULLY_SPECIFIED); - queryToGetObservations.setString("locale", Context.getLocale().getLanguage()); + queryToGetObservations.setParameterList("locale", localeList); if (null != obsIgnoreList && obsIgnoreList.size() > 0) { queryToGetObservations.setParameterList("obsIgnoreList", obsIgnoreList); } diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java index 9db4592d01..5d27b9b639 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java @@ -2,8 +2,11 @@ import org.apache.commons.collections.CollectionUtils; import org.openmrs.Concept; +import org.openmrs.ConceptName; import org.openmrs.api.ConceptService; +import org.openmrs.api.context.Context; import org.openmrs.module.bahmniemrapi.encountertransaction.contract.BahmniObservation; +import org.openmrs.util.LocaleUtility; import java.util.ArrayList; import java.util.Collection; @@ -18,6 +21,9 @@ public static List getConceptsForNames(List conceptNames, Conce List rootConcepts = new ArrayList<>(); for (String rootConceptName : conceptNames) { Concept concept = conceptService.getConceptByName(rootConceptName); + if (concept == null) { + concept = getConceptInDefaultLocale(conceptService, rootConceptName); + } if (concept != null) { rootConcepts.add(concept); } @@ -26,6 +32,19 @@ public static List getConceptsForNames(List conceptNames, Conce } return new ArrayList<>(); } + private static Concept getConceptInDefaultLocale(ConceptService conceptService, String rootConceptName) { + if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + List conceptsByName = conceptService.getConceptsByName(rootConceptName, LocaleUtility.getDefaultLocale(), false); + for (Concept concept : conceptsByName) { + for (ConceptName conceptname : concept.getNames()) { + if (conceptname.getName().equalsIgnoreCase(rootConceptName) && (conceptname.isPreferred() || conceptname.isFullySpecifiedName())) { + return concept; + } + } + } + } + return null; + } public static void setUuidsForObservations(Collection bahmniObservations) { for (BahmniObservation bahmniObservation : bahmniObservations) { diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java index 30ae7c0881..2149c2fa84 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java @@ -3,8 +3,10 @@ import org.apache.commons.collections.CollectionUtils; import org.openmrs.Concept; import org.openmrs.ConceptName; +import org.openmrs.ConceptSearchResult; import org.openmrs.api.APIException; import org.openmrs.api.ConceptService; +import org.openmrs.api.context.Context; import org.openmrs.module.webservices.rest.web.RequestContext; import org.openmrs.module.webservices.rest.web.RestConstants; import org.openmrs.module.webservices.rest.web.resource.api.PageableResult; @@ -14,6 +16,7 @@ import org.openmrs.module.webservices.rest.web.resource.impl.EmptySearchResult; import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; import org.openmrs.module.webservices.rest.web.response.ResponseException; +import org.openmrs.util.LocaleUtility; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @@ -21,6 +24,8 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; @Component public class BahmniConceptSearchHandler implements SearchHandler { @@ -38,7 +43,11 @@ public SearchConfig getSearchConfig() { @Override public PageableResult search(RequestContext context) throws ResponseException { String conceptName = context.getParameter("name"); - List conceptsByName = conceptService.getConceptsByName(conceptName); + List localeList = getLocales(context); + + List conceptsSearchResult = conceptService.getConcepts(conceptName, localeList, false, null, null, null, null, null, 0, null); + List conceptsByName = conceptsSearchResult.stream().map(conceptSearchResult -> conceptSearchResult.getConcept()).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(conceptsByName)) { return new EmptySearchResult(); } else { @@ -59,4 +68,20 @@ public PageableResult search(RequestContext context) throws ResponseException { } } + private List getLocales(RequestContext context) { + String locale = context.getParameter("locale"); + + List localeList = new ArrayList<>(); + localeList.add(LocaleUtility.getDefaultLocale()); + + if (locale != null) { + localeList.add(LocaleUtility.fromSpecification(locale)); + } else { + localeList.add(Context.getLocale()); + } + + localeList = localeList.stream().distinct().collect(Collectors.toList()); + return localeList; + } + } diff --git a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java new file mode 100644 index 0000000000..d6ad27b653 --- /dev/null +++ b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java @@ -0,0 +1,102 @@ +package org.bahmni.module.bahmnicore.web.v1_0.search; + + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.runners.MockitoJUnitRunner; +import org.openmrs.Concept; +import org.openmrs.ConceptName; +import org.openmrs.ConceptSearchResult; +import org.openmrs.api.ConceptNameType; +import org.openmrs.api.ConceptService; +import org.openmrs.module.webservices.rest.web.RequestContext; +import org.openmrs.module.webservices.rest.web.resource.api.SearchConfig; +import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; +import org.openmrs.util.LocaleUtility; +import org.springframework.beans.factory.annotation.Qualifier; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Locale; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyList; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNull; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@RunWith(MockitoJUnitRunner.class) +public class BahmniConceptSearchHandlerTest { + + @Mock + @Qualifier("conceptService") + private ConceptService conceptService; + + @Mock + RequestContext requestContext; + + @InjectMocks + private BahmniConceptSearchHandler bahmniConceptSearchHandler; + + + @Test + public void shouldSearchByQuestion() { + SearchConfig searchConfig = bahmniConceptSearchHandler.getSearchConfig(); + assertEquals(searchConfig.getId(), "byFullySpecifiedName"); + } + + @Test + public void shouldSupportVersions1_8To2() { + SearchConfig searchConfig = bahmniConceptSearchHandler.getSearchConfig(); + assertTrue(searchConfig.getSupportedOpenmrsVersions().contains("1.8.* - 2.*")); + } + + @Test + public void shouldSearchByGivenLocaleAndDefaultLocale_whenLocaleIsSpecified() { + List conceptSearchResults = new ArrayList<>(); + ConceptSearchResult result = new ConceptSearchResult(); + Concept concept = new Concept(); + concept.setId(10); + ConceptName conceptNameFullySpecified = new ConceptName(); + conceptNameFullySpecified.setConceptNameType(ConceptNameType.FULLY_SPECIFIED); + conceptNameFullySpecified.setName("Nutritional Values"); + concept.setNames(Collections.singleton(conceptNameFullySpecified)); + result.setConcept(concept); + conceptSearchResults.add(result); + + List localeList = new ArrayList<>(); + localeList.add(LocaleUtility.getDefaultLocale()); + localeList.add(Locale.FRENCH); + + when(conceptService.getConcepts(anyString(), anyList(), anyBoolean(), isNull(), isNull(), isNull(), isNull(), isNull(), any(Integer.class), isNull())).thenReturn(conceptSearchResults); + when(requestContext.getLimit()).thenReturn(10); + when(requestContext.getParameter("locale")).thenReturn("fr"); + when(requestContext.getParameter("name")).thenReturn("Nutritional Values"); + + + NeedsPaging searchResults = (NeedsPaging) bahmniConceptSearchHandler.search(requestContext); + + verify(conceptService, times(1)).getConcepts("Nutritional Values", localeList, false, null, null, null, null, null, 0, null); + assertEquals(1, searchResults.getPageOfResults().size()); + assertEquals(new Integer(10) , searchResults.getPageOfResults().get(0).getId()); + } + + @Test + public void shouldSearchByLoggedInLocaleAndDefaultLocale_whenLocaleIsNotSpecified() { + when(requestContext.getParameter("name")).thenReturn("Nutritional Values"); + + bahmniConceptSearchHandler.search(requestContext); + List localeList = new ArrayList<>(); + localeList.add(LocaleUtility.getDefaultLocale()); + + verify(conceptService, times(1)).getConcepts("Nutritional Values", localeList, false, null, null, null, null, null, 0, null); + } +} From 722e47fbd0d77178ccbd2de81892f72abd968e51 Mon Sep 17 00:00:00 2001 From: Siva Reddy Date: Wed, 22 Nov 2023 10:01:51 +0530 Subject: [PATCH 2/2] BAH-3266 | Review comments --- .../module/bahmnicore/util/MiscUtils.java | 15 ++++++++------- .../search/BahmniConceptSearchHandler.java | 19 +++++++++++++++++-- .../BahmniConceptSearchHandlerTest.java | 12 ++++++++---- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java index 5d27b9b639..73042231b6 100644 --- a/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java +++ b/bahmnicore-api/src/main/java/org/bahmni/module/bahmnicore/util/MiscUtils.java @@ -33,13 +33,14 @@ public static List getConceptsForNames(List conceptNames, Conce return new ArrayList<>(); } private static Concept getConceptInDefaultLocale(ConceptService conceptService, String rootConceptName) { - if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { - List conceptsByName = conceptService.getConceptsByName(rootConceptName, LocaleUtility.getDefaultLocale(), false); - for (Concept concept : conceptsByName) { - for (ConceptName conceptname : concept.getNames()) { - if (conceptname.getName().equalsIgnoreCase(rootConceptName) && (conceptname.isPreferred() || conceptname.isFullySpecifiedName())) { - return concept; - } + if (LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + return null; + } + List conceptsByName = conceptService.getConceptsByName(rootConceptName, LocaleUtility.getDefaultLocale(), false); + for (Concept concept : conceptsByName) { + for (ConceptName conceptname : concept.getNames()) { + if (conceptname.getName().equalsIgnoreCase(rootConceptName) && (conceptname.isPreferred() || conceptname.isFullySpecifiedName())) { + return concept; } } } diff --git a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java index 2149c2fa84..d401b7c432 100644 --- a/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java +++ b/bahmnicore-omod/src/main/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandler.java @@ -40,6 +40,14 @@ public SearchConfig getSearchConfig() { return new SearchConfig("byFullySpecifiedName", RestConstants.VERSION_1 + "/concept", Arrays.asList("1.8.* - 2.*"), searchQuery); } + /** + * Searches for concepts by the given parameters. (Currently only supports name and locale (optional)) + * @return a list of concepts matching the given parameters. + * @throws APIException + * Should return concepts in the specified locale if specified. + * Should return concepts in the default locale as well as logged in locale if locale is not specified. + */ + @Override public PageableResult search(RequestContext context) throws ResponseException { String conceptName = context.getParameter("name"); @@ -68,19 +76,26 @@ public PageableResult search(RequestContext context) throws ResponseException { } } + /** + * Returns list of unique locales based on the context.getParameter("locale") parameter + * Should return List of results for locales: If locale is specified, then return results for that locale. + * If locale is not specified, then return results for logged in locale and default locale. + */ + private List getLocales(RequestContext context) { String locale = context.getParameter("locale"); List localeList = new ArrayList<>(); - localeList.add(LocaleUtility.getDefaultLocale()); if (locale != null) { localeList.add(LocaleUtility.fromSpecification(locale)); } else { localeList.add(Context.getLocale()); + if (!LocaleUtility.getDefaultLocale().equals(Context.getLocale())) { + localeList.add(LocaleUtility.getDefaultLocale()); + } } - localeList = localeList.stream().distinct().collect(Collectors.toList()); return localeList; } diff --git a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java index d6ad27b653..5bdbd50bb0 100644 --- a/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java +++ b/bahmnicore-omod/src/test/java/org/bahmni/module/bahmnicore/web/v1_0/search/BahmniConceptSearchHandlerTest.java @@ -11,6 +11,7 @@ import org.openmrs.ConceptSearchResult; import org.openmrs.api.ConceptNameType; import org.openmrs.api.ConceptService; +import org.openmrs.api.context.UserContext; import org.openmrs.module.webservices.rest.web.RequestContext; import org.openmrs.module.webservices.rest.web.resource.api.SearchConfig; import org.openmrs.module.webservices.rest.web.resource.impl.NeedsPaging; @@ -43,6 +44,9 @@ public class BahmniConceptSearchHandlerTest { @Mock RequestContext requestContext; + @Mock + UserContext userContext; + @InjectMocks private BahmniConceptSearchHandler bahmniConceptSearchHandler; @@ -60,11 +64,11 @@ public void shouldSupportVersions1_8To2() { } @Test - public void shouldSearchByGivenLocaleAndDefaultLocale_whenLocaleIsSpecified() { + public void shouldSearchByGivenLocale_whenLocaleIsSpecified() { List conceptSearchResults = new ArrayList<>(); ConceptSearchResult result = new ConceptSearchResult(); Concept concept = new Concept(); - concept.setId(10); + concept.setId(123); ConceptName conceptNameFullySpecified = new ConceptName(); conceptNameFullySpecified.setConceptNameType(ConceptNameType.FULLY_SPECIFIED); conceptNameFullySpecified.setName("Nutritional Values"); @@ -73,7 +77,6 @@ public void shouldSearchByGivenLocaleAndDefaultLocale_whenLocaleIsSpecified() { conceptSearchResults.add(result); List localeList = new ArrayList<>(); - localeList.add(LocaleUtility.getDefaultLocale()); localeList.add(Locale.FRENCH); when(conceptService.getConcepts(anyString(), anyList(), anyBoolean(), isNull(), isNull(), isNull(), isNull(), isNull(), any(Integer.class), isNull())).thenReturn(conceptSearchResults); @@ -86,7 +89,8 @@ public void shouldSearchByGivenLocaleAndDefaultLocale_whenLocaleIsSpecified() { verify(conceptService, times(1)).getConcepts("Nutritional Values", localeList, false, null, null, null, null, null, 0, null); assertEquals(1, searchResults.getPageOfResults().size()); - assertEquals(new Integer(10) , searchResults.getPageOfResults().get(0).getId()); + assertEquals(1, localeList.size()); + assertEquals(new Integer(123) , searchResults.getPageOfResults().get(0).getId()); } @Test