From 891ad6a3e793503b2dada28f61f60b9c39398bda Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Fri, 17 Oct 2025 10:22:32 -0700 Subject: [PATCH 01/64] Set version to 2.4.0 --- CHANGELOG.md | 4 ++++ build.gradle | 2 +- .../gov/nih/nci/evs/api/configuration/OpenAPIDefinition.java | 2 +- .../gov/nih/nci/evs/api/controller/VersionController.java | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b61dd620d..2b43910da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [2.4.0.RELEASE] - 2025-MM-DD +### Changed +- TBD + ## [2.3.0.RELEASE] - 2025-10-15 ### Changed - Various minor bug fixes and typo corrections diff --git a/build.gradle b/build.gradle index 83001e70e..03e6b8275 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ ext { /* Version info */ group = "gov.nih.nci.evs.api" -version = "2.3.0.RELEASE" +version = "2.4.0.RELEASE" sourceCompatibility = 17 targetCompatibility = 17 diff --git a/src/main/java/gov/nih/nci/evs/api/configuration/OpenAPIDefinition.java b/src/main/java/gov/nih/nci/evs/api/configuration/OpenAPIDefinition.java index 05f1a9332..8d329b984 100644 --- a/src/main/java/gov/nih/nci/evs/api/configuration/OpenAPIDefinition.java +++ b/src/main/java/gov/nih/nci/evs/api/configuration/OpenAPIDefinition.java @@ -10,7 +10,7 @@ info = @Info( title = "NCI EVS Rest API", - version = "2.3.0.RELEASE", + version = "2.4.0.RELEASE", termsOfService = "https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/ThesaurusTermsofUse.htm", description = "Endpoints to support searching, metadata, and content retrieval for EVS" diff --git a/src/main/java/gov/nih/nci/evs/api/controller/VersionController.java b/src/main/java/gov/nih/nci/evs/api/controller/VersionController.java index 5e7145642..2914b933b 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/VersionController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/VersionController.java @@ -25,7 +25,7 @@ public class VersionController extends BaseController { private static final Logger log = LoggerFactory.getLogger(VersionController.class); // Used for FHIR metadata and other places where the version is needed - public static final String VERSION = "2.3.0.RELEASE"; + public static final String VERSION = "2.4.0.RELEASE"; /** * Returns the evs concept detail. From 4e78c7babde8d29214871ff7452a80a04ba7a3d8 Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Wed, 12 Nov 2025 10:52:46 -0800 Subject: [PATCH 02/64] EVSRESTAPI-681: avoid re-running for the same terminology (#428) --- .../gov/nih/nci/evs/api/service/BaseLoaderService.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java index 1b13981ec..deb77d1e2 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java @@ -270,9 +270,16 @@ public void updateLatestFlag(final Terminology terminology, final Set re boolean latestMonthlyFound = false; boolean latestWeeklyFound = false; boolean latestFound = false; + final Set seen = new HashSet<>(); for (final IndexMetadata iMeta : iMetas) { + // skip if seen + if (seen.contains(iMeta.getTerminology().getTerminology())) { + continue; + } + seen.add(iMeta.getTerminology().getTerminology()); + final boolean monthly = iMeta.getTerminology().getTags().containsKey("monthly"); final boolean weekly = iMeta.getTerminology().getTags().containsKey("weekly"); From 7d55530360f51b52cc9e06ffa7e0c44af9cbbbbe Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Wed, 12 Nov 2025 13:41:02 -0800 Subject: [PATCH 03/64] Dss/evsrestapi 634 search modifiers (#429) * EVSRESTAPI-636: spotless misc * EVSRESTAPI-634: uri search modifiers and string missing search modifiers --- .../evs/api/fhir/R5/CodeSystemProviderR5.java | 2 +- .../evs/api/fhir/R5/ConceptMapProviderR5.java | 5 +- .../evs/api/fhir/R5/ValueSetProviderR5.java | 11 +- .../gov/nih/nci/evs/api/util/FhirUtility.java | 136 +++++++++++- .../fhir/FhirR5CodeSystemReadSearchTests.java | 190 +++++++++++++++++ .../fhir/FhirR5ConceptMapReadSearchTests.java | 189 +++++++++++++++++ .../fhir/FhirR5ValueSetReadSearchTests.java | 193 ++++++++++++++++++ 7 files changed, 715 insertions(+), 11 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java index e06ca23a9..462a931cf 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java @@ -128,7 +128,7 @@ public Bundle findCodeSystems( // Skip non-matching if ((id != null && !id.getValue().equals(cs.getIdPart())) - || (url != null && !url.getValue().equals(cs.getUrl()))) { + || (url != null && !FhirUtility.compareUri(url, cs.getUrl()))) { logger.debug(" SKIP url mismatch = " + cs.getUrl()); continue; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java index c62ba8e62..51dae0d88 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java @@ -15,6 +15,7 @@ import ca.uhn.fhir.rest.param.NumberParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import gov.nih.nci.evs.api.model.Concept; @@ -101,7 +102,7 @@ public Bundle findConceptMaps( @OptionalParam(name = "_id") final TokenParam id, @OptionalParam(name = "date") final DateRangeParam date, @OptionalParam(name = "name") final StringParam name, - @OptionalParam(name = "url") final StringParam url, + @OptionalParam(name = "url") final UriParam url, @OptionalParam(name = "version") final StringParam version, @Description(shortDefinition = "Number of entries to return") @OptionalParam(name = "_count") final NumberParam count, @@ -135,7 +136,7 @@ public Bundle findConceptMaps( map.get(mapset.getPropertyValue("targetTerminology")), mapset); // Skip non-matching - if (url != null && !url.getValue().equals(cm.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, cm.getUrl())) { logger.debug(" SKIP url mismatch = " + cm.getUrl()); continue; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java index 3459112b4..f0f178e06 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java @@ -9,10 +9,7 @@ import ca.uhn.fhir.rest.annotation.OptionalParam; import ca.uhn.fhir.rest.annotation.Read; import ca.uhn.fhir.rest.annotation.Search; -import ca.uhn.fhir.rest.param.DateRangeParam; -import ca.uhn.fhir.rest.param.NumberParam; -import ca.uhn.fhir.rest.param.StringParam; -import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.*; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; @@ -126,7 +123,7 @@ public Bundle findValueSets( @OptionalParam(name = "code") final StringParam code, @OptionalParam(name = "name") final StringParam name, @OptionalParam(name = "title") final StringParam title, - @OptionalParam(name = "url") final StringParam url, + @OptionalParam(name = "url") final UriParam url, @OptionalParam(name = "version") final StringParam version, @Description(shortDefinition = "Number of entries to return") @OptionalParam(name = "_count") final NumberParam count, @@ -154,7 +151,7 @@ public Bundle findValueSets( logger.debug(" SKIP date mismatch = " + vs.getDate()); continue; } - if (url != null && !url.getValue().equals(vs.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, vs.getUrl())) { logger.debug(" SKIP url mismatch = " + vs.getUrl()); continue; } @@ -188,7 +185,7 @@ public Bundle findValueSets( logger.debug(" SKIP date mismatch = " + vs.getDate()); continue; } - if (url != null && !url.getValue().equals(vs.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, vs.getUrl())) { logger.debug(" SKIP url mismatch = " + vs.getUrl()); continue; } diff --git a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java index b836a6e5c..c6e64891c 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java +++ b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java @@ -12,6 +12,8 @@ import ca.uhn.fhir.rest.param.DateParam; import ca.uhn.fhir.rest.param.DateRangeParam; import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.UriParam; import java.util.Date; import java.util.HashMap; import java.util.Map; @@ -50,7 +52,20 @@ private static String getTypeName(final Object obj) { */ public static boolean compareString(final StringParam s1, final String s2) { // If we've not specified a search term, then we pass through a match - if (s1 == null || StringUtils.isEmpty(s1.getValue())) { + if (s1 == null) { + return true; + } + + // Handle :missing modifier FIRST (before checking if value is empty) + // FHIR spec: param:missing=true returns resources WITHOUT the value + // param:missing=false returns resources WITH the value + if (s1.getMissing() != null) { + boolean isMissing = (s2 == null || s2.isEmpty()); + return isMissing == s1.getMissing().booleanValue(); + } + + // Now check if search value is empty + if (StringUtils.isEmpty(s1.getValue())) { return true; } @@ -70,6 +85,125 @@ public static boolean compareString(final StringParam s1, final String s2) { } } + /** + * Compare token. Handles :missing and :not modifiers for TokenParam. FHIR spec: :not modifier + * only works with token parameters. + * + * @param t1 the token parameter + * @param t2 the target value + * @return true, if successful + */ + public static boolean compareToken(final TokenParam t1, final String t2) { + // If we've not specified a search term, then we pass through a match + if (t1 == null) { + return true; + } + + // Handle :missing modifier FIRST (before checking if value is empty) + // FHIR spec: param:missing=true returns resources WITHOUT the value + // param:missing=false returns resources WITH the value + // TokenParam has getMissing() method just like StringParam + if (t1.getMissing() != null) { + boolean isMissing = (t2 == null || t2.isEmpty()); + return isMissing == t1.getMissing().booleanValue(); + } + + // Handle :not modifier (FHIR spec: only for token parameters) + // Returns resources that do NOT match the value (includes resources without the element) + if (t1.getModifier() != null && t1.getModifier().equals(":not")) { + if (t2 == null || t2.isEmpty()) { + return true; // Include resources without the element + } + return !t1.getValue().equals(t2); + } + + // Now check if value is empty + if (StringUtils.isEmpty(t1.getValue())) { + return true; + } + + // If we've specified a search term but the target element is not populated, that's not a + // match + if (t2 == null) { + return false; + } + + // Default: exact match for token parameters + return t1.getValue().equals(t2); + } + + /** + * Compare URI with support for :above, :below, :contains, and :missing modifiers. FHIR spec: URI + * parameters support hierarchical and substring matching. Note: UriParam in HAPI FHIR supports + * modifiers through getQualifier(). + * + * @param u1 the URI parameter with possible modifiers + * @param u2 the target URI to compare against + * @return true, if successful + */ + public static boolean compareUri(final UriParam u1, final String u2) { + // If we've not specified a search term, then we pass through a match + if (u1 == null) { + return true; + } + + // Handle :missing modifier FIRST (before checking if value is empty) + // FHIR spec: param:missing=true returns resources WITHOUT the value + // param:missing=false returns resources WITH the value + if (u1.getMissing() != null) { + boolean isMissing = (u2 == null || u2.isEmpty()); + return isMissing == u1.getMissing().booleanValue(); + } + + // Now check if search value is empty + if (StringUtils.isEmpty(u1.getValue())) { + return true; + } + + // If we've specified a search term but the target element is not populated, that's not a + // match + if (u2 == null) { + return false; + } + + // Check for modifiers using getQualifier() + // HAPI FHIR stores modifiers like ":above", ":below", ":contains" in the qualifier + if (u1.getQualifier() != null) { + String qualifier = String.valueOf(u1.getQualifier()); + + if (qualifier.equals(":above")) { + // FHIR spec: :above returns resources where the resource URI is at or ABOVE + // (parent of) the search value in the URL hierarchy + // Example: search "url:above=http://example.com/a/b/c" + // matches: http://example.com/a/b/c (exact) + // matches: http://example.com/a/b (parent) + // matches: http://example.com/a (grandparent) + // Implementation: search value must start with resource URL (or be equal) + return u1.getValue().startsWith(u2) || u1.getValue().equals(u2); + } + + if (qualifier.equals(":below")) { + // FHIR spec: :below returns resources where the resource URI is at or BELOW + // (child of) the search value in the URL hierarchy + // Example: search "url:below=http://example.com/a" + // matches: http://example.com/a (exact) + // matches: http://example.com/a/b (child) + // matches: http://example.com/a/b/c (grandchild) + // Implementation: resource URL must start with search value (or be equal) + return u2.startsWith(u1.getValue()) || u2.equals(u1.getValue()); + } + + if (qualifier.equals(":contains")) { + // FHIR spec: :contains returns resources where the URI contains the search value + // Simple substring matching (case-insensitive for URIs) + return u2.toLowerCase().contains(u1.getValue().toLowerCase()); + } + } + + // Default: exact match for URI parameters + return u1.getValue().equals(u2); + } + /** * Compare date. * diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java index 5b15b81e7..40f757487 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java @@ -1162,4 +1162,194 @@ public void testCodeSystemSearchSortByInvalidField() throws Exception { assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test code system search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test 1: Find CodeSystems WITH a publisher (publisher:missing=false) + String url = endpoint + "?publisher:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a publisher + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find CodeSystems with publishers"); + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull( + cs.getPublisher(), "CodeSystem should have a publisher when publisher:missing=false"); + assertFalse(cs.getPublisher().isEmpty(), "CodeSystem publisher should not be empty"); + } + + // Test 2: Find CodeSystems WITHOUT a publisher (publisher:missing=true) + url = endpoint + "?publisher:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a publisher + assertNotNull(bundle); + // Note: May be empty if all CodeSystems have publishers + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertTrue( + cs.getPublisher() == null || cs.getPublisher().isEmpty(), + "CodeSystem should not have a publisher when publisher:missing=true"); + } + } + + /** + * Test code system search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test 1: Find CodeSystems WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find CodeSystems with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url when url:missing=false"); + assertFalse(cs.getUrl().isEmpty(), "CodeSystem url should not be empty"); + } + + // Test 2: Find CodeSystems WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all CodeSystems have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertTrue( + cs.getUrl() == null || cs.getUrl().isEmpty(), + "CodeSystem should not have a url when url:missing=true"); + } + } + + /** + * Test code system search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test: Find CodeSystems where URL contains "ncit" + String url = endpoint + "?url:contains=ncit&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "ncit" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + cs.getUrl().toLowerCase().contains("ncit"), + "CodeSystem url should contain 'ncit': " + cs.getUrl()); + } + } + } + + /** + * Test code system search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // First, get a known CodeSystem with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one CodeSystem"); + CodeSystem firstCs = (CodeSystem) data.getEntry().get(0).getResource(); + String baseUrl = firstCs.getUrl(); + + // Test: Find CodeSystems where URL is at or below the base URL + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + cs.getUrl().startsWith(parentUrl) || cs.getUrl().equals(parentUrl), + "CodeSystem url should be at or below '" + parentUrl + "': " + cs.getUrl()); + } + } + } + } + + /** + * Test code system search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // First, get a known CodeSystem with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one CodeSystem"); + CodeSystem firstCs = (CodeSystem) data.getEntry().get(0).getResource(); + String childUrl = firstCs.getUrl(); + + // Test: Find CodeSystems where URL is at or above the child URL + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + childUrl.startsWith(cs.getUrl()) || childUrl.equals(cs.getUrl()), + "Search url '" + + childUrl + + "' should be at or below CodeSystem url '" + + cs.getUrl() + + "'"); + } + } + } + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java index f349d2afa..805a86b3d 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java @@ -1121,4 +1121,193 @@ public void testConceptMapSearchSortByInvalidField() throws Exception { assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test concept map search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test 1: Find ConceptMaps WITH a name (name:missing=false) + String url = endpoint + "?name:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a name + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ConceptMaps with names"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getName(), "ConceptMap should have a name when name:missing=false"); + assertFalse(cm.getName().isEmpty(), "ConceptMap name should not be empty"); + } + + // Test 2: Find ConceptMaps WITHOUT a name (name:missing=true) + url = endpoint + "?name:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a name + assertNotNull(bundle); + // Note: May be empty if all ConceptMaps have names + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertTrue( + cm.getName() == null || cm.getName().isEmpty(), + "ConceptMap should not have a name when name:missing=true"); + } + } + + /** + * Test concept map search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test 1: Find ConceptMaps WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ConceptMaps with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url when url:missing=false"); + assertFalse(cm.getUrl().isEmpty(), "ConceptMap url should not be empty"); + } + + // Test 2: Find ConceptMaps WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all ConceptMaps have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertTrue( + cm.getUrl() == null || cm.getUrl().isEmpty(), + "ConceptMap should not have a url when url:missing=true"); + } + } + + /** + * Test concept map search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test: Find ConceptMaps where URL contains "ncit" + String url = endpoint + "?url:contains=ncit&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "ncit" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + cm.getUrl().toLowerCase().contains("ncit"), + "ConceptMap url should contain 'ncit': " + cm.getUrl()); + } + } + } + + /** + * Test concept map search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // First, get a known ConceptMap with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ConceptMap"); + ConceptMap firstCm = (ConceptMap) data.getEntry().get(0).getResource(); + String baseUrl = firstCm.getUrl(); + + // Test: Find ConceptMaps where URL is at or below the base URL + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + cm.getUrl().startsWith(parentUrl) || cm.getUrl().equals(parentUrl), + "ConceptMap url should be at or below '" + parentUrl + "': " + cm.getUrl()); + } + } + } + } + + /** + * Test concept map search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // First, get a known ConceptMap with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ConceptMap"); + ConceptMap firstCm = (ConceptMap) data.getEntry().get(0).getResource(); + String childUrl = firstCm.getUrl(); + + // Test: Find ConceptMaps where URL is at or above the child URL + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + childUrl.startsWith(cm.getUrl()) || childUrl.equals(cm.getUrl()), + "Search url '" + + childUrl + + "' should be at or below ConceptMap url '" + + cm.getUrl() + + "'"); + } + } + } + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index dbdcc5b09..ccc200762 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -1382,4 +1382,197 @@ public void testValueSetSearchSortByInvalidField() throws Exception { assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test value set search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test 1: Find ValueSets WITH a name (name:missing=false) + String url = endpoint + "?name:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a name + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ValueSets with names"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getName(), "ValueSet should have a name when name:missing=false"); + assertFalse(vs.getName().isEmpty(), "ValueSet name should not be empty"); + } + + // Test 2: Find ValueSets WITHOUT a name (name:missing=true) + url = endpoint + "?name:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a name + assertNotNull(bundle); + // Note: May be empty if all ValueSets have names + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertTrue( + vs.getName() == null || vs.getName().isEmpty(), + "ValueSet should not have a name when name:missing=true"); + } + } + + /** + * Test value set search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test 1: Find ValueSets WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ValueSets with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url when url:missing=false"); + assertFalse(vs.getUrl().isEmpty(), "ValueSet url should not be empty"); + } + + // Test 2: Find ValueSets WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all ValueSets have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertTrue( + vs.getUrl() == null || vs.getUrl().isEmpty(), + "ValueSet should not have a url when url:missing=true"); + } + } + + /** + * Test value set search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test: Find ValueSets where URL contains "ncit" + String url = endpoint + "?url:contains=ncit&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "ncit" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + vs.getUrl().toLowerCase().contains("ncit"), + "ValueSet url should contain 'ncit': " + vs.getUrl()); + } + } + } + + /** + * Test value set search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // First, get a known ValueSet with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ValueSet"); + ValueSet firstVs = (ValueSet) data.getEntry().get(0).getResource(); + String baseUrl = firstVs.getUrl(); + + // Test: Find ValueSets where URL is at or below the base URL + // For example, if baseUrl is "http://example.com/fhir/ValueSet/123" + // we'll search for everything below "http://example.com/fhir" + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + vs.getUrl().startsWith(parentUrl) || vs.getUrl().equals(parentUrl), + "ValueSet url should be at or below '" + parentUrl + "': " + vs.getUrl()); + } + } + } + } + + /** + * Test value set search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // First, get a known ValueSet with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ValueSet"); + ValueSet firstVs = (ValueSet) data.getEntry().get(0).getResource(); + String childUrl = firstVs.getUrl(); + + // Test: Find ValueSets where URL is at or above the child URL + // This should return ValueSets whose URLs are parents (or exact match) of the search value + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + // This means the search value should start with the resource URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + childUrl.startsWith(vs.getUrl()) || childUrl.equals(vs.getUrl()), + "Search url '" + + childUrl + + "' should be at or below ValueSet url '" + + vs.getUrl() + + "'"); + } + } + } + } } From 488d844d67eb52abc169cea8cc70ec1d72f86cc3 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 12 Nov 2025 14:51:54 -0800 Subject: [PATCH 04/64] fix string -> integer --- .../java/gov/nih/nci/evs/api/controller/SubsetController.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/controller/SubsetController.java b/src/main/java/gov/nih/nci/evs/api/controller/SubsetController.java index 9a40387c5..817b975af 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/SubsetController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/SubsetController.java @@ -255,13 +255,13 @@ public class SubsetController extends BaseController { name = "fromRecord", description = "Start index of the search results", required = false, - schema = @Schema(implementation = String.class), + schema = @Schema(implementation = Integer.class), example = "0"), @Parameter( name = "pageSize", description = "Max number of results to return", required = false, - schema = @Schema(implementation = String.class), + schema = @Schema(implementation = Integer.class), example = "10000"), }) @RecordMetric From da796e66dc968b6a85b507d198ba97fd8bf0e25c Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 12 Nov 2025 15:55:08 -0800 Subject: [PATCH 05/64] EVSRESTAPI-678 --- .../api/controller/MetadataController.java | 39 +---------- .../evs/api/model/TerminologyMetadata.java | 45 ++++++++++++ .../controller/MetadataControllerTests.java | 69 +++++++++++++++++++ 3 files changed, 115 insertions(+), 38 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java index 739f7b31c..e523ea2b6 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java @@ -137,44 +137,7 @@ public class MetadataController extends BaseController { final TerminologyMetadata meta = term.getMetadata(); // Some terminologies may not have metadata if (meta != null) { - - // Various other metadata things (schema=hidden) - meta.setWelcomeText(null); - meta.setExtraSubsets(null); - meta.setSources(null); - meta.setDefinitionSourceSet(null); - meta.setSynonymSourceSet(null); - meta.setSubsetPrefix(null); - meta.setSparqlPrefix(null); - meta.setSourcesToRemove(null); - meta.setSubsetMember(null); - meta.setUnpublished(null); - meta.setMonthlyDb(null); - meta.setLicenseCheck(null); - meta.setMapsets(null); - meta.setRelationshipToTarget(null); - meta.setCode(null); - meta.setConceptStatus(null); - meta.setPreferredName(null); - meta.setSynonym(null); - meta.setSynonymTermType(null); - meta.setSynonymSource(null); - meta.setSynonymCode(null); - meta.setSynonymSubSource(null); - meta.setDefinitionSource(null); - meta.setDefinition(null); - meta.setFhirPublisher(null); - meta.setFhirUri(null); - meta.setMapRelation(null); - meta.setMap(null); - meta.setMapTarget(null); - meta.setMapTargetTermType(null); - meta.setMapTargetTermGroup(null); - meta.setMapTargetTerminology(null); - meta.setMapTargetTerminologyVersion(null); - meta.setTermTypes(null); - meta.setPreferredTermTypes(null); - meta.setSubset(null); + meta.cleanForApi(); } } diff --git a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java index 77dc9e7c9..b3e14c879 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java +++ b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java @@ -280,6 +280,51 @@ public boolean equals(final Object obj) { return true; } + /** + * Cleans for API return + * + * @return the terminology + */ + public void cleanForApi() { + // hide anything that doesn't need to be sent through the API + this.setWelcomeText(null); + this.setExtraSubsets(null); + this.setSources(null); + this.setDefinitionSourceSet(null); + this.setSynonymSourceSet(null); + this.setSubsetPrefix(null); + this.setSparqlPrefix(null); + this.setSourcesToRemove(null); + this.setSubsetMember(null); + this.setUnpublished(null); + this.setMonthlyDb(null); + this.setLicenseCheck(null); + this.setMapsets(null); + this.setRelationshipToTarget(null); + this.setCode(null); + this.setConceptStatus(null); + this.setPreferredName(null); + this.setSynonym(null); + this.setSynonymTermType(null); + this.setSynonymSource(null); + this.setSynonymCode(null); + this.setSynonymSubSource(null); + this.setDefinitionSource(null); + this.setDefinition(null); + this.setFhirPublisher(null); + this.setFhirUri(null); + this.setMapRelation(null); + this.setMap(null); + this.setMapTarget(null); + this.setMapTargetTermType(null); + this.setMapTargetTermGroup(null); + this.setMapTargetTerminology(null); + this.setMapTargetTerminologyVersion(null); + this.setTermTypes(null); + this.setPreferredTermTypes(null); + this.setSubset(null); + } + /** * Returns the relationship to target. * diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 1ba699673..04ef6737b 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -10,6 +10,7 @@ import gov.nih.nci.evs.api.model.Property; import gov.nih.nci.evs.api.model.StatisticsEntry; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.model.TerminologyMetadata; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.util.ConceptUtils; import java.util.ArrayList; @@ -2044,4 +2045,72 @@ public void testSourceStats() throws Exception { }); assertThat(sourceStats.isEmpty()); } + + /** + * Test that terminology metadata fields are cleaned for API responses + * + * @throws Exception the exception + */ + @Test + public void testTerminologyMetadataFieldsCleared() throws Exception { + final String url = baseUrl + "/terminologies?terminology=ncit&tag=monthly&latest=true"; + log.info("Testing url - " + url); + + final MvcResult result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + final String content = result.getResponse().getContentAsString(); + log.info(" content = " + content); + + // Parse into objects and check metadata has been cleaned (fields either null or empty) + final List list = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + + assertThat(list).isNotEmpty(); + + for (final Terminology term : list) { + final TerminologyMetadata md = term.getMetadata(); + assertThat(md).isNotNull(); + + // String fields that are nulled by cleanForApi + assertThat(md.getWelcomeText()).isNull(); + assertThat(md.getSparqlPrefix()).isNull(); + assertThat(md.getMonthlyDb()).isNull(); + assertThat(md.getLicenseCheck()).isNull(); + assertThat(md.getRelationshipToTarget()).isNull(); + assertThat(md.getCode()).isNull(); + assertThat(md.getConceptStatus()).isNull(); + assertThat(md.getPreferredName()).isNull(); + assertThat(md.getSynonymTermType()).isNull(); + assertThat(md.getSynonymSource()).isNull(); + assertThat(md.getSynonymCode()).isNull(); + assertThat(md.getSynonymSubSource()).isNull(); + assertThat(md.getDefinitionSource()).isNull(); + assertThat(md.getFhirPublisher()).isNull(); + assertThat(md.getFhirUri()).isNull(); + assertThat(md.getMapRelation()).isNull(); + assertThat(md.getMap()).isNull(); + assertThat(md.getMapTarget()).isNull(); + assertThat(md.getMapTargetTermType()).isNull(); + assertThat(md.getMapTargetTerminology()).isNull(); + assertThat(md.getMapTargetTerminologyVersion()).isNull(); + + // Collections / maps are expected to be empty (getters return empty container when null) + assertThat(md.getExtraSubsets()).isEmpty(); + assertThat(md.getSources()).isEmpty(); + assertThat(md.getDefinitionSourceSet()).isEmpty(); + assertThat(md.getSynonymSourceSet()).isEmpty(); + assertThat(md.getSubsetMember()).isEmpty(); + assertThat(md.getUnpublished()).isEmpty(); + assertThat(md.getSubset()).isEmpty(); + assertThat(md.getTermTypes()).isEmpty(); + assertThat(md.getPreferredTermTypes()).isEmpty(); + assertThat(md.getSynonym()).isEmpty(); + assertThat(md.getDefinition()).isEmpty(); + } + } + } From 19523481c7de299c01699b7b422727e0fef1c0e4 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 12 Nov 2025 16:03:19 -0800 Subject: [PATCH 06/64] spotless --- .../java/gov/nih/nci/evs/api/model/TerminologyMetadata.java | 2 +- .../nih/nci/evs/api/controller/MetadataControllerTests.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java index b3e14c879..9e4159dc8 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java +++ b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java @@ -282,7 +282,7 @@ public boolean equals(final Object obj) { /** * Cleans for API return - * + * * @return the terminology */ public void cleanForApi() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 04ef6737b..945f7a0fc 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -2045,7 +2045,7 @@ public void testSourceStats() throws Exception { }); assertThat(sourceStats.isEmpty()); } - + /** * Test that terminology metadata fields are cleaned for API responses * @@ -2112,5 +2112,4 @@ public void testTerminologyMetadataFieldsCleared() throws Exception { assertThat(md.getDefinition()).isEmpty(); } } - } From 87ff970d3b6cea5203b630b5dd4cef6e8d1f6ac4 Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Thu, 13 Nov 2025 10:30:37 -0800 Subject: [PATCH 07/64] Dss/evsrestapi 634 search modifiers (#431) * EVSRESTAPI-636: spotless misc * EVSRESTAPI-634: uri search modifiers and string missing search modifiers * EVSRESTAPI-634: same search modifiers for R4 * EVSRESTAPI-634: spotless misc --- .../evs/api/fhir/R4/CodeSystemProviderR4.java | 2 +- .../evs/api/fhir/R4/ConceptMapProviderR4.java | 13 +- .../evs/api/fhir/R4/ValueSetProviderR4.java | 7 +- .../fhir/FhirR4CodeSystemReadSearchTests.java | 189 +++++++++++++++++ .../fhir/FhirR4ConceptMapReadSearchTests.java | 191 +++++++++++++++++- .../fhir/FhirR4ValueSetReadSearchTests.java | 189 +++++++++++++++++ 6 files changed, 580 insertions(+), 11 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java index a4d380667..d179f39b8 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java @@ -777,7 +777,7 @@ public Bundle findCodeSystems( logger.debug(" SKIP system mismatch = " + cs.getUrl()); continue; } - if (url != null && !url.getValue().equals(cs.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, cs.getUrl())) { logger.debug(" SKIP url mismatch = " + cs.getUrl()); continue; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java index 4f812cd7d..f798df3a8 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java @@ -15,6 +15,7 @@ import ca.uhn.fhir.rest.param.NumberParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import gov.nih.nci.evs.api.model.Concept; @@ -109,7 +110,7 @@ public Parameters translateInstance( final HttpServletResponse response, final ServletRequestDetails details, @IdParam final IdType id, - @OperationParam(name = "url") final UriType url, + @OperationParam(name = "url") final UriParam url, @OperationParam(name = "conceptMapVersion") final StringType conceptMapVersion, @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @@ -248,7 +249,7 @@ public Parameters translateImplicit( final HttpServletRequest request, final HttpServletResponse response, final ServletRequestDetails details, - @OperationParam(name = "url") final UriType url, + @OperationParam(name = "url") final UriParam url, @OperationParam(name = "conceptMapVersion") final StringType conceptMapVersion, @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @@ -391,7 +392,7 @@ public Bundle findConceptMaps( @OptionalParam(name = "_id") final TokenParam id, @OptionalParam(name = "date") final DateRangeParam date, @OptionalParam(name = "name") final StringParam name, - @OptionalParam(name = "url") final StringParam url, + @OptionalParam(name = "url") final UriParam url, @OptionalParam(name = "version") final StringParam version, @Description(shortDefinition = "Number of entries to return") @OptionalParam(name = "_count") final NumberParam count, @@ -425,7 +426,7 @@ public Bundle findConceptMaps( map.get(mapset.getPropertyValue("targetTerminology")), mapset); // Skip non-matching - if (url != null && !url.getValue().equals(cm.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, cm.getUrl())) { logger.debug(" SKIP url mismatch = " + cm.getUrl()); continue; } @@ -481,7 +482,7 @@ private List findPossibleConceptMaps( final IdType id, final DateRangeParam date, final UriType system, - final UriType url, + final UriParam url, final StringType version, final UriType source, final UriType target, @@ -515,7 +516,7 @@ private List findPossibleConceptMaps( map.get(mapset.getPropertyValue("targetTerminology")), mapset); // Skip non-matching - if (url != null && !url.getValue().equals(cm.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, cm.getUrl())) { logger.debug(" SKIP url mismatch = " + cm.getUrl()); continue; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java index d9299b766..9a10fe29b 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java @@ -13,6 +13,7 @@ import ca.uhn.fhir.rest.param.NumberParam; import ca.uhn.fhir.rest.param.StringParam; import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; @@ -1502,7 +1503,7 @@ public Bundle findValueSets( @OptionalParam(name = "code") final StringParam code, @OptionalParam(name = "name") final StringParam name, @OptionalParam(name = "title") final StringParam title, - @OptionalParam(name = "url") final StringParam url, + @OptionalParam(name = "url") final UriParam url, @OptionalParam(name = "version") final StringParam version, @Description(shortDefinition = "Number of entries to return") @OptionalParam(name = "_count") final NumberParam count, @@ -1530,7 +1531,7 @@ public Bundle findValueSets( logger.debug(" SKIP date mismatch = " + vs.getDate()); continue; } - if (url != null && !url.getValue().equals(vs.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, vs.getUrl())) { logger.debug(" SKIP url mismatch = " + vs.getUrl()); continue; } @@ -1564,7 +1565,7 @@ public Bundle findValueSets( logger.debug(" SKIP date mismatch = " + vs.getDate()); continue; } - if (url != null && !url.getValue().equals(vs.getUrl())) { + if (url != null && !FhirUtility.compareUri(url, vs.getUrl())) { logger.debug(" SKIP url mismatch = " + vs.getUrl()); continue; } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java index 77ab4937b..d77191ce1 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java @@ -1151,4 +1151,193 @@ public void testCodeSystemSearchSortByInvalidField() throws Exception { assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test code system search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test 1: Find CodeSystems WITH a title (title:missing=false) + String url = endpoint + "?title:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a title + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find CodeSystems with titles"); + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getTitle(), "CodeSystem should have a title when title:missing=false"); + assertFalse(cs.getTitle().isEmpty(), "CodeSystem title should not be empty"); + } + + // Test 2: Find CodeSystems WITHOUT a title (title:missing=true) + url = endpoint + "?title:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a title + assertNotNull(bundle); + // Note: May be empty if all CodeSystems have titles + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertTrue( + cs.getTitle() == null || cs.getTitle().isEmpty(), + "CodeSystem should not have a title when title:missing=true"); + } + } + + /** + * Test code system search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test 1: Find CodeSystems WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find CodeSystems with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url when url:missing=false"); + assertFalse(cs.getUrl().isEmpty(), "CodeSystem url should not be empty"); + } + + // Test 2: Find CodeSystems WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all CodeSystems have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertTrue( + cs.getUrl() == null || cs.getUrl().isEmpty(), + "CodeSystem should not have a url when url:missing=true"); + } + } + + /** + * Test code system search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // Test: Find CodeSystems where URL contains "ncit" + String url = endpoint + "?url:contains=ncit&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "ncit" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + cs.getUrl().toLowerCase().contains("ncit"), + "CodeSystem url should contain 'ncit': " + cs.getUrl()); + } + } + } + + /** + * Test code system search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // First, get a known CodeSystem with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one CodeSystem"); + CodeSystem firstCs = (CodeSystem) data.getEntry().get(0).getResource(); + String baseUrl = firstCs.getUrl(); + + // Test: Find CodeSystems where URL is at or below the base URL + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + cs.getUrl().startsWith(parentUrl) || cs.getUrl().equals(parentUrl), + "CodeSystem url should be at or below '" + parentUrl + "': " + cs.getUrl()); + } + } + } + } + + /** + * Test code system search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testCodeSystemSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCSPath; + + // First, get a known CodeSystem with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one CodeSystem"); + CodeSystem firstCs = (CodeSystem) data.getEntry().get(0).getResource(); + String childUrl = firstCs.getUrl(); + + // Test: Find CodeSystems where URL is at or above the child URL + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + CodeSystem cs = (CodeSystem) entry.getResource(); + assertNotNull(cs.getUrl(), "CodeSystem should have a url"); + assertTrue( + childUrl.startsWith(cs.getUrl()) || childUrl.equals(cs.getUrl()), + "Search url '" + + childUrl + + "' should be at or below CodeSystem url '" + + cs.getUrl() + + "'"); + } + } + } + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java index 077c6a8f7..ebdcfaadf 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java @@ -106,7 +106,7 @@ public void testConceptMapSearch() throws Exception { data.getEntry().stream().map(Bundle.BundleEntryComponent::getResource).toList(); // Verify things about this one - // {"resourceType":"ConceptMap","id":"ma_to_ncit_mapping_July2021","url":"http://hl7.org/fhir/sid/icd-10?fhir_cm=ICD10_to_MedDRA_Mapping","version":"Aug2024","name":"NCIt_to_HGNC_Mapping","title":"NCIt_to_HGNC_Mapping","status":"active","experimental":false,"publisher":"NCI","group":[{"source":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","target":"http://www.genenames.org"}]} + // {"resourceType":"ConceptMap","id":"ma_to_ncit_mapping_July2021","url":"http://hl7.org/fhir/sid/icd-10?fhir_cm=ICD10_to_MedDRA_Mapping","version":"Aug2024","name":"NCIt_to_HGNC_Mapping","name":"NCIt_to_HGNC_Mapping","status":"active","experimental":false,"publisher":"NCI","group":[{"source":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","target":"http://www.genenames.org"}]} final Set ids = new HashSet<>(Set.of("icd10_to_meddra_mapping_july2021")); final Set urls = new HashSet<>(Set.of("http://hl7.org/fhir/sid/icd-10?fhir_cm=ICD10_to_MedDRA_Mapping")); @@ -1035,4 +1035,193 @@ public void testConceptMapSearchSortInvalidField() throws Exception { assertEquals("invalid", outcome.getIssueFirstRep().getCode().toCode()); assertTrue(outcome.getIssueFirstRep().getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test concept map search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test 1: Find ConceptMaps WITH a name (name:missing=false) + String url = endpoint + "?name:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a name + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ConceptMaps with names"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getName(), "ConceptMap should have a name when name:missing=false"); + assertFalse(cm.getName().isEmpty(), "ConceptMap name should not be empty"); + } + + // Test 2: Find ConceptMaps WITHOUT a name (name:missing=true) + url = endpoint + "?name:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a name + assertNotNull(bundle); + // Note: May be empty if all ConceptMaps have names + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertTrue( + cm.getName() == null || cm.getName().isEmpty(), + "ConceptMap should not have a name when name:missing=true"); + } + } + + /** + * Test concept map search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test 1: Find ConceptMaps WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ConceptMaps with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url when url:missing=false"); + assertFalse(cm.getUrl().isEmpty(), "ConceptMap url should not be empty"); + } + + // Test 2: Find ConceptMaps WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all ConceptMaps have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertTrue( + cm.getUrl() == null || cm.getUrl().isEmpty(), + "ConceptMap should not have a url when url:missing=true"); + } + } + + /** + * Test concept map search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // Test: Find ConceptMaps where URL contains "icd" + String url = endpoint + "?url:contains=icd&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "icd" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + cm.getUrl().toLowerCase().contains("icd"), + "ConceptMap url should contain 'icd': " + cm.getUrl()); + } + } + } + + /** + * Test concept map search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // First, get a known ConceptMap with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ConceptMap"); + ConceptMap firstCm = (ConceptMap) data.getEntry().get(0).getResource(); + String baseUrl = firstCm.getUrl(); + + // Test: Find ConceptMaps where URL is at or below the base URL + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + cm.getUrl().startsWith(parentUrl) || cm.getUrl().equals(parentUrl), + "ConceptMap url should be at or below '" + parentUrl + "': " + cm.getUrl()); + } + } + } + } + + /** + * Test concept map search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testConceptMapSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirCMPath; + + // First, get a known ConceptMap with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ConceptMap"); + ConceptMap firstCm = (ConceptMap) data.getEntry().get(0).getResource(); + String childUrl = firstCm.getUrl(); + + // Test: Find ConceptMaps where URL is at or above the child URL + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ConceptMap cm = (ConceptMap) entry.getResource(); + assertNotNull(cm.getUrl(), "ConceptMap should have a url"); + assertTrue( + childUrl.startsWith(cm.getUrl()) || childUrl.equals(cm.getUrl()), + "Search url '" + + childUrl + + "' should be at or below ConceptMap url '" + + cm.getUrl() + + "'"); + } + } + } + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index 301b4e3e7..17ffe6d42 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -1272,4 +1272,193 @@ public void testValueSetSearchSortInvalidField() throws Exception { assertEquals("invalid", outcome.getIssueFirstRep().getCode().toCode()); assertTrue(outcome.getIssueFirstRep().getDiagnostics().contains("Unsupported sort field")); } + + /** + * Test value set search with :missing modifier on string parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithMissingModifierOnStringParams() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test 1: Find ValueSets WITH a title (title:missing=false) + String url = endpoint + "?title:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a title + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ValueSets with titles"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getTitle(), "ValueSet should have a title when title:missing=false"); + assertFalse(vs.getTitle().isEmpty(), "ValueSet title should not be empty"); + } + + // Test 2: Find ValueSets WITHOUT a title (title:missing=true) + url = endpoint + "?title:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a title + assertNotNull(bundle); + // Note: May be empty if all ValueSets have titles + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertTrue( + vs.getTitle() == null || vs.getTitle().isEmpty(), + "ValueSet should not have a title when title:missing=true"); + } + } + + /** + * Test value set search with :missing modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlMissingModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test 1: Find ValueSets WITH a url (url:missing=false) + String url = endpoint + "?url:missing=false&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have a url + assertNotNull(bundle); + assertTrue(bundle.hasEntry(), "Should find ValueSets with urls"); + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url when url:missing=false"); + assertFalse(vs.getUrl().isEmpty(), "ValueSet url should not be empty"); + } + + // Test 2: Find ValueSets WITHOUT a url (url:missing=true) + url = endpoint + "?url:missing=true&_count=100"; + content = this.restTemplate.getForObject(url, String.class); + bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should NOT have a url + assertNotNull(bundle); + // Note: May be empty if all ValueSets have urls + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertTrue( + vs.getUrl() == null || vs.getUrl().isEmpty(), + "ValueSet should not have a url when url:missing=true"); + } + } + + /** + * Test value set search with :contains modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlContainsModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // Test: Find ValueSets where URL contains "ncit" + String url = endpoint + "?url:contains=ncit&_count=100"; + String content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have "ncit" in their URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + vs.getUrl().toLowerCase().contains("ncit"), + "ValueSet url should contain 'ncit': " + vs.getUrl()); + } + } + } + + /** + * Test value set search with :below modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlBelowModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // First, get a known ValueSet with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ValueSet"); + ValueSet firstVs = (ValueSet) data.getEntry().get(0).getResource(); + String baseUrl = firstVs.getUrl(); + + // Test: Find ValueSets where URL is at or below the base URL + if (baseUrl != null && baseUrl.contains("/")) { + // Get parent URL (remove last path segment) + String parentUrl = baseUrl.substring(0, baseUrl.lastIndexOf("/")); + + String url = endpoint + "?url:below=" + URLEncoder.encode(parentUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or below parent URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + vs.getUrl().startsWith(parentUrl) || vs.getUrl().equals(parentUrl), + "ValueSet url should be at or below '" + parentUrl + "': " + vs.getUrl()); + } + } + } + } + + /** + * Test value set search with :above modifier on URI parameters. + * + * @throws Exception exception + */ + @Test + public void testValueSetSearchWithUrlAboveModifier() throws Exception { + // Arrange + final String endpoint = localHost + port + fhirVSPath; + + // First, get a known ValueSet with a URL + String content = this.restTemplate.getForObject(endpoint + "?_count=1", String.class); + Bundle data = parser.parseResource(Bundle.class, content); + assertTrue(data.hasEntry(), "Should have at least one ValueSet"); + ValueSet firstVs = (ValueSet) data.getEntry().get(0).getResource(); + String childUrl = firstVs.getUrl(); + + // Test: Find ValueSets where URL is at or above the child URL + if (childUrl != null) { + String url = endpoint + "?url:above=" + URLEncoder.encode(childUrl, StandardCharsets.UTF_8); + content = this.restTemplate.getForObject(url, String.class); + Bundle bundle = parser.parseResource(Bundle.class, content); + + // Assert - all returned resources should have URL at or above child URL + assertNotNull(bundle); + if (bundle.hasEntry()) { + for (BundleEntryComponent entry : bundle.getEntry()) { + ValueSet vs = (ValueSet) entry.getResource(); + assertNotNull(vs.getUrl(), "ValueSet should have a url"); + assertTrue( + childUrl.startsWith(vs.getUrl()) || childUrl.equals(vs.getUrl()), + "Search url '" + + childUrl + + "' should be at or below ValueSet url '" + + vs.getUrl() + + "'"); + } + } + } + } } From 550be09d8dd2b9b1db59058d8669655415544e7f Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 17 Nov 2025 15:49:39 -0800 Subject: [PATCH 08/64] most changes, need to filter remodeled properties --- .../api/controller/MetadataController.java | 66 +++++++++++ .../service/AbstractGraphLoadServiceImpl.java | 21 ++++ .../nci/evs/api/service/MetadataService.java | 11 ++ .../evs/api/service/MetadataServiceImpl.java | 20 ++++ .../api/service/OpensearchQueryService.java | 11 ++ .../service/OpensearchQueryServiceImpl.java | 11 ++ .../service/SparqlQueryManagerService.java | 11 ++ .../SparqlQueryManagerServiceImpl.java | 25 ++++ src/main/resources/sparql-queries.properties | 8 ++ .../controller/MetadataControllerTests.java | 112 ++++++++++++++++++ 10 files changed, 296 insertions(+) diff --git a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java index 739f7b31c..253bf85fb 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java @@ -1232,6 +1232,72 @@ public class MetadataController extends BaseController { } } + /** + * Returns the property values list. + * + * @param terminology the terminology + * @param code the code + * @return the property values list + * @throws Exception the exception + */ + @Operation(summary = "Get property values for the specified terminology and code/name") + @ApiResponses({ + @ApiResponse( + responseCode = "200", + description = "Successfully retrieved the requested information"), + @ApiResponse( + responseCode = "404", + description = "Resource not found", + content = + @Content( + mediaType = "application/json", + schema = @Schema(implementation = RestException.class))) + }) + @Parameters({ + @Parameter( + name = "terminology", + description = + "Terminology, e.g. 'ncit' or 'ncim' (See" + + " here for complete list)", + required = true, + schema = @Schema(implementation = String.class), + example = "ncit"), + @Parameter( + name = "codeOrName", + description = + "Property code (or name), e.g." + + "
  • 'P216' or 'BioCarta_ID' for ncit
  • " + + "
  • 'Semantic_Type' for ncim
", + required = true, + schema = @Schema(implementation = String.class)) + }) + @RecordMetric + @GetMapping( + value = "/metadata/{terminology}/property/{codeOrName}/values", + produces = "application/json") + public @ResponseBody List getPropertyValues( + @PathVariable(value = "terminology") final String terminology, + @PathVariable(value = "codeOrName") final String code) + throws Exception { + try { + // If the code contains a comma, just bail + if (code.contains(",")) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not found"); + } + + Optional> result = metadataService.getPropertyValues(terminology, code); + if (!result.isPresent()) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not found"); + } + + return result.get(); + } catch (Exception e) { + handleException(e, terminology); + return null; + } + } + /** * Returns the synonym types. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java index 9fec5849b..c9e40e377 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java @@ -441,6 +441,27 @@ public void loadObjects( operationsService.index(propertiesObject, indexName, OpensearchObject.class); logger.info(" Properties loaded"); + // Build property values map by code and by property name and index it + final Map> propertyMap = new HashMap<>(); + for (final Concept property : properties) { + for (final String value : + sparqlQueryManagerService.getPropertyValues(property.getCode(), terminology)) { + if (!propertyMap.containsKey(property.getCode())) { + propertyMap.put(property.getCode(), new HashSet<>()); + } + propertyMap.get(property.getCode()).add(value); + if (!propertyMap.containsKey(property.getName())) { + propertyMap.put(property.getName(), new HashSet<>()); + } + propertyMap.get(property.getName()).add(value); + } + } + ConceptUtils.limitQualMap(propertyMap, 1000); + OpensearchObject propertyValuesObject = new OpensearchObject("propertyValues"); + propertyValuesObject.setMap(propertyMap); + operationsService.index(propertyValuesObject, indexName, OpensearchObject.class); + logger.info(" Property values loaded"); + List associations = sparqlQueryManagerService.getAllAssociations(terminology, new IncludeParam("full")); OpensearchObject associationsObject = new OpensearchObject("associations"); diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetadataService.java b/src/main/java/gov/nih/nci/evs/api/service/MetadataService.java index e90c96ead..0d0bcdb20 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetadataService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetadataService.java @@ -153,6 +153,17 @@ Optional getProperty( Optional> getQualifierValues(final String terminology, final String code) throws Exception; + /** + * Get property values. + * + * @param terminology the terminology + * @param code the code + * @return the list of property values + * @throws Exception the exception + */ + Optional> getPropertyValues(final String terminology, final String code) + throws Exception; + /** * Get term types. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java index 177bb9fb1..c8dca05dd 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java @@ -311,6 +311,26 @@ public Optional> getQualifierValues(String terminology, String code return Optional.ofNullable(map.get(code).stream().sorted().collect(Collectors.toList())); } + /** + * Returns the property values list. + * + * @param terminology the terminology + * @param code the code + * @return the property values list + * @throws Exception the exception + */ + @Override + public Optional> getPropertyValues(String terminology, String code) + throws Exception { + final Terminology term = termUtils.getIndexedTerminology(terminology, osQueryService, true); + final Map> map = osQueryService.getPropertyValues(term); + if (map == null || !map.containsKey(code)) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not found"); + } + + return Optional.ofNullable(map.get(code).stream().sorted().collect(Collectors.toList())); + } + /** * Returns the term types. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryService.java b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryService.java index 2400739c9..90294aecd 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryService.java @@ -242,6 +242,17 @@ List getQualifiers(Terminology terminology, IncludeParam ip) */ Map> getQualifierValues(Terminology terminology) throws Exception; + /** + * Get property values. + * + * @param terminology the terminology + * @return the map of property values + * @throws JsonMappingException the json mapping exception + * @throws JsonProcessingException the json processing exception + * @throws Exception + */ + Map> getPropertyValues(Terminology terminology) throws Exception; + /** * Get qualifier. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java index 0f358d771..0c589d726 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java @@ -546,6 +546,17 @@ public Map> getQualifierValues(Terminology terminology) thro return esObject.get().getMap(); } + /* see superclass */ + @Override + public Map> getPropertyValues(Terminology terminology) throws Exception { + Optional esObject = getOpensearchObject("propertyValues", terminology); + if (!esObject.isPresent()) { + return new HashMap<>(); + } + + return esObject.get().getMap(); + } + /** * see superclass *. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerService.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerService.java index 68e00be12..55f288f23 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerService.java @@ -105,6 +105,17 @@ public List getRemodeledQualifiers(Terminology terminology, IncludePara public List getQualifierValues(String propertyCode, Terminology terminology) throws Exception; + /** + * Returns the distinct values used for a given property across concepts. + * + * @param propertyCode the property code + * @param terminology the terminology + * @return the property values + * @throws Exception the exception + */ + public List getPropertyValues(String propertyCode, Terminology terminology) + throws Exception; + /** * Returns the subset members. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index 0eef84846..5d2f532bb 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -2055,6 +2055,31 @@ public List getQualifierValues(final String propertyCode, final Terminol return propertyValues; } + /* see superclass */ + @Override + public List getPropertyValues(final String propertyCode, final Terminology terminology) + throws Exception { + final String queryPrefix = queryBuilderService.constructPrefix(terminology); + final Map values = + ConceptUtils.asMap("propertyCode", propertyCode, "namedGraph", terminology.getGraph()); + final String query = + queryBuilderService.constructQuery("concept.property.values", terminology, values); + final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); + + final ObjectMapper mapper = new ObjectMapper(); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final List propertyValues = new ArrayList<>(); + + final Sparql sparqlResult = mapper.readValue(res, Sparql.class); + final Bindings[] bindings = sparqlResult.getResults().getBindings(); + for (final Bindings b : bindings) { + final String propertyValue = b.getPropertyValue().getValue(); + propertyValues.add(propertyValue); + } + + return propertyValues; + } + /** * Returns the subset members. * diff --git a/src/main/resources/sparql-queries.properties b/src/main/resources/sparql-queries.properties index fbc5d625f..00d5b0146 100644 --- a/src/main/resources/sparql-queries.properties +++ b/src/main/resources/sparql-queries.properties @@ -1049,6 +1049,14 @@ distinct.property.values=SELECT DISTINCT ?propertyValue \ } \ } +concept.property.values=SELECT DISTINCT ?propertyValue \ +{ GRAPH <#{namedGraph}> \ + { ?x a owl:Class . \ + ?x #{propertyCode} ?propertyValue \ + } \ +} \ +ORDER BY ?propertyValue + all.qualifiers=SELECT DISTINCT ?property ?propertyCode ?propertyLabel \ { GRAPH <#{namedGraph}> \ { \ diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 1ba699673..c396d3188 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -893,6 +893,118 @@ public void testBadGetProperty() throws Exception { log.info(" content = " + content); } + /** + * Test get property values. + * + * @throws Exception the exception + */ + @Test + public void testGetPropertyValues() throws Exception { + + String url = null; + MvcResult result = null; + String content = null; + List list = null; + + // Get values for Semantic_Type property using code + url = baseUrl + "/ncit/property/P204/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content length = " + content.length()); + list = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + assertThat(list).isNotNull(); + assertThat(list.size()).isGreaterThan(0); + log.info(" Property P204 has " + list.size() + " values"); + + // Verify values are sorted + assertThat(list).isSorted(); + + // Get values using property name (if available) + // First get all properties to find a valid property with values + url = baseUrl + "/ncit/properties"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + final List properties = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + + // Test values endpoint for each property to ensure they work with both code and name + int testedCount = 0; + for (final Concept prop : properties) { + if (testedCount >= 3) { + break; // Just test a few properties + } + try { + // Test with code + url = baseUrl + "/ncit/property/" + prop.getCode() + "/values"; + log.info("Testing property values with code: " + prop.getCode()); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + list = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + if (list.size() > 0) { + log.info( + " Property " + + prop.getCode() + + " (" + + prop.getName() + + ") has " + + list.size() + + " values"); + testedCount++; + } + } catch (final Exception e) { + // Some properties may not have values, that's fine + log.info(" Property " + prop.getCode() + " has no values or error occurred"); + } + } + + assertThat(testedCount).isGreaterThan(0); + } + + /** + * Test bad get property values. + * + * @throws Exception the exception + */ + @Test + public void testBadGetPropertyValues() throws Exception { + String url = null; + MvcResult result = null; + String content = null; + + // Bad terminology + url = baseUrl + "/ncitXXX/property/P204/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isNotFound()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content = " + content); + + // Bad property code + url = baseUrl + "/ncit/property/P999999/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isNotFound()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content = " + content); + } + /** * Test concept statuses. * From 8f041301c4603e66147154eec4a58a749b4ba056 Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 18 Nov 2025 13:45:47 -0800 Subject: [PATCH 09/64] ignore remodeled properties --- .../service/AbstractGraphLoadServiceImpl.java | 4 ++ .../evs/api/service/MetadataServiceImpl.java | 4 ++ .../controller/MetadataControllerTests.java | 62 +++---------------- 3 files changed, 15 insertions(+), 55 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java index c9e40e377..df5f62d7e 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java @@ -444,6 +444,10 @@ public void loadObjects( // Build property values map by code and by property name and index it final Map> propertyMap = new HashMap<>(); for (final Concept property : properties) { + // skip any remodeled properties + if (terminology.getMetadata().isRemodeledProperty(property.getCode())) { + continue; + } for (final String value : sparqlQueryManagerService.getPropertyValues(property.getCode(), terminology)) { if (!propertyMap.containsKey(property.getCode())) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java index c8dca05dd..146a57690 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java @@ -323,6 +323,10 @@ public Optional> getQualifierValues(String terminology, String code public Optional> getPropertyValues(String terminology, String code) throws Exception { final Terminology term = termUtils.getIndexedTerminology(terminology, osQueryService, true); + // 404 out remodeled properties + if (term.getMetadata().isRemodeledProperty(code)) { + throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not valid for this endpoint as it is a remodeled property."); + } final Map> map = osQueryService.getPropertyValues(term); if (map == null || !map.containsKey(code)) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not found"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index c396d3188..31f91874f 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -922,61 +922,6 @@ public void testGetPropertyValues() throws Exception { assertThat(list).isNotNull(); assertThat(list.size()).isGreaterThan(0); log.info(" Property P204 has " + list.size() + " values"); - - // Verify values are sorted - assertThat(list).isSorted(); - - // Get values using property name (if available) - // First get all properties to find a valid property with values - url = baseUrl + "/ncit/properties"; - log.info("Testing url - " + url); - result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); - content = result.getResponse().getContentAsString(); - final List properties = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }); - - // Test values endpoint for each property to ensure they work with both code and name - int testedCount = 0; - for (final Concept prop : properties) { - if (testedCount >= 3) { - break; // Just test a few properties - } - try { - // Test with code - url = baseUrl + "/ncit/property/" + prop.getCode() + "/values"; - log.info("Testing property values with code: " + prop.getCode()); - result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); - content = result.getResponse().getContentAsString(); - list = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }); - if (list.size() > 0) { - log.info( - " Property " - + prop.getCode() - + " (" - + prop.getName() - + ") has " - + list.size() - + " values"); - testedCount++; - } - } catch (final Exception e) { - // Some properties may not have values, that's fine - log.info(" Property " + prop.getCode() + " has no values or error occurred"); - } - } - - assertThat(testedCount).isGreaterThan(0); } /** @@ -1003,6 +948,13 @@ public void testBadGetPropertyValues() throws Exception { result = mvc.perform(get(url)).andExpect(status().isNotFound()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); + + // Remodeled property like P325 gives 404 error + url = baseUrl + "/ncit/property/P325/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isNotFound()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content = " + content); } /** From 5ca0b1ec5442697734cd47565515037d1720c8ca Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 18 Nov 2025 13:56:26 -0800 Subject: [PATCH 10/64] spotless fix --- .../java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java index 146a57690..605affb90 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetadataServiceImpl.java @@ -325,7 +325,9 @@ public Optional> getPropertyValues(String terminology, String code) final Terminology term = termUtils.getIndexedTerminology(terminology, osQueryService, true); // 404 out remodeled properties if (term.getMetadata().isRemodeledProperty(code)) { - throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Property " + code + " not valid for this endpoint as it is a remodeled property."); + throw new ResponseStatusException( + HttpStatus.NOT_FOUND, + "Property " + code + " not valid for this endpoint as it is a remodeled property."); } final Map> map = osQueryService.getPropertyValues(term); if (map == null || !map.containsKey(code)) { From 6c05b01dd67f914d2a6aac4501e333217f539085 Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 18 Nov 2025 22:49:58 -0800 Subject: [PATCH 11/64] more thorough test --- .../controller/MetadataControllerTests.java | 76 ++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 31f91874f..d9c6a7358 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -11,7 +11,9 @@ import gov.nih.nci.evs.api.model.StatisticsEntry; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.ConceptUtils; +import gov.nih.nci.evs.api.util.TerminologyUtils; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -45,6 +47,12 @@ public class MetadataControllerTests { /** The mvc. */ @Autowired private MockMvc mvc; + /** The term utils. */ + @Autowired private TerminologyUtils termUtils; + + /** The os query service. */ + @Autowired private OpensearchQueryService osQueryService; + /** The test properties. */ @Autowired TestProperties testProperties; @@ -922,6 +930,23 @@ public void testGetPropertyValues() throws Exception { assertThat(list).isNotNull(); assertThat(list.size()).isGreaterThan(0); log.info(" Property P204 has " + list.size() + " values"); + + // Get values for Semantic_Type property using name + url = baseUrl + "/ncit/property/OLD_ROLE/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content length = " + content.length()); + list = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + assertThat(list).isNotNull(); + assertThat(list.size()).isGreaterThan(0); + log.info(" Property OLD_ROLE has " + list.size() + " values"); } /** @@ -950,13 +975,62 @@ public void testBadGetPropertyValues() throws Exception { log.info(" content = " + content); // Remodeled property like P325 gives 404 error - url = baseUrl + "/ncit/property/P325/values"; + url = baseUrl + "/ncit/property/NHC0/values"; log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isNotFound()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); } + /* + * Test all that all properties can retrieve property values with code or name + * + * @throws Exception the exception + */ + @Test + public void testPropertyValuesWithCodeAndName() throws Exception { + String url = null; + MvcResult result = null; + String content = null; + List properties = null; + + // Get all properties + url = baseUrl + "/ncit/properties"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + properties = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + + // get ncit terminology + Terminology term = termUtils.getIndexedTerminology("ncit", osQueryService, true); + for (Concept property : properties) { + // filter out remodeled properties because those should 404 + if (term.getMetadata().isRemodeledProperty(property.getCode()) + || term.getMetadata().isRemodeledProperty(property.getName())) { + continue; + } + // Try to get property values by code + url = baseUrl + "/ncit/property/" + property.getCode() + "/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content length = " + content.length()); + + // Try to get property values by name + url = baseUrl + "/ncit/property/" + property.getName() + "/values"; + log.info("Testing url - " + url); + result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); + content = result.getResponse().getContentAsString(); + log.info(" content length = " + content.length()); + } + } + /** * Test concept statuses. * From 29ad42922adfc9452c0286c4c60345458d8fe4be Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Mon, 24 Nov 2025 10:06:18 -0800 Subject: [PATCH 12/64] EVSRESTAPI-679: nci term forms attachment and tests for ncit (refactor for cdisc) (#434) --- .../TermSuggestionFormController.java | 31 ++- .../service/TermSuggestionFormService.java | 9 + .../TermSuggestionFormServiceImpl.java | 188 +++++++++++++++++- .../TermSuggestionFormControllerTests.java | 69 ++++++- .../nci/evs/api/model/EmailDetailsTest.java | 10 +- .../TermSuggestionFormServiceTest.java | 84 +++++++- .../formSamples/NCIT-Regimen-Suggestions.xlsx | Bin 0 -> 73914 bytes ...on.xls => blank-form-submission-cdisc.xls} | Bin .../blank-form-submission-ncit.xls | Bin 0 -> 4096 bytes ...=> blank-spreadsheet-submission-cdisc.xls} | Bin ...ls => changed-sheets-submission-cdisc.xls} | Bin .../formSamples/compareEmailDetailsFail.json | 2 +- ....xls => extra-sheets-submission-cdisc.xls} | Bin ...on.xls => fake-excel-submission-cdisc.xls} | Bin ...n.xls => filled-form-submission-cdisc.xls} | Bin .../filled-form-submission-ncit.xls | Bin 0 -> 5120 bytes .../formSamples/invalid-code-ncit.xls | Bin 0 -> 4096 bytes .../formSamples/invalid-header-ncit.xls | Bin 0 -> 4096 bytes .../formSamples/missing-columns-ncit.xls | Bin 0 -> 4096 bytes ...ISC.json => submissionFormTest-cdisc.json} | 0 ...Test.json => submissionFormTest-ncit.json} | 0 ...=> submissionFormWithArrayList-cdisc.json} | 0 22 files changed, 357 insertions(+), 36 deletions(-) create mode 100644 src/test/resources/formSamples/NCIT-Regimen-Suggestions.xlsx rename src/test/resources/formSamples/{blank-form-submission.xls => blank-form-submission-cdisc.xls} (100%) create mode 100644 src/test/resources/formSamples/blank-form-submission-ncit.xls rename src/test/resources/formSamples/{blank-spreadsheet-submission.xls => blank-spreadsheet-submission-cdisc.xls} (100%) rename src/test/resources/formSamples/{changed-sheets-submission.xls => changed-sheets-submission-cdisc.xls} (100%) rename src/test/resources/formSamples/{extra-sheets-submission.xls => extra-sheets-submission-cdisc.xls} (100%) rename src/test/resources/formSamples/{fake-excel-submission.xls => fake-excel-submission-cdisc.xls} (100%) rename src/test/resources/formSamples/{filled-form-submission.xls => filled-form-submission-cdisc.xls} (100%) create mode 100644 src/test/resources/formSamples/filled-form-submission-ncit.xls create mode 100644 src/test/resources/formSamples/invalid-code-ncit.xls create mode 100644 src/test/resources/formSamples/invalid-header-ncit.xls create mode 100644 src/test/resources/formSamples/missing-columns-ncit.xls rename src/test/resources/formSamples/{submissionFormTestCDISC.json => submissionFormTest-cdisc.json} (100%) rename src/test/resources/formSamples/{submissionFormTest.json => submissionFormTest-ncit.json} (100%) rename src/test/resources/formSamples/{submissionFormWithArrayList.json => submissionFormWithArrayList-cdisc.json} (100%) diff --git a/src/main/java/gov/nih/nci/evs/api/controller/TermSuggestionFormController.java b/src/main/java/gov/nih/nci/evs/api/controller/TermSuggestionFormController.java index ac8f0dcf2..407164e64 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/TermSuggestionFormController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/TermSuggestionFormController.java @@ -116,10 +116,10 @@ public void submitForm( *

Sample call in curl form: * *

-   * curl -X POST "http://localhost:8082/api/v1/submitWithAttachment" \
+   * curl -X POST "http://localhost:8082/api/v1/form/submitWithAttachment" \
    * -H "Captcha-Token: TEST-KEY" \
-   * -F 'formData=@src/test/resources/formSamples/submissionFormTestCDISC.json;type=application/json' \
-   * -F "file=@src/test/resources/formSamples/filled-form-submission.xls"
+   * -F 'formData=@src/test/resources/formSamples/submissionFormTest-cdisc.json;type=application/json' \
+   * -F "file=@src/test/resources/formSamples/filled-form-submission-cdisc.xls"
    * 
* *

Accepts multipart/form-data with a JSON part named `formData` and an optional file part @@ -151,18 +151,27 @@ public void submitWithAttachment( "Unable to submit form. Failed to verify the submitted Recaptcha!"); } - if (!formService.validateFileAttachment(file)) { - logger.error("Invalid attachment file, does not match the template."); + // Convert the form data into our email details object first to get form type + EmailDetails emailDetails = EmailDetails.generateEmailDetails(formData); + if (!"CDISC".equals(emailDetails.getSource()) && !"NCIT".equals(emailDetails.getSource())) { + logger.error("Form type is not valid for attachment. Must be CDISC or NCIT."); throw new ResponseStatusException( - HttpStatus.EXPECTATION_FAILED, "Invalid attachment file, does not match the template."); + HttpStatus.EXPECTATION_FAILED, + "Invalid form type for attachment. Must be CDISC or NCIT."); } - // convert the form data into our email details object - EmailDetails emailDetails = EmailDetails.generateEmailDetails(formData); - if (!"CDISC".equals(emailDetails.getSource())) { - logger.error("Form type is not valid for attachment. Must be CDISC."); + + // Validate file attachment with form-type-specific validation + if (!formService.validateFileAttachment(file, emailDetails.getSource())) { + logger.error( + "Invalid attachment file for {}, does not match the template.", + emailDetails.getSource()); throw new ResponseStatusException( - HttpStatus.EXPECTATION_FAILED, "Invalid form type for attachment. Must be CDISC."); + HttpStatus.EXPECTATION_FAILED, + "Invalid attachment file for " + + emailDetails.getSource() + + ", does not match the template."); } + // Send the email with optional attachment formService.sendEmailWithAttachment(emailDetails, file); } catch (Exception e) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormService.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormService.java index c6b85c993..ded937122 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormService.java @@ -28,6 +28,15 @@ public interface TermSuggestionFormService { */ boolean validateFileAttachment(MultipartFile file); + /** + * Validate file attachment with form type. + * + * @param file the file + * @param formType the form type (CDISC or NCIT) + * @return true, if successful + */ + boolean validateFileAttachment(MultipartFile file, String formType); + /** * Sends an email with the formatted form data and an optional attachment * diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 3ca953ac2..86c4efa1d 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -221,13 +221,25 @@ public void sendEmailWithAttachment(final EmailDetails emailDetails, final Multi } /** - * Validate file attachment. + * Validate file attachment (defaults to CDISC for backward compatibility). * * @param file the file * @return true, if successful */ @Override public boolean validateFileAttachment(final MultipartFile file) { + // Default to CDISC for backward compatibility + return validateFileAttachment(file, "CDISC"); + } + + /** + * Validate file attachment based on form type. + * + * @param file the file + * @param formType the form type (CDISC or NCIT) + * @return true, if successful + */ + public boolean validateFileAttachment(final MultipartFile file, final String formType) { if (file == null || file.isEmpty()) { // No file attached/empty file return false; @@ -243,6 +255,25 @@ public boolean validateFileAttachment(final MultipartFile file) { return false; } + // Route to appropriate validation method based on form type + if ("CDISC".equalsIgnoreCase(formType)) { + return validateCDISCAttachment(file, filename); + } else if ("NCIT".equalsIgnoreCase(formType)) { + return validateNCITAttachment(file, filename); + } else { + logger.warn("Unknown form type '{}' for file validation: {}", formType, filename); + return false; + } + } + + /** + * Validate CDISC file attachment. + * + * @param file the file + * @param filename the filename + * @return true, if successful + */ + private boolean validateCDISCAttachment(final MultipartFile file, final String filename) { // Try to open the workbook once to ensure it's a valid Excel file and collect sheet names final java.util.Set sheets = new java.util.HashSet<>(); try (final java.io.InputStream is = file.getInputStream(); @@ -333,6 +364,161 @@ public boolean validateFileAttachment(final MultipartFile file) { return true; } + /** + * Validate NCIT file attachment. + * + * @param file the file + * @param filename the filename + * @return true, if successful + */ + private boolean validateNCITAttachment(final MultipartFile file, final String filename) { + try (final java.io.InputStream is = file.getInputStream(); + final Workbook wb = WorkbookFactory.create(is)) { + + // NCIT template should have exactly 1 sheet + if (wb.getNumberOfSheets() != 1) { + logger.warn( + "NCIT template should have exactly 1 sheet, found {} sheets in uploaded workbook: {}", + wb.getNumberOfSheets(), + filename); + return false; + } + + final org.apache.poi.ss.usermodel.Sheet sheet = wb.getSheetAt(0); + final org.apache.poi.ss.usermodel.DataFormatter formatter = + new org.apache.poi.ss.usermodel.DataFormatter(); + + // Expected headers in row 1 (index 0) + final String[] expectedHeaders = { + "Requested Term", "Use Case", "NCIt Code", "NCIt PT", "NCIt SY", "NCIt DEF" + }; + + // Validate header row + final org.apache.poi.ss.usermodel.Row headerRow = sheet.getRow(0); + if (headerRow == null) { + logger.warn("Header row missing in NCIT uploaded workbook: {}", filename); + return false; + } + + for (int col = 0; col < expectedHeaders.length; col++) { + final String cellValue = getMergedCellValue(sheet, 0, col, formatter); + if (!expectedHeaders[col].equals(cellValue)) { + logger.warn( + "Header mismatch at column {}: expected '{}', found '{}' in uploaded workbook: {}", + (char) ('A' + col), + expectedHeaders[col], + cellValue, + filename); + return false; + } + } + + // Validate data rows (starting from row 2, index 1) + // Pattern for NCIt Code: C followed by digits + final java.util.regex.Pattern ncitCodePattern = java.util.regex.Pattern.compile("^C\\d+$"); + + boolean hasDataRows = false; + for (int rowIndex = 1; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + final org.apache.poi.ss.usermodel.Row row = sheet.getRow(rowIndex); + if (row == null) { + continue; + } + + // Check if row has any data in columns A-F + boolean rowHasData = false; + for (int col = 0; col < 6; col++) { + final String cellValue = getMergedCellValue(sheet, rowIndex, col, formatter); + if (cellValue != null && !cellValue.isEmpty()) { + rowHasData = true; + break; + } + } + + if (!rowHasData) { + continue; // Skip empty rows + } + + hasDataRows = true; + + // Column A (Requested Term) - must have text + final String colA = getMergedCellValue(sheet, rowIndex, 0, formatter); + if (colA == null || colA.trim().isEmpty()) { + logger.warn( + "Column A (Requested Term) is empty at row {} in uploaded workbook: {}", + rowIndex + 1, + filename); + return false; + } + + // Column B (Use Case) - must have text + final String colB = getMergedCellValue(sheet, rowIndex, 1, formatter); + if (colB == null || colB.trim().isEmpty()) { + logger.warn( + "Column B (Use Case) is empty at row {} in uploaded workbook: {}", + rowIndex + 1, + filename); + return false; + } + + // Column C (NCIt Code) - must match pattern C\d+ + final String colC = getMergedCellValue(sheet, rowIndex, 2, formatter); + if (colC == null || !ncitCodePattern.matcher(colC.trim()).matches()) { + logger.warn( + "Column C (NCIt Code) invalid or missing at row {}: '{}' (expected format: C followed" + + " by digits) in uploaded workbook: {}", + rowIndex + 1, + colC, + filename); + return false; + } + + // Column D (NCIt PT) - must have text + final String colD = getMergedCellValue(sheet, rowIndex, 3, formatter); + if (colD == null || colD.trim().isEmpty()) { + logger.warn( + "Column D (NCIt PT) is empty at row {} in uploaded workbook: {}", + rowIndex + 1, + filename); + return false; + } + + // Column E (NCIt SY) - optional, but if present should be semicolon-separated + // We just log a warning if it doesn't contain semicolons but has commas + final String colE = getMergedCellValue(sheet, rowIndex, 4, formatter); + if (colE != null && !colE.trim().isEmpty() && colE.contains(",") && !colE.contains(";")) { + logger.warn( + "Column E (NCIt SY) at row {} contains commas but no semicolons. Expected" + + " semicolon-separated values in uploaded workbook: {}", + rowIndex + 1, + filename); + // Not a fatal error, just a warning + } + + // Column F (NCIt DEF) - must have text + final String colF = getMergedCellValue(sheet, rowIndex, 5, formatter); + if (colF == null || colF.trim().isEmpty()) { + logger.warn( + "Column F (NCIt DEF) is empty at row {} in uploaded workbook: {}", + rowIndex + 1, + filename); + return false; + } + } + + if (!hasDataRows) { + logger.warn("No data rows found in NCIT uploaded workbook: {}", filename); + return false; + } + + } catch (final Exception e) { + logger.warn( + "Invalid excel file uploaded or failed to validate NCIT workbook: {}", filename, e); + return false; + } + + return true; + } + /** * Read a cell value and correctly handle merged regions. Returns trimmed string or empty string. */ diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java index 5545da34e..2acb58078 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java @@ -186,7 +186,7 @@ public void testGetFormThrowsException() throws Exception { @Test public void testSubmitForm() throws Exception { // SET UP - create our form data JsonNode - final String formPath = "formSamples/submissionFormTest.json"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); // Create expected EmailDetails EmailDetails expectedEmailDetails = EmailDetails.generateEmailDetails(formData); @@ -267,7 +267,7 @@ public void testSubmitFormThrowsExceptionWhenFormIsEmpty() throws Exception { @Test public void testSubmitFormThrowsExceptionWhenSendEmailFails() throws Exception { // SET UP - create our form data JsonNode - final String formPath = "formSamples/submissionFormTest.json"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); final String expectedResponse = "500 INTERNAL_SERVER_ERROR"; @@ -316,7 +316,7 @@ public void testSubmitFormThrowsExceptionWhenSendEmailFails() throws Exception { @Test public void testSubmitFormRecaptchaVerificationPasses() throws Exception { // SET UP - final String formPath = "formSamples/submissionFormTest.json"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); // Mock the RecaptchaService to always return true for verifyRecaptcha @@ -348,7 +348,7 @@ public void testSubmitFormRecaptchaVerificationPasses() throws Exception { @Test public void testSubmitFormRecaptchaVerificationFails() throws Exception { // SET UP - final String formPath = "formSamples/submissionFormTest.json"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); // Create expected EmailDetails @@ -413,7 +413,7 @@ public void integrationTestGetFormTemplate() throws Exception { public void integrationTestSubmitForm() throws Exception { // SET UP baseUrl = "/api/v1/form/submit"; - final String formPath = "formSamples/submissionFormTest.json"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); // Mock the RecaptchaService to always return true for verifyRecaptcha @@ -448,7 +448,7 @@ public void integrationTestSubmitForm() throws Exception { public void integrationTestSubmitFormWithAttachment() throws Exception { // SET UP baseUrl = "/api/v1/form/submitWithAttachment"; - final String formPath = "formSamples/submissionFormTestCDISC.json"; + final String formPath = "formSamples/submissionFormTest-cdisc.json"; JsonNode formData = createForm(formPath); // Mock the RecaptchaService to always return true for verifyRecaptcha @@ -467,14 +467,67 @@ public void integrationTestSubmitFormWithAttachment() throws Exception { // Prepare multipart file from resources final org.springframework.mock.web.MockMultipartFile attachment; try (final InputStream is = - getClass().getClassLoader().getResourceAsStream("formSamples/filled-form-submission.xls")) { + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-cdisc.xls")) { if (is == null) { fail("Test attachment not found in resources"); return; } attachment = new org.springframework.mock.web.MockMultipartFile( - "file", "filled-form-submission.xls", "application/vnd.ms-excel", is); + "file", "filled-form-submission-cdisc.xls", "application/vnd.ms-excel", is); + } + + // formData part as application/json + final org.springframework.mock.web.MockMultipartFile jsonPart = + new org.springframework.mock.web.MockMultipartFile( + "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); + + // ACT & ASSERT - perform multipart request + this.mvc + .perform( + MockMvcRequestBuilders.multipart(baseUrl) + .file(attachment) + .file(jsonPart) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andExpect(status().isOk()); + } + + @Test + public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { + // SET UP + baseUrl = "/api/v1/form/submitWithAttachment"; + final String formPath = "formSamples/testNCIT.json"; + JsonNode formData = createForm(formPath); + + // Mock the RecaptchaService to always return true for verifyRecaptcha + when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); + + if (!hasSmtpConfig()) { + // If no configuration, bail + return; + } else { + // If smtp is configured, we will actually send the email + log.info("SMTP is configured."); + // Set credentials in the form data + formData = setCredentials(formData, false); + } + + // Prepare NCIT multipart file from resources + final org.springframework.mock.web.MockMultipartFile attachment; + try (final InputStream is = + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-ncit.xls")) { + if (is == null) { + fail("NCIT test attachment not found in resources"); + return; + } + attachment = + new org.springframework.mock.web.MockMultipartFile( + "file", "filled-form-submission-ncit.xls", "application/vnd.ms-excel", is); } // formData part as application/json diff --git a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java index 4bfad22e6..8088d0a18 100644 --- a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java +++ b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java @@ -54,7 +54,7 @@ public void setUp() { @Test public void testGenerateEmailDetailsPasses() throws Exception { // SETUP - create JsonObject from the json test form - String formPath = "formSamples/submissionFormTest.json"; + String formPath = "formSamples/submissionFormTest-ncit.json"; testFormObject = createJsonNode(formPath); assertNotNull(testFormObject); @@ -78,7 +78,7 @@ public void testGenerateEmailDetailsPasses() throws Exception { @Test public void testGenerateHtmlEmailBodyHandlesArray() throws Exception { // SETUP - create JsonObject - String formPath = "formSamples/submissionFormWithArrayList.json"; + String formPath = "formSamples/submissionFormWithArrayList-cdisc.json"; testFormObject = createJsonNode(formPath); assertNotNull(testFormObject); @@ -160,7 +160,7 @@ public void testGenerateEmailDetailsThrowsExceptionWithEmptyForm() throws Except @Test public void testEqualsWithEqualEmailDetails() throws Exception { // SETUP - String formPath1 = "formSamples/submissionFormTest.json"; + String formPath1 = "formSamples/submissionFormTest-ncit.json"; testFormObject = createJsonNode(formPath1); JsonNode compTestFormObject = createJsonNode(formPath1); @@ -185,7 +185,7 @@ public void testEqualsWithEqualEmailDetails() throws Exception { @Test public void testEqualWithDifferentEmailDetails() throws Exception { // SETUP - String formPath1 = "formSamples/submissionFormTest.json"; + String formPath1 = "formSamples/submissionFormTest-ncit.json"; String formPath2 = "formSamples/compareEmailDetailsFail.json"; testFormObject = createJsonNode(formPath1); JsonNode compTestFormObject = createJsonNode(formPath2); @@ -211,7 +211,7 @@ public void testEqualWithDifferentEmailDetails() throws Exception { @Test public void testEqualWithNullEmailDetails() throws Exception { // SETUP - String formPath1 = "formSamples/submissionFormTest.json"; + String formPath1 = "formSamples/submissionFormTest-ncit.json"; testFormObject = createJsonNode(formPath1); // ACT - populate Email details diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index 627d18fd9..26b661c16 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.doNothing; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -261,7 +262,7 @@ public void testSendEmailThrowsException() throws Exception { @Test public void blankFormSubmissionFailsValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/blank-form-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/blank-form-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -273,7 +274,7 @@ public void blankFormSubmissionFailsValidation() throws Exception { @Test public void blankSpreadsheetSubmissionFailsValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/blank-spreadsheet-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/blank-spreadsheet-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -285,7 +286,7 @@ public void blankSpreadsheetSubmissionFailsValidation() throws Exception { @Test public void FakeExcelSubmissionFailsValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/fake-excel-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/fake-excel-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -297,7 +298,7 @@ public void FakeExcelSubmissionFailsValidation() throws Exception { @Test public void ExtraSheetAddedFailsValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/extra-sheets-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/extra-sheets-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -309,7 +310,7 @@ public void ExtraSheetAddedFailsValidation() throws Exception { @Test public void ChangedSheetNameFailsValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/changed-sheets-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/changed-sheets-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -321,7 +322,7 @@ public void ChangedSheetNameFailsValidation() throws Exception { @Test public void filledFormSubmissionPassesValidation() throws Exception { // SET UP - Path p = Paths.get("src/test/resources/formSamples/filled-form-submission.xls"); + Path p = Paths.get("src/test/resources/formSamples/filled-form-submission-cdisc.xls"); byte[] content = Files.readAllBytes(p); MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); @@ -329,6 +330,66 @@ public void filledFormSubmissionPassesValidation() throws Exception { assertTrue(termFormService.validateFileAttachment(testFile)); } + /** Check that filled out NCIT form attachment passes validation. */ + @Test + public void filledFormSubmissionNCITPassesValidation() throws Exception { + // SET UP + Path p = Paths.get("src/test/resources/formSamples/filled-form-submission-ncit.xls"); + byte[] content = Files.readAllBytes(p); + MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); + + // ACT & ASSERT - Using the form-type-aware version + assertTrue(termFormService.validateFileAttachment(testFile, "NCIT")); + } + + /** Check that blank NCIT form attachment fails validation. */ + @Test + public void blankFormSubmissionNCITFailsValidation() throws Exception { + // SET UP + Path p = Paths.get("src/test/resources/formSamples/blank-form-submission-ncit.xls"); + byte[] content = Files.readAllBytes(p); + MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); + + // ACT & ASSERT - Should fail because there are no data rows + assertFalse(termFormService.validateFileAttachment(testFile, "NCIT")); + } + + /** Check that NCIT form with invalid C-code format fails validation. */ + @Test + public void invalidCodeFormatNCITFailsValidation() throws Exception { + // SET UP + Path p = Paths.get("src/test/resources/formSamples/invalid-code-ncit.xls"); + byte[] content = Files.readAllBytes(p); + MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); + + // ACT & ASSERT - Should fail because C-code format is invalid + assertFalse(termFormService.validateFileAttachment(testFile, "NCIT")); + } + + /** Check that NCIT form with missing required columns fails validation. */ + @Test + public void missingRequiredColumnsNCITFailsValidation() throws Exception { + // SET UP + Path p = Paths.get("src/test/resources/formSamples/missing-columns-ncit.xls"); + byte[] content = Files.readAllBytes(p); + MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); + + // ACT & ASSERT - Should fail because required column D is empty + assertFalse(termFormService.validateFileAttachment(testFile, "NCIT")); + } + + /** Check that NCIT form with wrong header fails validation. */ + @Test + public void invalidHeaderRowNCITFailsValidation() throws Exception { + // SET UP + Path p = Paths.get("src/test/resources/formSamples/invalid-header-ncit.xls"); + byte[] content = Files.readAllBytes(p); + MultipartFile testFile = new MockMultipartFile(p.getFileName().toString(), content); + + // ACT & ASSERT - Should fail because headers don't match + assertFalse(termFormService.validateFileAttachment(testFile, "NCIT")); + } + /** * Test that TermSuggestionFormController.suggestWithAttachment throws EXPECTATION_FAILED when the * service's validateFileAttachment returns false. @@ -342,14 +403,17 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro TermSuggestionFormController controller = new TermSuggestionFormController(mockedService, mockedCaptcha); - // Prepare inputs - JsonNode formData = new ObjectMapper().createObjectNode(); + // Prepare inputs - Load a valid form JSON + Path p = Paths.get("src/test/resources/formSamples/testNCIT.json"); + String formJsonString = Files.readString(p); + JsonNode formData = new ObjectMapper().readTree(formJsonString); MultipartFile file = new MockMultipartFile("file.xlsx", new byte[] {1, 2, 3}); // Mock captcha to succeed when(mockedCaptcha.verifyRecaptcha(any())).thenReturn(true); - // Mock validateFileAttachment to return false - when(mockedService.validateFileAttachment(file)).thenReturn(false); + // Mock validateFileAttachment with form type to return false + when(mockedService.validateFileAttachment(any(MultipartFile.class), anyString())) + .thenReturn(false); // ACT & ASSERT: calling submitWithAttachment should raise ResponseStatusException ResponseStatusException ex = diff --git a/src/test/resources/formSamples/NCIT-Regimen-Suggestions.xlsx b/src/test/resources/formSamples/NCIT-Regimen-Suggestions.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..9a912256cafc48c19672242c7f19de9de33faf68 GIT binary patch literal 73914 zcmeHQ2RxPS`#(mckgbf2jIzt#tKry*G)Pt@D|?fjR1QKit5b;3kUfe*Dmp^Ls;oni zmF@iRbIf{sD^9=v@BQ^2pHH%$=eeKzzOU=P#`pSO+G+%ZG!P=lS_lNf1_`*;8Rm@# zfvBv3K&T;W@eeE8+BllqI2!4?oicYY6mYe+V!cX;zcm?x5B?ta@h_f%4BcwYav_T1 zErT1vvr_G9@Yr5nB&ea}$?+_s(4tNcv39$0ea3^UpFJS?`qh}7w`FZ($De)nZV-D- zwdLTzI?<{r9%X%ZQ$xMfT%^Ome)EcUQju2UD~&3>-i~hD<1-0#xEe03(-RJszLl17 zd(9Is1#W3!mcvIU&P9=HKfj{n)iTi5gOJ``Dcdjf^2GQV;R7P^vbW6Ku649XMafz{ zchU{?qhL6UAF5sK*u@B~tvz;s=ZBhIymgX+XO5=s?zmsAeDC2#?kc{=Do7T|Enz>Z#^pvq!|JLJmxZZ^$iyBeF_+}isQ zzr=(E!4}T2hebt)ad1T7BRfKG%nxF07CHr+c6|Ni9MyzRE^}e5N!@h#VZTOpf4m?9 zXcUsrt|ibQMN(pt5CTD=2q4;DiEWOa(3TOf7uA7Ot_NakWN&WeASi(Tj1$*?v5YQz z^^6D&t#TpKpaGTX;Ht5P78r$+nv0@JA)BuEX=w9?ob%T>7+XrYnJ9D_{0a8>6njrU zdD|j$zPF0)%X^WGP%0YfE%#k+1;tF-IT7=4*+=iT%Xn8o>D(~d@FjMSs@qoQ;xL}{ zywodd)oojL*AMQzO;IbL&p<+bohgV;HrDshV~vBYCgYiS4NChy-3rRi6;JMstc~+& zioSs)lRqP={t*#NTjgMK{B@>hl@;6Q1cTnb6OtC$CW-b^>~2P8R%OFG<4UP#Joz=_ zt8~~!sK$5H?y2NV9`!kNPh_wr!L34^q&&UqbG2V6OKK}P!Tu^FO?0M|R0I&nMPoMhQ7#hhq|wht1P+%yjI+gV(a;SD8rCQr3Q;m?^4W|$(grM&W?J6Gu-PT_Ow@b_OYL0+C?2r>BO-v+TWbbY`2J& z`NveH9aL!n+Y_#9);M`_Z;{z!8KB@zsLV$fe3F?qf(Gs#lh%v@w+Wj@R-(eEv9^X>gq-g48o*DI$>lBg5!F^^ZhQlZ3x zckeEjSG&A3^SLplY^ie(Dq%8v?r@4rHs6VuL>>D2U$}^xpI6 z!|M|g`COlDZbam$>}`&CYR0o`zv@M~u)Je?&lF_S(!MQZt1;0YqRF^*q|oVHeEqF> zZYnX@l=scpry<9b!!2QNf+qFN^-MQV0Lwb^!gRs9$<%B}lNhL>J5F>+yg>Mkx;m0=i;dvqSZhXM-RnZSNn&<*2SY*e^PY`wt+V=G zCyIZ3Ju{nc8|H3^x>~;}@7lX|+9H^@!kTSPcc29iNW+OY$qBW<^h_VvXb+umnGG$> zw-PR8WO$oC`0`#Z@pGP>$l%w9()T3pxwT(!ENHdtHurG1ft{n$H<^oOsvRk6Lx+OsCu^HtBhNOl&YP zhxF+td!~0%KF=&K!X4T9g=2{gP0e_{ZaK>OSPKhV~mWfldcH!C8gT9pWXRr-;I-9vwJP?h)O7L|I%)*V{$6!I%!n@d25X| zlVVUYsp&@T33Xv9n%H&0O4DJ=g3nQwrU%97zMRk^modt&(~W~XT2Fj1Z0DeuL&&)jgRUjjL?y#rqB7RwS86%jkn1jd zL7DHpM9wq(o0Bcl&YM~7p!B}nuM*pQ9t%I8L_TEfj#7QJ^Kf$6Xt?rWcGbqs>qb8H z*@Uz2v1pFYqvYqWi{cr%=Z3QJq8my*shUF&u%9-yv7km)EBvy3hQW&$bo+VOBpW~L zZl9sU=$pgdG+B^PAYeYJ-M;>JEEgrV=xp6U zd0*(Q8#(>g#bq!-)A7C54jCP!W4FC~pLrzV#oYoAXOUK)D`cFP{Zvmg)hBzfT{!k( zz4}C%uCu?f$<^1qUNn4i-6xjiC6M4%gLrHq+;{uf_6T1*XLYu? zSlJ@gTQaX6h>oWMMM!gbMw1-<`;yT)uh?M`Y`$FnYP(B7avqjdWwGA%;bRl%qRVs-dfw%(#ifT zR9#l0k=NKTYG#xL^~L9o(d-y%l0Bi*3)3(5UW+tv%Uw-!U z@XR)pz0XslBgG!03A6r2*HMEX`dDU1SitX6l33`I+y)&>@`??5+I&17#|`hQ2+i#d zy+l9ooSsB5v6dd`V>FE%G?I0wVqO=FxMH8m%n;mo#i56pDENi3{Uv6);09xdSIie6 zv+z3a^iR*4PI|b{&eqEtHP7tzaU1>8;Nue|S6Wus*4{-ip=J_X!8Ur_j67fYowk%N zd5-djIw?o;;_`MODRuI@kpI4`HZi)o;;A&&%15EpapBcMI;7jBrw@Hi_*40!eA^ua$QQN%N7Xmv?1L zGvUP_sF?qQ1N08<$83oV^0@N;Q-r5_+mWNWB=2e*G&yBBRPd-2O;qrqEL05jtwDx%kHd$xA(>@Rd&4hSidnQ*DL+ozzavL=m<3?AqR+q^?zcNJkQ+j_G=D;TqVfW2mioT*pn&Ldsf zLg7G@?lQQ_9W#IRxKzxC8>cVA*6AoSsH{h_%9@=%2P4^`Ojot;HLG;T+RpeYua-%= zkfIDTV|GC*uJ=^3`4uq22ssY*iamu);y-y|<)&Pf4s)UP)Nbh4?U}80)e=514Qnf% zCgBJ)gE8s+WZ1swVc)oi9yYaINTR{qOqYa?-}(8lnWxahw)*R^OMg1-^4I8LpI#Vt zHD?e9Y=q62y@a?cZyPHo-0vlf2%#jUvSAbJ7Bj!6ur+s-#Hz?8l_a_C+g_IJVi$aC zaH%RZAS7?6mcYUarwRRdg|~%^8yV`id1qaD=QDevJ%&C}KF!HTcRcK; zMljL{<#j3~X{@4f-+M4}gfdap+E`X$Gv5pt*&XEz+RrsSuSt%Qb-fHGv}J^?rBbF+ znS`}l6a3_=5Kkw~nJu=Aue92Z$_FlNEsdk{kAAo*^Fy-wQ+(hgq&IAZE-76No}O(u z&-M!oYx6$cAIV~YzaGiR2Z!~r8B>=yapghTHgN>gz^HT-PpS}Durb4fNnw;b6pvNm zA7o=R3ud|!A2;5sG`Z(;8OKc)y+K>a?IG{Ez{1c(DB7$1NOr(5HLrqUS|yLMxZIHs zI!f?JgA~e&RDL+Xo$dSnhugooLSMX29znRfR(zu@8zslwMxfp(`(ud%Z+NX6ydiHl zV@CYKI%Jb%#Q%8vhz~YI4Tp*N9vmh+rlCR@0w&W-bH1Od7X=B(5wwWZC18 zpYX+hAl>42POm&e!HgJFZxpkmo)fMODL+wTHt&10C(v{Gkn6LBCVC=)_O!w;=d$^+ zBrltj63ifhw%0iNs^TXix%6t?qVr?SCLxXc@x~J!?C+YZ-)|B73o1%UNirXuq_uIsP$c*x|A?_2Q{-|MDiC@K)Q67 zbQ_txvdx?{uB&F1g#SninkyQZhZ6>ZlGw!O1o5ZG6pQO4`QZ-vRrDH|JRCn;TL6`kTM37zVFivwi?YEM7XZs}07;;fLO| zN;_1@e|Y!-@u>9t!Z|41LG-Jql|jq)q?tX%zdkt3vTTy(TG=CRn<}kn-Tze&(9|d@ zEieU#hDBw-isZ@T_ z%`4ohZKnUhMGzf)2UJvNV9E;DfhBu|@8L(YkxXNaf}homWYAITRgtw|Jr55NiKIiQzEP1zN`!aXJALqUKOY_m zH<(t`I-v18hNK0Cq!{%ZhLq9>X6exH7*Ze@(x&L&FeKtPV3tn&jv*C- zAq`?Zqyz`If}&n;w@$Z)H7$t>l-syC;TJE4+v_OuKxxysMB&jd!`%@I3{YwdE`E5_ zy>MrQ9eYiuT>H$Fmd}))(YSo+i(CnxnPBhHFCJu~sELvOlqA%27K(OesIRtkT4Q>0 zO1w79d-`4X!0c>{K5A&B!?OK&g#94z&v(BpG=DtmJHnx+5MAR{Ru~goCuq$v@Fde+fx7zY77N-A=&&)ofkOf%L_DiigY)-| zIn5U{b=rlW-iRP-MRWXDovWtMZP03P#HqAssHoS^Ml1PO^*YOEf#SlVLDA2{)GFWK zvA;U9KYxmGlKZP0{&z~QRQJ%Ap_@~kQQdm1t8G;ckWJ~9*EZ?Lg1?+7NoO1j%W&RIUj{iu>t&@y#iP3Kn z%#z6}NPbJbmHiPs;9|rM9Zen;&NTK0c+krTDIF~al`R(R&)|XgBE%4yQks|}QEfnA zz>{oxnovi;`}*pS#@~AW{3E9rXV(1K?ptP0{zl0~)rJ(CHu#zyrun23;vRdjlbwP} zgjW{5(prwLm3>r_nj1*3HGPuszXy?1? z3Fzdjbh1Z<>i+T? zopp1|?BJ`m}x zJ}HT8g16CQ46aGT**=`vh%+0pG#hsb=%b_zols*#CJhNA-iTH1#tFmBS>VOUrWq9B ze2|qN4u6IZg7pE_vm?f(GQB@3CMLZf!p zssDM+h^T@8#WYnNLJY)xsHev7=Ipni+uKo(Jp zdO^a7F`@+?7AdDukTfEM9EJ-_9pp-on9t)SBFm?1mdfdK*!oO|Qc0>Ycff$BoMIPZQ)^v{>u||wR<+*0! zM=TKo>(Nmz<{1H>e4-;pxY+l9FOBgBC}$A+9{4?~@h#4Y!Nqs5jPIBWpqLiZf<|No zv5wNna(E$>h1=`0qdd|W0fLNNvYPIfM`VzF@EB-TWGk0f+=v$<3@Xn(b9rRS51kv` zQ(7aBvl?+}b}ZBEz-p`=ygAj~*?CjCXQlxQ!~{AKgNyIr5EIxTCQ!0RoKQtY22RAq zr3|Y_OrQ#IR^xva{PHJQja8j(D^J9rByT%>R6WHJ>Ua32`VLEN=wlh;PfF^NQHObjTpt+UrC(^ota7Xw;(2n+);!-3`iXl^|l(egF%}aaWD64JTP&gIRqL8n)_+N(E;Icaa?#DhbP7cPb}b&FSTG=wj3b? zm~b1!6hQf40+MKt8^pwy#~(3p@p&&C1BP4(Nb3I&ZN`EmU4bKCVb_;s4w23}tH8J8 zl=E*;&H!dXF$2K% zw7|zefh(p?0bNW83b&S*C17Ab^96<&^x5({1zdRNUtOJwb$}j(cTmg=d2Abie$;Rm zN6r9{52m~ojeIQ8{HmH2Q%N(AhQy%H7Rp;u`8cx?m#o3AV7;KKbJ8d!y&qLtbij$b zMRS$$orGzDCX_u{QS7&Ilkdf;|H=!13y%DT;K-kW3^!VGV*0RfVg#GY;`(q{TpSh` zJ1nl(0v5NRcrzAeqcd4i{$`wN{NLpy!P@Hk9Yr$@i-5B)?yL8x^T9EV+l*MK1#I2X zKjWMp{XLuUU#1y@pTq^X zQ>ubw_9E$?nSdSO%R z1!&HE5;6-=9&WdLH475wYrW7#umBt00+NNxAi03NLUNvePY@8NVEFgu*l{(zW710v z2->u8?706mqT~O5Q1N$|jY|m|Kz_3NgE|Hr)Hw1K9CbN1)a8IYrEM`RIeBuPk90K$ zb*<=UP}Kbw3bJ3JL|>vQTUjV?i2(f%&GDwv;|BSt!b0=|K%>?0pJ}N=g}U z=|f!laP`Ln;M^-*@~9X1D&_%@{eZ|G5H&ACa*Y9V{bD_#C5F*{vBO7^1DU4}uEKTo z-sJy&gAT0ECjfy=|1F!*ARnh0SJ>>Ob~#nTw@pr3G*{>j{t4^>AbmLYd#pxhoNC0X zY6PbmU!&3Ci!5iEi`=;AW;0%i0DNjBaFGCV6@UqxYQ&C;6Ke+mYcwp@forS- zRE8ZxW0=C3BS$g{A~U(?N$gj8Py+(9f&XA02Gasmf35|nxp{P|JtbB0238Kjt0*!z zURTX#x1v+s67OzNJ{I^{zsWzr(#N6BFsQS|>O){(dR@XK5SMM+a*)2BPa)QWR$Ymp zZx>*?cfvF?1bsFa?MqN$GlnCV!jVg1M=mw-mFpc0#Uv2XT=(6e;VZiP0`PCZIQ9hNOQ16^(VlWR zrYSqR1@6g!gNS#UDgB}jSk0IjX0|jJF9Vt zk`%;&0IL+bOVYA9P%y||&y)J3K-;)wwE!)yDM(|Zo5z86NsEOuQ8>(*OLXY!K?SRd z!XTX%=~KT`>+tsL0?EHpg?#mse*oR{3v+>i-=i8qqgNc}499ea4WrT5OlKtwpsOaP z3-%H?d;=(znJ-t+0zC{tgUubFt7g+&ha@rN95@_c&Ojp&oYjc48nHSafYpflJ*p9O z*2GzjI7(8iz$F6qZev;XdSfV~xrEIsBi|rl)AAoo*!&c&fGeHv{EpeUvhv1%KrRc^ zTW2jnAPW^)xG)JsJ46cT@QSH$6#|7@^H?7dMpw9EmxpP=70%%LDy*K41MS4fE%a3|EM;816H{tP z&{oQbE1ba<&a6Jh1)P|#h*4G_`UXt)I4TO96N8--v%Kx_WJ~gfNE@ye&1Gd=?w0^f z)Ere0XoT&B7zT~7{m9b*hx z#e6yJVo^gmfcMN7H8jE7Fz7Sj^UO7S1-)s|$O;^}RHpAw!vx>o+kb-Rj6HI!&Iiz^Y@es|@z$7>#h}lcptcL$Kw3fdp^tc~K@rc-z_Z~`zGV*h z2ZSK7p2+`M%$R%Pyif2w?T)lr%ug;-GW_iqUlX|gWtIQB?%)1I3|l&bAtaiNbRJ%@$O35$z-IF-kd}x64B)3&)4h<@{vbi?i-94W zvxA3&Kw=Alw9lXHb8MJts|nR}L5$7;Ak{Hsq~ElW1745mJZHtsC4wSn{*9_=!7wDR^prv#0 zGb!X^S9Wyv&8tp1?(!O;Y?9>ju=6ITn1X}~bBl+0eB30Uz# zJyJOR7Keev(F9;m6X3Aewri1h55vjLq z>{83)lK%j3_J3bFqbp~^mQ~KI{-8F(VIXlHHMSnL!^9HK2NV^e>t;4Y_M_<^C6M*- z+J&l_0Z?5C%C{UqQCAAIlxrptQ(f2x&s~oW8Z*xb;3!GSaH_HKG`8^Y?@*Gi!fM1( zl47YAaJ+kH-o5WolCEMi;wVY~y_(S-)BgN#>|W%r2cW<1Xt+pZzls#~Ea*6cV{5j< zu{C3XyX#?(@tKt}bV7{{nKUFg%3`XmS8g>XObei<|C~I`Y!bC}(=Gpe#MVg_vanKH z1m3Q_cemP6Y%?b(mB?*lDOO8(X~>=Kc!lS!#NYM;{aaiCNI3lWeb-f$cc&S^7m9KI z0pPn#hlzT??L5^zdQ-aRnR(qOcrI{visMGS5y8-9*fZb&iGd;;G;u&8m#h|m{g}`3 z1sGzMp{HQF8nlMpk!s+n_cv`_aZ5SZzwmG7;d@A%Wm{!&&-~pNG3WpHjno%T0zROy z!3R}z#EG~#pR@n~8vzK?C9+iua9Au$X;00yHbhr|)q}z>fZv@j{Nly9--a>rg+#3e zfZI81HHf2sFYaprr-y6NlV%`R@VrwHbbK91YD(`<7LQTPjcnB{h#Rp%OhH+==6fcg zBjup=>s!DBiKd$Zh;kXg77#PXGUc=jjhMRDHw0{pxEfINr3dolezV<#lwc|U0EuqOpB@D;$eCgH2Ii5j9X-y7w}1e$Rl{8#S-u>52AXZgfwBfPNvRe< zhl3#HjyZ19Obn;6qv32XgR8?PU4fDXVgD9+`z-=<*@=S#%p4sd&2n(so40g2DRZP6qu=$ab~06GKAr1PaVv}kPfh0K~Z z0|HwC(0*8drHU~Whq^+euCQLpKY?kyduR-xE5>U3^jzw|LHibJ3m5|2#gQ{0ce4z8 zR**De4XF3f3_r3OfY`?raOGl%eG1qypj@YkLd*7N=Gyt=Hivk^G?$DPbwq z1Rf3fS`yJ>hxUr~=iYPCQS9m8@0kSYwLX?}`LbiZp2y6#XAF2;BzC(rZic>ngh8HFwIGqz3Yt{VdQXXL!6TYInWq2oNACT0_w zM5T}aaO&N5pS4GCo|pa{451>V*yS-W=qhFqR#VImbF-Q%dHq!Eny-KEbl9QzEUwAE zc1pA9u*2h@oXHM4d|ta_9J*dUKhen600q9bSTEmaWc^sUQr?d$dT7e|F?aoog0uI7 zc1lipGPNcrPdat?@L!Ej@1ESc#U=k0z5>Cfz1zlK?o-@CrC@s`#uKi5q9wx1Wl=E7I&o$?LZ#Q%-Le zewaBPvjN}Q%)yZ1e_y#O zu7QZu$E`^(owr`x(SyveXn!NCs&I~7hqBHR6&R2ct7h_2(PaOoE9-o=_=YD0JSy^k zl<#a5b@Qf4!n)-B`fDyk?zvZ|^?0|4>?Vrc%7)z6lJuOM>@*J{yCbSUlJ}IyZS35|d$0u*jj;eZyv)6Q}m@WO+cqy^oq6PvY-14&Q*2%O;%d6%i3R)@{4jlAoRU zO6j0y;j@BPtm-%OkNV3Z1+SFKY=E1pp&)e{OIYKfiw?K-M$liFRYH;xW?mt(m53Q zmdq_wPk1Nu{@n$Gk2x7{#pxd+KL19N^MZN{Jt<-6p}Vol8p1X;*^M6&y*kqG0?VFM zjKmf-2wxSZ&Ptfh?$5RyJ)PPg=JioB6nHCKMd zJjYRDv-`n3}TQ5Z6v**1}_H<&WsfI;5 z$BFBq0fcKUl;1aK#5cBwRoU%X_ui-bBZu`3YwalO4e0~#3#VFA1l``QyU?F%b17mQ zxgh?zR6gD64z5Q=HV(Eydri;qk?2R4$amdqxT~dl@#mQv zuXGeIuh-j0V#ITO&31*}^KCCLN8Gus}O_6(ubW&V6i&|GEfKNyO-ml)+$oRh>-UeZBl5kk-p24rJ?tV8H}9=8 zM?KpPp51(at!?w|J9iHdjSHGp=Qo@-IybDWvV~Fhs2R!2#4Cro6q08>3$xgqsoucX zhZc^7y=Bz+VoVc8=y_a7tx+|mE?RlVtz+)UcN(&EI+Jv3>b{aax4m&|%(fuKd3?E zUiczS4Rw{*jO}c7nJ#aBeO%~K(nq@TJ)I@3+ifm+nyH_Den*yk^O(%0!tlIs$83B% zL5p3^&CQ$TZj8Ims;J$krnouVc-%SV+`jPlA13_02p*;-ysE2VVc7WkbExy>>*GzM zL(e>&685z69e7?;&3V4qt;oP_u%pF3=SjCBP0^I>o6uQPUVBR>QrM|GCnP><7P#Ce z_HpRA?z+?QbBhN-cIB(?7b1CQ%gbs6{p;e?tDnYc2$~9pm7fqz;LG|Tv)MSTwmA`B zp0rT*sb3g<5XqBRCVNq{6Hfy<@FwWFr`f1y?e;vM1!DGBLBu2QS9k+{a}*B(p_v!N z6UO%DX8RoNEo_cs#=WV!1brd;(=%HWbaO?UXwC@cd7c}=ncHUm)#V|6YuIiW%VoGc3tQFG=Q!o+_+mn zko0cqq?(m6MeO}U4)RBbimIt~I9c*J1ofh?b)_Y5kYQD27}cn6?(Nv(+dHgo@{ata z`k=$(FIv*&FE-g_9WbOLy;&Y{j_&w~k~h+KZ%*Q1vyV;E&K$`M{}>xl)R&Tz@-qFk z)7QtMx!am#Pi}u~uap|cH^$Q7#5M+0&tK<4+IolD126|lU@o@I&4r7ty`{qmb8|-r zK_h!}D+fW$HyCR}0R4SH*n_hVg=lt-5zH#PdPFt`k}B^LXV25?CNPUMw;;*GiwO4AlleC1FS9uBu2@?fNuy+C;I>!&rtUr4?; z1GVjY?mYx=&qoV^aL>)aDX*o7-sv-&67kO=KQ(8+GvWlpcp?hmK!RemO`kg^G}3Fc8=F z56L}oXaBWL2R>v_)|<7M=^oD%wyn#J6@9^T$JT5_y)B#1@xxX!VcPtey_Y6mD6Xv` z#jp2|+-)2`HoP_Doz#(bYe#%n<7iTsPzL4W@T){`s)eAR%qV6r%$BsAr0qcl$>vWX zAD)=tWGg+v@Ts6fcO+DHs-yRH<@LLbgBuz%1~>D#7_3Vlin^^oA$2QdXxHailBuTx z&aVh`k0bB2rP{P#t=(F_d2Ao)+F5$!DZxa_w_KHSyF11v0;IH@?!=33x_Wvm>$)@e z-}&$9)iQpt$bS`tt4B^x>49xvjSqoPLe}D$*_vwG+n#a|G_|!iN1xEFR|)a9CPToV z{JTFqBlcPX@egbxp4z}UV14%&{czYzBXk5y) z!*)9Ewija`O-b{B9N&2Igo0Ekbm!-=CSQw>Nd(3AomK(T7HvqTvCGe1vtH=GMtkkH z_1n~hk?o$|enz=rg(WAqn&t8mrB+F(#p3l|+!noCds9Yg8h;h3(Y6*k%abjQf}Vn> z1+^YAv_@Ug%T74=RUTABiSl3jH2&Ew-+JSL^qL!k&l%ny?j=6Huj0U7=exJtqnHF~>-oz{ zxc3}R;FYv#c*w9p-ztOm1Lei(&8gBth9?|8P@QZ*WUNu!Zr&p&ao;q&m?3~Xh2j?U zIiX30rkIG=Cq_8j$i%&z;j}iCjx}p9^*`tzd;f)Hex5M%rJMdW2^PwZe zgO2LW!lXq6&#!)9e9kmHs^1mq?b=rOIY{f-jw6hISs%XypWGWq$XQuj<1DW2!gP2j zp<2)S;kqY+&jxmlA!^HA8td;uy(5OVTsWrc?PDEJ=%;N-IL!TSTw#Q<=Q_7!_G_hZ65A2SXKAUk z{AapE`HU}Kv^b=$l+~ILkIXSi#@kJ0`tX6!=DmL74m~0CH#_d}2-gqZI8V`BL}#|~ z?gIs%C)+Byn@IT?^HaoZSLOBwf1UT3XBvzcEO^YoLC6)2|JjrCWl{Lyrgfi@Edd z*qsIN zXyDU50FHUa*V^je0ghSD;~bOO=g;9$0`LLW0oDUb0cC)4Km`CLfGPn2Koy`GumMm5 zs0C~UYy#8)HUqW**6!86b*FqKIK^TQeeh3t+i^Y|`_s4)PmD>q7hix6&_&J*No!~{ zW&WjhP<$BF_-?jIe;<@`+$W|W>!Yud{;_ahI+EZFYvtO&{#T)Wkl;7T2|X@yccc$W zUyfd*=d$LrP+D+v-$35Jde<#u9%@gW9X$638TCdT_7M>h+#U=?L!stGxV2Hu!}Z2C z>^@>eQNTUbVSmm<_mlwbo9Q+ec~je>_; zT{O5e2!9fd@dPYHDNH+fVfLzsxv(T+=E%2ElyDr`h8)jxY_U^W=3=o0gL|lnc4rw> ztCdZ6shC|@mywJ_^xejG%(vGj)A^8v{!KBKr}KTwCtrxpTJy=TX1d1LZoaAgY;yMD zhhivtxBxv`fF3D8_bs8{(+%>ci)K9{Y^sfm_Hf5BT|m zDC`}!tnrrHsE8VVk2D#LS_GDx9B77)Nv`C4iF(*$UAkD@@rpmm#PtAHyLR4s-U59KG+7jx73tVWq=sL;SPcO=*yp!S>3bD>* z)@jO_Pw=8lQd%kcB#JYqw@OKDe(0Qe`1Spfq3&2h=nqHFSzgiO$akp1W^#t%7Fd zYn?|0xtNBpV6_fUmv2&75iowRI6MOw`|MyIV0?-nVPO~}(E&X`&-k1u&Yjz~x;lWW PZR9Qg-Ri8=t<>=+K^C41 literal 0 HcmV?d00001 diff --git a/src/test/resources/formSamples/blank-spreadsheet-submission.xls b/src/test/resources/formSamples/blank-spreadsheet-submission-cdisc.xls similarity index 100% rename from src/test/resources/formSamples/blank-spreadsheet-submission.xls rename to src/test/resources/formSamples/blank-spreadsheet-submission-cdisc.xls diff --git a/src/test/resources/formSamples/changed-sheets-submission.xls b/src/test/resources/formSamples/changed-sheets-submission-cdisc.xls similarity index 100% rename from src/test/resources/formSamples/changed-sheets-submission.xls rename to src/test/resources/formSamples/changed-sheets-submission-cdisc.xls diff --git a/src/test/resources/formSamples/compareEmailDetailsFail.json b/src/test/resources/formSamples/compareEmailDetailsFail.json index 180f7747c..97448c853 100644 --- a/src/test/resources/formSamples/compareEmailDetailsFail.json +++ b/src/test/resources/formSamples/compareEmailDetailsFail.json @@ -1,5 +1,5 @@ { - "formName": "CDISC", + "formName": "NCIT", "recipientEmail": "agarcia@nih.gov", "businessEmail": "bcarlsen@nih.gov", "subject": "New Term: Test ", diff --git a/src/test/resources/formSamples/extra-sheets-submission.xls b/src/test/resources/formSamples/extra-sheets-submission-cdisc.xls similarity index 100% rename from src/test/resources/formSamples/extra-sheets-submission.xls rename to src/test/resources/formSamples/extra-sheets-submission-cdisc.xls diff --git a/src/test/resources/formSamples/fake-excel-submission.xls b/src/test/resources/formSamples/fake-excel-submission-cdisc.xls similarity index 100% rename from src/test/resources/formSamples/fake-excel-submission.xls rename to src/test/resources/formSamples/fake-excel-submission-cdisc.xls diff --git a/src/test/resources/formSamples/filled-form-submission.xls b/src/test/resources/formSamples/filled-form-submission-cdisc.xls similarity index 100% rename from src/test/resources/formSamples/filled-form-submission.xls rename to src/test/resources/formSamples/filled-form-submission-cdisc.xls diff --git a/src/test/resources/formSamples/filled-form-submission-ncit.xls b/src/test/resources/formSamples/filled-form-submission-ncit.xls new file mode 100644 index 0000000000000000000000000000000000000000..f743d777ba72b30699cec71eee804d31abcef56e GIT binary patch literal 5120 zcmeHJ&2Jk;6o2d3`JhegB>f`Lbm}yaI1a?35fsxV!D$2%kSIw-fr8oClX}(lu32v& zIbpse4j>_M<UBlJV;O3MV|&1e4_cEo4lRkbgEfqafiyxx;?!S&37m@Aki z%X7sorN`AAOoR94NmYIXO$YW9YjEqM>{jKcs`qPciJpSdVVryPo4!Y2!8ys<(73XD zUzKrHcAzxqOEu;vrAcAuehd5R>mTru07YoRvrPLx?C1^m02L=Bek|UX?CTrJ4yFf! z_F!-L2%?X(5@^u-!mP}{*k~efG2yteq7vQv&}{%Z8%B^8X?NEgMe;lN}h(!b6e<`G95z8b>8WeMmxVus=yj!g4e^(lg)Sizn6KZfvaX z@Hh?8gAERY(Sgs}Q02BhZcW`tM88)Nj&-^$SkH^B^uGliJL`GBZDqfmo>8~5zmxR_ zZ@YC0;yI+_@JG-Q=m)paC%4fjw$Zo!P5)siOtDH+mFvz*v#Pr)VO4imT2xIHQuV${ zr24YD2j0Q$@)D;#IE8ZsDgD%Yco7YJpBSnRAH>0`T@G{|&*mZ6@>_@Za8|yuB+I_c zi+Sl4kvN?xOOY|l67T0TnJ0abaq|-3sy#CwwC0|JsnSiJo&wC&^ixyQXT_{MZxy9; zlqh3cj+HZQ;qzUDQkp(`d{OdT-_5x;?(0k{l{)b-8hZ3_&`66ZR}B{vIV(RrWiPp& zyX2WU%O0LyHf^h9o4(~t6HSO*K^9%VAU(6RB0TM0D6bCBr}sb@z5w@hx=zjXv3uX2lXmqc?M0c#Ys>Fbr+S%U@Nxa)U#~vBFf*1_`h?OCsq#&w zslXMI~_Lj1KTa}k64)i>jzYryjWNllojcJs%F@w&a2dE*=_H=Hj z=ieH_ih`QqLy-|B)-l9p9p8?db)0E7>Tak=>5P&{O9mpqcv=dncmz@tB*xHvVMzSH zT8cozGAN11N8u@u7?Y1TTk>CH*6R{ua;B^M7?W2|ON`0cFH8JCQMKAyVoc76wZxbl zEiEx7?+Yz4Cg;prVoZ)AOZ+cUl}BrdF*&2w5@T|1ttH0fj9W{L$?K~n#^mh#M|i!6 ppMQ+z)psh?MPG0jXq<~09fmb~263R6_?Q26vZ+Sy7PoB#{sLE<8)5(e literal 0 HcmV?d00001 diff --git a/src/test/resources/formSamples/invalid-code-ncit.xls b/src/test/resources/formSamples/invalid-code-ncit.xls new file mode 100644 index 0000000000000000000000000000000000000000..ae921e4575dc24f3493eb234f4a1fbc41b125582 GIT binary patch literal 4096 zcmeHKO-xfk5T5sVr67Oh$3IkfDH>_13Mz?_U{S!tgN8tj8Zi~pXCNxoQV*W2e>Y5w zUcGQKUi`V}L1W}#;(C`}vt4+VpO|PgBHPUF&Ns6&`(}4%x36B7 zPmDgOeosG?7RsY9T@+hW^}~{jq?BJeCzGg+uV3qLb7w^EkP{sJTTIWKR3%dCaXf8-4Ddjs1@ZpWP`C zw-y561M!(>eyJ?}2=JNZJkDp*yZ(GU_=pyQmVt^u#h?;UDX0vDD}c&D6`)E`6=*qV z1!yH`6=*f68ngzq7PJmj1F8ir?XkbVzX}Vmiupcz6BzgJ#+vZie~%q;-x`yB@d11< zo#DKYaQc%e`wx{pGKW5c_hzfqw}6ylKQV%=kGfLodm??JG$9!ZDX~NEZ0e$zv_3Sm~qur^&zEi(ZP-9gijyNH~^})JGU0q{5 z)Kahep&F|e(Z^ZQ2&6~5oy0M(icNk#N?K)eV~!25FtY&%*Zxr_*OF3frZ6=U#o0mF z)-%eo^}>f*vTSfu5c7%Gx5eQhLLu771HGfd_RNs5oul7M5yEnK9jTe;_~J=<+(n}^ z4!2VSZSgqNqqWcMP;ommZbC8=(H9rtm@dz3#(9wi|EvWI^Wc$r@bEl%;Vk^7X;C1P=W<(~$(ObwV@X??@k>h?lC~=2bB{|N zxQguZk)J;}g*^j~lWrQpjcDL^*O1m)iG!6*4m3$O+V`dH_GH4rohtpVnC|r)fvR8~oqM4ggAK8OYgYQ&4Cd9eb=&r4 z3>3U82EVw2h3Rlk3=R#Z2a`iC@?QaUK%3`v8*LIT-`^_F2k3FhxPJ^h=lLR&Z){a~ zA9ERjhZ4z-#i$eT!I`pLa%2FuC+~cEy}!RJ8W%h)c!SiJ1j#^0mko$NGAdn!WX#g9 zgUh0QMe0!s!g>P4Ka(OxBpcv~sIoE^I7YF*f1F zrX&LD%|fI&17F5^iZkUqHJ1mD-$P1ff#dH`oDUpt66Sb(nM6`?Y!l(j%Gf5yLdn=B xzoit%HhEPP$2R$W^%nZC&{k25c9|9QQ2us#i7rs(5Dn zQROUsS6V5HzPh=T?c*E1K81)((9HYlx-N^jkM3Ieiz0BChVhM(O$TTQZHg}PQvPr$ zr+}e(9p{2gn810eL_^PyiGHMF6eRImf#oI>m;<{;~%E|vO$NS`ZBNX{CC#__!`YW6^b-y}!PcG0^j zby(^`)CN73G4F-bfSvmi`tIdh-Zd7Wj?_T!xnC%#wki=voRIL=a80bHral>It=0WV zwY3G&$63)FNRJ(M`cL>(Yzp#G(keUaGi-o_nQb_@_V+rOmXu-(MX8=B$qu5no{>k^ z3LR#Pr^ftBD9?c`bS0W#UW8UL%)q;gyrx%QZvu+#gp>6i^mroHd7t# z@;TI_wNG!TxLq7KBN>V4vx{&nlnI;pyvV};qy?+oh@xi+LE?39h8>RByCwb;GU8^a2?s@ z9Y23?3Xhz1oY96GxDgF}_YG;S3LGpiInW%9$$iLoB64O=YIx{OgYGoyPLu95>rRXA z?8eQSa7IS$gp)dtTUGkqBaYqKJK{j8v!Su6xdqp-2o5FS2Y0RzUC!x&p@GqX;UO3K zE{D1>Yo5m)v?tN>eXa6(h@KTp1t&qnBITKUL#x93mdho0D3ENJkGdZ|I5QSYP7J~J z+`W&l5B433Cxsssex1}~!bw9%mu-kQGALbvWYW^Ffvci@P3mz9!+Jl!pGh$z<^^;n zuB^<&4eEvjR!x3qsMm>_e~!s74(@x;e4~h%$0q!|d5M5}qYx>|z@M?6qD=WuO=W@N z_m7fUp!h!&6#&JXf+-$fB#~4U+eG+08QbJoC>h)2x09mSCa;R3*e1WH-a>yGZ5btK epIJgrc#)``E3Z^RlV^tF#YxQgo(@X*^Yu4L%Zc^? literal 0 HcmV?d00001 diff --git a/src/test/resources/formSamples/missing-columns-ncit.xls b/src/test/resources/formSamples/missing-columns-ncit.xls new file mode 100644 index 0000000000000000000000000000000000000000..5f646ed9c4579c0d224ea232cb4d11dd8a6a11d4 GIT binary patch literal 4096 zcmeHJ%}Z2K6hH6z#?jPq{3y%P9%GR+PNk&~iH)WPEecViB4bkKg;F^+PK#DeS&N_` zXxqkBwCQ70izIZ{A}DGRv`PC9f`S&->vzt5Pv7`OL`0eAaqhk6dxVEMp-DvI)OZI12A6Izt1pjx)>5T3l30`mBFm$KqNGx#N!ig_8e^!*}-^ zkb48a?gR3jXL=P@egyc=avtY9>D_<69(llg;2K~7un<@T3;>IPC;?OgECrSU%Ykcw z>wp!&^}r3lO5jG|CSVn?8n}AC{*JSipNCz{_0iklOMe^oh420}PQ)W)QqILk(0z2C z^FqQJNT$p`1p8$T{TiRm7HRK-6To?54zfPlGHD-*bX;jdGN=W#zP-dd0R|>DLz|WOn)WwH9mH; z;Ks8~#o?>0GIbi++lL=E2qO?smO7t2WwG($I}9&%koJ?yqFT(m~gR>JJHQs+=O zkBnGmd;f@q`gyqhVA^a?CM?uc8F%%%qn_hX6<$Z@0jT!EhFCzEm9c9EX}P^&*Y3t9 zxI^g`S%-CcXm}_+lpMB^_VTC$i{}!34}B6nmu;2agY>NErGFAMr}qM#3$+41z6_&S zQIRCYLbM6^-~?GBsWAxKGxtBeIW*7}iwi#@{5ol`3MT^{7q%koNThTHl1amT6pV`Y zHEG8v1nUVPe>z3As1w(zn6fez)945!u&VQOLp@T|`tx*tc<|VH?Q6xvJT~FweUk{N zrwWmxH2fLsDN2|Bbg3Lr{0veu0~G&wYM$wYoZDDJPfKLG8Lgx~-G literal 0 HcmV?d00001 diff --git a/src/test/resources/formSamples/submissionFormTestCDISC.json b/src/test/resources/formSamples/submissionFormTest-cdisc.json similarity index 100% rename from src/test/resources/formSamples/submissionFormTestCDISC.json rename to src/test/resources/formSamples/submissionFormTest-cdisc.json diff --git a/src/test/resources/formSamples/submissionFormTest.json b/src/test/resources/formSamples/submissionFormTest-ncit.json similarity index 100% rename from src/test/resources/formSamples/submissionFormTest.json rename to src/test/resources/formSamples/submissionFormTest-ncit.json diff --git a/src/test/resources/formSamples/submissionFormWithArrayList.json b/src/test/resources/formSamples/submissionFormWithArrayList-cdisc.json similarity index 100% rename from src/test/resources/formSamples/submissionFormWithArrayList.json rename to src/test/resources/formSamples/submissionFormWithArrayList-cdisc.json From 2aa1af0d17e7de65146f85bfc5f8eb8ec25af050 Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Tue, 25 Nov 2025 15:43:15 -0800 Subject: [PATCH 13/64] Dss/evsrestapi 671 prefix docs (#435) * EVSRESTAPI-671: sparql prefix documentation * EVSRESTAPI-671: spotless misc. --- .../api/service/QueryBuilderServiceImpl.java | 35 +++++++++++++++-- .../gov/nih/nci/evs/api/util/EVSUtils.java | 39 +++++++++++++++++-- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java index b6de9f859..25a4ea6bd 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java @@ -33,10 +33,39 @@ public class QueryBuilderServiceImpl implements QueryBuilderService { @Autowired Environment env; /** - * Contruct prefix. + * Construct SPARQL prefix declarations for a terminology's queries. * - * @param terminology the terminology - * @return the string + *

This method implements the dual-prefix strategy used throughout the system: + * + *

    + *
  1. Terminology-specific prefixes: If the terminology metadata defines a custom + * sparqlPrefix field (e.g., for CTCAE6, ChEBI, GO), that takes precedence and is prepended + * to the query. This handles ontologies that reference external namespaces or use + * non-standard namespace patterns. + *
  2. Default graph prefix: If no custom sparqlPrefix is defined, uses the prefix.graph + * template which declares the ontology's default namespace as PREFIX : and PREFIX base:. + *
  3. Common prefixes: Always appends prefix.common which declares standard W3C and OBO + * namespaces (owl:, rdf:, rdfs:, xsd:, dc:, oboInOwl:, xml:) that are universally + * available. + *
+ * + *

Examples: + * + *

    + *
  • CTCAE6 (external dependency): Uses custom sparqlPrefix to declare both local + * ctcae6.owl namespace AND external ncit: namespace for NCIt Thesaurus properties + *
  • CTCAE5 (self-contained): No custom sparqlPrefix, uses default graph template + *
  • ChEBI (OBO standard): Uses custom sparqlPrefix for OBO Foundation namespaces + *
+ * + *

Why this design: Separates configuration (what namespaces are needed) from query + * logic (how to retrieve data). Enables one set of generic SPARQL query templates to work across + * all terminologies by substituting property codes from metadata. + * + *

See: config/metadata/README.md for detailed configuration patterns and examples. + * + * @param terminology the terminology with metadata containing optional sparqlPrefix + * @return the complete SPARQL prefix declarations to prepend to queries */ @Override public String constructPrefix(final Terminology terminology) { diff --git a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java index 04f42e6e8..b542f8e83 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java @@ -353,10 +353,43 @@ public static String getCodeFromUri(final String uri) { } /** - * Returns the qualified code from uri. + * Converts a full RDF property URI to qualified (prefixed) form. * - * @param uri the uri - * @return the qualified code from uri + *

This is a key method in the prefix handling strategy. It converts full URIs returned from + * SPARQL queries into the qualified codes used in metadata configuration and API responses. + * + *

Conversion Rules: + * + *

    + *
  1. Extract the fragment after the last "/" in the URI + *
  2. Normalize rdfs namespace: "rdf-schema" → "rdfs" + *
  3. If fragment contains "." (e.g., "HGNC.owl#P108"), strip everything before "#" + *
  4. Otherwise, convert "#" to ":" to create qualified form + *
+ * + *

Examples: + * + *

    + *
  • Input: {@code http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#P108}
    + * Output: {@code ncit:P108} (qualified form) + *
  • Input: {@code http://www.w3.org/2000/01/rdf-schema#label}
    + * Output: {@code rdfs:label} (normalized) + *
  • Input: {@code http://purl.obolibrary.org/obo/chebi.owl#12345}
    + * Output: {@code chebi:12345} + *
+ * + *

Used by: Axiom processing, property code extraction, qualifier identification. This + * method PRESERVES namespace information as a prefix, unlike {@link #getCodeFromUri(String)} + * which fully strips the namespace. + * + *

Design rationale: Property codes need namespace context to match against metadata + * configuration (e.g., matching "ncit:P108" in axioms against "ncit:P108" in ctcae6.json). + * Concept codes don't need namespace context, so they use getCodeFromUri() instead. + * + * @param uri the full RDF property URI + * @return the qualified code with namespace prefix (e.g., "ncit:P108", "rdfs:label") + * @see #getCodeFromUri(String) for fully stripping prefixes from concept codes + * @see #getLabelFromUri(String) for extracting human-readable labels */ public static String getQualifiedCodeFromUri(final String uri) { // Replace up to the last slash and fix rdfs From 82a9066bc0614ebd07b50976a8110099f5eb93ad Mon Sep 17 00:00:00 2001 From: akuppusamy-wci <99685732+akuppusamy-wci@users.noreply.github.com> Date: Wed, 3 Dec 2025 11:58:20 -0500 Subject: [PATCH 14/64] [EVSRESTAPI-677] Fix issue with TermSuggestionFormControllerTests (#432) * [EVSRESTAPI-574] Improve handling of the triplestore databases - NCIT2, CTRP * [EVSRESTAPI-677] Fix issue with TermSuggestionFormControllerTests * [EVSRESTAPI-677] Fix issue with TermSuggestionFormControllerTests --- build.gradle | 4 +- ...ermSuggestionFormControllerEmailTests.java | 221 ++++++++ .../TermSuggestionFormControllerTests.java | 527 +++--------------- .../filled-form-submission-ncit.xls | Bin 5120 -> 5120 bytes src/test/resources/formSamples/testNCIT.json | 7 +- 5 files changed, 312 insertions(+), 447 deletions(-) create mode 100644 src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java diff --git a/build.gradle b/build.gradle index 03e6b8275..f4ba7665c 100644 --- a/build.gradle +++ b/build.gradle @@ -164,9 +164,7 @@ dependencies { /* * Test Dependencies */ - testImplementation("org.springframework.boot:spring-boot-starter-test") { - exclude group: "net.minidev", module: "json-smart" - } + testImplementation("org.springframework.boot:spring-boot-starter-test") // Use spring-boot-starter-test defaults // testImplementation "org.opensearch.client:spring-data-opensearch-test-autoconfigure:1.6.0" // testImplementation "org.junit.jupiter:junit-jupiter-params:5.10.5" diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java new file mode 100644 index 000000000..310bdfd2b --- /dev/null +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java @@ -0,0 +1,221 @@ +package gov.nih.nci.evs.api.controller; + +import static org.junit.jupiter.api.Assertions.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import java.io.InputStream; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; +import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.MediaType; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +/** + * Test class for the Term Form Controller. Unlike TermSuggestionFormControllerTests here we call + * real captcha and email service. So to run this you need to set some stuff up. Otherwise these + * tests will be skipped. + * + *

+ * Uses the following env vars (if not set, tests do not run):
+ *
+ * MAIL_USERNAME
+ * MAIL_PASSWORD
+ *
+ * as well as the following yml properties:
+ *
+ * mail.host
+ * mail.port
+ * mail.smtp.auth
+ * mail.smtp.starttls.enable
+ * 
+ */ +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@ExtendWith(SpringExtension.class) +@AutoConfigureMockMvc +@ActiveProfiles("test") +@EnabledIfEnvironmentVariable(named = "MAIL_USER", matches = ".+") +@EnabledIfEnvironmentVariable(named = "MAIL_PASSWORD", matches = ".+") +public class TermSuggestionFormControllerEmailTests { + + /** The Constant log. */ + // logger + private static final Logger log = + LoggerFactory.getLogger(TermSuggestionFormControllerEmailTests.class); + + /** The mvc. */ + // Mock the MVC automatically + @Autowired private MockMvc mvc; + + /** The base url. */ + // Base url for api calls + private String baseUrl = "/api/v1/submit/"; + ; + + private String recaptchaToken = "TEST-KEY"; + + /** The object mapper. */ + @Qualifier("objectMapper") + @Autowired + private ObjectMapper objectMapper; + + /** + * Integration test to verify we can call the api path, path the formType, and return the JsonNode + * form. + * + * @throws Exception exception + */ + @Test + public void integrationTestGetFormTemplate() throws Exception { + // SET UP + final String formType = "ncit-form"; + final String url = "/api/v1/form/suggest/" + formType; + JsonNode form; + + // ACT + log.info("Testing url: {}", url); + final MvcResult mvcResult = + this.mvc.perform(MockMvcRequestBuilders.get(url)).andExpect(status().isOk()).andReturn(); + form = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); + log.info(" Form = {}", form); + + // ASSERT + assertNotNull(form); + assertFalse(form.isEmpty()); + assertEquals("NCIt Term Suggestion Request", form.get("formName").asText()); + assertEquals("ncithesaurus@mail.nih.gov", form.get("recipientEmail").asText()); + } + + /** + * Integration test for submitting a filled out form and sending the email. NOTE: Set your local + * environment variables in your config. Your test email will need an App Password for access, if + * using Gmail. This is an integration test that requires extra info. We need to set these tests + * up to avoid running if environment vars are not set, but to support them if they are. + * + * @throws Exception exception + */ + @Test + public void integrationTestSubmitForm() throws Exception { + // SET UP + baseUrl = "/api/v1/form/submit"; + final String formPath = "formSamples/submissionFormTest-ncit.json"; + JsonNode formData = createForm(formPath); + + final String requestBody = objectMapper.writeValueAsString(formData); + log.info("Form data = {}", formData); + @SuppressWarnings("unused") + final MvcResult result = + this.mvc + .perform( + MockMvcRequestBuilders.post(baseUrl) + .contentType(MediaType.APPLICATION_JSON) + .header("Captcha-Token", recaptchaToken) + .content(requestBody)) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void integrationTestSubmitFormWithAttachment() throws Exception { + // SET UP + baseUrl = "/api/v1/form/submitWithAttachment"; + final String formPath = "formSamples/submissionFormTest-cdisc.json"; + JsonNode formData = createForm(formPath); + + // Prepare multipart file from resources + final org.springframework.mock.web.MockMultipartFile attachment; + try (final InputStream is = + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-cdisc.xls")) { + if (is == null) { + fail("Test attachment not found in resources"); + return; + } + attachment = + new org.springframework.mock.web.MockMultipartFile( + "file", "filled-form-submission-cdisc.xls", "application/vnd.ms-excel", is); + } + + // formData part as application/json + final org.springframework.mock.web.MockMultipartFile jsonPart = + new org.springframework.mock.web.MockMultipartFile( + "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); + + // ACT & ASSERT - perform multipart request + this.mvc + .perform( + MockMvcRequestBuilders.multipart(baseUrl) + .file(attachment) + .file(jsonPart) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andExpect(status().isOk()); + } + + @Test + public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { + // SET UP + baseUrl = "/api/v1/form/submitWithAttachment"; + final String formPath = "formSamples/testNCIT.json"; + JsonNode formData = createForm(formPath); + + // Prepare NCIT multipart file from resources + final org.springframework.mock.web.MockMultipartFile attachment; + try (final InputStream is = + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-ncit.xls")) { + if (is == null) { + fail("NCIT test attachment not found in resources"); + return; + } + attachment = + new org.springframework.mock.web.MockMultipartFile( + "file", "filled-form-submission-ncit.xls", "application/vnd.ms-excel", is); + } + + // formData part as application/json + final org.springframework.mock.web.MockMultipartFile jsonPart = + new org.springframework.mock.web.MockMultipartFile( + "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); + + // ACT & ASSERT - perform multipart request + this.mvc + .perform( + MockMvcRequestBuilders.multipart(baseUrl) + .file(attachment) + .file(jsonPart) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andExpect(status().isOk()); + } + + /** + * Helper method for creating a JsonNode from a Json file. + * + * @param path path for the json file + * @return JsonNode + * @throws Exception exception + */ + private JsonNode createForm(final String path) throws Exception { + final ObjectMapper mapper = new ObjectMapper(); + // read the file as an Input Stream + try (final InputStream input = getClass().getClassLoader().getResourceAsStream(path); ) { + // Set our expected response to the form from the formPath + return mapper.readTree(input); + } + } +} diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java index 2acb58078..b5fc3c56c 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java @@ -1,70 +1,37 @@ package gov.nih.nci.evs.api.controller; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.when; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.mockito.Mockito.*; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; import gov.nih.nci.evs.api.model.EmailDetails; -import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.service.CaptchaService; -import gov.nih.nci.evs.api.service.TermSuggestionFormServiceImpl; +import gov.nih.nci.evs.api.service.TermSuggestionFormService; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Objects; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; +import org.mockito.ArgumentCaptor; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; -import org.springframework.http.ResponseEntity; -import org.springframework.mail.javamail.JavaMailSender; -import org.springframework.mail.javamail.JavaMailSenderImpl; -import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.junit.jupiter.SpringExtension; -import org.springframework.test.util.ReflectionTestUtils; import org.springframework.test.web.servlet.MockMvc; -import org.springframework.test.web.servlet.MvcResult; -import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; -import org.springframework.web.context.request.RequestContextHolder; -import org.springframework.web.context.request.ServletRequestAttributes; -import org.springframework.web.server.ResponseStatusException; - -/** - * Test class for the Term Form Controller. To run this you need to set some stuff up. - * - *
- * Uses the following env vars (if not set, tests do not run):
- *
- * MAIL_USERNAME
- * MAIL_PASSWORD
- *
- * as well as the following yml properties:
- *
- * mail.host
- * mail.port
- * mail.smtp.auth
- * mail.smtp.starttls.enable
- * 
- */ + +/** Test class for the Term Form Controller. This test mocks the email and captcha services. */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @ExtendWith(SpringExtension.class) @AutoConfigureMockMvc @@ -82,45 +49,22 @@ public class TermSuggestionFormControllerTests { /** The term form service. */ // Mock the email service and captcha service - @Mock private TermSuggestionFormServiceImpl termFormService; + @MockitoBean private TermSuggestionFormService termFormService; /** The captcha service. */ @MockitoBean private CaptchaService captchaService; - /** The term suggestion form controller. */ - // create an instance of the controller and inject service - @Autowired private TermSuggestionFormController termSuggestionFormController; - - /** The mail sender. */ - @Autowired private JavaMailSender mailSender; - - /** The request. */ - // mock request servlet - private MockHttpServletRequest request; - /** The base url. */ // Base url for api calls - String baseUrl; + private String baseUrl = "/api/v1/submit/"; /** The recaptcha token. */ // Recaptcha Token final String recaptchaToken = "testTokenString"; - /** The object mapper. */ - @Qualifier("objectMapper") - @Autowired - private ObjectMapper objectMapper; - - /** Setup method to create a mock request for testing. */ - @BeforeEach - public void setUp() { - baseUrl = "/api/v1/submit/"; - // termSuggestionFormController = - // new TermSuggestionFormController(termFormService, captchaService); - request = new MockHttpServletRequest(); - request.addHeader("Captcha-Token", recaptchaToken); - RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); - } + final String licenseKey = "test-key-123"; + + private ObjectMapper objectMapper = new ObjectMapper(); /** * Test the getForm returns our expected response JsonObject when passing formType and test Json. @@ -141,11 +85,12 @@ public void testGetFormTemplateWithTestData() throws Exception { // ACT - mock the email service and call the getForm when(termFormService.getFormTemplate(formType)).thenReturn(expectedResponse); - final ResponseEntity responseEntity = termSuggestionFormController.getForm(formType, null); - - // ASSERT - assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); - assertEquals(expectedResponse, responseEntity.getBody()); + mvc.perform(get("/api/v1/form/suggest/{formType}", formType).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) // Check for HTTP 200 + .andExpect(content().contentType(MediaType.APPLICATION_JSON)) + .andExpect( + jsonPath("$.formName").value("NCIT")) // Verify JSON content + .andExpect(jsonPath("$.formType").value("NCIT")); } /** @@ -164,50 +109,45 @@ public void testGetFormThrowsException() throws Exception { // ACT when(termFormService.getFormTemplate(formType)).thenThrow(new FileNotFoundException()); - - // ASSERT - final Exception exception = - assertThrows( - ResponseStatusException.class, - () -> { - termSuggestionFormController.getForm(formType, null); - }); - assertTrue(Objects.requireNonNull(exception.getMessage()).contains(expectedResponse)); + mvc.perform(get("/api/v1/form/suggest/{formType}", formType).accept(MediaType.APPLICATION_JSON)) + .andExpect(status().is5xxServerError()) // Check for HTTP 200 + .andExpect( + result -> + assertTrue( + Objects.requireNonNull(result.getResolvedException()) + .getMessage() + .contains(expectedResponse))); } - /** - * Test the submitForm successfully sends email with submitted form. - * - *

This is really an integration test that requires properties for mail authentication to - * succeed. - * - * @throws Exception exception - */ + /** Tests the "happy path" where captcha is valid and email sends successfully. */ @Test - public void testSubmitForm() throws Exception { - // SET UP - create our form data JsonNode - final String formPath = "formSamples/submissionFormTest-ncit.json"; - JsonNode formData = createForm(formPath); - // Create expected EmailDetails - EmailDetails expectedEmailDetails = EmailDetails.generateEmailDetails(formData); - - // Mock the RecaptchaService to always return true for verifyRecaptcha - when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - - boolean smtpConfigured = hasSmtpConfig(); - - if (!smtpConfigured) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually send the email - formData = setCredentials(formData, false); - expectedEmailDetails = EmailDetails.generateEmailDetails(formData); - log.info(" SMTP is configured, will send email to: {}", expectedEmailDetails.getToEmail()); - } - - // ACT - termSuggestionFormController.submitForm(formData, null, recaptchaToken); + void testSubmitForm() throws Exception { + // Create a mock JSON payload that will pass validation + JsonNode formData = createForm("formSamples/submissionFormTest-ncit.json"); + ArgumentCaptor emailDetailsCaptor = ArgumentCaptor.forClass(EmailDetails.class); + + // Mock the service calls + when(captchaService.verifyRecaptcha(recaptchaToken)).thenReturn(true); + // use doNothing() for void methods. Use any() since the object is created inside the method. + EmailDetails emailDetails = mock(EmailDetails.class); + doNothing().when(termFormService).sendEmail(emailDetailsCaptor.capture()); + + // 2. Act & 3. Assert + mvc.perform( + post("/api/v1/form/submit") // Assuming /api/v1 based on your GET test + .header("X-EVSRESTAPI-License-Key", licenseKey) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(formData))) + .andExpect(status().isOk()); // Default status for a void method is 200 OK + + // Verify that all our mocks were called correctly + verify(captchaService).verifyRecaptcha(recaptchaToken); + verify(termFormService).sendEmail(emailDetailsCaptor.getValue()); + EmailDetails capturedEmailDetails = emailDetailsCaptor.getValue(); + assertEquals(formData.get("recipientEmail").asText(), capturedEmailDetails.getToEmail()); + assertEquals(formData.get("subject").asText(), capturedEmailDetails.getSubject()); + assertEquals(formData.get("businessEmail").asText(), capturedEmailDetails.getFromEmail()); } /** @@ -225,14 +165,13 @@ public void testSubmitFormThrowsExceptionWithNullFields() throws Exception { // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - // ACT & ASSERT - final Exception exception = - assertThrows( - Exception.class, - () -> { - termSuggestionFormController.submitForm(formData, null, recaptchaToken); - }); - assertTrue(exception.getMessage().contains(expectedResponse)); + mvc.perform( + post("/api/v1/form/submit") // Assuming /api/v1 based on your GET test + .header("X-EVSRESTAPI-License-Key", licenseKey) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(formData))) + .andExpect(status().isExpectationFailed()); // Default status for a void method is 200 OK } /** @@ -249,14 +188,13 @@ public void testSubmitFormThrowsExceptionWhenFormIsEmpty() throws Exception { // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - // ACT & ASSERT - final Exception exception = - assertThrows( - Exception.class, - () -> { - termSuggestionFormController.submitForm(formData, null, recaptchaToken); - }); - assertTrue(exception.getMessage().contains(expectedResponse)); + mvc.perform( + post("/api/v1/form/submit") // Assuming /api/v1 based on your GET test + .header("X-EVSRESTAPI-License-Key", licenseKey) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(formData))) + .andExpect(status().is5xxServerError()); // Default status for a void method is 200 OK } /** @@ -273,71 +211,18 @@ public void testSubmitFormThrowsExceptionWhenSendEmailFails() throws Exception { // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - - // ACT - stub the void method to do throw an exception when called - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually attempt to send the email - // but we will give it bad credentials so it will fail - log.info( - "SMTP is configured, will send email to: {}", formData.get("recipientEmail").asText()); - formData = setCredentials(formData, true); - } + doThrow(new RuntimeException("Simulated email sending failure")) + .when(termFormService) + .sendEmail(any()); // ASSERT - final JsonNode formDataFinal = formData; - // create a props object that returns no override - ApplicationProperties props = new ApplicationProperties(); - props.setMailRecipient(""); - - // find the formService instance used by the controller - Object form = ReflectionTestUtils.getField(termSuggestionFormController, "formService"); - - // set the applicationProperties on THAT instance - ReflectionTestUtils.setField(form, "applicationProperties", props); - final Exception exception = - assertThrows( - Exception.class, - () -> { - termSuggestionFormController.submitForm(formDataFinal, null, recaptchaToken); - }); - assertTrue(exception.getMessage().contains(expectedResponse)); - } - - /** - * Test submit form recaptcha verification passes. This is an integration test that requires email - * credentials. We need an escape hatch to avoid actually trying to send an email here but verify - * everything else works. - * - * @throws Exception the exception - */ - @Test - public void testSubmitFormRecaptchaVerificationPasses() throws Exception { - // SET UP - final String formPath = "formSamples/submissionFormTest-ncit.json"; - JsonNode formData = createForm(formPath); - - // Mock the RecaptchaService to always return true for verifyRecaptcha - when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - // Mock the email service to do nothing if not configured - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually send the email - log.info( - "SMTP is configured, will send email to: {}", formData.get("recipientEmail").asText()); - formData = setCredentials(formData, false); - } - - // ACT & ASSERT - try { - termSuggestionFormController.submitForm(formData, null, recaptchaToken); - } catch (ResponseStatusException e) { - fail("Should not have thrown any exception"); - } + mvc.perform( + post("/api/v1/form/submit") // Assuming /api/v1 based on your GET test + .header("X-EVSRESTAPI-License-Key", licenseKey) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(formData))) + .andExpect(status().is5xxServerError()); // Default status for a void method is 200 OK } /** @@ -354,196 +239,14 @@ public void testSubmitFormRecaptchaVerificationFails() throws Exception { // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(false); - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually attempt send the email - // but we will fail because fo the recaptcha failure - log.info( - "SMTP is configured, will send email to: {}", formData.get("recipientEmail").asText()); - formData = setCredentials(formData, false); - } - // ACT & ASSERT - try { - termSuggestionFormController.submitForm(formData, null, recaptchaToken); - fail("Expected a ResponseStatusException to be thrown"); - } catch (ResponseStatusException e) { - assertEquals(HttpStatus.EXPECTATION_FAILED, e.getStatusCode()); - } - } - - /** - * Integration test to verify we can call the api path, path the formType, and return the JsonNode - * form. - * - * @throws Exception exception - */ - @Test - public void integrationTestGetFormTemplate() throws Exception { - // SET UP - final String formType = "ncit-form"; - final String url = "/api/v1/form/suggest/" + formType; - JsonNode form; - - // ACT - log.info("Testing url: {}", url); - final MvcResult mvcResult = - this.mvc.perform(MockMvcRequestBuilders.get(url)).andExpect(status().isOk()).andReturn(); - form = objectMapper.readTree(mvcResult.getResponse().getContentAsString()); - log.info(" Form = {}", form); - - // ASSERT - assertNotNull(form); - assertFalse(form.isEmpty()); - assertEquals("NCIt Term Suggestion Request", form.get("formName").asText()); - assertEquals("ncithesaurus@mail.nih.gov", form.get("recipientEmail").asText()); - } - - /** - * Integration test for submitting a filled out form and sending the email. NOTE: Set your local - * environment variables in your config. Your test email will need an App Password for access, if - * using Gmail. This is an integration test that requires extra info. We need to set these tests - * up to avoid running if environment vars are not set, but to support them if they are. - * - * @throws Exception exception - */ - @Test - public void integrationTestSubmitForm() throws Exception { - // SET UP - baseUrl = "/api/v1/form/submit"; - final String formPath = "formSamples/submissionFormTest-ncit.json"; - JsonNode formData = createForm(formPath); - - // Mock the RecaptchaService to always return true for verifyRecaptcha - when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - - // ACT & ASSERT - Verify the email was sent to the receiver in the form - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually send the email - log.info( - "SMTP is configured, will send email to: {}", formData.get("recipientEmail").asText()); - // Set credentials in the form data - formData = setCredentials(formData, false); - } - final String requestBody = objectMapper.writeValueAsString(formData); - log.info("Form data = {}", formData); - @SuppressWarnings("unused") - final MvcResult result = - this.mvc - .perform( - MockMvcRequestBuilders.post(baseUrl) - .contentType(MediaType.APPLICATION_JSON) - .header("Captcha-Token", recaptchaToken) - .content(requestBody)) - .andExpect(status().isOk()) - .andReturn(); - } - - @Test - public void integrationTestSubmitFormWithAttachment() throws Exception { - // SET UP - baseUrl = "/api/v1/form/submitWithAttachment"; - final String formPath = "formSamples/submissionFormTest-cdisc.json"; - JsonNode formData = createForm(formPath); - - // Mock the RecaptchaService to always return true for verifyRecaptcha - when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually send the email - log.info("SMTP is configured."); - // Set credentials in the form data - formData = setCredentials(formData, false); - } - - // Prepare multipart file from resources - final org.springframework.mock.web.MockMultipartFile attachment; - try (final InputStream is = - getClass() - .getClassLoader() - .getResourceAsStream("formSamples/filled-form-submission-cdisc.xls")) { - if (is == null) { - fail("Test attachment not found in resources"); - return; - } - attachment = - new org.springframework.mock.web.MockMultipartFile( - "file", "filled-form-submission-cdisc.xls", "application/vnd.ms-excel", is); - } - - // formData part as application/json - final org.springframework.mock.web.MockMultipartFile jsonPart = - new org.springframework.mock.web.MockMultipartFile( - "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); - - // ACT & ASSERT - perform multipart request - this.mvc - .perform( - MockMvcRequestBuilders.multipart(baseUrl) - .file(attachment) - .file(jsonPart) + mvc.perform( + post("/api/v1/form/submit") // Assuming /api/v1 based on your GET test + .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) - .contentType(MediaType.MULTIPART_FORM_DATA)) - .andExpect(status().isOk()); - } - - @Test - public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { - // SET UP - baseUrl = "/api/v1/form/submitWithAttachment"; - final String formPath = "formSamples/testNCIT.json"; - JsonNode formData = createForm(formPath); - - // Mock the RecaptchaService to always return true for verifyRecaptcha - when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); - - if (!hasSmtpConfig()) { - // If no configuration, bail - return; - } else { - // If smtp is configured, we will actually send the email - log.info("SMTP is configured."); - // Set credentials in the form data - formData = setCredentials(formData, false); - } - - // Prepare NCIT multipart file from resources - final org.springframework.mock.web.MockMultipartFile attachment; - try (final InputStream is = - getClass() - .getClassLoader() - .getResourceAsStream("formSamples/filled-form-submission-ncit.xls")) { - if (is == null) { - fail("NCIT test attachment not found in resources"); - return; - } - attachment = - new org.springframework.mock.web.MockMultipartFile( - "file", "filled-form-submission-ncit.xls", "application/vnd.ms-excel", is); - } - - // formData part as application/json - final org.springframework.mock.web.MockMultipartFile jsonPart = - new org.springframework.mock.web.MockMultipartFile( - "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); - - // ACT & ASSERT - perform multipart request - this.mvc - .perform( - MockMvcRequestBuilders.multipart(baseUrl) - .file(attachment) - .file(jsonPart) - .header("Captcha-Token", recaptchaToken) - .contentType(MediaType.MULTIPART_FORM_DATA)) - .andExpect(status().isOk()); + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(formData))) + .andExpect(status().isExpectationFailed()); } /** @@ -561,64 +264,4 @@ private JsonNode createForm(final String path) throws Exception { return mapper.readTree(input); } } - - private boolean hasSmtpConfig() { - // check that MAIL_USER and MAIL_PASSWORD are set - // as environment variables - if (System.getenv("MAIL_USER") == null) { - log.info(" MAIL_USER not set, skipping test"); - return false; - } - // to generate a valid MAIL_PASSWORD, you need to set up an App Password - // for your email account, e.g., Gmail, and set it in your environment variables. - // See https://support.google.com/mail/answer/185833?hl=en - // for more information on how to set up App Passwords - if (System.getenv("MAIL_PASSWORD") == null) { - log.info(" MAIL_PASSWORD not set, skipping test"); - return false; - } - - if (mailSender == null || !(mailSender instanceof JavaMailSenderImpl)) { - return false; - } - JavaMailSenderImpl impl = (JavaMailSenderImpl) mailSender; - - return impl.getHost() != null - && impl.getPort() > 0 - && impl.getUsername() != null - && impl.getPassword() != null - && !"false" - .equalsIgnoreCase( - impl.getJavaMailProperties().getProperty("mail.smtp.starttls.enable")); - } - - /** - * Set credentials in the form data to test email sending. - * - * @param formData the form data - * @return JsonNode with bad credentials - */ - private JsonNode setCredentials(JsonNode formData, boolean badCredentials) { - if (!(mailSender instanceof JavaMailSenderImpl)) { - throw new IllegalStateException("Mail sender is not configured correctly."); - } - JavaMailSenderImpl impl = (JavaMailSenderImpl) mailSender; - - ObjectNode o = (ObjectNode) formData; - o.put("businessEmail", impl.getUsername()); - - if (badCredentials) { - // Set bad recipient email - o.put("recipientEmail", "invalid@@westcoastinformatics.com"); - - } else { - // Set real credentials - o.put("mail.smtp.auth", "true"); - o.put("mail.smtp.starttls.enable", "true"); - o.put("recipientEmail", impl.getUsername()); - o.put("MAIL_USERNAME", impl.getUsername()); - o.put("MAIL_PASSWORD", impl.getPassword()); - } - return o; - } } diff --git a/src/test/resources/formSamples/filled-form-submission-ncit.xls b/src/test/resources/formSamples/filled-form-submission-ncit.xls index f743d777ba72b30699cec71eee804d31abcef56e..6108737026f9889c47ca71430199338bf87b8d55 100644 GIT binary patch delta 52 zcmZqBXwcY@!^FlQ`sw@s Date: Thu, 4 Dec 2025 17:34:55 -0800 Subject: [PATCH 15/64] EVSRESTAPI-679: nci term forms attach (#436) --- build.gradle | 2 +- .../TermSuggestionFormServiceImpl.java | 11 +- src/main/resources/forms/ncit-form.json | 166 +++++++++++---- ...ermSuggestionFormControllerEmailTests.java | 54 ++--- .../TermSuggestionFormControllerTests.java | 196 +++++++++++++++--- .../formSamples/compareEmailDetailsFail.json | 4 +- .../formSamples/submissionFormTest-ncit.json | 4 +- src/test/resources/formSamples/testNCIT.json | 171 +++++++++++---- 8 files changed, 470 insertions(+), 138 deletions(-) diff --git a/build.gradle b/build.gradle index c7ae70aad..0b5b82577 100644 --- a/build.gradle +++ b/build.gradle @@ -57,7 +57,7 @@ ext { /* Version info */ group = "gov.nih.nci.evs.api" -version = "2.4.0.RELEASE" +version = "2.3.0.RELEASE" sourceCompatibility = 17 targetCompatibility = 17 diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 86c4efa1d..c649d3af4 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -48,7 +48,7 @@ public class TermSuggestionFormServiceImpl implements TermSuggestionFormService /** The object mapper to read the config url with readTree. */ private final ObjectMapper mapper = new ObjectMapper(); - /** Pattern for optional instruction sheets with date suffix */ + /** Pattern for optional instruction sheets with date suffix. */ private static final Pattern INSTRUCTION_PATTERN = Pattern.compile(".*\\d{4}_\\d{2}_\\d{2} Instructions$"); @@ -111,6 +111,7 @@ public JsonNode getFormTemplate(final String formType) throws Exception { * * @param emailDetails details of the email created from the form data * @throws MessagingException the messaging exception + * @throws Exception the exception */ @Override public void sendEmail(final EmailDetails emailDetails) throws MessagingException, Exception { @@ -163,6 +164,7 @@ public void sendEmail(final EmailDetails emailDetails) throws MessagingException * @param emailDetails details of the email created from the form data * @param file optional multipart file to attach * @throws MessagingException the messaging exception + * @throws Exception the exception */ @Override public void sendEmailWithAttachment(final EmailDetails emailDetails, final MultipartFile file) @@ -239,6 +241,7 @@ public boolean validateFileAttachment(final MultipartFile file) { * @param formType the form type (CDISC or NCIT) * @return true, if successful */ + @Override public boolean validateFileAttachment(final MultipartFile file, final String formType) { if (file == null || file.isEmpty()) { // No file attached/empty file @@ -521,6 +524,12 @@ private boolean validateNCITAttachment(final MultipartFile file, final String fi /** * Read a cell value and correctly handle merged regions. Returns trimmed string or empty string. + * + * @param sheet the sheet + * @param rowIndex the row index + * @param colIndex the col index + * @param formatter the formatter + * @return the merged cell value */ private String getMergedCellValue( final org.apache.poi.ss.usermodel.Sheet sheet, diff --git a/src/main/resources/forms/ncit-form.json b/src/main/resources/forms/ncit-form.json index 3db9a4549..74b0f7a45 100644 --- a/src/main/resources/forms/ncit-form.json +++ b/src/main/resources/forms/ncit-form.json @@ -37,49 +37,41 @@ ] }, { - "name": "other", - "label": "Other", - "type": "textarea", + "name": "name", + "label": "Name", + "type": "text", "value": "", - "placeholder": "Enter additional contact information" + "placeholder": "Enter your name" } ] }, { - "name": "termInfo", - "label": "Term Information", + "name": "requestType", + "label": "Request Type", "instructions": { "parts": [ { - "text": "Fill in the following fields as appropriate. For multiple terms, please consider emailing an Excel, delimited text, or similar file to" - }, - { - "text": "ncithesaurus@mail.nih.gov", - "link": "mailto:ncithesaurus@mail.nih.gov?Subject=NCIt%20New%20Term%20Request%20File" - }, - { - "text": ", which can also respond to any questions." + "text": "Please select the type of request and fill in the appropriate fields below." } ] }, "fields": [ { - "name": "vocabulary", - "label": "Vocabulary", + "name": "requestTypeSelection", + "label": "Please select", "type": "dropdown", "value": "", "options": [ - "NCI Thesaurus", - "NCI Metathesaurus", - "NPO", - "Other" + "Proposed New Concept", + "Proposed Modification to Existing Concept", + "Inquiry" ], - "placeholder": "Select vocabulary", + "placeholder": "Select request type", "validations": [ { "name": "required", "validator": "required", - "message": "Vocabulary is required" + "message": "Request type is required" } ] }, @@ -88,35 +80,110 @@ "label": "Term", "type": "textarea", "value": "", - "placeholder": "Enter the term(s)", + "placeholder": "Enter the term", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + }, "validations": [ { - "name": "required", - "validator": "required", - "message": "Term is required" + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Proposed New Concept" + }, + "message": "Term is required for new concept proposals" } ] }, { "name": "synonym", - "label": "Synonym(s)", + "label": "Synonym", + "type": "textarea", + "value": "", + "placeholder": "Enter synonym(s)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + } + }, + { + "name": "definition", + "label": "Definition", "type": "textarea", "value": "", - "placeholder": "Enter synonyms (if any)" + "placeholder": "Enter the definition", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + } }, { - "name": "nearestCode", - "label": "Nearest Code/CUI", + "name": "currentCCode", + "label": "Current C-Code", + "type": "text", + "value": "", + "placeholder": "Enter current C-Code (e.g., C12345)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + }, + "validations": [ + { + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Proposed Modification to Existing Concept" + }, + "message": "C-Code is required for concept modification requests" + } + ] + }, + { + "name": "newSynonym", + "label": "New Synonym", "type": "textarea", "value": "", - "placeholder": "Enter nearest code/CUI" + "placeholder": "Enter new synonym(s)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + } }, { - "name": "other", - "label": "Definition/Other", + "name": "changeToDefinition", + "label": "Change to Definition", "type": "textarea", "value": "", - "placeholder": "Enter definition/other information" + "placeholder": "Enter proposed changes to definition", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + } + }, + { + "name": "detailedDescription", + "label": "Detailed Description", + "type": "textarea", + "value": "", + "placeholder": "Enter detailed description of your inquiry", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Inquiry" + }, + "validations": [ + { + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Inquiry" + }, + "message": "Detailed description is required for inquiries" + } + ] } ] }, @@ -124,19 +191,40 @@ "name": "additionalInfo", "label": "Additional Information", "fields": [ + { + "name": "organization", + "label": "Organization", + "type": "text", + "value": "", + "placeholder": "Enter your organization", + "validations": [ + { + "name": "required", + "validator": "required", + "message": "Organization is required" + } + ] + }, { "name": "project", - "label": "Project/Product term needed for", + "label": "Project", "type": "textarea", "value": "", - "placeholder": "Enter project/product term" + "placeholder": "Enter project name", + "validations": [ + { + "name": "required", + "validator": "required", + "message": "Project is required" + } + ] }, { - "name": "reason", - "label": "Reason for suggestion or any additional information", + "name": "additionalInfo", + "label": "Additional Information", "type": "textarea", "value": "", - "placeholder": "Enter reason for suggestion or any additional information that may help us" + "placeholder": "Enter any additional information that may be helpful" } ] } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java index 310bdfd2b..3d61f69d7 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java @@ -137,32 +137,32 @@ public void integrationTestSubmitFormWithAttachment() throws Exception { // Prepare multipart file from resources final org.springframework.mock.web.MockMultipartFile attachment; try (final InputStream is = - getClass() - .getClassLoader() - .getResourceAsStream("formSamples/filled-form-submission-cdisc.xls")) { + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-cdisc.xls")) { if (is == null) { fail("Test attachment not found in resources"); return; } attachment = new org.springframework.mock.web.MockMultipartFile( - "file", "filled-form-submission-cdisc.xls", "application/vnd.ms-excel", is); + "file", "filled-form-submission-cdisc.xls", "application/vnd.ms-excel", is); } // formData part as application/json final org.springframework.mock.web.MockMultipartFile jsonPart = - new org.springframework.mock.web.MockMultipartFile( - "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); + new org.springframework.mock.web.MockMultipartFile( + "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); // ACT & ASSERT - perform multipart request this.mvc - .perform( - MockMvcRequestBuilders.multipart(baseUrl) - .file(attachment) - .file(jsonPart) - .header("Captcha-Token", recaptchaToken) - .contentType(MediaType.MULTIPART_FORM_DATA)) - .andExpect(status().isOk()); + .perform( + MockMvcRequestBuilders.multipart(baseUrl) + .file(attachment) + .file(jsonPart) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andExpect(status().isOk()); } @Test @@ -175,32 +175,32 @@ public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { // Prepare NCIT multipart file from resources final org.springframework.mock.web.MockMultipartFile attachment; try (final InputStream is = - getClass() - .getClassLoader() - .getResourceAsStream("formSamples/filled-form-submission-ncit.xls")) { + getClass() + .getClassLoader() + .getResourceAsStream("formSamples/filled-form-submission-ncit.xls")) { if (is == null) { fail("NCIT test attachment not found in resources"); return; } attachment = - new org.springframework.mock.web.MockMultipartFile( - "file", "filled-form-submission-ncit.xls", "application/vnd.ms-excel", is); + new org.springframework.mock.web.MockMultipartFile( + "file", "filled-form-submission-ncit.xls", "application/vnd.ms-excel", is); } // formData part as application/json final org.springframework.mock.web.MockMultipartFile jsonPart = - new org.springframework.mock.web.MockMultipartFile( - "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); + new org.springframework.mock.web.MockMultipartFile( + "formData", "formData", "application/json", objectMapper.writeValueAsBytes(formData)); // ACT & ASSERT - perform multipart request this.mvc - .perform( - MockMvcRequestBuilders.multipart(baseUrl) - .file(attachment) - .file(jsonPart) - .header("Captcha-Token", recaptchaToken) - .contentType(MediaType.MULTIPART_FORM_DATA)) - .andExpect(status().isOk()); + .perform( + MockMvcRequestBuilders.multipart(baseUrl) + .file(attachment) + .file(jsonPart) + .header("Captcha-Token", recaptchaToken) + .contentType(MediaType.MULTIPART_FORM_DATA)) + .andExpect(status().isOk()); } /** diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java index b5fc3c56c..50bd69333 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java @@ -1,21 +1,30 @@ package gov.nih.nci.evs.api.controller; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.EmailDetails; import gov.nih.nci.evs.api.service.CaptchaService; import gov.nih.nci.evs.api.service.TermSuggestionFormService; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.FileNotFoundException; import java.io.InputStream; import java.util.Objects; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.ArgumentCaptor; @@ -25,11 +34,16 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; /** Test class for the Term Form Controller. This test mocks the email and captcha services. */ @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @@ -40,31 +54,47 @@ public class TermSuggestionFormControllerTests { /** The Constant log. */ // logger + @SuppressWarnings("unused") private static final Logger log = LoggerFactory.getLogger(TermSuggestionFormControllerTests.class); - /** The mvc. */ - // Mock the MVC automatically + /** The mvc mock. */ @Autowired private MockMvc mvc; /** The term form service. */ - // Mock the email service and captcha service @MockitoBean private TermSuggestionFormService termFormService; + /** The term suggestion form controller. */ + @Autowired private TermSuggestionFormController termSuggestionFormController; + /** The captcha service. */ @MockitoBean private CaptchaService captchaService; - /** The base url. */ - // Base url for api calls - private String baseUrl = "/api/v1/submit/"; - /** The recaptcha token. */ - // Recaptcha Token final String recaptchaToken = "testTokenString"; + /** The license key. */ final String licenseKey = "test-key-123"; - private ObjectMapper objectMapper = new ObjectMapper(); + /** + * Setup method to create a mock request for testing. + * + * @throws Exception the exception + */ + @BeforeEach + public void setUp() throws Exception { + // termSuggestionFormController = + // new TermSuggestionFormController(termFormService, captchaService); + MockHttpServletRequest request = new MockHttpServletRequest(); + request.addHeader("Captcha-Token", recaptchaToken); + RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request)); + + // Set up default mock behavior for ncit-form that works for all tests + // Individual tests can override this if needed + final String formPath = "formSamples/testNCIT.json"; + final JsonNode defaultFormResponse = createForm(formPath); + when(termFormService.getFormTemplate("ncit-form")).thenReturn(defaultFormResponse); + } /** * Test the getForm returns our expected response JsonObject when passing formType and test Json. @@ -83,13 +113,127 @@ public void testGetFormTemplateWithTestData() throws Exception { // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); + // ACT - call the getForm (mock behavior is set up in setUp()) + final ResponseEntity responseEntity = termSuggestionFormController.getForm(formType, null); + + // ASSERT + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + + // Get response body as JsonNode for detailed assertions + JsonNode responseBody = (JsonNode) responseEntity.getBody(); + assertNotNull(responseBody); + + // 1. Validate top-level metadata (critical for form identification) + assertEquals("NCIt Term Suggestion Request", responseBody.get("formName").asText()); + assertEquals("NCIT", responseBody.get("formType").asText()); + assertEquals("ncithesaurus@mail.nih.gov", responseBody.get("recipientEmail").asText()); + + // this may not be null if properites are configured + // assertNotNull(responseBody.get("recaptchaSiteKey")); + + // 2. Validate section structure (validates major form reorganization) + JsonNode sections = responseBody.get("sections"); + assertNotNull(sections); + assertEquals(3, sections.size()); + assertEquals("contact", sections.get(0).get("name").asText()); + assertEquals("Contact Information", sections.get(0).get("label").asText()); + assertEquals("requestType", sections.get(1).get("name").asText()); + assertEquals("Request Type", sections.get(1).get("label").asText()); + assertEquals("additionalInfo", sections.get(2).get("name").asText()); + assertEquals("Additional Information", sections.get(2).get("label").asText()); + + // 3. Validate Contact section - new "name" field (key change from "other") + JsonNode contactFields = sections.get(0).get("fields"); + assertEquals(2, contactFields.size()); + assertEquals("email", contactFields.get(0).get("name").asText()); + assertEquals("name", contactFields.get(1).get("name").asText()); // NEW FIELD + + // 4. Validate Request Type dropdown options (most critical new feature) + JsonNode requestTypeFields = sections.get(1).get("fields"); + JsonNode requestTypeDropdown = requestTypeFields.get(0); + assertEquals("requestTypeSelection", requestTypeDropdown.get("name").asText()); + assertEquals("dropdown", requestTypeDropdown.get("type").asText()); + + JsonNode options = requestTypeDropdown.get("options"); + assertEquals(3, options.size()); + assertEquals("Proposed New Concept", options.get(0).asText()); + assertEquals("Proposed Modification to Existing Concept", options.get(1).asText()); + assertEquals("Inquiry", options.get(2).asText()); + + // 5. Validate conditional display fields (validates conditional logic) + // Find the "term" field (conditionally displayed for "Proposed New Concept") + JsonNode termField = null; + for (JsonNode field : requestTypeFields) { + if ("term".equals(field.get("name").asText())) { + termField = field; + break; + } + } + assertNotNull(termField); + JsonNode termConditionalDisplay = termField.get("conditionalDisplay"); + assertNotNull(termConditionalDisplay); + assertEquals("requestTypeSelection", termConditionalDisplay.get("dependsOn").asText()); + assertEquals("Proposed New Concept", termConditionalDisplay.get("showWhen").asText()); + + // Find the "currentCCode" field (conditionally displayed for "Proposed Modification to Existing + // Concept") + JsonNode currentCCodeField = null; + for (JsonNode field : requestTypeFields) { + if ("currentCCode".equals(field.get("name").asText())) { + currentCCodeField = field; + break; + } + } + assertNotNull(currentCCodeField); + JsonNode codeConditionalDisplay = currentCCodeField.get("conditionalDisplay"); + assertNotNull(codeConditionalDisplay); + assertEquals("requestTypeSelection", codeConditionalDisplay.get("dependsOn").asText()); + assertEquals( + "Proposed Modification to Existing Concept", + codeConditionalDisplay.get("showWhen").asText()); + + // Find the "detailedDescription" field (conditionally displayed for "Inquiry") + JsonNode detailedDescField = null; + for (JsonNode field : requestTypeFields) { + if ("detailedDescription".equals(field.get("name").asText())) { + detailedDescField = field; + break; + } + } + assertNotNull(detailedDescField); + JsonNode descConditionalDisplay = detailedDescField.get("conditionalDisplay"); + assertNotNull(descConditionalDisplay); + assertEquals("requestTypeSelection", descConditionalDisplay.get("dependsOn").asText()); + assertEquals("Inquiry", descConditionalDisplay.get("showWhen").asText()); + + // 6. Validate required fields in Additional Info section (new requirements) + JsonNode additionalInfoFields = sections.get(2).get("fields"); + assertEquals(3, additionalInfoFields.size()); + + // Organization - NEW REQUIRED FIELD + JsonNode organization = additionalInfoFields.get(0); + assertEquals("organization", organization.get("name").asText()); + assertNotNull(organization.get("validations")); + assertTrue(organization.get("validations").toString().contains("required")); + + // Project - NOW REQUIRED (was optional) + JsonNode project = additionalInfoFields.get(1); + assertEquals("project", project.get("name").asText()); + assertNotNull(project.get("validations")); + assertTrue(project.get("validations").toString().contains("required")); + + // 7. Validate count of conditional fields (validates all request type scenarios) + assertEquals(8, requestTypeFields.size()); // 1 dropdown + 7 conditional fields + + // Final assertion - overall JSON equality + assertEquals(expectedResponse, responseBody); + // ACT - mock the email service and call the getForm when(termFormService.getFormTemplate(formType)).thenReturn(expectedResponse); mvc.perform(get("/api/v1/form/suggest/{formType}", formType).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()) // Check for HTTP 200 .andExpect(content().contentType(MediaType.APPLICATION_JSON)) - .andExpect( - jsonPath("$.formName").value("NCIT")) // Verify JSON content + .andExpect(jsonPath("$.formName").value("NCIt Term Suggestion Request")) .andExpect(jsonPath("$.formType").value("NCIT")); } @@ -119,7 +263,11 @@ public void testGetFormThrowsException() throws Exception { .contains(expectedResponse))); } - /** Tests the "happy path" where captcha is valid and email sends successfully. */ + /** + * Tests the "happy path" where captcha is valid and email sends successfully. + * + * @throws Exception the exception + */ @Test void testSubmitForm() throws Exception { // Create a mock JSON payload that will pass validation @@ -129,7 +277,7 @@ void testSubmitForm() throws Exception { // Mock the service calls when(captchaService.verifyRecaptcha(recaptchaToken)).thenReturn(true); // use doNothing() for void methods. Use any() since the object is created inside the method. - EmailDetails emailDetails = mock(EmailDetails.class); + // EmailDetails emailDetails = mock(EmailDetails.class); doNothing().when(termFormService).sendEmail(emailDetailsCaptor.capture()); // 2. Act & 3. Assert @@ -138,7 +286,7 @@ void testSubmitForm() throws Exception { .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(formData))) + .content(ThreadLocalMapper.get().writeValueAsString(formData))) .andExpect(status().isOk()); // Default status for a void method is 200 OK // Verify that all our mocks were called correctly @@ -160,7 +308,7 @@ public void testSubmitFormThrowsExceptionWithNullFields() throws Exception { // SET UP - create our form data JsonNode final String formPath = "formSamples/submissionFormNullTest.json"; final JsonNode formData = createForm(formPath); - final String expectedResponse = "417 EXPECTATION_FAILED"; + // final String expectedResponse = "417 EXPECTATION_FAILED"; // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); @@ -170,7 +318,7 @@ public void testSubmitFormThrowsExceptionWithNullFields() throws Exception { .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(formData))) + .content(ThreadLocalMapper.get().writeValueAsString(formData))) .andExpect(status().isExpectationFailed()); // Default status for a void method is 200 OK } @@ -182,8 +330,8 @@ public void testSubmitFormThrowsExceptionWithNullFields() throws Exception { @Test public void testSubmitFormThrowsExceptionWhenFormIsEmpty() throws Exception { // SET UP - create our form data JsonNode - final JsonNode formData = objectMapper.createObjectNode(); - final String expectedResponse = "500 INTERNAL_SERVER_ERROR"; + final JsonNode formData = ThreadLocalMapper.get().createObjectNode(); + // final String expectedResponse = "500 INTERNAL_SERVER_ERROR"; // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); @@ -193,7 +341,7 @@ public void testSubmitFormThrowsExceptionWhenFormIsEmpty() throws Exception { .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(formData))) + .content(ThreadLocalMapper.get().writeValueAsString(formData))) .andExpect(status().is5xxServerError()); // Default status for a void method is 200 OK } @@ -207,7 +355,7 @@ public void testSubmitFormThrowsExceptionWhenSendEmailFails() throws Exception { // SET UP - create our form data JsonNode final String formPath = "formSamples/submissionFormTest-ncit.json"; JsonNode formData = createForm(formPath); - final String expectedResponse = "500 INTERNAL_SERVER_ERROR"; + // final String expectedResponse = "500 INTERNAL_SERVER_ERROR"; // Mock the RecaptchaService to always return true for verifyRecaptcha when(captchaService.verifyRecaptcha(anyString())).thenReturn(true); @@ -221,7 +369,7 @@ public void testSubmitFormThrowsExceptionWhenSendEmailFails() throws Exception { .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(formData))) + .content(ThreadLocalMapper.get().writeValueAsString(formData))) .andExpect(status().is5xxServerError()); // Default status for a void method is 200 OK } @@ -245,7 +393,7 @@ public void testSubmitFormRecaptchaVerificationFails() throws Exception { .header("X-EVSRESTAPI-License-Key", licenseKey) .header("Captcha-Token", recaptchaToken) .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(formData))) + .content(ThreadLocalMapper.get().writeValueAsString(formData))) .andExpect(status().isExpectationFailed()); } diff --git a/src/test/resources/formSamples/compareEmailDetailsFail.json b/src/test/resources/formSamples/compareEmailDetailsFail.json index 97448c853..aa57375c7 100644 --- a/src/test/resources/formSamples/compareEmailDetailsFail.json +++ b/src/test/resources/formSamples/compareEmailDetailsFail.json @@ -3,5 +3,5 @@ "recipientEmail": "agarcia@nih.gov", "businessEmail": "bcarlsen@nih.gov", "subject": "New Term: Test ", - "body": {"Contact Information": { "Business Email": "fakeEmail@email.com", "Other": "Test" }, "Term Information": { "Vocabulary": "NCI Metathesaurus", "Term": "C9864583", "Synonym(s)": "C9874354, C35468", "Nearest Code/CUI": "code test", "Definition/Other": "different def" }, "Additional Information": { "Project/Product term needed for": "Fail Form", "Reason for suggestion or any additional information": "nothing" } } -} \ No newline at end of file + "body": {"Contact Information": { "Business Email": "fakeEmail@email.com", "Name": "Jane Smith" }, "Request Type": { "Please select": "Proposed New Concept", "Term": "DifferentTermName", "Synonym": "DifferentSynonym1", "Definition": "This is a different definition" }, "Additional Information": { "Organization": "Different Organization", "Project": "Different Project", "Additional Information": "Different notes" } } +} diff --git a/src/test/resources/formSamples/submissionFormTest-ncit.json b/src/test/resources/formSamples/submissionFormTest-ncit.json index 608ac1fe7..737002077 100644 --- a/src/test/resources/formSamples/submissionFormTest-ncit.json +++ b/src/test/resources/formSamples/submissionFormTest-ncit.json @@ -3,5 +3,5 @@ "recipientEmail": "agarcia@westcoastinformatics.com", "businessEmail": "bcarlsen@westcoastinformatics.com ", "subject": "New Terminology Suggestion: TestTermName", - "body": {"Contact Information": { "Business Email": "testEmail@email.com", "Other": "Test" }, "Term Information": { "Vocabulary": "NCI Thesaurus", "Term": "C65498", "Synonym(s)": "C431587, C94635", "Nearest Code/CUI": "nearest test", "Definition/Other": "this is definition" }, "Additional Information": { "Project/Product term needed for": "Project Term Form", "Reason for suggestion or any additional information": "random reason" } } -} \ No newline at end of file + "body": {"Contact Information": { "Business Email": "testEmail@email.com", "Name": "John Doe" }, "Request Type": { "Please select": "Proposed New Concept", "Term": "TestTermName", "Synonym": "TestSynonym1, TestSynonym2", "Definition": "This is a test definition for the new concept" }, "Additional Information": { "Organization": "Test Organization", "Project": "Test Project", "Additional Information": "Additional test notes and context" } } +} diff --git a/src/test/resources/formSamples/testNCIT.json b/src/test/resources/formSamples/testNCIT.json index d9d4769ee..e89f4c44b 100644 --- a/src/test/resources/formSamples/testNCIT.json +++ b/src/test/resources/formSamples/testNCIT.json @@ -1,5 +1,5 @@ { - "formName": "NCIT", + "formName": "NCIt Term Suggestion Request", "formType": "NCIT", "recipientEmail": "ncithesaurus@mail.nih.gov", "businessEmail": "test@test.com", @@ -38,49 +38,41 @@ ] }, { - "name": "other", - "label": "Other", - "type": "textarea", + "name": "name", + "label": "Name", + "type": "text", "value": "", - "placeholder": "Enter additional contact information" + "placeholder": "Enter your name" } ] }, { - "name": "termInfo", - "label": "Term Information", + "name": "requestType", + "label": "Request Type", "instructions": { "parts": [ { - "text": "Fill in the following fields as appropriate. For multiple terms, please consider emailing an Excel, delimited text, or similar file to" - }, - { - "text": "ncithesaurus@mail.nih.gov", - "link": "mailto:ncithesaurus@mail.nih.gov?Subject=NCIt%20New%20Term%20Request%20File" - }, - { - "text": ", which can also respond to any questions." + "text": "Please select the type of request and fill in the appropriate fields below." } ] }, "fields": [ { - "name": "vocabulary", - "label": "Vocabulary", + "name": "requestTypeSelection", + "label": "Please select", "type": "dropdown", "value": "", "options": [ - "NCI Thesaurus", - "NCI Metathesaurus", - "NPO", - "Other" + "Proposed New Concept", + "Proposed Modification to Existing Concept", + "Inquiry" ], - "placeholder": "Select vocabulary", + "placeholder": "Select request type", "validations": [ { "name": "required", "validator": "required", - "message": "Vocabulary is required" + "message": "Request type is required" } ] }, @@ -89,35 +81,110 @@ "label": "Term", "type": "textarea", "value": "", - "placeholder": "Enter the term(s)", + "placeholder": "Enter the term", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + }, "validations": [ { - "name": "required", - "validator": "required", - "message": "Term is required" + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Proposed New Concept" + }, + "message": "Term is required for new concept proposals" } ] }, { "name": "synonym", - "label": "Synonym(s)", + "label": "Synonym", + "type": "textarea", + "value": "", + "placeholder": "Enter synonym(s)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + } + }, + { + "name": "definition", + "label": "Definition", "type": "textarea", "value": "", - "placeholder": "Enter synonyms (if any)" + "placeholder": "Enter the definition", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed New Concept" + } }, { - "name": "nearestCode", - "label": "Nearest Code/CUI", + "name": "currentCCode", + "label": "Current C-Code", + "type": "text", + "value": "", + "placeholder": "Enter current C-Code (e.g., C12345)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + }, + "validations": [ + { + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Proposed Modification to Existing Concept" + }, + "message": "C-Code is required for concept modification requests" + } + ] + }, + { + "name": "newSynonym", + "label": "New Synonym", "type": "textarea", "value": "", - "placeholder": "Enter nearest code/CUI" + "placeholder": "Enter new synonym(s)", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + } }, { - "name": "other", - "label": "Definition/Other", + "name": "changeToDefinition", + "label": "Change to Definition", "type": "textarea", "value": "", - "placeholder": "Enter definition/other information" + "placeholder": "Enter proposed changes to definition", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Proposed Modification to Existing Concept" + } + }, + { + "name": "detailedDescription", + "label": "Detailed Description", + "type": "textarea", + "value": "", + "placeholder": "Enter detailed description of your inquiry", + "conditionalDisplay": { + "dependsOn": "requestTypeSelection", + "showWhen": "Inquiry" + }, + "validations": [ + { + "name": "requiredIf", + "validator": "requiredIf", + "condition": { + "field": "requestTypeSelection", + "value": "Inquiry" + }, + "message": "Detailed description is required for inquiries" + } + ] } ] }, @@ -125,24 +192,44 @@ "name": "additionalInfo", "label": "Additional Information", "fields": [ + { + "name": "organization", + "label": "Organization", + "type": "text", + "value": "", + "placeholder": "Enter your organization", + "validations": [ + { + "name": "required", + "validator": "required", + "message": "Organization is required" + } + ] + }, { "name": "project", - "label": "Project/Product term needed for", + "label": "Project", "type": "textarea", "value": "", - "placeholder": "Enter project/product term" + "placeholder": "Enter project name", + "validations": [ + { + "name": "required", + "validator": "required", + "message": "Project is required" + } + ] }, { - "name": "reason", - "label": "Reason for suggestion or any additional information", + "name": "additionalInfo", + "label": "Additional Information", "type": "textarea", "value": "", - "placeholder": "Enter reason for suggestion or any additional information that may help us" + "placeholder": "Enter any additional information that may be helpful" } ] } ], - "recaptchaSiteKey": "TEST-KEY", "subject": "NCIT Term Suggestion Request", "body": "Test" -} \ No newline at end of file +} From effe281c825687ad6fbd364fa22db0a7cdf6ddbc Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Wed, 17 Dec 2025 13:02:28 -0800 Subject: [PATCH 16/64] Dss/evsrestapi 689 todos (#443) * EVSRESTAPI-689: GraphReportLoadServiceImpl.java log hierarchy info * EVSRESTAPI-689: removing TODOs; some minor test adjustments * EVSRESTAPI-689: resolve more todos * EVSRESTAPI-689: more notes * spotless misc --- .../evs/api/fhir/R4/OpenApiInterceptorR4.java | 1 - .../evs/api/fhir/R4/ValueSetProviderR4.java | 2 - .../evs/api/fhir/R5/ConceptMapProviderR5.java | 4 +- .../evs/api/fhir/R5/OpenApiInterceptorR5.java | 1 - .../evs/api/fhir/R5/ValueSetProviderR5.java | 6 -- .../SearchCriteriaWithoutTerminology.java | 4 - .../nih/nci/evs/api/model/Terminology.java | 5 +- .../service/GraphReportLoadServiceImpl.java | 46 +++++++++++- .../api/service/OpenSearchServiceImpl.java | 15 ++-- .../TermSuggestionFormServiceImpl.java | 33 ++++----- .../nih/nci/evs/api/util/ConceptUtils.java | 4 - .../nci/evs/api/util/RrfSampleGenerator.java | 2 +- src/main/resources/application.yml | 8 -- .../nih/nci/evs/api/ConceptSampleTester.java | 40 +++++----- .../controller/ConceptControllerTests.java | 6 -- .../api/controller/NcimControllerTests.java | 2 +- .../evs/api/controller/NcimSampleTest.java | 1 - .../api/controller/SnomedctUsSampleTest.java | 2 - .../fhir/FhirR4CodeSystemReadSearchTests.java | 2 +- .../fhir/FhirR4CodeSystemSubsumesTests.java | 73 ++++++++++++++++++- .../api/fhir/FhirR4ValueSetExpandTests.java | 6 +- .../fhir/FhirR4ValueSetReadSearchTests.java | 2 +- .../api/fhir/FhirR4ValueSetValidateTests.java | 2 - .../fhir/FhirR5CodeSystemReadSearchTests.java | 2 +- .../fhir/FhirR5CodeSystemSubsumesTests.java | 72 +++++++++++++++++- .../fhir/FhirR5ValueSetReadSearchTests.java | 4 +- 26 files changed, 239 insertions(+), 106 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/OpenApiInterceptorR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/OpenApiInterceptorR4.java index e496c6194..be569566d 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/OpenApiInterceptorR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/OpenApiInterceptorR4.java @@ -197,7 +197,6 @@ private void initResources() { ignoreParameter.add(Triple.of("CodeSystem", "validate-code", "system")); ignoreParameter.add(Triple.of("CodeSystem", "validate-code", "systemVersion")); - // TODO: we probably want this ignoreParameter.add(Triple.of("ValueSet", "validate-code", "version")); } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java index 9a10fe29b..d58bd7c26 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java @@ -1241,7 +1241,6 @@ public Parameters validateCodeImplicit( FhirUtilityR4.mutuallyRequired("code", code, "system", system, "url", url); FhirUtilityR4.mutuallyRequired("system", system, "systemVersion", systemVersion); - // TODO: not sure that "version" should be in this list for (final String param : new String[] { "context", @@ -1381,7 +1380,6 @@ public Parameters validateCodeInstance( FhirUtilityR4.requireAtLeastOneOf( "code", code, "coding", coding, "systemVersion", systemVersion, "url", url); - // TODO: not sure that "version" should be in this list for (final String param : new String[] { "context", diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java index 51dae0d88..d772f070f 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java @@ -220,7 +220,7 @@ public Parameters translateInstance( @OperationParam(name = "sourceScope") final UriType sourceScope, @OperationParam(name = "sourceCoding") final Coding sourceCoding, @OperationParam(name = "targetCode") final UriType targetCode, - // TODO: support for targetCoding not provided due to API error; should be Coding + // NOTE: support for targetCoding not provided due to API error; should be Coding @OperationParam(name = "targetCoding") final UriType targetCoding, @OperationParam(name = "targetScope") final UriType targetScope, @OperationParam(name = "targetSystem") final UriType targetSystem) @@ -398,7 +398,7 @@ public Parameters translateImplicit( // @OperationParam(name = "codeableConcept") final CodeableConcept // sourceCodeableConcept, @OperationParam(name = "targetCode") final UriType targetCode, - // TODO: support for targetCoding not provided due to API error; should be Coding + // NOTE: support for targetCoding not provided due to API error; should be Coding @OperationParam(name = "targetCoding") final UriType targetCoding, @OperationParam(name = "targetScope") final UriType targetScope, @OperationParam(name = "targetSystem") final UriType targetSystem diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java index 0542c54b0..bfbab3fca 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java @@ -204,7 +204,6 @@ private void initResources() { ignoreParameter.add(Triple.of("CodeSystem", "validate-code", "system")); ignoreParameter.add(Triple.of("CodeSystem", "validate-code", "systemVersion")); - // TODO: we probably want this ignoreParameter.add(Triple.of("ValueSet", "validate-code", "version")); } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java index f0f178e06..cd13e9229 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java @@ -357,10 +357,6 @@ public ValueSet expandImplicit( activeOnlyValue); } - // TODO add more test cases for exclude, after adding filter is-a - // TODO add remainder of parameters to expandValueSet - // TODO add include.version processing (use latest if not specified) - // check if request is a post, throw exception as we don't support post // calls if (request.getMethod().equals("POST")) { @@ -982,7 +978,6 @@ public Parameters validateCodeImplicit( FhirUtilityR5.mutuallyRequired("system", system, "systemVersion", systemVersion); FhirUtilityR5.mutuallyRequired("display", display, "code", code); - // TODO: not sure that "version" should be in this list for (final String param : new String[] { "context", @@ -1114,7 +1109,6 @@ public Parameters validateCodeInstance( FhirUtilityR5.mutuallyExclusive("code", code, "coding", coding); FhirUtilityR5.mutuallyRequired("display", display, "code", code); - // TODO: not sure that "version" should be in this list for (final String param : new String[] { "context", diff --git a/src/main/java/gov/nih/nci/evs/api/model/SearchCriteriaWithoutTerminology.java b/src/main/java/gov/nih/nci/evs/api/model/SearchCriteriaWithoutTerminology.java index cf4928c52..2b55f4684 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/SearchCriteriaWithoutTerminology.java +++ b/src/main/java/gov/nih/nci/evs/api/model/SearchCriteriaWithoutTerminology.java @@ -557,10 +557,6 @@ public IncludeParam computeIncludeParam() { * @return true, if successful */ public boolean checkRequiredFields() { - // if (term == null && codeList == null) { - // return false; - // TODO: Update this section to fix the validation check with search params - // } return true; } diff --git a/src/main/java/gov/nih/nci/evs/api/model/Terminology.java b/src/main/java/gov/nih/nci/evs/api/model/Terminology.java index f2074a87e..44dd5659c 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/Terminology.java +++ b/src/main/java/gov/nih/nci/evs/api/model/Terminology.java @@ -76,10 +76,7 @@ public class Terminology extends BaseModel implements Comparable { private String objectIndexName; /** The metadata. */ - // TODO: we really should leave this off, but requires 4.1.RC - // or greater (spring data elasticsearch) - // @Field(type = FieldType.Object, enabled = false) - @Field(type = FieldType.Object) + @Field(type = FieldType.Object, enabled = false) private TerminologyMetadata metadata; /** The flag for using sparql searches. */ diff --git a/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java index 582638fd8..4a5261dfe 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java @@ -125,7 +125,51 @@ public void loadObjects( final HierarchyUtils hierarchy) throws Exception { - // TODO: show hierarchy (passed in) + // Show hierarchy information + if (terminology.getMetadata().getHierarchy() != null + && terminology.getMetadata().getHierarchy()) { + try { + // Report total paths in the pathsMap + logReport(" ", "hierarchy = " + hierarchy.getPathsMap(terminology).size()); + + // Report hierarchy roots + logReport(" ", "roots = " + hierarchy.getHierarchyRoots()); + + // Report min paths statistics + final String minPathsCode = hierarchy.getCodeWithMinPaths(terminology); + logReport( + " ", + " min paths = " + + minPathsCode + + ", " + + hierarchy.getPathsMap(terminology).get(minPathsCode).size()); + + // Report max paths statistics + final String maxPathsCode = hierarchy.getCodeWithMaxPaths(terminology); + logReport( + " ", + " max paths = " + + maxPathsCode + + ", " + + hierarchy.getPathsMap(terminology).get(maxPathsCode).size()); + + // Report max children statistics + final String maxChildrenCode = hierarchy.getCodeWithMaxChildren(terminology); + logReport( + " ", + " max children = " + + maxChildrenCode + + ", " + + (maxChildrenCode == null + ? "0" + : hierarchy.getChildNodes(maxChildrenCode, 0).size())); + } catch (Exception e) { + logReport(" ", "hierarchy = error retrieving statistics: " + e.getMessage()); + logger.error("Error retrieving hierarchy statistics", e); + } + } else { + logReport(" ", "hierarchy = not applicable"); + } // Show qualifiers final List qualifiers = diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index 4573a84eb..168841731 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -838,9 +838,12 @@ private List getCriteriaQueries( List queries = new ArrayList<>(); // concept status - QueryBuilder conceptStatusQuery = getConceptStatusQueryBuilder(searchCriteria); - if (conceptStatusQuery != null) { - queries.add(conceptStatusQuery); + // check only if ncit + if (terminologies.stream().filter(t -> t.getTerminology().equals("ncit")).count() > 0) { + QueryBuilder conceptStatusQuery = getConceptStatusQueryBuilder(searchCriteria); + if (conceptStatusQuery != null) { + queries.add(conceptStatusQuery); + } } // property @@ -917,10 +920,7 @@ private QueryBuilder getConceptStatusQueryBuilder(SearchCriteria searchCriteria) } } - // TODO: this shouldn't be hardcoded, but need to read from the particular - // terminology - // we are searching, or otherwise make this a top-level field of "Concept" - // bool query to match property.type and property.value + // This query is only meaningful for ncit BoolQueryBuilder fieldBoolQuery = QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("properties.type", "Concept_Status")) @@ -1244,7 +1244,6 @@ private String[] buildIndicesArray(SearchCriteria searchCriteria) throws Excepti } String[] indices = new String[terminologies.size()]; - // TODO: add getTerminologies call to avoid looping for (int i = 0; i < terminologies.size(); i++) { indices[i] = termUtils diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index e094613ce..99b6d2eba 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -1,12 +1,21 @@ package gov.nih.nci.evs.api.service; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import gov.nih.nci.evs.api.model.EmailDetails; +import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.util.EVSUtils; +import jakarta.mail.Message.RecipientType; +import jakarta.mail.MessagingException; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; import java.io.FileNotFoundException; import java.net.URL; import java.util.Arrays; import java.util.Properties; import java.util.regex.Matcher; import java.util.regex.Pattern; - import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.slf4j.Logger; @@ -17,18 +26,6 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; - -import gov.nih.nci.evs.api.model.EmailDetails; -import gov.nih.nci.evs.api.properties.ApplicationProperties; -import gov.nih.nci.evs.api.util.EVSUtils; -import jakarta.mail.Message.RecipientType; -import jakarta.mail.MessagingException; -import jakarta.mail.internet.InternetAddress; -import jakarta.mail.internet.MimeMessage; - /** Implementation class for the terminology suggestion form service. */ @Service public class TermSuggestionFormServiceImpl implements TermSuggestionFormService { @@ -388,7 +385,8 @@ private String validateNCITAttachment(final MultipartFile file, final String fil if (wb.getNumberOfSheets() != 1) { return prefix + String.format( - "NCIT template should have exactly 1 sheet, found {} sheets in uploaded workbook: {}", + "NCIT template should have exactly 1 sheet, found {} sheets in uploaded workbook:" + + " {}", wb.getNumberOfSheets(), filename); } @@ -413,7 +411,8 @@ private String validateNCITAttachment(final MultipartFile file, final String fil if (!expectedHeaders[col].equals(cellValue)) { return prefix + String.format( - "Header mismatch at column {}: expected '{}', found '{}' in uploaded workbook: {}", + "Header mismatch at column {}: expected '{}', found '{}' in uploaded workbook:" + + " {}", (char) ('A' + col), expectedHeaders[col], cellValue, @@ -473,8 +472,8 @@ private String validateNCITAttachment(final MultipartFile file, final String fil if (colC == null || !ncitCodePattern.matcher(colC.trim()).matches()) { return prefix + String.format( - "Column C (NCIt Code) invalid or missing at row {}: '{}' (expected format: C followed" - + " by digits) in uploaded workbook: {}", + "Column C (NCIt Code) invalid or missing at row {}: '{}' (expected format: C" + + " followed by digits) in uploaded workbook: {}", rowIndex + 1, colC, filename); diff --git a/src/main/java/gov/nih/nci/evs/api/util/ConceptUtils.java b/src/main/java/gov/nih/nci/evs/api/util/ConceptUtils.java index 08254058f..1e74fcf50 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/ConceptUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/ConceptUtils.java @@ -145,10 +145,6 @@ public static void applyHighlights(final Concept concept, final Map children = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }); - if (children.size() < 1) { - // TODO: what's supposed to happen here?! + // subtree/children testing + for (String root : rootCodes) { + url = "/api/v1/concept/" + terminology.getTerminology() + "/" + root + "/subtree"; + result = + testMvc + .perform(get(url).header("X-EVSRESTAPI-License-Key", licenseKey)) + .andExpect(status().isOk()) + .andReturn(); + content = result.getResponse().getContentAsString(); + List children = + new ObjectMapper() + .readValue( + content, + new TypeReference>() { + // n/a + }); + if (children.size() < 1) { + errors.add( + "ERROR: root is expected to have children " + root + " in terminology " + term); + } + } } if (errors.size() > 0) { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java index caed024ec..6c7273d6d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java @@ -182,12 +182,6 @@ public void testGetConceptExtraMappings() throws Exception { String content = null; Concept concept = null; - // TODO: if there was a case of a map that had a P375 in the owl (mapsTo) and ALSO - // was represented in an explicit viewable map - then we could test that concept - // details properly de-duplicates that. But we don't have any such data at the moment. - - // - // Verify this concept has a "maps to" to an HGNC code // This comes from the independent NCI-HGNC map distributed by Liz // and isn't in the owl file itself. diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java index 380f6a3f6..0e4749d02 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java @@ -521,7 +521,7 @@ public void testMRSAT() throws Exception { .isEqualTo(1); // last concept in MRSTY/MRSAT - // TODO: we're ignoring AUI attributes so for the moment this turns up + // NOTE: we're ignoring AUI attributes so for the moment this turns up // nothing // url = baseUrl + "/ncim/CL988043"; // log.info("Testing url - " + url + "?terminology=ncim&code=CL988043"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java index d03e71416..6a134efd0 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java @@ -75,7 +75,6 @@ public void testGetConceptWithMappings() throws Exception { assertThat(concept.getMaps().get(1).getGroup()).isEqualTo("1"); assertThat(concept.getMaps().get(1).getRank()).isEqualTo("1"); assertThat(concept.getMaps().get(1).getRule()).isEqualTo("TRUE"); - // TODO: test what the maps are } /** diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java index 5b27a33c9..32d94a3cf 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java @@ -72,8 +72,6 @@ public void testGetConceptWithMappings() throws Exception { assertThat(concept.getMaps().get(1).getGroup()).isEqualTo("1"); assertThat(concept.getMaps().get(1).getRank()).isEqualTo("1"); assertThat(concept.getMaps().get(1).getRule()).isEqualTo("TRUE"); - - // TODO: test what the maps are } /** diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java index d77191ce1..0ba256fe2 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java @@ -409,7 +409,7 @@ private void validateCanmedCodeSystemResults(final Bundle data, final boolean ex */ @Test public void testCodeSystemReadWithParameters() throws Exception { - // TODO: implement for date when the CodeSystem data has dates + // NOTE: implement for date when the CodeSystem data has dates // implement for url when the custom parameter is registered to the HAPI // FHIR server diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java index 0b43184b9..81d67451f 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java @@ -31,8 +31,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.util.UriComponentsBuilder; -// TODO: Auto-generated Javadoc - /** * Class tests for FhirR4Tests. Tests the functionality of the FHIR R4 endpoints, CodeSystem, * ValueSet, and ConceptMap. All passed ids MUST be lowercase, so they match our internally set id's @@ -78,8 +76,6 @@ public void setUp() { JacksonTester.initFields(this, objectMapper); } - // TODO: test invalid parameter such as url instead of system - /** * Test code system lookup code. * @@ -466,4 +462,73 @@ public void testCodeSystemSubsumesImplicitWithCodeANoSystem() throws Exception { assertEquals(errorCode, component.getCode().toCode()); assertEquals(messageNotSupported, component.getDiagnostics()); } + + /** + * Test subsumes operation with url parameter instead of system (implicit). + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemSubsumesImplicitWithUrlInsteadOfSystem() throws Exception { + // Arrange + final String activeCodeA = "448772000"; + final String activeCodeB = "271860004"; + final String url = "http://snomed.info/sct"; + + final String messageNotSupported = + "Input parameter 'codeA' can only be used in conjunction with parameter 'system'."; + final String errorCode = "invariant"; + + final UriComponentsBuilder builder = + UriComponentsBuilder.fromUriString( + localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_SUBSUMES); + builder.queryParam("codeA", activeCodeA); + builder.queryParam("codeB", activeCodeB); + builder.queryParam("url", url); // Using 'url' instead of 'system' + final URI getUri = builder.build().toUri(); + + // Act + final String content = this.restTemplate.getForObject(getUri, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals(errorCode, component.getCode().toCode()); + assertEquals(messageNotSupported, component.getDiagnostics()); + } + + /** + * Test subsumes operation with url parameter instead of system (instance). + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemSubsumesInstanceWithUrlInsteadOfSystem() throws Exception { + // Arrange + final String activeCodeA = "448772000"; + final String activeCodeB = "271860004"; + final String activeId = "snomedct_us_2025_03_01"; + final String url = "http://snomed.info/sct"; + + final String messageNotSupported = + "Input parameter 'codeA' can only be used in conjunction with parameter 'system'."; + final String errorCode = "invariant"; + + final UriComponentsBuilder builder = + UriComponentsBuilder.fromUriString( + localHost + port + fhirCSPath + "/" + activeId + "/" + JpaConstants.OPERATION_SUBSUMES); + builder.queryParam("codeA", activeCodeA); + builder.queryParam("codeB", activeCodeB); + builder.queryParam("url", url); // Using 'url' instead of 'system' + final URI getUri = builder.build().toUri(); + + // Act + final String content = this.restTemplate.getForObject(getUri, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals(errorCode, component.getCode().toCode()); + assertEquals(messageNotSupported, component.getDiagnostics()); + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java index 420ec7a3a..c6efb4dd4 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java @@ -53,8 +53,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit.jupiter.SpringExtension; -// TODO: Auto-generated Javadoc - /** * Class tests for FhirR4Tests. Tests the functionality of the FHIR R4 endpoints, CodeSystem, * ValueSet, and ConceptMap. All passed ids MUST be lowercase, so they match our internally set id's @@ -3315,7 +3313,7 @@ public void testValueSetExpandWithIncludeVersionDirectConceptsCurrent() throws E currentNCItVersion = "24.01d"; // Fallback to a recent version } - // TODO: investigate why currentNCItVersion as 25.07b doesn't match concepts + // NOTE: new ticket - investigate why currentNCItVersion as 25.07b doesn't match concepts currentNCItVersion = "25.06e"; log.info("Using current NCIt version: {} for R4 include.version test", currentNCItVersion); @@ -3464,7 +3462,7 @@ public void testValueSetExpandWithIncludeVersionFilterBasedCurrent() throws Exce log.warn("Could not determine current NCIt version, using fallback"); currentNCItVersion = "24.01d"; // Fallback to a recent version } - // TODO: investigate why currentNCI + // NOTE: new ticket - investigate why currentNCI currentNCItVersion = "25.06e"; log.info( "Using current NCIt version: {} for R4 include.version filter test", currentNCItVersion); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index 17ffe6d42..73d52862d 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -253,7 +253,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") .queryParam("_id", "ncit_c100110") - // TODO + // NOTE investigate on ticket EVSRESTAPI-699 // .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java index f2843b036..966f7af63 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java @@ -34,8 +34,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.util.UriComponentsBuilder; -// TODO: Auto-generated Javadoc - /** * Class tests for FhirR4Tests. Tests the functionality of the FHIR R4 endpoints, CodeSystem, * ValueSet, and ConceptMap. All passed ids MUST be lowercase, so they match our internally set id's diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java index 40f757487..4dac53234 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java @@ -168,7 +168,7 @@ public void testCodeSystemRead() throws Exception { @Test public void testCodeSystemSearchWithParameters() throws Exception { - // TODO: currently data doesn't have the code, description or date data + // NOTE: currently data doesn't have the code, description or date data // these tests should be amended when the data is updated // Arrange diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java index 6db6917eb..dd276168f 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java @@ -31,7 +31,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.web.util.UriComponentsBuilder; -// TODO: Auto-generated Javadoc /** * Class tests for FhirR5Tests. Tests the functionality of the FHIR R5 endpoints, CodeSystem, * ValueSet, and ConceptMap. All passed ids MUST be lowercase, so they match our internally set id's @@ -77,8 +76,6 @@ public void setUp() { JacksonTester.initFields(this, objectMapper); } - // TODO: test invalid parameter such as url instead of system - /** * Test code system lookup code. * @@ -466,4 +463,73 @@ public void testCodeSystemSubsumesImplicitWithCodeANoSystem() throws Exception { assertEquals(errorCode, component.getCode().toCode()); assertEquals(messageNotSupported, component.getDiagnostics()); } + + /** + * Test subsumes operation with url parameter instead of system (implicit). + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemSubsumesImplicitWithUrlInsteadOfSystem() throws Exception { + // Arrange + final String activeCodeA = "448772000"; + final String activeCodeB = "271860004"; + final String url = "http://snomed.info/sct"; + + final String messageNotSupported = + "Input parameter 'codeA' can only be used in conjunction with parameter 'system'."; + final String errorCode = "invariant"; + + final UriComponentsBuilder builder = + UriComponentsBuilder.fromUriString( + localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_SUBSUMES); + builder.queryParam("codeA", activeCodeA); + builder.queryParam("codeB", activeCodeB); + builder.queryParam("url", url); // Using 'url' instead of 'system' + final URI getUri = builder.build().toUri(); + + // Act + final String content = this.restTemplate.getForObject(getUri, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals(errorCode, component.getCode().toCode()); + assertEquals(messageNotSupported, component.getDiagnostics()); + } + + /** + * Test subsumes operation with url parameter instead of system (instance). + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemSubsumesInstanceWithUrlInsteadOfSystem() throws Exception { + // Arrange + final String activeCodeA = "448772000"; + final String activeCodeB = "271860004"; + final String activeId = "snomedct_us_2025_03_01"; + final String url = "http://snomed.info/sct"; + + final String messageNotSupported = + "Input parameter 'codeA' can only be used in conjunction with parameter 'system'."; + final String errorCode = "invariant"; + + final UriComponentsBuilder builder = + UriComponentsBuilder.fromUriString( + localHost + port + fhirCSPath + "/" + activeId + "/" + JpaConstants.OPERATION_SUBSUMES); + builder.queryParam("codeA", activeCodeA); + builder.queryParam("codeB", activeCodeB); + builder.queryParam("url", url); // Using 'url' instead of 'system' + final URI getUri = builder.build().toUri(); + + // Act + final String content = this.restTemplate.getForObject(getUri, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals(errorCode, component.getCode().toCode()); + assertEquals(messageNotSupported, component.getDiagnostics()); + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index ccc200762..882cce05b 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -275,7 +275,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") .queryParam("_id", "ncit_c100110") - // TODO + // NOTE investigate on ticket EVSRESTAPI-699 // .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") @@ -384,7 +384,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { */ @Test public void testValueSetSearchWithParameters() throws Exception { - // TODO: currently data doesn't have the system data and only subsets have + // NOTE: currently data doesn't have the system data and only subsets have // the code // these tests should be amended when the data is updated From d1001658667c78dcc6504d6571e54960e7185f4c Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Tue, 23 Dec 2025 11:16:39 -0800 Subject: [PATCH 17/64] Dss/evsrestapi 690 property param adding property parameter for CodeSystem$lookup operation --- .gitignore | 3 + CHANGELOG.md | 4 +- .../evs/api/fhir/R4/CodeSystemProviderR4.java | 226 ++++++++++++++-- .../nci/evs/api/fhir/R4/FhirUtilityR4.java | 22 ++ .../evs/api/fhir/R5/CodeSystemProviderR5.java | 223 +++++++++++++-- .../nci/evs/api/fhir/R5/FhirUtilityR5.java | 22 ++ .../SparqlQueryManagerServiceImpl.java | 7 + .../TermSuggestionFormServiceImpl.java | 24 -- .../api/fhir/FhirR4CodeSystemLookupTests.java | 249 +++++++++++++---- .../api/fhir/FhirR5CodeSystemLookupTests.java | 254 ++++++++++++++---- 10 files changed, 842 insertions(+), 192 deletions(-) diff --git a/.gitignore b/.gitignore index 2865edb07..b49ac2df0 100644 --- a/.gitignore +++ b/.gitignore @@ -31,3 +31,6 @@ report.html gradle.lockfile /.apt_generated/ /.apt_generated_tests/ +UnitTestData/* +src/main/main.iml +src/test/test.iml diff --git a/CHANGELOG.md b/CHANGELOG.md index f338313ba..9a551abb3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,11 +4,11 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + ## [2.4.0.RELEASE] - 2025-MM-DD ### Changed - TBD -## [2.3.0.RELEASE] - 2025-11-04 ### Changed - Various minor bug fixes and typo corrections - FHIR improvements (resource _history, improved parameter support, POST call support for adhoc value sets, set dates properly on ConceptMap) @@ -18,7 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Address CodeQL, dependabot, and trivy reported vulnerability issues - Support viewable maps the NCI Thesaurus mappings - Bring online support for CTCAE6 -- Improve term form to support attachments in the style of the CDISC template +- Improve term form to support attachments in the style of the CDISC template (and improve error messages) - Better handling of NPO complex definitions - Swagger version update diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java index d179f39b8..509d56995 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java @@ -18,7 +18,10 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import gov.nih.nci.evs.api.controller.ConceptController; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.model.Definition; import gov.nih.nci.evs.api.model.IncludeParam; +import gov.nih.nci.evs.api.model.Property; +import gov.nih.nci.evs.api.model.Synonym; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.service.OpenSearchService; import gov.nih.nci.evs.api.service.OpensearchOperationsService; @@ -97,10 +100,10 @@ public Parameters lookupImplicit( @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @OperationParam(name = "version") final StringType version, - @OperationParam(name = "coding") final Coding coding - // @OperationParam(name = "date") final DateRangeParam date + @OperationParam(name = "coding") final Coding coding, // @OperationParam(name = "displayLanguage") final StringType displayLanguage, - // @OperationParam(name = "property") final CodeType property + @OperationParam(name = "property") final List property + // @OperationParam(name = "date") final DateRangeParam date ) throws Exception { // check if request is a post, throw exception as we don't support post calls if (request.getMethod().equals("POST")) { @@ -112,9 +115,7 @@ public Parameters lookupImplicit( try { FhirUtilityR4.mutuallyRequired("code", code, "system", system); FhirUtilityR4.mutuallyExclusive("code", code, "coding", coding); - // FhirUtilityR4.notSupported("displayLanguage", displayLanguage); - // FhirUtilityR4.notSupported("property", property); - for (final String param : new String[] {"displayLanguage", "property", "date"}) { + for (final String param : new String[] {"date", "displayLanguage"}) { FhirUtilityR4.notSupported(request, param); } if (Collections.list(request.getParameterNames()).stream() @@ -143,20 +144,77 @@ public Parameters lookupImplicit( final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); - final Concept conc = - osQueryService.getConcept(codeToLookup, term, new IncludeParam("children")).get(); - // required in the specification + // Fetch concept with properties, synonyms, and definitions + final Optional conceptOpt = + osQueryService.getConcept( + codeToLookup, + term, + new IncludeParam("parents,children,properties,synonyms,definitions")); + if (!conceptOpt.isPresent()) { + throw FhirUtilityR4.exception( + "Failed to lookup code", OperationOutcome.IssueType.EXCEPTION, 500); + } + final Concept conc = conceptOpt.get(); + + // Required in the specification params.addParameter("name", codeSys.getName()); params.addParameter("display", conc.getName()); - // optional in the specification + + // Optional in the specification params.addParameter("version", codeSys.getVersion()); - // properties + + // Hardcoded properties - active is always included, parent/child are conditionally included + // Active property is always included as per FHIR spec params.addParameter(FhirUtilityR4.createProperty("active", conc.getActive(), false)); - for (final Concept parent : conc.getParents()) { - params.addParameter(FhirUtilityR4.createProperty("parent", parent.getCode(), true)); + + // Parent properties - only include if no filter OR filter includes "parent" + if (shouldIncludeHardcodedProperty("parent", property)) { + for (final Concept parent : conc.getParents()) { + params.addParameter(FhirUtilityR4.createProperty("parent", parent.getCode(), true)); + } + } + + // Child properties - only include if no filter OR filter includes "child" + if (shouldIncludeHardcodedProperty("child", property)) { + for (final Concept child : conc.getChildren()) { + params.addParameter(FhirUtilityR4.createProperty("child", child.getCode(), true)); + } + } + + // Add concept properties (filtered if property parameter specified) + if (conc.getProperties() != null) { + for (final Property prop : conc.getProperties()) { + if (shouldIncludeProperty(prop, property)) { + params.addParameter( + FhirUtilityR4.createProperty(prop.getType(), prop.getValue(), false)); + } + } } - for (final Concept child : conc.getChildren()) { - params.addParameter(FhirUtilityR4.createProperty("child", child.getCode(), true)); + + // Add designations (synonyms and definitions) + // Add synonyms as designations + if (conc.getSynonyms() != null) { + for (final Synonym synonym : conc.getSynonyms()) { + if (synonym.getName() != null) { + final Coding use = + new Coding(synonym.getUri(), synonym.getTermType(), synonym.getName()); + params.addParameter(FhirUtilityR4.createDesignation("en", use, synonym.getName())); + } + } + } + + // Add definitions as designations + if (conc.getDefinitions() != null) { + for (final Definition def : conc.getDefinitions()) { + if (def.getDefinition() != null) { + final Coding use = + new Coding( + "http://terminology.hl7.org/CodeSystem/designation-usage", + "definition", + "Definition"); + params.addParameter(FhirUtilityR4.createDesignation("en", use, def.getDefinition())); + } + } } } else { throw FhirUtilityR4.exception( @@ -198,10 +256,10 @@ public Parameters lookupInstance( @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @OperationParam(name = "version") final StringType version, - @OperationParam(name = "coding") final Coding coding - // @OperationParam(name = "date") final DateRangeParam date + @OperationParam(name = "coding") final Coding coding, // @OperationParam(name = "displayLanguage") final StringType displayLanguage, - // @OperationParam(name = "property") final CodeType property + @OperationParam(name = "property") final List property + // @OperationParam(name = "date") final DateRangeParam date ) throws Exception { // check if request is a post, throw exception as we don't support post calls if (request.getMethod().equals("POST")) { @@ -212,9 +270,7 @@ public Parameters lookupInstance( } try { FhirUtilityR4.mutuallyExclusive("code", code, "coding", coding); - // FhirUtilityR4.notSupported("displayLanguage", displayLanguage); - // FhirUtilityR4.notSupported("property", property); - for (final String param : new String[] {"displayLanguage", "property", "date"}) { + for (final String param : new String[] {"date", "displayLanguage"}) { FhirUtilityR4.notSupported(request, param); } if (Collections.list(request.getParameterNames()).stream() @@ -255,19 +311,77 @@ public Parameters lookupInstance( } final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); - final Concept conc = - osQueryService.getConcept(codeToLookup, term, new IncludeParam("children")).get(); - // required in the specification + // Fetch concept with properties, synonyms, and definitions + final Optional conceptOpt = + osQueryService.getConcept( + codeToLookup, + term, + new IncludeParam("parents,children,properties,synonyms,definitions")); + if (!conceptOpt.isPresent()) { + throw FhirUtilityR4.exception( + "Failed to lookup code", OperationOutcome.IssueType.EXCEPTION, 500); + } + final Concept conc = conceptOpt.get(); + + // Required in the specification params.addParameter("name", codeSys.getName()); params.addParameter("display", conc.getName()); - // optional in the specification + + // Optional in the specification params.addParameter("version", codeSys.getVersion()); + + // Hardcoded properties - active is always included, parent/child are conditionally included + // Active property is always included as per FHIR spec params.addParameter(FhirUtilityR4.createProperty("active", conc.getActive(), false)); - for (final Concept parent : conc.getParents()) { - params.addParameter(FhirUtilityR4.createProperty("parent", parent.getCode(), true)); + + // Parent properties - only include if no filter OR filter includes "parent" + if (shouldIncludeHardcodedProperty("parent", property)) { + for (final Concept parent : conc.getParents()) { + params.addParameter(FhirUtilityR4.createProperty("parent", parent.getCode(), true)); + } } - for (final Concept child : conc.getChildren()) { - params.addParameter(FhirUtilityR4.createProperty("child", child.getCode(), true)); + + // Child properties - only include if no filter OR filter includes "child" + if (shouldIncludeHardcodedProperty("child", property)) { + for (final Concept child : conc.getChildren()) { + params.addParameter(FhirUtilityR4.createProperty("child", child.getCode(), true)); + } + } + + // Add concept properties (filtered if property parameter specified) + if (conc.getProperties() != null) { + for (final Property prop : conc.getProperties()) { + if (shouldIncludeProperty(prop, property)) { + params.addParameter( + FhirUtilityR4.createProperty(prop.getType(), prop.getValue(), false)); + } + } + } + + // Add designations (synonyms and definitions) + // Add synonyms as designations + if (conc.getSynonyms() != null) { + for (final Synonym synonym : conc.getSynonyms()) { + if (synonym.getName() != null) { + final Coding use = + new Coding(synonym.getUri(), synonym.getTermType(), synonym.getName()); + params.addParameter(FhirUtilityR4.createDesignation("en", use, synonym.getName())); + } + } + } + + // Add definitions as designations + if (conc.getDefinitions() != null) { + for (final Definition def : conc.getDefinitions()) { + if (def.getDefinition() != null) { + final Coding use = + new Coding( + "http://terminology.hl7.org/CodeSystem/designation-usage", + "definition", + "Definition"); + params.addParameter(FhirUtilityR4.createDesignation("en", use, def.getDefinition())); + } + } } } else { throw FhirUtilityR4.exception( @@ -1098,4 +1212,58 @@ private Comparator getCodeSystemComparator(final String field) { throw new IllegalArgumentException("Unsupported sort field: " + field); } } + + /** + * Helper method to filter properties based on requested property codes. + * + * @param property the property to check + * @param requestedProperties the list of requested property codes + * @return true if the property should be included, false otherwise + */ + private boolean shouldIncludeProperty( + final Property property, final List requestedProperties) { + // If no property filter specified, include all properties + if (requestedProperties == null || requestedProperties.isEmpty()) { + return true; + } + // Check if property type matches any requested property code + for (CodeType requestedProp : requestedProperties) { + if (property.getType().equals(requestedProp.getValue())) { + return true; + } + } + return false; + } + + /** + * Helper method to determine if a hardcoded property should be included based on the property + * filter. The 'active' property is always included per FHIR spec. The 'parent' and 'child' + * properties are only included if no filter is specified OR if the filter explicitly includes + * them. + * + * @param propertyName the name of the hardcoded property (active, parent, or child) + * @param requestedProperties the list of requested property codes from the property parameter + * @return true if the property should be included, false otherwise + */ + private boolean shouldIncludeHardcodedProperty( + final String propertyName, final List requestedProperties) { + // Active property is always included per FHIR spec + if ("active".equals(propertyName)) { + return true; + } + + // If no property filter specified, include all hardcoded properties + if (requestedProperties == null || requestedProperties.isEmpty()) { + return true; + } + + // Check if the hardcoded property name matches any requested property code + for (CodeType requestedProp : requestedProperties) { + if (propertyName.equals(requestedProp.getValue())) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/FhirUtilityR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/FhirUtilityR4.java index 89d9b069b..3a3fb03de 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/FhirUtilityR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/FhirUtilityR4.java @@ -572,6 +572,28 @@ else if (propertyValue instanceof Date) { return property; } + /** + * Create designation. + * + * @param language the language code (e.g., "en") + * @param use the Coding describing the type of designation + * @param value the designation text value + * @return the parameters parameter component representing a designation + */ + public static ParametersParameterComponent createDesignation( + final String language, final Coding use, final String value) { + final ParametersParameterComponent designation = + new ParametersParameterComponent().setName("designation"); + if (language != null) { + designation.addPart().setName("language").setValue(new CodeType(language)); + } + if (use != null) { + designation.addPart().setName("use").setValue(use); + } + designation.addPart().setName("value").setValue(new StringType(value)); + return designation; + } + /** * Returns the next link. * diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java index 462a931cf..5d4d430a0 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java @@ -17,7 +17,10 @@ import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.model.Definition; import gov.nih.nci.evs.api.model.IncludeParam; +import gov.nih.nci.evs.api.model.Property; +import gov.nih.nci.evs.api.model.Synonym; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.FHIRServerResponseException; @@ -201,10 +204,10 @@ public Parameters lookupImplicit( @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @OperationParam(name = "version") final StringType version, - @OperationParam(name = "coding") final Coding coding - // @OperationParam(name = "date") final DateRangeParam date + @OperationParam(name = "coding") final Coding coding, // @OperationParam(name = "displayLanguage") final StringType displayLanguage, - // @OperationParam(name = "property") final CodeType property + @OperationParam(name = "property") final List property + // @OperationParam(name = "date") final DateRangeParam date ) throws Exception { // Check if the request is a POST, throw exception as we don't support post calls // exception for coding parameter @@ -217,9 +220,7 @@ public Parameters lookupImplicit( try { FhirUtilityR5.mutuallyRequired("code", code, "system", system); FhirUtilityR5.mutuallyExclusive("code", code, "coding", coding); - // FhirUtilityR5.notSupported(displayLanguage, "displayLanguage"); - // FhirUtilityR5.notSupported(property, "property"); - for (final String param : new String[] {"displayLanguage", "date", "property"}) { + for (final String param : new String[] {"date", "displayLanguage"}) { FhirUtilityR5.notSupported(request, param); } if (Collections.list(request.getParameterNames()).stream() @@ -248,20 +249,76 @@ public Parameters lookupImplicit( final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); - final Concept concept = - osQueryService.getConcept(codeToLookup, term, new IncludeParam("children")).get(); - // required in the specification + // Fetch concept with properties, synonyms, and definitions + final Optional conceptOpt = + osQueryService.getConcept( + codeToLookup, + term, + new IncludeParam("parents,children,properties,synonyms,definitions")); + if (!conceptOpt.isPresent()) { + throw FhirUtilityR5.exception("Failed to lookup code", IssueType.EXCEPTION, 500); + } + final Concept concept = conceptOpt.get(); + + // Required in the specification params.addParameter("name", codeSys.getName()); params.addParameter("display", concept.getName()); - // optional in the specification + + // Optional in the specification params.addParameter("version", codeSys.getVersion()); - // properties + + // Hardcoded properties - active is always included, parent/child are conditionally included + // Active property is always included as per FHIR spec params.addParameter(FhirUtilityR5.createProperty(concept.getActive(), "active", false)); - for (final Concept parent : concept.getParents()) { - params.addParameter(FhirUtilityR5.createProperty("parent", parent.getCode(), true)); + + // Parent properties - only include if no filter OR filter includes "parent" + if (shouldIncludeHardcodedProperty("parent", property)) { + for (final Concept parent : concept.getParents()) { + params.addParameter(FhirUtilityR5.createProperty(parent.getCode(), "parent", true)); + } } - for (final Concept child : concept.getChildren()) { - params.addParameter(FhirUtilityR5.createProperty("child", child.getCode(), true)); + + // Child properties - only include if no filter OR filter includes "child" + if (shouldIncludeHardcodedProperty("child", property)) { + for (final Concept child : concept.getChildren()) { + params.addParameter(FhirUtilityR5.createProperty(child.getCode(), "child", true)); + } + } + + // Add concept properties (filtered if property parameter specified) + if (concept.getProperties() != null) { + for (final Property prop : concept.getProperties()) { + if (shouldIncludeProperty(prop, property)) { + params.addParameter( + FhirUtilityR5.createProperty(prop.getValue(), prop.getType(), false)); + } + } + } + + // Add designations (synonyms and definitions) + // Add synonyms as designations + if (concept.getSynonyms() != null) { + for (final Synonym synonym : concept.getSynonyms()) { + if (synonym.getName() != null) { + final Coding use = + new Coding(synonym.getUri(), synonym.getTermType(), synonym.getName()); + params.addParameter(FhirUtilityR5.createDesignation("en", use, synonym.getName())); + } + } + } + + // Add definitions as designations + if (concept.getDefinitions() != null) { + for (final Definition def : concept.getDefinitions()) { + if (def.getDefinition() != null) { + final Coding use = + new Coding( + "http://terminology.hl7.org/CodeSystem/designation-usage", + "definition", + "Definition"); + params.addParameter(FhirUtilityR5.createDesignation("en", use, def.getDefinition())); + } + } } } else { throw FhirUtilityR5.exception( @@ -301,10 +358,10 @@ public Parameters lookupInstance( @OperationParam(name = "code") final CodeType code, @OperationParam(name = "system") final UriType system, @OperationParam(name = "version") final StringType version, - @OperationParam(name = "coding") final Coding coding - // @OperationParam(name = "date") final DateRangeParam date + @OperationParam(name = "coding") final Coding coding, // @OperationParam(name = "displayLanguage") final StringType displayLanguage, - // @OperationParam(name = "property") final CodeType property + @OperationParam(name = "property") final List property + // @OperationParam(name = "date") final DateRangeParam date ) throws Exception { // Check if the request is a POST, throw exception as we don't support post calls // exception for coding parameter @@ -316,7 +373,7 @@ public Parameters lookupInstance( } try { FhirUtilityR5.mutuallyExclusive("code", code, "coding", coding); - for (final String param : new String[] {"displayLanguage", "property", "date"}) { + for (final String param : new String[] {"date"}) { FhirUtilityR5.notSupported(request, param); } if (Collections.list(request.getParameterNames()).stream() @@ -356,22 +413,76 @@ public Parameters lookupInstance( } final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); - final Concept concept = - osQueryService.getConcept(codeToLookup, term, new IncludeParam("children")).get(); - // required in the specification + // Fetch concept with properties, synonyms, and definitions + final Optional conceptOpt = + osQueryService.getConcept( + codeToLookup, + term, + new IncludeParam("parents,children,properties,synonyms,definitions")); + if (!conceptOpt.isPresent()) { + throw FhirUtilityR5.exception("Failed to lookup code", IssueType.EXCEPTION, 500); + } + final Concept concept = conceptOpt.get(); + + // Required in the specification params.addParameter("name", codeSys.getName()); params.addParameter("display", concept.getName()); - // optional in the specification + + // Optional in the specification params.addParameter("version", codeSys.getVersion()); + + // Hardcoded properties - active is always included, parent/child are conditionally included + // Active property is always included as per FHIR spec params.addParameter(FhirUtilityR5.createProperty(concept.getActive(), "active", false)); - for (final Concept parent : concept.getParents()) { - params.addParameter(FhirUtilityR5.createProperty(parent.getCode(), "parent", true)); + + // Parent properties - only include if no filter OR filter includes "parent" + if (shouldIncludeHardcodedProperty("parent", property)) { + for (final Concept parent : concept.getParents()) { + params.addParameter(FhirUtilityR5.createProperty(parent.getCode(), "parent", true)); + } } - for (final Concept parent : concept.getParents()) { - params.addParameter(FhirUtilityR5.createProperty(parent.getCode(), "parent", true)); + + // Child properties - only include if no filter OR filter includes "child" + if (shouldIncludeHardcodedProperty("child", property)) { + for (final Concept child : concept.getChildren()) { + params.addParameter(FhirUtilityR5.createProperty(child.getCode(), "child", true)); + } + } + + // Add concept properties (filtered if property parameter specified) + if (concept.getProperties() != null) { + for (final Property prop : concept.getProperties()) { + if (shouldIncludeProperty(prop, property)) { + params.addParameter( + FhirUtilityR5.createProperty(prop.getValue(), prop.getType(), false)); + } + } + } + + // Add designations (synonyms and definitions) + // Add synonyms as designations + if (concept.getSynonyms() != null) { + for (final Synonym synonym : concept.getSynonyms()) { + if (synonym.getName() != null) { + final Coding use = + new Coding(synonym.getUri(), synonym.getTermType(), synonym.getName()); + params.addParameter(FhirUtilityR5.createDesignation("en", use, synonym.getName())); + } + } } - for (final Concept child : concept.getChildren()) { - params.addParameter(FhirUtilityR5.createProperty(child.getCode(), "child", true)); + + // Add definitions as designations + if (concept.getDefinitions() != null) { + for (final Definition def : concept.getDefinitions()) { + if (def.getDefinition() != null) { + final Coding use = + new Coding( + "http://terminology.hl7.org/CodeSystem/designation-usage", + "definition", + "Definition"); + params.addParameter(FhirUtilityR5.createDesignation("en", use, def.getDefinition())); + } + } } } else { throw FhirUtilityR5.exception( @@ -1094,4 +1205,58 @@ private java.util.Comparator getCodeSystemComparator( return ascending ? comparator : comparator.reversed(); } + + /** + * Helper method to filter properties based on requested property codes. + * + * @param property the property to check + * @param requestedProperties the list of requested property codes + * @return true if the property should be included, false otherwise + */ + private boolean shouldIncludeProperty( + final Property property, final List requestedProperties) { + // If no property filter specified, include all properties + if (requestedProperties == null || requestedProperties.isEmpty()) { + return true; + } + // Check if property type matches any requested property code + for (CodeType requestedProp : requestedProperties) { + if (property.getType().equals(requestedProp.getValue())) { + return true; + } + } + return false; + } + + /** + * Helper method to determine if a hardcoded property should be included based on the property + * filter. The 'active' property is always included per FHIR spec. The 'parent' and 'child' + * properties are only included if no filter is specified OR if the filter explicitly includes + * them. + * + * @param propertyName the name of the hardcoded property (active, parent, or child) + * @param requestedProperties the list of requested property codes from the property parameter + * @return true if the property should be included, false otherwise + */ + private boolean shouldIncludeHardcodedProperty( + final String propertyName, final List requestedProperties) { + // Active property is always included per FHIR spec + if ("active".equals(propertyName)) { + return true; + } + + // If no property filter specified, include all hardcoded properties + if (requestedProperties == null || requestedProperties.isEmpty()) { + return true; + } + + // Check if the hardcoded property name matches any requested property code + for (CodeType requestedProp : requestedProperties) { + if (propertyName.equals(requestedProp.getValue())) { + return true; + } + } + + return false; + } } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/FhirUtilityR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/FhirUtilityR5.java index e295ae9b3..c0deb5e34 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/FhirUtilityR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/FhirUtilityR5.java @@ -564,6 +564,28 @@ public static ParametersParameterComponent createProperty( return property; } + /** + * Create designation. + * + * @param language the language code (e.g., "en") + * @param use the Coding describing the type of designation + * @param value the designation text value + * @return the parameters parameter component representing a designation + */ + public static ParametersParameterComponent createDesignation( + final String language, final Coding use, final String value) { + final ParametersParameterComponent designation = + new ParametersParameterComponent().setName("designation"); + if (language != null) { + designation.addPart().setName("language").setValue(new CodeType(language)); + } + if (use != null) { + designation.addPart().setName("use").setValue(use); + } + designation.addPart().setName("value").setValue(new StringType(value)); + return designation; + } + /** * Get the next link component. * diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index 5d2f532bb..7f02e2181 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -205,6 +205,13 @@ public List getTerminologies(final String db) throws Exception, Par term.setSource(b.getSource().getValue()); term.setTerminology(getTerm(term.getSource())); + // Special handling for chebi to avoid "247.0" as a version + // We are doing this to avoid a much more complicated sparql-queries.properties file + // but may want to do something about this going forward. + if (term.getTerminology().equals("chebi")) { + term.setVersion(term.getVersion().replaceFirst(".0$", "")); + } + final String startDate = FhirUtility.convertToYYYYMMDD( (b.getDate() == null) ? term.getVersion() : b.getDate().getValue()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 99b6d2eba..9b1f9aedc 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -334,30 +334,6 @@ private String validateCDISCAttachment(final MultipartFile file, final String fi "Required sheet '%s' missing content in uploaded workbook: %s", sheetName, filename); } - final org.apache.poi.ss.usermodel.DataFormatter formatter = - new org.apache.poi.ss.usermodel.DataFormatter(); - - // Handle merged cells for C3:F3, C4:F4, C5:F5 by checking the merged region's first cell - for (int r = 2; r <= 4; r++) { - final String cellValue = getMergedCellValue(metaSheet, r, 2, formatter); - if (cellValue == null || cellValue.isEmpty()) { - return prefix - + String.format( - "Required metadata missing in sheet '%s' at C%d in uploaded workbook: %s", - sheetName, r + 1, filename); - } - } - - // Check that A8..E8 (columns 0..4, row index 7) are filled out - for (int c = 0; c <= 4; c++) { - final String v = getMergedCellValue(metaSheet, 7, c, formatter); - if (v == null || v.isEmpty()) { - return prefix - + String.format( - "Required row 8 column %d missing in sheet '%s' in uploaded workbook: %s", - c + 1, sheetName, filename); - } - } } catch (final Exception e) { return prefix + String.format( diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java index 9c77410e3..334318a32 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java @@ -14,6 +14,7 @@ import java.util.List; import java.util.stream.Collectors; import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; @@ -176,60 +177,6 @@ public void testCodeSystemLookupInstanceCodeWithCoding() throws Exception { assertEquals(version, ((StringType) params.getParameter("version").getValue()).getValue()); } - /** - * Test code system lookup implicit parameter not supported. - * - * @throws Exception the exception - */ - @Test - public void testCodeSystemLookupImplicitParameterNotSupported() throws Exception { - // Arrange - String content; - final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl?fhir_vs"; - final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; - final String parameters = "?url=" + url + "&displayLanguage=notfound"; - - final String messageNotSupported = "Input parameter 'displayLanguage' is not supported."; - final String errorCode = "not-supported"; - - // Act - content = this.restTemplate.getForObject(endpoint + parameters, String.class); - final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); - final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); - - // Assert - assertEquals(errorCode, component.getCode().toCode()); - assertEquals(messageNotSupported, (component.getDiagnostics())); - } - - /** - * Test code system lookup instance parameter not supported. - * - * @throws Exception the exception - */ - @Test - public void testCodeSystemLookupInstanceParameterNotSupported() throws Exception { - // Arrange - String content; - final String activeID = "umlssemnet_2023aa"; - final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl?fhir_vs"; - final String endpoint = - localHost + port + fhirCSPath + "/" + activeID + "/" + JpaConstants.OPERATION_LOOKUP; - final String parameters = "?url=" + url + "&displayLanguage=notfound"; - - final String messageNotSupported = "Input parameter 'displayLanguage' is not supported."; - final String errorCode = "not-supported"; - - // Act - content = this.restTemplate.getForObject(endpoint + parameters, String.class); - final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); - final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); - - // Assert - assertEquals(errorCode, component.getCode().toCode()); - assertEquals(messageNotSupported, (component.getDiagnostics())); - } - /** * Test code system lookup code and display string. * @@ -568,4 +515,198 @@ public void testCodeSystemLookupImplicitCodeWithNoSystem() throws Exception { assertEquals(errorCode, component.getCode().toCode()); assertEquals(messageNotSupported, (component.getDiagnostics())); } + + /** + * Test code system lookup returns all properties by default. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupReturnsAllProperties() throws Exception { + // Arrange + final String activeCode = "T100"; + final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode; + + // Act + final String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final Parameters params = parser.parseResource(Parameters.class, content); + + // Assert - should have at least the hardcoded properties (active, parent, child) + final List properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + assertTrue( + properties.size() > 0, + "Should have at least one property (active property should always be present)"); + + // Check that active property is present + final boolean hasActiveProperty = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("active"))); + assertTrue(hasActiveProperty, "Should have 'active' property"); + } + + /** + * Test code system lookup with specific property parameter. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupWithSpecificProperty() throws Exception { + // Arrange + final String activeCode = "T100"; + final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode + "&property=parent"; + + // Act + final String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final Parameters params = parser.parseResource(Parameters.class, content); + + // Assert - should still have name, display, version + assertNotNull(params.getParameter("name")); + assertNotNull(params.getParameter("display")); + assertNotNull(params.getParameter("version")); + + // Should have hardcoded properties (active, parent, child) + final List properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + assertTrue(properties.size() > 0, "Should have properties"); + } + + /** + * Test code system lookup with property parameter filters hardcoded properties correctly. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupPropertyParameterFiltersHardcodedProperties() throws Exception { + // Test 1: Request only parent property + final String activeCode = "T100"; + final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + + String parameters = "?system=" + url + "&code=" + activeCode + "&property=parent"; + String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + Parameters params = parser.parseResource(Parameters.class, content); + + List properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + + // Verify active is present (always included) + boolean hasActive = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("active"))); + assertTrue(hasActive, "Should always have 'active' property"); + + // Verify parent is present (requested) + boolean hasParent = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))); + assertTrue(hasParent, "Should have 'parent' property when requested"); + + // Verify child is NOT present (not requested) + boolean hasChild = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("child"))); + assertFalse(hasChild, "Should NOT have 'child' property when not requested"); + + // Test 2: Request only active property + parameters = "?system=" + url + "&code=" + activeCode + "&property=active"; + content = this.restTemplate.getForObject(endpoint + parameters, String.class); + params = parser.parseResource(Parameters.class, content); + + properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + + // Should only have active, not parent or child + hasActive = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("active"))); + assertTrue(hasActive, "Should have 'active' property"); + + hasParent = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))); + assertFalse(hasParent, "Should NOT have 'parent' when not requested"); + + hasChild = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("child"))); + assertFalse(hasChild, "Should NOT have 'child' when not requested"); + } + + /** + * Test code system lookup displayLanguage parameter not supported. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupDisplayLanguageNotSupported() throws Exception { + // Arrange + final String activeCode = "C3224"; + final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode + "&displayLanguage=en"; + + // Act + String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals("not-supported", component.getCode().toCode()); + assertTrue(component.getDiagnostics().contains("displayLanguage")); + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java index b442810b9..8dea7a1c1 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java @@ -17,6 +17,7 @@ import java.util.Set; import java.util.stream.Collectors; import org.hl7.fhir.r5.model.BooleanType; +import org.hl7.fhir.r5.model.CodeType; import org.hl7.fhir.r5.model.Coding; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; @@ -179,60 +180,6 @@ public void testCodeSystemLookupInstanceCodeWithCoding() throws Exception { assertEquals(version, ((StringType) params.getParameter("version").getValue()).getValue()); } - /** - * Test code system lookup implicit parameter not supported. - * - * @throws Exception the exception - */ - @Test - public void testCodeSystemLookupImplicitParameterNotSupported() throws Exception { - // Arrange - String content; - final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl?fhir_vs"; - final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; - final String parameters = "?url=" + url + "&displayLanguage=notfound"; - - final String messageNotSupported = "Input parameter 'displayLanguage' is not supported."; - final String errorCode = "not-supported"; - - // Act - content = this.restTemplate.getForObject(endpoint + parameters, String.class); - final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); - final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); - - // Assert - assertEquals(errorCode, component.getCode().toCode()); - assertEquals(messageNotSupported, (component.getDiagnostics())); - } - - /** - * Test code system lookup instance parameter not supported. - * - * @throws Exception the exception - */ - @Test - public void testCodeSystemLookupInstanceParameterNotSupported() throws Exception { - // Arrange - String content; - final String activeID = "umlssemnet_2023aa"; - final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl?fhir_vs"; - final String endpoint = - localHost + port + fhirCSPath + "/" + activeID + "/" + JpaConstants.OPERATION_LOOKUP; - final String parameters = "?url=" + url + "&displayLanguage=notfound"; - - final String messageNotSupported = "Input parameter 'displayLanguage' is not supported."; - final String errorCode = "not-supported"; - - // Act - content = this.restTemplate.getForObject(endpoint + parameters, String.class); - final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); - final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); - - // Assert - assertEquals(errorCode, component.getCode().toCode()); - assertEquals(messageNotSupported, (component.getDiagnostics())); - } - /** * Test code system lookup code and display string. * @@ -572,4 +519,203 @@ public void testCodeSystemLookupImplicitCodeWithNoSystem() throws Exception { assertEquals(errorCode, component.getCode().toCode()); assertEquals(messageNotSupported, (component.getDiagnostics())); } + + /** + * Test code system lookup returns all properties when no property parameter specified. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupReturnsAllProperties() throws Exception { + // Arrange + final String activeCode = "C3224"; + final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode; + + // Act + final String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final Parameters params = parser.parseResource(Parameters.class, content); + + // Assert - verify that properties are returned + final List properties = + params.getParameter().stream() + .filter(param -> param.getName().equals("property")) + .collect(Collectors.toList()); + assertFalse(properties.isEmpty(), "Properties should be returned"); + + // Verify that standard properties are included + final Set propertyNames = + properties.stream() + .flatMap(prop -> prop.getPart().stream()) + .filter(part -> part.getName().equals("code")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .collect(Collectors.toSet()); + assertTrue(propertyNames.contains("active"), "Should include 'active' property"); + } + + /** + * Test code system lookup with specific property filter. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupWithSpecificProperty() throws Exception { + // Arrange + final String activeCode = "C3224"; + final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode + "&property=Semantic_Type"; + + // Act + final String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final Parameters params = parser.parseResource(Parameters.class, content); + + // Assert - verify standard fields are returned + assertNotNull(params.getParameter("name"), "Should return 'name' field"); + assertNotNull(params.getParameter("display"), "Should return 'display' field"); + + // Verify that properties are filtered + final List properties = + params.getParameter().stream() + .filter(param -> param.getName().equals("property")) + .collect(Collectors.toList()); + assertFalse(properties.isEmpty(), "Should have properties"); + + // Verify that hardcoded properties are always included + final Set propertyNames = + properties.stream() + .flatMap(prop -> prop.getPart().stream()) + .filter(part -> part.getName().equals("code")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .collect(Collectors.toSet()); + assertTrue( + propertyNames.contains("active"), + "Should include hardcoded 'active' property even with filter"); + } + + /** + * Test code system lookup with property parameter filters hardcoded properties correctly. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupPropertyParameterFiltersHardcodedProperties() throws Exception { + // Test 1: Request only parent property + final String activeCode = "T100"; + final String url = "http://www.nlm.nih.gov/research/umls/umlssemnet.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + + String parameters = "?system=" + url + "&code=" + activeCode + "&property=parent"; + String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + Parameters params = parser.parseResource(Parameters.class, content); + + List properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + + // Verify active is present (always included) + boolean hasActive = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("active"))); + assertTrue(hasActive, "Should always have 'active' property"); + + // Verify parent is present (requested) + boolean hasParent = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))); + assertTrue(hasParent, "Should have 'parent' property when requested"); + + // Verify child is NOT present (not requested) + boolean hasChild = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("child"))); + assertFalse(hasChild, "Should NOT have 'child' property when not requested"); + + // Test 2: Request only active property + parameters = "?system=" + url + "&code=" + activeCode + "&property=active"; + content = this.restTemplate.getForObject(endpoint + parameters, String.class); + params = parser.parseResource(Parameters.class, content); + + properties = + params.getParameter().stream() + .filter(p -> p.getName().equals("property")) + .collect(Collectors.toList()); + + // Should only have active, not parent or child + hasActive = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("active"))); + assertTrue(hasActive, "Should have 'active' property"); + + hasParent = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))); + assertFalse(hasParent, "Should NOT have 'parent' when not requested"); + + hasChild = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("child"))); + assertFalse(hasChild, "Should NOT have 'child' when not requested"); + } + + /** + * Test code system lookup displayLanguage parameter not supported. + * + * @throws Exception the exception + */ + @Test + public void testCodeSystemLookupDisplayLanguageNotSupported() throws Exception { + // Arrange + final String activeCode = "C3224"; + final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; + final String parameters = "?system=" + url + "&code=" + activeCode + "&displayLanguage=en"; + + // Act + String content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final OperationOutcome outcome = parser.parseResource(OperationOutcome.class, content); + final OperationOutcomeIssueComponent component = outcome.getIssueFirstRep(); + + // Assert + assertEquals("not-supported", component.getCode().toCode()); + assertTrue(component.getDiagnostics().contains("displayLanguage")); + } } From d3ed6d8058d9088c3a9e1f54cf6b2a6531e2a991 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 12:12:00 -0800 Subject: [PATCH 18/64] migrate ObjectMapper to ThreadLocalMapper --- .../controller/ErrorHandlerController.java | 4 +- .../evs/api/controller/SearchController.java | 7 +- .../gov/nih/nci/evs/api/model/BaseModel.java | 4 +- .../gov/nih/nci/evs/api/model/Metric.java | 4 +- .../nci/evs/api/model/sparql/Bindings.java | 4 +- .../service/AbstractGraphLoadServiceImpl.java | 4 +- .../evs/api/service/BaseLoaderService.java | 8 +- .../service/GraphReportLoadServiceImpl.java | 3 +- .../MetaOpensearchLoadServiceImpl.java | 4 +- .../MetaSourceOpensearchLoadServiceImpl.java | 4 +- .../api/service/SparqlQueryCacheService.java | 11 +- .../SparqlQueryManagerServiceImpl.java | 73 ++--- .../TermSuggestionFormServiceImpl.java | 12 +- .../evs/api/support/es/OpensearchObject.java | 6 +- .../nci/evs/api/util/ThreadLocalMapper.java | 13 +- .../nih/nci/evs/api/ConceptSampleTester.java | 184 ++++++------ .../nih/nci/evs/api/DynamicMappingTest.java | 4 +- .../nih/nci/evs/api/SerializationTester.java | 5 +- .../nci/evs/api/controller/AuditTests.java | 4 +- .../evs/api/controller/CanmedSampleTest.java | 10 +- .../evs/api/controller/ChebiSampleTest.java | 6 +- .../ConceptControllerExtensionTests.java | 16 +- .../ConceptControllerIncludeTests.java | 39 +-- .../controller/ConceptControllerTests.java | 177 ++++++------ .../evs/api/controller/Ctcae5SampleTest.java | 6 +- .../evs/api/controller/Ctcae6SampleTest.java | 6 +- .../DocumentationPayloadExamplesTests.java | 3 +- .../nci/evs/api/controller/DuoSampleTest.java | 12 +- .../nci/evs/api/controller/GoSampleTest.java | 8 +- .../evs/api/controller/HgncSampleTest.java | 6 +- .../controller/HistoryControllerTests.java | 24 +- .../evs/api/controller/Icd10SampleTest.java | 4 +- .../evs/api/controller/Icd10cmSampleTest.java | 4 +- .../evs/api/controller/Icd9cmSampleTest.java | 4 +- .../nci/evs/api/controller/LncSampleTest.java | 8 +- .../api/controller/MapsetControllerTests.java | 62 ++-- .../api/controller/MdrControllerTests.java | 61 ++-- .../nci/evs/api/controller/MdrSampleTest.java | 16 +- .../evs/api/controller/MedrtSampleTest.java | 6 +- .../MetadataControllerIncludeTests.java | 25 +- .../controller/MetadataControllerTests.java | 273 +++++++++--------- .../evs/api/controller/MgedSampleTest.java | 8 +- .../controller/MouseAnatomySampleTest.java | 6 +- .../api/controller/NcimControllerTests.java | 85 +++--- .../evs/api/controller/NcimSampleTest.java | 10 +- .../evs/api/controller/NcitSampleTest.java | 14 +- .../evs/api/controller/NdfrtSampleTest.java | 6 +- .../nci/evs/api/controller/NpoSampleTest.java | 6 +- .../nci/evs/api/controller/ObiSampleTest.java | 10 +- .../evs/api/controller/ObibSampleTest.java | 12 +- .../nci/evs/api/controller/PdqSampleTest.java | 4 +- .../evs/api/controller/QualifierTests.java | 31 +- .../api/controller/SearchControllerTests.java | 264 ++++++++--------- .../api/controller/SnomedctUsSampleTest.java | 6 +- .../api/controller/SubsetControllerTests.java | 55 ++-- ...ermSuggestionFormControllerEmailTests.java | 3 +- .../TermSuggestionFormControllerTests.java | 2 +- .../api/controller/UmlssemnetSampleTest.java | 6 +- .../controller/VersionControllerTests.java | 6 +- .../api/controller/ZebrafishSampleTest.java | 6 +- .../evs/api/fhir/FhirR4ClientSDKTests.java | 3 +- .../FhirR4CodeSystemGeneralOperations.java | 3 +- .../api/fhir/FhirR4CodeSystemLookupTests.java | 11 +- .../fhir/FhirR4CodeSystemReadSearchTests.java | 11 +- .../fhir/FhirR4CodeSystemSubsumesTests.java | 11 +- .../fhir/FhirR4CodeSystemValidateTests.java | 11 +- .../FhirR4ConceptMapGeneralOperations.java | 8 +- .../fhir/FhirR4ConceptMapReadSearchTests.java | 11 +- .../fhir/FhirR4ConceptMapTranslateTests.java | 11 +- .../api/fhir/FhirR4ValueSetExpandTests.java | 11 +- .../fhir/FhirR4ValueSetGeneralOperations.java | 8 +- .../fhir/FhirR4ValueSetReadSearchTests.java | 11 +- .../api/fhir/FhirR4ValueSetValidateTests.java | 11 +- .../evs/api/fhir/FhirR5ClientSDKTests.java | 13 +- .../FhirR5CodeSystemGeneralOperations.java | 8 +- .../api/fhir/FhirR5CodeSystemLookupTests.java | 11 +- .../fhir/FhirR5CodeSystemReadSearchTests.java | 8 +- .../fhir/FhirR5CodeSystemSubsumesTests.java | 11 +- .../fhir/FhirR5CodeSystemValidateTests.java | 11 +- .../FhirR5ConceptMapGeneralOperations.java | 8 +- .../fhir/FhirR5ConceptMapReadSearchTests.java | 8 +- .../fhir/FhirR5ConceptMapTranslateTests.java | 11 +- .../api/fhir/FhirR5ValueSetExpandTests.java | 9 +- .../fhir/FhirR5ValueSetGeneralOperations.java | 8 +- .../fhir/FhirR5ValueSetReadSearchTests.java | 8 +- .../api/fhir/FhirR5ValueSetValidateTests.java | 11 +- .../nci/evs/api/model/EmailDetailsTest.java | 8 +- .../evs/api/service/ConceptMappingTest.java | 4 +- .../evs/api/service/HierarchyUtilsTest.java | 6 +- .../api/service/MainTypeHierarchyTest.java | 1 - .../TermSuggestionFormServiceTest.java | 10 +- .../evs/api/util/TerminologyUtilsTest.java | 3 +- 92 files changed, 845 insertions(+), 1107 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/controller/ErrorHandlerController.java b/src/main/java/gov/nih/nci/evs/api/controller/ErrorHandlerController.java index b6d5dcc70..6dcc90e4d 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/ErrorHandlerController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/ErrorHandlerController.java @@ -1,6 +1,6 @@ package gov.nih.nci.evs.api.controller; -import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import io.swagger.v3.oas.annotations.Hidden; import jakarta.servlet.http.HttpServletRequest; import java.util.Map; @@ -67,7 +67,7 @@ public String handleErrorHtml(final HttpServletRequest request) { } String ppBody = null; try { - ppBody = new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(body); + ppBody = ThreadLocalMapper.get().writerWithDefaultPrettyPrinter().writeValueAsString(body); } catch (Exception e) { ppBody = body.toString(); } diff --git a/src/main/java/gov/nih/nci/evs/api/controller/SearchController.java b/src/main/java/gov/nih/nci/evs/api/controller/SearchController.java index dc77a8498..d1de80854 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/SearchController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/SearchController.java @@ -21,6 +21,7 @@ import gov.nih.nci.evs.api.util.ConceptUtils; import gov.nih.nci.evs.api.util.RESTUtils; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameters; @@ -884,7 +885,7 @@ public void postInit() throws Exception { } termUtils.checkLicense(term, license); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); try { final String sparqlQuery = queryBuilderService.prepSparql(term, query, prefixes); @@ -1080,7 +1081,7 @@ public void postInit() throws Exception { + "characters (if using curl use --data-binary instead of -d)"); } - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); String sparqlQuery = queryBuilderService.prepSparql(term, query, prefixes); // The following messages up "total" - so we need to either find it another way from @@ -1169,7 +1170,7 @@ public void postInit() throws Exception { } final String prefixes = queryBuilderService.constructPrefix(term).replaceAll("\\r", ""); return new ResponseEntity<>( - new ObjectMapper().writeValueAsString(prefixes), new HttpHeaders(), HttpStatus.OK); + ThreadLocalMapper.get().writeValueAsString(prefixes), new HttpHeaders(), HttpStatus.OK); } catch (final Exception e) { handleException(e, terminology); diff --git a/src/main/java/gov/nih/nci/evs/api/model/BaseModel.java b/src/main/java/gov/nih/nci/evs/api/model/BaseModel.java index 5df50df8c..d93a9a08b 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/BaseModel.java +++ b/src/main/java/gov/nih/nci/evs/api/model/BaseModel.java @@ -1,6 +1,6 @@ package gov.nih.nci.evs.api.model; -import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import io.swagger.v3.oas.annotations.media.Schema; import org.springframework.data.annotation.Transient; @@ -81,7 +81,7 @@ public void setCt(Integer ct) { @Override public String toString() { try { - return new ObjectMapper().writeValueAsString(this); + return ThreadLocalMapper.get().writeValueAsString(this); } catch (final Exception e) { return e.getMessage(); } diff --git a/src/main/java/gov/nih/nci/evs/api/model/Metric.java b/src/main/java/gov/nih/nci/evs/api/model/Metric.java index 5fb8afca1..913ce3ae3 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/Metric.java +++ b/src/main/java/gov/nih/nci/evs/api/model/Metric.java @@ -1,7 +1,7 @@ package gov.nih.nci.evs.api.model; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import io.swagger.v3.oas.annotations.media.Schema; import java.util.Date; import java.util.Map; @@ -192,7 +192,7 @@ public void setGeoPoint(GeoPoint geoPoint) { @Override public String toString() { try { - return new ObjectMapper().writeValueAsString(this); + return ThreadLocalMapper.get().writeValueAsString(this); } catch (final Exception e) { return e.getMessage(); } diff --git a/src/main/java/gov/nih/nci/evs/api/model/sparql/Bindings.java b/src/main/java/gov/nih/nci/evs/api/model/sparql/Bindings.java index fed488087..3e4ffdc38 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/sparql/Bindings.java +++ b/src/main/java/gov/nih/nci/evs/api/model/sparql/Bindings.java @@ -1,6 +1,6 @@ package gov.nih.nci.evs.api.model.sparql; -import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; /** Bindings for sparql queries. */ public class Bindings { @@ -307,7 +307,7 @@ public void setSuperclassLabel(Property superclassLabel) { @Override public String toString() { try { - return new ObjectMapper().writeValueAsString(this); + return ThreadLocalMapper.get().writeValueAsString(this); } catch (final Exception e) { return e.getMessage(); } diff --git a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java index df5f62d7e..1ac32ab69 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java @@ -1,7 +1,6 @@ package gov.nih.nci.evs.api.service; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.AssociationEntry; import gov.nih.nci.evs.api.model.Audit; @@ -18,6 +17,7 @@ import gov.nih.nci.evs.api.support.es.OpensearchLoadConfig; import gov.nih.nci.evs.api.support.es.OpensearchObject; import gov.nih.nci.evs.api.util.*; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.BufferedReader; import java.io.FileInputStream; import java.io.IOException; @@ -873,7 +873,7 @@ public Terminology getTerminology( // Load from config final JsonNode node = getMetadataAsNode(terminology.toLowerCase()); final TerminologyMetadata metadata = - new ObjectMapper().treeToValue(node, TerminologyMetadata.class); + ThreadLocalMapper.get().treeToValue(node, TerminologyMetadata.class); // Set term name and description term.setName(metadata.getUiLabel() + " " + term.getVersion()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java index deb77d1e2..4f6718c74 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java @@ -1,7 +1,6 @@ package gov.nih.nci.evs.api.service; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Audit; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Mapping; @@ -12,6 +11,7 @@ import gov.nih.nci.evs.api.support.es.OpensearchLoadConfig; import gov.nih.nci.evs.api.util.EVSUtils; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.IOException; import java.util.Arrays; import java.util.Collections; @@ -457,7 +457,7 @@ protected void setConceptInactive(final Terminology term, final Concept concept) * @throws Exception the exception */ public TerminologyMetadata getMetadata(final String terminology) throws Exception { - return new ObjectMapper() + return ThreadLocalMapper.get() .treeToValue(getMetadataAsNode(terminology), TerminologyMetadata.class); } @@ -477,7 +477,7 @@ public JsonNode getMetadataAsNode(final String terminology) throws Exception { + termUtils.getTerminologyName(terminology) + ".json"; logger.info(" get config for " + terminology + " = " + uri); - return new ObjectMapper().readTree(EVSUtils.getValueFromFile(uri)); + return ThreadLocalMapper.get().readTree(EVSUtils.getValueFromFile(uri)); } /** @@ -492,7 +492,7 @@ public JsonNode getMetadataAsNodeLocal(final String terminology) throws Exceptio // If terminology is {term}_{version} -> strip the version final String uri = "src/test/resources/" + termUtils.getTerminologyName(terminology) + ".json"; logger.info(" get config for " + terminology + " = " + uri); - return new ObjectMapper().readTree(StringUtils.join(EVSUtils.getValueFromFile(uri), '\n')); + return ThreadLocalMapper.get().readTree(StringUtils.join(EVSUtils.getValueFromFile(uri), '\n')); } /** diff --git a/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java index 4a5261dfe..b405827a3 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/GraphReportLoadServiceImpl.java @@ -10,6 +10,7 @@ import gov.nih.nci.evs.api.support.es.OpensearchLoadConfig; import gov.nih.nci.evs.api.util.HierarchyUtils; import gov.nih.nci.evs.api.util.MainTypeHierarchy; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -39,7 +40,7 @@ public class GraphReportLoadServiceImpl extends AbstractGraphLoadServiceImpl { private static final Logger logger = LoggerFactory.getLogger(GraphReportLoadServiceImpl.class); /** The mapper. */ - private ObjectMapper mapper = new ObjectMapper(); + private ObjectMapper mapper = ThreadLocalMapper.get(); /** The lines. */ private List lines = new ArrayList<>(); diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetaOpensearchLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/MetaOpensearchLoadServiceImpl.java index 92c41c3a1..b96fed872 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetaOpensearchLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetaOpensearchLoadServiceImpl.java @@ -1,7 +1,6 @@ package gov.nih.nci.evs.api.service; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.Audit; import gov.nih.nci.evs.api.model.Concept; @@ -24,6 +23,7 @@ import gov.nih.nci.evs.api.util.PushBackReader; import gov.nih.nci.evs.api.util.RrfReaders; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -1534,7 +1534,7 @@ public Terminology getTerminology( // Load from config final JsonNode node = getMetadataAsNode(terminology.toLowerCase()); final TerminologyMetadata metadata = - new ObjectMapper().treeToValue(node, TerminologyMetadata.class); + ThreadLocalMapper.get().treeToValue(node, TerminologyMetadata.class); // Set term name and description term.setName(metadata.getUiLabel() + " " + term.getVersion()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/MetaSourceOpensearchLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/MetaSourceOpensearchLoadServiceImpl.java index f7f39f585..1a113e65b 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/MetaSourceOpensearchLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/MetaSourceOpensearchLoadServiceImpl.java @@ -1,7 +1,6 @@ package gov.nih.nci.evs.api.service; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Definition; @@ -14,6 +13,7 @@ import gov.nih.nci.evs.api.support.es.OpensearchLoadConfig; import gov.nih.nci.evs.api.support.es.OpensearchObject; import gov.nih.nci.evs.api.util.*; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -1410,7 +1410,7 @@ public Terminology getTerminology( // Load from config final JsonNode node = getMetadataAsNode(terminology.toLowerCase()); final TerminologyMetadata metadata = - new ObjectMapper().treeToValue(node, TerminologyMetadata.class); + ThreadLocalMapper.get().treeToValue(node, TerminologyMetadata.class); // Set term name and description term.setName(metadata.getUiLabel() + " " + term.getVersion()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java index b4afedd94..5869f2c90 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java @@ -1,6 +1,5 @@ package gov.nih.nci.evs.api.service; -import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.IncludeParam; @@ -14,6 +13,7 @@ import gov.nih.nci.evs.api.util.EVSUtils; import gov.nih.nci.evs.api.util.HierarchyUtils; import gov.nih.nci.evs.api.util.RESTUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -62,8 +62,7 @@ public List getHierarchy( final String res = restUtils.runSPARQL(queryPrefix + query, sparqlQueryManagerService.getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final ObjectMapper mapper = ThreadLocalMapper.get(); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); final Bindings[] bindings = sparqlResult.getResults().getBindings(); @@ -129,8 +128,7 @@ private List getHierarchyRoleHelper( final String res = restUtils.runSPARQL(queryPrefix + query, sparqlQueryManagerService.getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final ObjectMapper mapper = ThreadLocalMapper.get(); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); final Bindings[] bindings = sparqlResult.getResults().getBindings(); @@ -190,8 +188,7 @@ public List getAllQualifiers( final String res = restUtils.runSPARQL(queryPrefix + query, sparqlQueryManagerService.getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); - mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); + final ObjectMapper mapper = ThreadLocalMapper.get(); final List qualifiers = new ArrayList<>(); final List concepts = new ArrayList<>(); diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index 7f02e2181..55301135f 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -32,6 +32,7 @@ import gov.nih.nci.evs.api.util.HierarchyUtils; import gov.nih.nci.evs.api.util.RESTUtils; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import jakarta.annotation.PostConstruct; import java.io.IOException; import java.text.ParseException; @@ -149,7 +150,7 @@ public List getAllGraphNames() throws Exception { final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); log.debug("getAllGraphNames response - " + res); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); final Bindings[] bindings = sparqlResult.getResults().getBindings(); @@ -183,7 +184,7 @@ public List getTerminologies(final String db) throws Exception, Par // if (log.isDebugEnabled()) { // log.debug("getTerminologies response - " + res); // } - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List termList = new ArrayList<>(); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); @@ -765,7 +766,7 @@ public List getProperties(final String conceptCode, final Terminology final String query = queryBuilderService.constructQuery("properties", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List properties = new ArrayList<>(); @@ -814,7 +815,7 @@ private Map> getProperties( queryBuilderService.constructBatchQuery("properties.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -853,7 +854,7 @@ public List getChildren(final String conceptCode, final Terminology ter final String query = queryBuilderService.constructQuery("children", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List children = new ArrayList<>(); @@ -907,7 +908,7 @@ public List getParents(final String conceptCode, final Terminology term final String query = queryBuilderService.constructQuery("parents", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List parents = new ArrayList<>(); @@ -962,7 +963,7 @@ public List getAssociations(final String conceptCode, final Termino queryBuilderService.constructQuery("associations", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List associations = new ArrayList<>(); @@ -995,7 +996,7 @@ public Map> getAssociations( queryBuilderService.constructBatchQuery("associations.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1032,7 +1033,7 @@ public Map> getAssociationsForAllCodes( queryBuilderService.constructBatchQuery("associations.all", terminology, new ArrayList<>()); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1073,7 +1074,7 @@ public List getInverseAssociations( queryBuilderService.constructQuery("inverse.associations", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List associations = new ArrayList<>(); @@ -1108,7 +1109,7 @@ public Map> getInverseAssociations( "inverse.associations.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1145,7 +1146,7 @@ public List getInverseRoles(final String conceptCode, final Terminology te // log.info("INVERSE ROLE REPORT QUERY = {}", query); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List roles = new ArrayList<>(); @@ -1191,7 +1192,7 @@ public Map> getInverseRoles( final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1235,7 +1236,7 @@ public List getRoles(final String conceptCode, final Terminology terminolo final String query = queryBuilderService.constructQuery("roles", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List roles = new ArrayList<>(); @@ -1281,7 +1282,7 @@ public Map> getRoles( queryBuilderService.constructBatchQuery("roles.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1333,7 +1334,7 @@ public Map> getComplexRolesForAllCodes( } final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1392,7 +1393,7 @@ public List getDisjointWith(final String conceptCode, final Termin queryBuilderService.constructQuery("disjoint.with", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List disjointWithList = new ArrayList<>(); @@ -1424,7 +1425,7 @@ public Map> getDisjointWith( queryBuilderService.constructBatchQuery("disjoint.with.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1458,7 +1459,7 @@ public List getAxioms( final String queryPrefix = queryBuilderService.constructPrefix(terminology); final String query = queryBuilderService.constructQuery("axioms", terminology, conceptCode); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List axioms = new ArrayList<>(); @@ -1507,7 +1508,7 @@ private Map> getAxioms( queryBuilderService.constructBatchQuery("axioms.batch", terminology, conceptCodes); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); // log.info("AXIOM QUERY: {}", queryPrefix + query); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Map> resultMap = new HashMap<>(); @@ -1784,7 +1785,7 @@ public List getAllProperties(final Terminology terminology, final Inclu final String query = queryBuilderService.constructQuery("all.properties", terminology); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List properties = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -1870,7 +1871,7 @@ public List getRemodeledProperties(final Terminology terminology, final final String query = queryBuilderService.constructQuery("all.properties", terminology); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List properties = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -1919,7 +1920,7 @@ public List getNeverUsedProperties(final Terminology terminology, final queryBuilderService.constructQuery("all.properties.never.used", terminology); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List properties = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -1980,7 +1981,7 @@ public List getDistinctPropertyValues( queryBuilderService.constructQuery("distinct.property.values", terminology, values); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List propertyValues = new ArrayList<>(); @@ -2002,7 +2003,7 @@ public List getRemodeledQualifiers(final Terminology terminology, final final String query = queryBuilderService.constructQuery("all.qualifiers", terminology); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List qualifiers = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -2048,7 +2049,7 @@ public List getQualifierValues(final String propertyCode, final Terminol final String query = queryBuilderService.constructQuery("axiom.qualifier", terminology, values); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List propertyValues = new ArrayList<>(); @@ -2073,7 +2074,7 @@ public List getPropertyValues(final String propertyCode, final Terminolo queryBuilderService.constructQuery("concept.property.values", terminology, values); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List propertyValues = new ArrayList<>(); @@ -2112,7 +2113,7 @@ public List getSubsetMembers(final String subsetCode, final Terminology final String query = queryBuilderService.constructQuery("subset", terminology, values); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List subsetMembers = new ArrayList<>(); @@ -2136,7 +2137,7 @@ public List getAllAssociations(final Terminology terminology, final Inc final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List associations = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -2174,7 +2175,7 @@ public List getAllRoles(final Terminology terminology, final IncludePar final String query = queryBuilderService.constructQuery("all.roles", terminology); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List roles = new ArrayList<>(); final List concepts = new ArrayList<>(); @@ -2387,7 +2388,7 @@ public List getSynonymSources(final Terminology terminology) thr terminology.getMetadata().getRetiredStatusValue())); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List sources = new ArrayList<>(); final Map map = terminology.getMetadata().getSources(); @@ -2436,7 +2437,7 @@ public List getTermTypes(final Terminology terminology) throws E terminology.getMetadata().getRetiredStatusValue())); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List sources = new ArrayList<>(); final Map map = terminology.getMetadata().getTermTypes(); @@ -2483,7 +2484,7 @@ public List getDefinitionSources(final Terminology terminology) terminology.getMetadata().getRetiredStatusValue())); final String res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List sources = new ArrayList<>(); // Documentation on source definitions @@ -2518,7 +2519,7 @@ public List getAllConceptsWithCode(final Terminology terminology) throw String res = null; res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); @@ -2554,7 +2555,7 @@ public List getAllConceptsWithoutCode(final Terminology terminology) th String res = null; res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final Sparql sparqlResult = mapper.readValue(res, Sparql.class); @@ -2643,7 +2644,7 @@ public List getAssociationEntries( String res = null; res = restUtils.runSPARQL(queryPrefix + query, getQueryURL()); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); final List entries = new ArrayList<>(); Sparql sparqlResult = null; diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 9b1f9aedc..4a34c162e 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -1,11 +1,11 @@ package gov.nih.nci.evs.api.service; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import gov.nih.nci.evs.api.model.EmailDetails; import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.util.EVSUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import jakarta.mail.Message.RecipientType; import jakarta.mail.MessagingException; import jakarta.mail.internet.InternetAddress; @@ -45,9 +45,6 @@ public class TermSuggestionFormServiceImpl implements TermSuggestionFormService // path for the form file URL formFilePath; - /** The object mapper to read the config url with readTree. */ - private final ObjectMapper mapper = new ObjectMapper(); - /** Pattern for optional instruction sheets with date suffix. */ private static final Pattern INSTRUCTION_PATTERN = Pattern.compile(".*\\d{4}_\\d{2}_\\d{2} Instructions$"); @@ -57,12 +54,9 @@ public class TermSuggestionFormServiceImpl implements TermSuggestionFormService * * @param mailSender java mail sender * @param applicationProperties the application properties - * @param mapper the mapper */ public TermSuggestionFormServiceImpl( - final JavaMailSender mailSender, - final ApplicationProperties applicationProperties, - final ObjectMapper mapper) { + final JavaMailSender mailSender, final ApplicationProperties applicationProperties) { this.mailSender = mailSender; this.applicationProperties = applicationProperties; } @@ -87,7 +81,7 @@ public JsonNode getFormTemplate(final String formType) throws Exception { String json = EVSUtils.getValueFromFile( applicationProperties.getConfigBaseUri() + "/" + formType + ".json"); - final JsonNode termForm = mapper.readTree(json); + final JsonNode termForm = ThreadLocalMapper.get().readTree(json); // Get the recaptcha_site_key from application properties final String recaptchaSiteKey = applicationProperties.getRecaptchaSiteKey(); diff --git a/src/main/java/gov/nih/nci/evs/api/support/es/OpensearchObject.java b/src/main/java/gov/nih/nci/evs/api/support/es/OpensearchObject.java index 5f8132c6e..2043bf39e 100644 --- a/src/main/java/gov/nih/nci/evs/api/support/es/OpensearchObject.java +++ b/src/main/java/gov/nih/nci/evs/api/support/es/OpensearchObject.java @@ -4,7 +4,6 @@ import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.AssociationEntry; import gov.nih.nci.evs.api.model.BaseModel; import gov.nih.nci.evs.api.model.Concept; @@ -12,6 +11,7 @@ import gov.nih.nci.evs.api.model.Paths; import gov.nih.nci.evs.api.model.StatisticsEntry; import gov.nih.nci.evs.api.util.HierarchyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -209,7 +209,7 @@ public Map> getMap() throws Exception { return new HashMap<>(); } // Turn back into a map - return new ObjectMapper() + return ThreadLocalMapper.get() .readValue( mapString.substring(1), new TypeReference>>() { @@ -229,7 +229,7 @@ public void setMap(Map> map) throws Exception { } else { // The X is to trick opensearch into avoiding trying to index this like // a map - this.mapString = "X" + new ObjectMapper().writeValueAsString(map); + this.mapString = "X" + ThreadLocalMapper.get().writeValueAsString(map); } } diff --git a/src/main/java/gov/nih/nci/evs/api/util/ThreadLocalMapper.java b/src/main/java/gov/nih/nci/evs/api/util/ThreadLocalMapper.java index 54ff2b98a..ebff0d536 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/ThreadLocalMapper.java +++ b/src/main/java/gov/nih/nci/evs/api/util/ThreadLocalMapper.java @@ -1,15 +1,21 @@ package gov.nih.nci.evs.api.util; import com.fasterxml.jackson.annotation.JsonInclude.Include; +import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import java.util.TimeZone; /** Supply object mapper per thread. */ -public class ThreadLocalMapper { +public final class ThreadLocalMapper { + + /** Instantiates a new thread local mapper. */ + private ThreadLocalMapper() { + // n/a + } /** The Constant mapper. */ - private static final ThreadLocal mapper = + private static final ThreadLocal MAPPER = ThreadLocal.withInitial(ThreadLocalMapper::newMapper); /** @@ -24,6 +30,7 @@ public static ObjectMapper newMapper() { .findAndRegisterModules() .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false); mapper.setTimeZone(TimeZone.getDefault()); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); return mapper; } @@ -33,6 +40,6 @@ public static ObjectMapper newMapper() { * @return the object mapper */ public static ObjectMapper get() { - return mapper.get(); + return MAPPER.get(); } } diff --git a/src/test/java/gov/nih/nci/evs/api/ConceptSampleTester.java b/src/test/java/gov/nih/nci/evs/api/ConceptSampleTester.java index e651a62e5..9392f9a0e 100644 --- a/src/test/java/gov/nih/nci/evs/api/ConceptSampleTester.java +++ b/src/test/java/gov/nih/nci/evs/api/ConceptSampleTester.java @@ -6,7 +6,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.AssociationEntryResultList; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.ConceptResultList; @@ -15,6 +14,7 @@ import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -118,15 +118,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List associations = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get qualifiers url = baseMetadataUrl + term + "/qualifiers?include=minimal"; @@ -136,7 +136,7 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List qualifiers = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -176,15 +176,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List roles = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get synonym term types url = baseMetadataUrl + term + "/termTypes?include=minimal"; @@ -194,15 +194,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List termTypes = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get synonym sources url = baseMetadataUrl + term + "/synonymSources?include=minimal"; @@ -212,15 +212,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List synonymSources = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get definition types url = baseMetadataUrl + term + "/definitionTypes?include=minimal"; @@ -230,15 +230,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List definitionTypes = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get definition sources url = baseMetadataUrl + term + "/definitionSources?include=minimal"; @@ -248,15 +248,15 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List definitionSources = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(entry -> entry.getCode()) - .collect(Collectors.toList()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(entry -> entry.getCode()) + .collect(Collectors.toList()); // get properties url = baseMetadataUrl + term + "/properties?include=properties"; @@ -266,7 +266,7 @@ public void performMetadataTests( .andReturn(); content = result.getResponse().getContentAsString(); List properties = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -479,7 +479,7 @@ public void performContentTests( .andReturn(); content = result.getResponse().getContentAsString(StandardCharsets.UTF_8); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(content).isNotNull(); log.info(content); @@ -490,7 +490,7 @@ public void performContentTests( .andReturn(); content = result.getResponse().getContentAsString(); List properties = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -507,7 +507,7 @@ public void performContentTests( .andReturn(); content = result.getResponse().getContentAsString(); List associations = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -736,7 +736,7 @@ private boolean checkSubsetLink(final String conceptCode, final SampleRecord sam .andExpect(status().isOk()) .andReturn(); String content = result.getResponse().getContentAsString(); - Concept concept = new ObjectMapper().readValue(content, Concept.class); + Concept concept = ThreadLocalMapper.get().readValue(content, Concept.class); return concept.getSubsetLink().equals(link); } return false; @@ -984,7 +984,7 @@ private boolean checkOther( if (content.equals("[]")) { return false; } - final Concept otherProperty = new ObjectMapper().readValue(content, Concept.class); + final Concept otherProperty = ThreadLocalMapper.get().readValue(content, Concept.class); url = "/api/v1/metadata/" @@ -999,7 +999,7 @@ private boolean checkOther( .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - final Concept otherQualifier = new ObjectMapper().readValue(content, Concept.class); + final Concept otherQualifier = ThreadLocalMapper.get().readValue(content, Concept.class); return concept.getProperties().stream() .filter( o -> @@ -1088,7 +1088,7 @@ private boolean checkSynonymMetadata( if (content.equals("[]")) { return false; } - final Concept otherProperty = new ObjectMapper().readValue(content, Concept.class); + final Concept otherProperty = ThreadLocalMapper.get().readValue(content, Concept.class); url = "/api/v1/metadata/" @@ -1103,7 +1103,7 @@ private boolean checkSynonymMetadata( .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - final Concept otherQualifier = new ObjectMapper().readValue(content, Concept.class); + final Concept otherQualifier = ThreadLocalMapper.get().readValue(content, Concept.class); return concept.getSynonyms().stream() .filter( o -> @@ -1345,7 +1345,7 @@ private boolean checkRole(final Concept concept, final SampleRecord sample) thro .andReturn(); final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); - final Concept minMatchedRole = new ObjectMapper().readValue(content, Concept.class); + final Concept minMatchedRole = ThreadLocalMapper.get().readValue(content, Concept.class); final Role conceptMatchedRole = concept.getRoles().stream() .filter( @@ -1410,7 +1410,7 @@ public void performPathsSubtreeAndRootsTests( .andReturn(); content = result.getResponse().getContentAsString(); List roots = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1438,7 +1438,7 @@ public void performPathsSubtreeAndRootsTests( ancestorCode = null; List reverseToRootPath = null; List> pathsToRoot = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1490,7 +1490,7 @@ public void performPathsSubtreeAndRootsTests( List fromRootPath = null; Boolean reversePathFound = false; List> pathsFromRoot = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1541,7 +1541,7 @@ public void performPathsSubtreeAndRootsTests( .andReturn(); content = result.getResponse().getContentAsString(); pathsFromRoot = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1571,7 +1571,7 @@ public void performPathsSubtreeAndRootsTests( .andReturn(); content = result.getResponse().getContentAsString(); List> pathsToAncestor = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1610,7 +1610,7 @@ public void performPathsSubtreeAndRootsTests( .andReturn(); content = result.getResponse().getContentAsString(); List subtree = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1635,7 +1635,7 @@ public void performPathsSubtreeAndRootsTests( .andReturn(); content = result.getResponse().getContentAsString(); List children = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1698,7 +1698,7 @@ public void performSearchTests( .andReturn(); content = result.getResponse().getContentAsString(); testConcept = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -1731,7 +1731,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); assertThat( list.getConcepts().stream() @@ -1749,7 +1749,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); assertThat( list.getConcepts().stream() @@ -1768,7 +1768,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); for (Concept conc : list.getConcepts()) { assertThat( @@ -1790,7 +1790,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); for (Concept conc : list.getConcepts()) { assertThat( @@ -1812,7 +1812,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); for (Concept conc : list.getConcepts()) { assertThat( @@ -1834,7 +1834,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); for (Concept conc : list.getConcepts()) { assertThat( @@ -1857,7 +1857,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); for (Concept conc : list.getConcepts()) { assertThat( @@ -1881,7 +1881,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); assertThat(list.getConcepts().size()).isLessThanOrEqualTo(6); if (list.getConcepts().size() > 10) { @@ -1899,7 +1899,7 @@ public void performSearchTests( .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() > 0); assertThat(list.getConcepts().get(0)).isEqualTo(eleventhConcept); } @@ -1950,7 +1950,7 @@ public void performSubsetsTests( .andReturn(); String content = result.getResponse().getContentAsString(); List roots = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1997,7 +1997,7 @@ public void performSubsetsTests( .andReturn(); content = result.getResponse().getContentAsString(); Concept firstLeaf = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -2040,7 +2040,7 @@ public void performSubsetsTests( .andReturn(); content = result.getResponse().getContentAsString(); List firstLeafMembers = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2097,7 +2097,7 @@ public String getLeafCode(Concept root) throws Exception { .andReturn(); String content = result.getResponse().getContentAsString(); Concept rootSubset = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -2148,7 +2148,7 @@ public void performAssociationEntryTests( String content = result.getResponse().getContentAsString(); List associations = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2181,7 +2181,7 @@ public void performAssociationEntryTests( .andReturn(); content = result.getResponse().getContentAsString(); AssociationEntryResultList fullFirstAssociationByCode = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -2200,7 +2200,7 @@ public void performAssociationEntryTests( .andReturn(); content = result.getResponse().getContentAsString(); AssociationEntryResultList fullFirstAssociationByName = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -2229,7 +2229,7 @@ public void performAssociationEntryTests( .andReturn(); content = result.getResponse().getContentAsString(); AssociationEntryResultList firstFromRecord = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -2245,7 +2245,7 @@ public void performAssociationEntryTests( result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); AssociationEntryResultList secondFromRecord = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { diff --git a/src/test/java/gov/nih/nci/evs/api/DynamicMappingTest.java b/src/test/java/gov/nih/nci/evs/api/DynamicMappingTest.java index 8257c8320..144f1f58f 100644 --- a/src/test/java/gov/nih/nci/evs/api/DynamicMappingTest.java +++ b/src/test/java/gov/nih/nci/evs/api/DynamicMappingTest.java @@ -2,13 +2,13 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.IncludeParam; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.service.OpensearchOperationsService; import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.apache.commons.io.IOUtils; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -61,7 +61,7 @@ public class DynamicMappingTest { public void testConceptDynamicMapping() throws Exception { // SETUP Concept concept = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( IOUtils.toString( getClass().getClassLoader().getResource("conceptTestDM.json"), "UTF-8"), diff --git a/src/test/java/gov/nih/nci/evs/api/SerializationTester.java b/src/test/java/gov/nih/nci/evs/api/SerializationTester.java index 0ecf95cb5..9a9a74f16 100644 --- a/src/test/java/gov/nih/nci/evs/api/SerializationTester.java +++ b/src/test/java/gov/nih/nci/evs/api/SerializationTester.java @@ -1,7 +1,7 @@ package gov.nih.nci.evs.api; -import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.lang.reflect.Method; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -30,8 +30,7 @@ public SerializationTester(final Object obj) { public boolean testJsonSerialization() throws Exception { logger.debug("Test json serialization - " + getClazz().getName()); final Object obj = createObject(1); - final ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(Include.NON_EMPTY); + final ObjectMapper mapper = ThreadLocalMapper.get(); logger.debug(" " + obj); final String json = mapper.writeValueAsString(obj); logger.info("json = " + json); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/AuditTests.java b/src/test/java/gov/nih/nci/evs/api/controller/AuditTests.java index 25ab56aad..324022e23 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/AuditTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/AuditTests.java @@ -7,12 +7,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Audit; import gov.nih.nci.evs.api.model.SearchCriteria; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.service.OpensearchQueryServiceImpl; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.Test; @@ -61,7 +61,7 @@ public void testGetAllAudits() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/CanmedSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/CanmedSampleTest.java index c5ce6c4cc..5c0f2da3b 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/CanmedSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/CanmedSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testCANMEDTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -112,7 +112,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("NDC_16729-0131-30"); assertThat(concept.getName()).isEqualTo("FLUDARABINE 25.0 mg/mL"); @@ -138,7 +138,7 @@ public void testHcpcsCodeThing() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("J9017"); @@ -170,7 +170,7 @@ public void testHcpcsCodeThing() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("HCPCS_ABEMACICLIB_200_MG"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java index 97ace2d5d..e3ee1581c 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testCHEBITerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -115,7 +115,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CHEBI:104926"); assertThat(concept.getTerminology()).isEqualTo("chebi"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerExtensionTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerExtensionTests.java index 8e7c844e3..db1f002ef 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerExtensionTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerExtensionTests.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.InputStream; import java.util.HashMap; import java.util.List; @@ -23,7 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -43,9 +43,6 @@ public class ConceptControllerExtensionTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -53,9 +50,6 @@ public class ConceptControllerExtensionTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/concept"; } @@ -116,7 +110,7 @@ public void testHelper(final String codeSetPath, final String resultPath) throws String content = null; Concept concept = null; final Map map = new HashMap<>(); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); int ct = 0; try (final InputStream is = getClass().getClassLoader().getResourceAsStream(codeSetPath)) { for (final String code : IOUtils.readLines(is, "UTF-8")) { @@ -127,7 +121,7 @@ public void testHelper(final String codeSetPath, final String resultPath) throws url = baseUrl + "/ncit/" + code + "?include=extensions"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); // For comparing main menu ancestors, null all concept fields in paths // except for the codes concept.getExtensions().getMainMenuAncestors().stream() @@ -170,7 +164,7 @@ private void compare(final Map map, Map cmpMap) int matchCt = 0; int mismatchCt = 0; for (final String code : map.keySet()) { - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); final JsonNode node = mapper.readTree(map.get(code)); final JsonNode cmpNode = mapper.readTree(cmpMap.get(code)); final StringBuilder sb = new StringBuilder(); @@ -287,7 +281,7 @@ private Map getResults(final String path) throws Exception { // result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); // content = result.getResponse().getContentAsString(); // log.info(" content = " + content); - // concept = new ObjectMapper().readValue(content, Concept.class); + // concept = ThreadLocalMapper.get().readValue(content, Concept.class); // log.info(" extensions = " + concept.getExtensions()); // assertThat(concept).isNotNull(); // } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerIncludeTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerIncludeTests.java index 684ce0bf3..a2b6d4790 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerIncludeTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerIncludeTests.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -18,7 +18,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -38,9 +37,6 @@ public class ConceptControllerIncludeTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -48,9 +44,6 @@ public class ConceptControllerIncludeTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/concept"; } @@ -73,7 +66,7 @@ public void testIncludeMinimal() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); // Assertions about contents assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); @@ -124,7 +117,7 @@ public void testIncludeSummary() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -180,7 +173,7 @@ public void testIncludeFull() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -236,7 +229,7 @@ public void testIncludeSynonyms() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -282,7 +275,7 @@ public void testIncludeDefinitions() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -315,7 +308,7 @@ public void testIncludeProperties() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -354,7 +347,7 @@ public void testIncludeChildren() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -387,7 +380,7 @@ public void testIncludeParents() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -421,7 +414,7 @@ public void testIncludeAssociations() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("CDISC Questionnaire MDS-UPDRS Test Name Terminology"); assertThat(concept.getCode()).isEqualTo("C100139"); assertThat(concept.getSynonyms()).isEmpty(); @@ -454,7 +447,7 @@ public void testIncludeRoles() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -487,7 +480,7 @@ public void testIncludeMaps() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isEmpty(); @@ -520,7 +513,7 @@ public void testIncludeDisjointWith() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Molecular Abnormality"); assertThat(concept.getCode()).isEqualTo("C3910"); assertThat(concept.getSynonyms()).isEmpty(); @@ -554,7 +547,7 @@ public void testIncludeSynonymsAndDefinitions() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Melanoma"); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -590,7 +583,7 @@ public void testSubsetMembersInclude() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -615,7 +608,7 @@ public void testSubsetMembersInclude() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java index 6c7273d6d..ec3d865e6 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java @@ -6,7 +6,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.AssociationEntry; import gov.nih.nci.evs.api.model.AssociationEntryResultList; @@ -22,6 +21,7 @@ import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.service.SparqlQueryManagerService; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; @@ -37,7 +37,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -64,9 +63,6 @@ public class ConceptControllerTests { /** The application properties. */ @Autowired ApplicationProperties appProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -74,9 +70,6 @@ public class ConceptControllerTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/concept"; } @@ -110,7 +103,7 @@ public void testGetConcept() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getName()).isEqualTo("Melanoma"); @@ -144,7 +137,7 @@ public void testGetConceptFull() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C3224"); assertThat(concept.getName()).isEqualTo("Melanoma"); @@ -189,7 +182,7 @@ public void testGetConceptExtraMappings() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getMaps().size()).isGreaterThan(0); assertThat( concept.getMaps().stream() @@ -305,7 +298,7 @@ public void testGetConceptsWithList() throws Exception { final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -346,7 +339,7 @@ public void testGetConceptsWithListWithLicenseRestriction() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -387,7 +380,7 @@ public void testGetConceptAssociations() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -403,7 +396,7 @@ public void testGetConceptAssociations() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -432,7 +425,7 @@ public void testGetConceptInverseAssociations() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -449,7 +442,7 @@ public void testGetConceptInverseAssociations() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -479,7 +472,7 @@ public void testGetConceptRoles() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -494,7 +487,7 @@ public void testGetConceptRoles() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -524,7 +517,7 @@ public void testGetConceptInverseRoles() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -540,7 +533,7 @@ public void testGetConceptInverseRoles() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -570,7 +563,7 @@ public void testGetConceptParents() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -586,7 +579,7 @@ public void testGetConceptParents() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -616,7 +609,7 @@ public void testGetConceptChildren() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -633,7 +626,7 @@ public void testGetConceptChildren() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -663,7 +656,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -684,7 +677,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -705,7 +698,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -726,7 +719,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -746,7 +739,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -761,7 +754,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -778,7 +771,7 @@ public void testGetConceptDescendants() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -816,7 +809,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -832,7 +825,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -847,7 +840,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); Concept concept = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -863,7 +856,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List conceptList = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -883,7 +876,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); concept = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference() { @@ -901,7 +894,7 @@ public void testGetConceptMaps() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -930,7 +923,7 @@ public void testGetConceptHistory() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); log.info(" list = " + concept.getHistory().size()); assertThat(concept.getHistory()).isNotEmpty(); @@ -962,7 +955,7 @@ public void testGetConceptHistory() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); log.info(" list = " + concept.getHistory().size()); assertThat(concept.getHistory()).isEmpty(); } @@ -988,7 +981,7 @@ public void testGetConceptDisjointWith() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1006,7 +999,7 @@ public void testGetConceptDisjointWith() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1036,7 +1029,7 @@ public void testGetRoots() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1058,7 +1051,7 @@ public void testGetRoots() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1075,7 +1068,7 @@ public void testGetRoots() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1121,7 +1114,7 @@ public void testGetSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1177,7 +1170,7 @@ public void testGetSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1226,7 +1219,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1255,7 +1248,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1284,7 +1277,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1304,7 +1297,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1322,7 +1315,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1341,7 +1334,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1360,7 +1353,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1377,7 +1370,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1394,7 +1387,7 @@ public void testGetPathsFromRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1426,7 +1419,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1456,7 +1449,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1480,7 +1473,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1499,7 +1492,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1517,7 +1510,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1536,7 +1529,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1555,7 +1548,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1572,7 +1565,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1589,7 +1582,7 @@ public void testGetPathsToRoot() throws Exception { content = result.getResponse().getContentAsString(); // log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1620,7 +1613,7 @@ public void testGetPathsToAncestor() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1651,7 +1644,7 @@ public void testGetPathsToAncestor() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1675,7 +1668,7 @@ public void testGetPathsToAncestor() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1698,7 +1691,7 @@ public void testGetPathsToAncestor() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1715,7 +1708,7 @@ public void testGetPathsToAncestor() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1732,7 +1725,7 @@ public void testGetPathsToAncestor() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -1761,7 +1754,7 @@ public void testCheckDefsAndSynsAreRight() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); for (Definition def : concept.getDefinitions()) { assertFalse(def.getDefinition().contains("nephron")); @@ -1773,7 +1766,7 @@ public void testCheckDefsAndSynsAreRight() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); for (Synonym syn : concept.getSynonyms()) { assertFalse(syn.getName().contains("nephron")); @@ -1785,7 +1778,7 @@ public void testCheckDefsAndSynsAreRight() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); for (Definition def : concept.getDefinitions()) { assertFalse(def.getDefinition().contains("arrhythmia")); @@ -1810,7 +1803,7 @@ public void testAssociationEntries() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - resultList = new ObjectMapper().readValue(content, AssociationEntryResultList.class); + resultList = ThreadLocalMapper.get().readValue(content, AssociationEntryResultList.class); assertThat(resultList).isNotNull(); assertThat(resultList.getTimeTaken()).isGreaterThan(0); assertThat(resultList.getTotal()).isGreaterThan(2500); @@ -1825,7 +1818,7 @@ public void testAssociationEntries() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - resultList = new ObjectMapper().readValue(content, AssociationEntryResultList.class); + resultList = ThreadLocalMapper.get().readValue(content, AssociationEntryResultList.class); assertThat(resultList).isNotNull(); assertThat(resultList.getTimeTaken()).isGreaterThan(0); assertThat(resultList.getTotal()).isGreaterThan(2500); @@ -1840,7 +1833,7 @@ public void testAssociationEntries() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - resultList = new ObjectMapper().readValue(content, AssociationEntryResultList.class); + resultList = ThreadLocalMapper.get().readValue(content, AssociationEntryResultList.class); assertThat(resultList).isNotNull(); assertThat(resultList.getTimeTaken()).isGreaterThan(0); assertThat(resultList.getTotal()).isLessThan(3000); @@ -1860,7 +1853,7 @@ public void testAssociationEntries() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - resultList = new ObjectMapper().readValue(content, AssociationEntryResultList.class); + resultList = ThreadLocalMapper.get().readValue(content, AssociationEntryResultList.class); assertThat(resultList).isNotNull(); assertThat(resultList.getTotal()).isGreaterThan(0); assertThat(resultList.getParameters().getTerminology()).contains("12"); @@ -1872,7 +1865,7 @@ public void testAssociationEntries() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - resultList = new ObjectMapper().readValue(content, AssociationEntryResultList.class); + resultList = ThreadLocalMapper.get().readValue(content, AssociationEntryResultList.class); assertThat(resultList).isNotNull(); assertThat(resultList.getTotal()).isGreaterThan(0); assertThat(resultList.getParameters().getTerminology()).contains("1"); @@ -1916,7 +1909,7 @@ public void testSubsetMembers() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); subsetMembers = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1930,7 +1923,7 @@ public void testSubsetMembers() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); subsetMembers = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1945,7 +1938,7 @@ public void testSubsetMembers() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); subsetMembers = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1972,7 +1965,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); Terminology terminology = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1988,7 +1981,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); List conceptResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1998,14 +1991,14 @@ public void testTerminologyVersion() throws Exception { result = mvc.perform(get(baseWeeklyUrl + "/C3224")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - Concept concept = new ObjectMapper().readValue(content, Concept.class); + Concept concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getVersion() == terminology.getVersion()); result = mvc.perform(get(baseWeeklyUrl + "/C3224/children")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); conceptResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2030,7 +2023,7 @@ public void testGetTerminologyConcepts() throws Exception { // very small terminology ArrayList terminologyCodes = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2043,7 +2036,7 @@ public void testGetTerminologyConcepts() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologyCodes = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2057,7 +2050,7 @@ public void testGetTerminologyConcepts() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologyCodes = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2071,7 +2064,7 @@ public void testGetTerminologyConcepts() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologyCodes = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2098,7 +2091,7 @@ public void testCodeValuesPresentInFullInclude() throws Exception { url = baseUrl + "/ncit/C101669?include=full"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getSynonyms().get(0).getTypeCode() != null).isTrue(); assertThat(concept.getDefinitions().get(0).getCode() != null).isTrue(); @@ -2117,7 +2110,7 @@ public void testCodeValuesPresentInFullInclude() throws Exception { url = baseUrl + "/ncit/C3224?include=full"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getSynonyms().get(0).getTypeCode() != null).isTrue(); assertThat(concept.getDefinitions().get(0).getCode() != null).isTrue(); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/Ctcae5SampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/Ctcae5SampleTest.java index 9e21a9592..b68b995ef 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/Ctcae5SampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/Ctcae5SampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testCTCAET5erminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -112,7 +112,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C143164"); assertThat(concept.getName()).isEqualTo("Blood and Lymphatic System Disorders"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/Ctcae6SampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/Ctcae6SampleTest.java index 13149319d..5bbd2576d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/Ctcae6SampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/Ctcae6SampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testCTCAE6Terminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -112,7 +112,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C221229"); assertThat(concept.getName()) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/DocumentationPayloadExamplesTests.java b/src/test/java/gov/nih/nci/evs/api/controller/DocumentationPayloadExamplesTests.java index 12f6821fe..8911f9662 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/DocumentationPayloadExamplesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/DocumentationPayloadExamplesTests.java @@ -6,6 +6,7 @@ import com.fasterxml.jackson.annotation.JsonInclude.Include; import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -78,7 +79,7 @@ public void testIncludeMinimal() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); mapper.setSerializationInclusion(Include.NON_EMPTY); log.info( " content = " diff --git a/src/test/java/gov/nih/nci/evs/api/controller/DuoSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/DuoSampleTest.java index 8b4f28ddd..7568c08c9 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/DuoSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/DuoSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testDUOTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -112,7 +112,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("DUO_0000001"); assertThat(concept.getTerminology()).isEqualTo("duo"); @@ -138,7 +138,7 @@ public void testDisjointWith() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("BFO_0000031"); // Verify no "disjointWith" associations @@ -174,7 +174,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("ObsoleteClass"); assertThat(concept.getChildren()).isNotEmpty(); @@ -186,7 +186,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo(obsoleteCode); } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/GoSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/GoSampleTest.java index afad5044c..874bdfa36 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/GoSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/GoSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testGOTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -114,7 +114,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("GO:0002451"); assertThat(concept.getTerminology()).isEqualTo("go"); @@ -140,7 +140,7 @@ public void testPartOfParent() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("GO:0000015"); assertThat(concept.getParents().stream().filter(p -> p.getCode().equals("GO:0005829")).count()) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/HgncSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/HgncSampleTest.java index 9f24b76dc..876632608 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/HgncSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/HgncSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testHGNCTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -114,7 +114,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("HGNC:11231"); assertThat(concept.getTerminology()).isEqualTo("hgnc"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/HistoryControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/HistoryControllerTests.java index df6a4c038..a44288e2d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/HistoryControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/HistoryControllerTests.java @@ -6,9 +6,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.History; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.BeforeEach; @@ -22,7 +22,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -42,9 +41,6 @@ public class HistoryControllerTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -52,9 +48,6 @@ public class HistoryControllerTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1"; } @@ -93,11 +86,12 @@ public void testReplacementsWithNCItCodes( String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - objectMapper.readValue( - content, - new TypeReference>() { - // n/a - }); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }); // Assert assertNotNull(list); @@ -132,7 +126,7 @@ public void testReplacementsWithNCImCodes( String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -175,7 +169,7 @@ public void testReplacementsListWithNCItCodes( String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/Icd10SampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/Icd10SampleTest.java index 4f9423e3b..469a1f4f0 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/Icd10SampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/Icd10SampleTest.java @@ -4,8 +4,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,7 +60,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("M14.6"); assertThat(concept.getTerminology()).isEqualTo("icd10"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/Icd10cmSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/Icd10cmSampleTest.java index 810cbca54..5237812aa 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/Icd10cmSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/Icd10cmSampleTest.java @@ -4,8 +4,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,7 +60,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("Q89.9"); assertThat(concept.getTerminology()).isEqualTo("icd10cm"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/Icd9cmSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/Icd9cmSampleTest.java index 1e418d19b..d41cb03e8 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/Icd9cmSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/Icd9cmSampleTest.java @@ -4,8 +4,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,7 +60,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("759.9"); assertThat(concept.getTerminology()).isEqualTo("icd9cm"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/LncSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/LncSampleTest.java index 85ccf11a2..53f78eda6 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/LncSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/LncSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -63,7 +63,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("LA26702-3"); assertThat(concept.getTerminology()).isEqualTo("lnc"); @@ -75,7 +75,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("36926-4"); assertThat(concept.getTerminology()).isEqualTo("lnc"); @@ -90,7 +90,7 @@ public void testActive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java index 4df899075..8fe32ec27 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java @@ -9,12 +9,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dnault.xmlpatch.internal.Log; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Mapping; import gov.nih.nci.evs.api.model.MappingResultList; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -27,7 +27,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -47,14 +46,9 @@ public class MapsetControllerTests { /** The base url. */ private String baseUrl; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** Sets the up. */ @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); baseUrl = "/api/v1/mapset"; } @@ -72,7 +66,7 @@ public void testMapsetsNoParams() throws Exception { MvcResult result = mvc.perform(get(baseUrl)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); List metadataMappings = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -130,7 +124,7 @@ public void testMapsetsWithIncludeParams() throws Exception { .andReturn(); String content = result.getResponse().getContentAsString(); List metadataMappings = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -169,7 +163,7 @@ public void testMapsetsWithCodeAndIncludeParams() throws Exception { .andExpect(status().isOk()) .andReturn(); String content = result.getResponse().getContentAsString(); - Concept singleMetadataMap = new ObjectMapper().readValue(content, Concept.class); + Concept singleMetadataMap = ThreadLocalMapper.get().readValue(content, Concept.class); // Assert assertNotNull(singleMetadataMap); @@ -208,7 +202,7 @@ public void testMapsetsWithCodeDownloadTrueIncludeParams() throws Exception { .andExpect(status().isOk()) .andReturn(); String content = result.getResponse().getContentAsString(); - Concept singleMetadataMap = new ObjectMapper().readValue(content, Concept.class); + Concept singleMetadataMap = ThreadLocalMapper.get().readValue(content, Concept.class); // Assert assertNotNull(singleMetadataMap); @@ -251,7 +245,7 @@ public void testMapsetsWithCodeDownloadTrue() throws Exception { .andExpect(status().isOk()) .andReturn(); String content = result.getResponse().getContentAsString(); - Concept singleMetadataMap = new ObjectMapper().readValue(content, Concept.class); + Concept singleMetadataMap = ThreadLocalMapper.get().readValue(content, Concept.class); // Assert assertNotNull(singleMetadataMap); @@ -306,7 +300,7 @@ public void testMapsetsWithMapsCodeUsingDefaults() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertTrue(mapList.getTotal() > 0); @@ -327,7 +321,7 @@ public void testNciHgncMapForFirstRow() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert matches for this code assertTrue(!mapList.getMaps().isEmpty()); @@ -348,13 +342,13 @@ public void testMapsetsWithMapsCodeFromRecordAndPageSize() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping tenFromZero = mapList.getMaps().get(9); // testing fromRecord and pageSize result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - mapList = new ObjectMapper().readValue(content, MappingResultList.class); + mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping tenFromTen = mapList.getMaps().get(0); // Assert @@ -378,13 +372,13 @@ public void testMapsetsWithMapsCodeFromRecordOffPageSize() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping tenFromZero = mapList.getMaps().get(9); // testing fromRecord off page size result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - mapList = new ObjectMapper().readValue(content, MappingResultList.class); + mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping tenFromOne = mapList.getMaps().get(8); // Assert @@ -407,7 +401,7 @@ public void testMapsetsWithMapsCodeFromRecordPastTheEnd() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertNull(mapList.getMaps()); @@ -428,7 +422,7 @@ public void testMapsetsWithMapsCodeWithZeroMatches() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertNull(mapList.getMaps()); @@ -449,7 +443,7 @@ public void testMapsetsWithMapsCodeWithNonZeroMatches() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -474,7 +468,7 @@ public void testMapsetsWithMapsCodeWithNonZeroMatchesTrimSpacing() throws Except MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -500,13 +494,13 @@ public void testMapsetsWithMapsCodeWithNonZeroMatchesAndFromRecordAndPageSize() MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping sixFromZero = mapList.getMaps().get(5); result = mvc.perform(get(baseUrl + "/" + path + params2)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - mapList = new ObjectMapper().readValue(content, MappingResultList.class); + mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); Mapping sixFromThree = mapList.getMaps().get(2); // Assert @@ -529,7 +523,7 @@ public void testMapsetsWithMapsCodeSuccess() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -553,7 +547,7 @@ public void testMapsetsWithSNOMEDMappingExists() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -574,7 +568,7 @@ public void testMapsetsWithSNOMEDMappingANDTermExists() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -596,7 +590,7 @@ public void testMapsetsWithSNOMEDMappingsANDCodeExists() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertFalse(mapList.getMaps().isEmpty()); @@ -618,7 +612,7 @@ public void testMapsetsWithSNOMEDANDSortAscendingTrue() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); List sortedNames = mapList.getMaps().stream() .map(Mapping::getSourceName) @@ -647,7 +641,7 @@ public void testMapsetsWithSNOMEDANDSortDescendingTrue() throws Exception { MvcResult result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); List sortedNames = mapList.getMaps().stream() .map(Mapping::getSourceName) @@ -678,7 +672,7 @@ public void testNciMapsetDownload() throws Exception { result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); assertNotNull(content); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); assertEquals(10, mapList.getMaps().size()); } @@ -690,7 +684,7 @@ public void testNciMapsToViewable() throws Exception { mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); assertNotNull(content); - Concept singleMetadataMap = new ObjectMapper().readValue(content, Concept.class); + Concept singleMetadataMap = ThreadLocalMapper.get().readValue(content, Concept.class); assertTrue( singleMetadataMap.getProperties().stream() .anyMatch( @@ -732,7 +726,7 @@ public void testNciMapsToViewable() throws Exception { result = mvc.perform(get(baseUrl + "/" + path + params)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); assertNotNull(content); - singleMetadataMap = new ObjectMapper().readValue(content, Concept.class); + singleMetadataMap = ThreadLocalMapper.get().readValue(content, Concept.class); assertTrue( singleMetadataMap.getProperties().stream() .anyMatch( @@ -782,7 +776,7 @@ public void testMapsetsNoRetiredConcepts(String path, String params) throws Exce mvc.perform(get(baseUrl + path + params)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); Log.info(" content = " + content); - MappingResultList mapList = new ObjectMapper().readValue(content, MappingResultList.class); + MappingResultList mapList = ThreadLocalMapper.get().readValue(content, MappingResultList.class); // Assert assertNull(mapList.getMaps()); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MdrControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MdrControllerTests.java index adbfac258..9b26c5244 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MdrControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MdrControllerTests.java @@ -5,12 +5,12 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.ConceptResultList; import gov.nih.nci.evs.api.model.HierarchyNode; import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; @@ -22,7 +22,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -45,20 +44,12 @@ public class MdrControllerTests { /** The application properties. */ @Autowired ApplicationProperties appProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; /** Sets the up. */ @BeforeEach public void setUp() { - /* - * Configure the JacksonTester object - */ - this.objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); baseUrl = "/api/v1/concept"; // baseUrlMetadata = "/api/v1/metadata"; @@ -97,7 +88,7 @@ public void testMRCONSO() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10009802"); assertThat(concept.getName()).isEqualTo("Coagulopathy"); @@ -136,7 +127,7 @@ public void testMRSTY() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getProperties().size()).isGreaterThan(1); assertThat( concept.getProperties().stream() @@ -174,7 +165,7 @@ public void testMRREL() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10009802"); assertThat(concept.getAssociations().size()).isEqualTo(17); @@ -249,7 +240,7 @@ public void testMRSAT() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10009802"); assertThat(concept.getProperties().size()).isGreaterThan(1); @@ -268,7 +259,7 @@ public void testMRSAT() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10036030"); assertThat(concept.getAssociations().size()).isGreaterThan(0); @@ -329,7 +320,7 @@ public void testMdrSearchContains() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list).isNotNull(); // Look for the Stenosis code assertThat( @@ -402,7 +393,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -435,7 +426,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -454,7 +445,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -472,7 +463,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -492,7 +483,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -514,7 +505,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -550,7 +541,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -570,7 +561,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -590,7 +581,7 @@ public void testMdrMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -625,7 +616,7 @@ public void testQualifierValues() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -658,7 +649,7 @@ public void testSubree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -677,7 +668,7 @@ public void testSubree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -695,7 +686,7 @@ public void testSubree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -713,7 +704,7 @@ public void testSubree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -746,7 +737,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); roots = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -763,7 +754,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -788,7 +779,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -812,7 +803,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -836,7 +827,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MdrSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/MdrSampleTest.java index c12b68533..7cad5564e 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MdrSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MdrSampleTest.java @@ -6,11 +6,11 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.model.TerminologyMetadata; import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -81,7 +81,7 @@ public void testActive() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10062368"); assertThat(concept.getTerminology()).isEqualTo("mdr"); @@ -98,7 +98,7 @@ public void testActive() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("10002614"); assertThat(concept.getTerminology()).isEqualTo("mdr"); @@ -118,7 +118,7 @@ public void testActive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -149,7 +149,7 @@ public void testMDRTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -180,7 +180,7 @@ public void testMDRTerminology() throws Exception { // Load from config (verify this works) final JsonNode node = getMetadataAsNode("mdr"); - new ObjectMapper().treeToValue(node, TerminologyMetadata.class); + ThreadLocalMapper.get().treeToValue(node, TerminologyMetadata.class); } /** @@ -193,10 +193,10 @@ public void testMDRTerminology() throws Exception { public JsonNode getMetadataAsNode(final String terminology) throws Exception { final String uri = applicationProperties.getConfigBaseUri() + "/" + terminology + ".json"; try (final InputStream is = new URL(uri).openConnection().getInputStream()) { - return new ObjectMapper().readTree(IOUtils.toString(is, "UTF-8")); + return ThreadLocalMapper.get().readTree(IOUtils.toString(is, "UTF-8")); } catch (Throwable t) { // read as file if no url try { - return new ObjectMapper() + return ThreadLocalMapper.get() .readTree(FileUtils.readFileToString(new File(uri), StandardCharsets.UTF_8)); } catch (IOException ex) { throw new IOException( diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MedrtSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/MedrtSampleTest.java index 1dde45339..07f27a9b9 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MedrtSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MedrtSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testMEDRTTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -111,7 +111,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("N0000175809"); assertThat(concept.getName()).isEqualTo("4-Hydroxyphenyl-Pyruvate Dioxygenase Inhibitor"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerIncludeTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerIncludeTests.java index 2c4b241c5..3e2dc194a 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerIncludeTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerIncludeTests.java @@ -4,9 +4,9 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -16,7 +16,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -36,9 +35,6 @@ public class MetadataControllerIncludeTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -46,9 +42,6 @@ public class MetadataControllerIncludeTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/metadata"; } @@ -71,7 +64,7 @@ public void testIncludeMinimal() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); // Assertions about contents assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); @@ -105,7 +98,7 @@ public void testIncludeSummary() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -161,7 +154,7 @@ public void testIncludeFull() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -208,7 +201,7 @@ public void testIncludeSynonyms() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -249,7 +242,7 @@ public void testIncludeDefinitions() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isEmpty(); @@ -282,7 +275,7 @@ public void testIncludeProperties() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isEmpty(); @@ -323,7 +316,7 @@ public void testIncludeOtherEmptyParts() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isEmpty(); @@ -356,7 +349,7 @@ public void testIncludeSynonymsAndDefinitions() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 1f69ef672..c6b4b16b1 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -5,7 +5,6 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Property; import gov.nih.nci.evs.api.model.StatisticsEntry; @@ -15,6 +14,7 @@ import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.ConceptUtils; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -31,7 +31,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -57,9 +56,6 @@ public class MetadataControllerTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -67,9 +63,6 @@ public class MetadataControllerTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/metadata"; } @@ -100,7 +93,7 @@ public void testGetTerminologies() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -118,7 +111,7 @@ public void testGetTerminologies() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -136,7 +129,7 @@ public void testGetTerminologies() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -154,7 +147,7 @@ public void testGetTerminologies() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -172,7 +165,7 @@ public void testGetTerminologies() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -200,7 +193,7 @@ public void testGetOverviewMetadata() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); Map> metadata = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -244,7 +237,7 @@ public void testGetTerminologyMetadata() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -265,7 +258,7 @@ public void testGetTerminologyMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -286,7 +279,7 @@ public void testGetTerminologyMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -316,7 +309,7 @@ public void testGetHierarchy() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -334,7 +327,7 @@ public void testGetHierarchy() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -352,7 +345,7 @@ public void testGetHierarchy() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -379,7 +372,7 @@ public void testGetAssociations() throws Exception { final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -413,7 +406,7 @@ public void testGetAssociationsWithList() throws Exception { final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -443,7 +436,7 @@ public void testGetAssociation() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -454,7 +447,7 @@ public void testGetAssociation() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("A8"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -470,7 +463,7 @@ public void testGetAssociation() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Concept_In_Subset"); assertThat(concept.getCode()).isEqualTo("A8"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -552,7 +545,7 @@ public void testGetRoles() throws Exception { final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -585,7 +578,7 @@ public void testGetRolesWithList() throws Exception { final String content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -615,7 +608,7 @@ public void testGetRole() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Conceptual_Part_Of"); assertThat(concept.getCode()).isEqualTo("R27"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -626,7 +619,7 @@ public void testGetRole() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("R27"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -642,7 +635,7 @@ public void testGetRole() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Conceptual_Part_Of"); assertThat(concept.getCode()).isEqualTo("R27"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -724,7 +717,7 @@ public void testGetProperties() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -777,7 +770,7 @@ public void testGetPropertiesWithList() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -807,7 +800,7 @@ public void testGetProperty() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Chemical_Formula"); assertThat(concept.getCode()).isEqualTo("P350"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -818,7 +811,7 @@ public void testGetProperty() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("P350"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -835,7 +828,7 @@ public void testGetProperty() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("Chemical_Formula"); assertThat(concept.getCode()).isEqualTo("P350"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -922,7 +915,7 @@ public void testGetPropertyValues() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content length = " + content.length()); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -939,7 +932,7 @@ public void testGetPropertyValues() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content length = " + content.length()); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1001,7 +994,7 @@ public void testPropertyValuesWithCodeAndName() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); properties = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1051,7 +1044,7 @@ public void testConceptStatuses() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1086,7 +1079,7 @@ public void testSynonymSources() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1129,7 +1122,7 @@ public void testDefinitionSources() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1173,7 +1166,7 @@ public void testTermTypes() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1214,7 +1207,7 @@ public void testPropertyQualifiers() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("attribution"); assertThat(concept.getCode()).isEqualTo("P381"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -1225,7 +1218,7 @@ public void testPropertyQualifiers() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("P381"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -1280,7 +1273,7 @@ public void testSynonymTypes() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("FULL_SYN"); assertThat(concept.getCode()).isEqualTo("P90"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -1291,7 +1284,7 @@ public void testSynonymTypes() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("P90"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -1331,7 +1324,7 @@ public void testDefinitionTypes() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("DEFINITION"); assertThat(concept.getCode()).isEqualTo("P97"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -1342,7 +1335,7 @@ public void testDefinitionTypes() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getCode()).isEqualTo("P97"); // Even full doesn't include descendants and paths assertThat(concept.getDescendants()).isEmpty(); @@ -1382,7 +1375,7 @@ public void testQualifiersWithoutTypeValue() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1408,7 +1401,7 @@ public void testQualifiersWithoutTypeValue() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1432,7 +1425,7 @@ public void testQualifiersWithoutTypeValue() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1464,15 +1457,15 @@ public void testMutuallyExclusive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); Set properties = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(c -> c.getCode()) - .collect(Collectors.toSet()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(c -> c.getCode()) + .collect(Collectors.toSet()); // Qualifiers url = baseUrl + "/ncit/qualifiers"; @@ -1481,15 +1474,15 @@ public void testMutuallyExclusive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); Set qualifiers = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(c -> c.getCode()) - .collect(Collectors.toSet()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(c -> c.getCode()) + .collect(Collectors.toSet()); // Synonym Types url = baseUrl + "/ncit/synonymTypes"; @@ -1498,15 +1491,15 @@ public void testMutuallyExclusive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); Set synonymTypes = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(c -> c.getCode()) - .collect(Collectors.toSet()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(c -> c.getCode()) + .collect(Collectors.toSet()); // Definition Types url = baseUrl + "/ncit/definitionTypes"; @@ -1515,30 +1508,30 @@ public void testMutuallyExclusive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); Set definitionTypes = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .map(c -> c.getCode()) - .collect(Collectors.toSet()); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .map(c -> c.getCode()) + .collect(Collectors.toSet()); url = baseUrl + "/terminologies"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); Terminology terminology = - new ObjectMapper() - .readValue( - content, - new TypeReference>() { - // n/a - }) - .stream() - .filter(t -> t.getTerminology().equals("ncit")) - .findFirst() - .get(); + ThreadLocalMapper.get() + .readValue( + content, + new TypeReference>() { + // n/a + }) + .stream() + .filter(t -> t.getTerminology().equals("ncit")) + .findFirst() + .get(); properties = properties.stream() .filter(c -> !terminology.getMetadata().isRemodeledProperty(c)) @@ -1573,7 +1566,7 @@ public void testTerminolgyMetadata() throws Exception { mvc.perform(get(url).param("terminology", "ncit")).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1585,7 +1578,7 @@ public void testTerminolgyMetadata() throws Exception { mvc.perform(get(url).param("terminology", "ncim")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1596,7 +1589,7 @@ public void testTerminolgyMetadata() throws Exception { result = mvc.perform(get(url).param("latest", "true")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1608,7 +1601,7 @@ public void testTerminolgyMetadata() throws Exception { result = mvc.perform(get(url).param("latest", "false")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1620,7 +1613,7 @@ public void testTerminolgyMetadata() throws Exception { result = mvc.perform(get(url).param("tag", "monthly")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1632,7 +1625,7 @@ public void testTerminolgyMetadata() throws Exception { result = mvc.perform(get(url).param("tag", "weekly")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1647,7 +1640,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1662,7 +1655,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1677,7 +1670,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1692,7 +1685,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1707,7 +1700,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1722,7 +1715,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1737,7 +1730,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1752,7 +1745,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1767,7 +1760,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1782,7 +1775,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1797,7 +1790,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1812,7 +1805,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1831,7 +1824,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1850,7 +1843,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1869,7 +1862,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1888,7 +1881,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1907,7 +1900,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1926,7 +1919,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1945,7 +1938,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1964,7 +1957,7 @@ public void testTerminolgyMetadata() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -1976,7 +1969,7 @@ public void testTerminolgyMetadata() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2003,7 +1996,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); Terminology terminology = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2019,7 +2012,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); List metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2032,7 +2025,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - Concept metadataConcept = new ObjectMapper().readValue(content, Concept.class); + Concept metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2041,7 +2034,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2055,7 +2048,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2068,7 +2061,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - metadataConcept = new ObjectMapper().readValue(content, Concept.class); + metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2076,7 +2069,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - metadataConcept = new ObjectMapper().readValue(content, Concept.class); + metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2085,7 +2078,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2098,7 +2091,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - metadataConcept = new ObjectMapper().readValue(content, Concept.class); + metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2106,7 +2099,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - metadataConcept = new ObjectMapper().readValue(content, Concept.class); + metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2115,7 +2108,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2128,7 +2121,7 @@ public void testTerminologyVersion() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - metadataConcept = new ObjectMapper().readValue(content, Concept.class); + metadataConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(metadataConcept.getVersion() == terminology.getVersion()); result = @@ -2137,7 +2130,7 @@ public void testTerminologyVersion() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); metadataResults = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -2162,7 +2155,7 @@ public void testSourceStats() throws Exception { content = result.getResponse().getContentAsString(); log.info("content = " + content); Map> sourceStats = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -2175,7 +2168,7 @@ public void testSourceStats() throws Exception { result = mvc.perform(get(url + "/ncim/stats/NO-STATS")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); sourceStats = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -2200,7 +2193,7 @@ public void testTerminologyMetadataFieldsCleared() throws Exception { // Parse into objects and check metadata has been cleaned (fields either null or empty) final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MgedSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/MgedSampleTest.java index 9bbf518b8..dd0829e27 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MgedSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MgedSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -67,7 +67,7 @@ public void testTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -108,7 +108,7 @@ public void testFixFile() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("MO_824"); @@ -118,7 +118,7 @@ public void testFixFile() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("MO_113"); assertThat(concept.getChildren().size()).isGreaterThan(2); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MouseAnatomySampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/MouseAnatomySampleTest.java index bbe38c4bb..4b7b2bb5b 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MouseAnatomySampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MouseAnatomySampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -112,7 +112,7 @@ public void testPartOfParent() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("MA:0000003"); assertThat(concept.getParents().stream().filter(p -> p.getCode().equals("MA:0002405")).count()) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java index 0e4749d02..236eedd3b 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcimControllerTests.java @@ -5,13 +5,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.ConceptResultList; import gov.nih.nci.evs.api.model.HierarchyNode; import gov.nih.nci.evs.api.model.Terminology; import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeEach; @@ -23,7 +23,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -46,20 +45,12 @@ public class NcimControllerTests { /** The application properties. */ @Autowired ApplicationProperties appProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; /** Sets the up. */ @BeforeEach public void setUp() { - /* - * Configure the JacksonTester object - */ - this.objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); baseUrl = "/api/v1/concept"; } @@ -95,7 +86,7 @@ public void testNCIMTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -136,7 +127,7 @@ public void testMRCONSO() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000005"); assertThat(concept.getName()).isEqualTo("(131)I-Macroaggregated Albumin"); @@ -148,7 +139,7 @@ public void testMRCONSO() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL990362"); assertThat(concept.getName()).isEqualTo("Foundational Model of Anatomy Ontology, 4_15"); @@ -173,7 +164,7 @@ public void testMRDEF() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000005"); assertThat(concept.getName()).isEqualTo("(131)I-Macroaggregated Albumin"); @@ -185,7 +176,7 @@ public void testMRDEF() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL977629"); assertThat(concept.getName()).isEqualTo("Concurrent Disease Type"); @@ -201,7 +192,7 @@ public void testMRDEF() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL990362"); assertThat(concept.getName()).isEqualTo("Foundational Model of Anatomy Ontology, 4_15"); @@ -213,7 +204,7 @@ public void testMRDEF() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0030274"); assertThat(concept.getName()).isEqualTo("Pancreas"); @@ -230,7 +221,7 @@ public void testMRDEF() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0426679"); assertThat(concept.getName()).isEqualTo("Puddle sign"); @@ -255,7 +246,7 @@ public void testMRSTY() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000005"); assertThat(concept.getName()).isEqualTo("(131)I-Macroaggregated Albumin"); @@ -276,7 +267,7 @@ public void testMRSTY() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0718043"); assertThat(concept.getName()).isEqualTo("Sacrosidase"); @@ -300,7 +291,7 @@ public void testMRSTY() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL988042"); assertThat(concept.getName()) @@ -327,7 +318,7 @@ public void testMRSTY() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL990362"); assertThat(concept.getName()).isEqualTo("Foundational Model of Anatomy Ontology, 4_15"); @@ -364,7 +355,7 @@ public void testMRREL() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000005"); assertThat(concept.getAssociations().size()).isEqualTo(1); @@ -380,7 +371,7 @@ public void testMRREL() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0242354"); assertThat(concept.getChildren().size()).isEqualTo(20); @@ -409,7 +400,7 @@ public void testMRREL2() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL979355"); assertThat(concept.getParents().size()).isGreaterThan(0); @@ -439,7 +430,7 @@ public void testMRREL2() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000726"); @@ -484,7 +475,7 @@ public void testMRSAT() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000052"); assertThat(concept.getName()).isEqualTo("1,4-alpha-Glucan Branching Enzyme"); @@ -505,7 +496,7 @@ public void testMRSAT() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C0000578"); assertThat(concept.getName()).isEqualTo("Oxitriptan"); @@ -528,7 +519,7 @@ public void testMRSAT() throws Exception { // result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); // content = result.getResponse().getContentAsString(); // log.info(" content = " + content); - // concept = new ObjectMapper().readValue(content, Concept.class); + // concept = ThreadLocalMapper.get().readValue(content, Concept.class); // assertThat(concept).isNotNull(); // assertThat(concept.getCode()).isEqualTo("CL988043"); // assertThat(concept.getName()).isEqualTo( @@ -573,7 +564,7 @@ public void testNcimSearchContains() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list).isNotNull(); // Look for the Aspirin CUI. assertThat( @@ -608,7 +599,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -645,7 +636,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -664,7 +655,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -684,7 +675,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -700,7 +691,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -722,7 +713,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -757,7 +748,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -777,7 +768,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -797,7 +788,7 @@ public void testNcimMetadata() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -832,7 +823,7 @@ public void testQualifierValues() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -865,7 +856,7 @@ public void testSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -883,7 +874,7 @@ public void testSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -901,7 +892,7 @@ public void testSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -919,7 +910,7 @@ public void testSubtree() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -950,7 +941,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -968,7 +959,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { @@ -986,7 +977,7 @@ public void testPaths() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java index 6a134efd0..ceab4b70c 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcimSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -62,7 +62,7 @@ public void testGetConceptWithMappings() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL547438"); assertThat(concept.getTerminology()).isEqualTo("ncim"); @@ -96,7 +96,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("CL547438"); assertThat(concept.getTerminology()).isEqualTo("ncim"); @@ -108,7 +108,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C1550508"); assertThat(concept.getTerminology()).isEqualTo("ncim"); @@ -123,7 +123,7 @@ public void testActive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java index 22259820a..5fdafa133 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -71,7 +71,7 @@ public void testNCITerminologyMonthly() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -128,7 +128,7 @@ public void testNCITerminologyWeekly() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -177,7 +177,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C12756"); assertThat(concept.getTerminology()).isEqualTo("ncit"); @@ -191,7 +191,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C4631"); assertThat(concept.getTerminology()).isEqualTo("ncit"); @@ -206,7 +206,7 @@ public void testActive() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -237,7 +237,7 @@ public void testComplexrole() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C111020"); assertThat( diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NdfrtSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NdfrtSampleTest.java index 27012cc30..c9d40b24f 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NdfrtSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NdfrtSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -62,7 +62,7 @@ public void testNDFRTTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -109,7 +109,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("N0000000004"); assertThat(concept.getTerminology()).isEqualTo("ndfrt"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NpoSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NpoSampleTest.java index d57b091f7..c750d25ae 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NpoSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NpoSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -111,7 +111,7 @@ public void testDefinition() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("NPO_1009"); // Verify no definition property diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ObiSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ObiSampleTest.java index 5d7703094..ad092235c 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ObiSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ObiSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -62,7 +62,7 @@ public void testTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -109,7 +109,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("APOLLO_SV_00000008"); assertThat(concept.getTerminology()).isEqualTo("obi"); @@ -134,7 +134,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("ObsoleteClass"); assertThat(concept.getChildren()).isNotEmpty(); @@ -146,7 +146,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo(obsoleteCode); } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ObibSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ObibSampleTest.java index 77099b387..7c8a9ad0d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ObibSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ObibSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.stream.Collectors; import org.junit.jupiter.api.BeforeAll; @@ -63,7 +63,7 @@ public void testDUOTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -109,7 +109,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("APOLLO_SV_00000032"); assertThat(concept.getTerminology()).isEqualTo("obib"); @@ -136,7 +136,7 @@ public void testChildrenNotDuplicated() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - final Concept concept = new ObjectMapper().readValue(content, Concept.class); + final Concept concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getChildren()).isNotEmpty(); // Verify child codes are unique assertThat(concept.getChildren().size()) @@ -165,7 +165,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("ObsoleteClass"); assertThat(concept.getChildren()).isNotEmpty(); @@ -177,7 +177,7 @@ public void testObsoleteChildren() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo(obsoleteCode); } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/PdqSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/PdqSampleTest.java index 4bb8471f5..a13ae4bf1 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/PdqSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/PdqSampleTest.java @@ -4,8 +4,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -60,7 +60,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("100001"); assertThat(concept.getTerminology()).isEqualTo("pdq"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/QualifierTests.java b/src/test/java/gov/nih/nci/evs/api/controller/QualifierTests.java index b83148afb..04b7afae0 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/QualifierTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/QualifierTests.java @@ -5,10 +5,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.collect.Sets; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import java.util.Set; import java.util.stream.Collectors; @@ -21,7 +21,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -44,9 +43,6 @@ public class QualifierTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -57,9 +53,6 @@ public class QualifierTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/concept"; metaBaseUrl = "/api/v1/metadata"; } @@ -82,7 +75,7 @@ public void testAltDefinitionQualifiers() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C101669"); assertThat(concept.getDefinitions().size()).isGreaterThan(0); @@ -118,7 +111,7 @@ public void testDefinitionQualifiers() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C101046"); assertThat(concept.getDefinitions().size()).isGreaterThan(0); @@ -154,7 +147,7 @@ public void testFullSyn() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C100065"); assertThat(concept.getSynonyms().size()).isGreaterThan(0); @@ -188,7 +181,7 @@ public void testMappings() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C101034"); assertThat(concept.getMaps().size()).isGreaterThan(0); @@ -223,7 +216,7 @@ public void testGoAnnotation() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("C19799"); assertThat(concept.getProperties().size()).isGreaterThan(0); @@ -280,7 +273,7 @@ public void testNoPropertyQualifierOverlap() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list1 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -295,7 +288,7 @@ public void testNoPropertyQualifierOverlap() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -332,7 +325,7 @@ public void testNoPropertyQualifierOverlapViaLookup() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list1 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -347,7 +340,7 @@ public void testNoPropertyQualifierOverlapViaLookup() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -445,7 +438,7 @@ public void testQualifierAttr() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); // Assert that the "preferred name" synonym does match the concept name @@ -481,7 +474,7 @@ public void testAllQualifiers() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); final List list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java index daa063e98..5ecca172a 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java @@ -7,7 +7,6 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.ConceptResultList; @@ -23,6 +22,7 @@ import gov.nih.nci.evs.api.service.OpensearchQueryService; import gov.nih.nci.evs.api.util.ConceptUtils; import gov.nih.nci.evs.api.util.TerminologyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -121,7 +121,7 @@ public void testSearchTerm() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); Concept concept = list.getConcepts().get(0); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(10); @@ -180,7 +180,7 @@ public void testSearchTermFull() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); Concept concept = list.getConcepts().get(0); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(10); @@ -233,7 +233,7 @@ public void testHighlight() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(10); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -271,7 +271,7 @@ public void testHighlight() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isEqualTo(1); assertThat( list.getConcepts().get(0).getSynonyms().stream() @@ -293,7 +293,7 @@ public void testHighlight() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isEqualTo(1); assertThat( list.getConcepts().get(0).getSynonyms().stream() @@ -388,7 +388,7 @@ public void testSearchInclude() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(10); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -451,7 +451,7 @@ public void testPageSizeFromRecord() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(2); @@ -473,7 +473,7 @@ public void testPageSizeFromRecord() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isEqualTo(10); } result = @@ -488,7 +488,7 @@ public void testPageSizeFromRecord() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list2 = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list2 = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list2.getConcepts().size()).isEqualTo(10); // should be a different code starting on 16 assertThat(list.getConcepts().get(0).getCode()) @@ -517,7 +517,7 @@ public void testPageSizeFromRecord() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts()).isEmpty(); @@ -541,7 +541,7 @@ public void testPageSizeFromRecord() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(5); final List cl1 = list.getConcepts(); @@ -561,7 +561,7 @@ public void testPageSizeFromRecord() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(10); assertThat(list.getConcepts().subList(5, 10).toString()).isEqualTo(cl1.toString()); @@ -664,7 +664,7 @@ public void testPageSizeLicenseRestricted() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); @@ -696,7 +696,7 @@ public void testPageSizeLicenseRestricted() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); @@ -736,7 +736,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); result = @@ -749,7 +749,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); result = @@ -762,7 +762,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); log.info( @@ -781,7 +781,7 @@ public void testSearchProperty() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(1); assertThat(list.getConcepts().get(0).getName()).isEqualTo("Sivifene"); @@ -847,7 +847,7 @@ public void testSearchProperty() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isEqualTo(1); assertThat(list.getConcepts().get(0).getName()).isEqualTo("Sivifene"); @@ -901,7 +901,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); // Test with single terminology form @@ -915,7 +915,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); log.info("Done Testing testSearchProperty "); @@ -933,7 +933,7 @@ public void testSearchProperty() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); // all should have a name containing "Toluene" and have an FDA_UNII_CODE assertThat( @@ -986,7 +986,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getName()).containsIgnoringCase("enzyme"); @@ -1004,7 +1004,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getName()).isEqualToIgnoringCase("melanoma"); @@ -1022,7 +1022,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Match search @@ -1039,7 +1039,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // startsWith search @@ -1056,7 +1056,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // AND search @@ -1073,7 +1073,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // OR search @@ -1090,7 +1090,7 @@ public void testSearchType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Bad type @@ -1137,7 +1137,7 @@ public void testConceptStatus() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Verify property of "Obsolete_Concept on each results assertThat( @@ -1163,7 +1163,7 @@ public void testConceptStatus() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Verify property of "Obsolete_Concept on each results assertThat( @@ -1189,7 +1189,7 @@ public void testConceptStatus() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Verify property of "Obsolete_Concept on each results assertThat( @@ -1258,7 +1258,7 @@ public void testSynonymSource() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); boolean found = false; @@ -1290,7 +1290,7 @@ public void testSynonymSource() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); found = false; @@ -1341,7 +1341,7 @@ public void testSynonymTermType() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal() == 0); // Test single SynonymTermType @@ -1357,7 +1357,7 @@ public void testSynonymTermType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); boolean found = false; @@ -1382,7 +1382,7 @@ public void testSynonymTermType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); found = false; @@ -1426,7 +1426,7 @@ public void testSynonymTermType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Verify that each concept contains a CDISC/SY synonym assertThat( @@ -1461,7 +1461,7 @@ public void testSynonymTermType() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // Verify that each concept contains a CDISC/SY synonym assertThat( @@ -1503,7 +1503,7 @@ public void testSynonymType() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); boolean found = false; for (final Synonym syn : list.getConcepts().get(0).getSynonyms()) { @@ -1525,7 +1525,7 @@ public void testSynonymType() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); for (final Synonym syn : list.getConcepts().get(0).getSynonyms()) { if (syn.getType().equals("FULL_SYN")) { @@ -1563,7 +1563,7 @@ public void testDefinitionSource() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); boolean found = false; @@ -1627,7 +1627,7 @@ public void testDefinitionType() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); boolean found = false; for (final Definition def : list.getConcepts().get(0).getDefinitions()) { @@ -1653,7 +1653,7 @@ public void testDefinitionType() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); for (final Definition def : list.getConcepts().get(0).getDefinitions()) { if (def.getType().equals("ALT_DEFINITION")) { @@ -1714,7 +1714,7 @@ public void testSearchContains() throws Exception { assertThat(content).isEqualToIgnoringCase(content2); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); boolean currentExact = true; for (Concept concept : conceptList) { @@ -1776,7 +1776,7 @@ public void testSearchContains() throws Exception { assertThat(content).isEqualToIgnoringCase(content2); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); currentExact = true; for (Concept concept : conceptList) { @@ -1824,7 +1824,7 @@ public void testSearchContainsCoronaryVein() throws Exception { log.info(" content = " + content); assertThat(content).isNotEmpty(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); // The first one should contain the word "corona" (e.g. crown, corona // dentist) assertThat( @@ -1865,7 +1865,7 @@ public void testSearchContainsCoronaryVein() throws Exception { log.info(" content = " + content); assertThat(content).isNotEmpty(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); // The first one should contain the word "corona" (e.g. crown, corona // dentist) assertThat( @@ -1910,7 +1910,7 @@ public void testSearchContainsBoneCancer() throws Exception { log.info(" content = " + content); assertThat(content).isNotEmpty(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); // The first one should contain the word "corona" (e.g. crown, corona // dentist) assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C4016"); @@ -1946,7 +1946,7 @@ public void testSearchPhrase() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); boolean currentExact = true; for (Concept concept : conceptList) { @@ -1980,7 +1980,7 @@ public void testSearchPhrase() throws Exception { .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); assertThat(conceptList.size()).isEqualTo(2); } @@ -2015,7 +2015,7 @@ public void testSearchStartsWith() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); for (Concept concept : conceptList) { assertTrue( @@ -2052,7 +2052,7 @@ public void testSearchStartsWith() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); assertTrue(conceptList.get(0).getName().equalsIgnoreCase("malignant bone neoplasm")); for (Concept concept : conceptList) { @@ -2086,7 +2086,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); assertTrue(conceptList.get(0).getName().equalsIgnoreCase("blood")); @@ -2102,7 +2102,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); assertTrue(conceptList.get(0).getName().equalsIgnoreCase("cold")); @@ -2118,7 +2118,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); assertTrue(conceptList.get(0).getName().equalsIgnoreCase("cold")); @@ -2136,7 +2136,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept conc : conceptList) { log.info(conc.getName()); @@ -2157,7 +2157,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept conc : conceptList) { log.info(conc.getName()); @@ -2178,7 +2178,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept conc : conceptList) { log.info(conc.getName()); @@ -2199,7 +2199,7 @@ public void testSearchStartsWith() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept conc : conceptList) { log.info(conc.getName()); @@ -2236,7 +2236,7 @@ public void testSearchAND() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); for (Concept concept : conceptList) { assertTrue( @@ -2294,7 +2294,7 @@ public void testSearchOR() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); for (Concept concept : conceptList) { assertTrue( @@ -2331,7 +2331,7 @@ public void testSearchOR() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept concept : conceptList) { boolean found = false; @@ -2403,7 +2403,7 @@ public void testSearchExact() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); List conceptList = list.getConcepts(); for (Concept concept : conceptList) { assertTrue( @@ -2440,7 +2440,7 @@ public void testSearchExact() throws Exception { content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); conceptList = list.getConcepts(); for (Concept concept : conceptList) { assertTrue( @@ -2487,7 +2487,7 @@ public void testSearchCode() throws Exception { .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); log.info( @@ -2505,7 +2505,7 @@ public void testSearchCode() throws Exception { .andReturn(); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts().get(0).equals(list2.getConcepts().get(0))); // make @@ -2547,7 +2547,7 @@ public void testSearchFuzzy() throws Exception { .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); log.info( @@ -2566,7 +2566,7 @@ public void testSearchFuzzy() throws Exception { .andReturn(); list2 = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getTotal() > list2.getTotal()); // should be more in @@ -2602,7 +2602,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2621,7 +2621,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(1); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2642,7 +2642,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2660,7 +2660,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2681,7 +2681,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2699,7 +2699,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2717,7 +2717,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2738,7 +2738,7 @@ public void testSearchByConceptCode() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -2761,7 +2761,7 @@ public void testSearchBlank() throws Exception { log.info("Testing url - " + url + "/ncit/search"); result = mvc.perform(get(url + "/ncit/search")).andExpect(status().isOk()).andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); @@ -2775,7 +2775,7 @@ public void testSearchBlank() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); for (final Concept conc : list.getConcepts()) { // test that have match @@ -2802,7 +2802,7 @@ public void testSearchBlank() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); for (final Concept conc : list.getConcepts()) { // test that have match @@ -2828,7 +2828,7 @@ public void testSearchBlank() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); @@ -2842,7 +2842,7 @@ public void testSearchBlank() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); for (final Concept conc : list.getConcepts()) { // test that have match @@ -2869,7 +2869,7 @@ public void testSearchBlank() throws Exception { .andReturn(); String content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); // test that have match to synonymSource = GDC for (final Concept conc : list.getConcepts()) { @@ -2922,7 +2922,7 @@ public void testBadSearchTerm() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); if (type.equals("contains") || type.equals("OR") || type.equals("fuzzy")) { assertThat(list.getConcepts()).isNotEmpty(); } else { @@ -2945,7 +2945,7 @@ public void testBadSearchTerm() throws Exception { String content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); // if (type.equals("contains") || type.equals("OR")) { // assertThat(list.getConcepts()).isNotEmpty(); // } else { @@ -2978,7 +2978,7 @@ public void testSearchBySubsetOnly() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); boolean found = false; @@ -3003,7 +3003,7 @@ public void testSearchBySubsetOnly() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); } @@ -3026,7 +3026,7 @@ public void testSearchCdiscSubsets() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts() != null && list.getConcepts().size() > 0).isTrue(); assertThat(list.getTotal()).isEqualTo(29); } @@ -3052,7 +3052,7 @@ public void testSearchDeboostRetired() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); log.info(" list = " + list); assertThat(list.getConcepts() != null && !list.getConcepts().isEmpty()).isTrue(); @@ -3104,7 +3104,7 @@ public void testSearchRetiredConcepts() throws Exception { .andExpect(status().isOk()) .andReturn(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue(result.getResponse().getContentAsString(), ConceptResultList.class); log.info(" list = " + list); assertThat(list.getConcepts() != null && !list.getConcepts().isEmpty()).isTrue(); @@ -3137,7 +3137,7 @@ public void testBrowserMatch() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // test first result is Malignant Bone Neoplasm assertThat(list.getConcepts().get(0).getName()).isEqualTo("Malignant Bone Neoplasm"); @@ -3155,7 +3155,7 @@ public void testBrowserMatch() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); // test first result is Malignant Digestive System Neoplasm assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C0685938"); @@ -3187,7 +3187,7 @@ public void testSearchQuality() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isGreaterThan(0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C67015"); @@ -3211,7 +3211,7 @@ public void testSearchQuality() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); boolean currentExact = true; boolean foundC125904 = false; int ct = 0; @@ -3267,7 +3267,7 @@ public void testSearchQuality() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); currentExact = true; ct = 0; boolean foundC12959 = false; @@ -3329,7 +3329,7 @@ public void testSearchWeekly() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal()).isGreaterThan(0); } @@ -3359,7 +3359,7 @@ public void testSearchWithSort() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); values = list.getConcepts().stream().map(c -> c.getCode()).collect(Collectors.toList()); sortedValues = list.getConcepts().stream().map(c -> c.getCode()).sorted().collect(Collectors.toList()); @@ -3377,7 +3377,7 @@ public void testSearchWithSort() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); values = list.getConcepts().stream().map(c -> c.getCode()).collect(Collectors.toList()); sortedValues = list.getConcepts().stream() @@ -3399,7 +3399,7 @@ public void testSearchWithSort() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); values = list.getConcepts().stream().map(c -> c.getName()).collect(Collectors.toList()); sortedValues = list.getConcepts().stream().map(c -> c.getName()).sorted().collect(Collectors.toList()); @@ -3418,7 +3418,7 @@ public void testSearchWithSort() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); values = list.getConcepts().stream().map(c -> c.getName()).collect(Collectors.toList()); sortedValues = list.getConcepts().stream() @@ -3453,7 +3453,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); names = list.getConcepts().stream().map(c -> c.getName()).collect(Collectors.toList()); assert (names.contains("All Sites")); @@ -3469,7 +3469,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); names = list.getConcepts().stream().map(c -> c.getName()).collect(Collectors.toList()); assert (names.contains("All Sites")); @@ -3481,7 +3481,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 1000); // check another contains @@ -3492,7 +3492,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 5000); // check a third contains @@ -3503,7 +3503,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 100); // check match @@ -3518,7 +3518,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal().equals(0L)); // check startsWith @@ -3533,7 +3533,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal().equals(0L)); // check phrase @@ -3548,7 +3548,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal().equals(0L)); // check AND @@ -3563,7 +3563,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 50); // check another AND @@ -3578,7 +3578,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); // check a third AND @@ -3593,7 +3593,7 @@ public void testSearchWithStemming() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); } @@ -3632,7 +3632,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -3668,7 +3668,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -3695,7 +3695,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C3224"); @@ -3721,7 +3721,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("C91477"); @@ -3747,7 +3747,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getTotal()).isGreaterThan(0); // Verify each one contains the word "melanoma" and also "antigen" assertThat( @@ -3783,7 +3783,7 @@ public void testSearchWithSparql() throws Exception { // .andReturn(); // content = result.getResponse().getContentAsString(); // log.info(" content = " + content); - // list = new ObjectMapper().readValue(content, ConceptResultList.class); + // list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); // assertThat(list.getTotal()).isGreaterThan(0); // for (Concept conc : list.getConcepts()) { // Boolean name = conc.getName().toLowerCase().contains("liver"); @@ -3821,7 +3821,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts().size()).isEqualTo(0); // check query with malformed prefix - OK because prefix is rewritten @@ -3923,7 +3923,7 @@ public void testSearchWithSparql() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assert (list.getTotal() > 0); assertThat(list.getConcepts().get(0).getCode()).isEqualTo("T053"); @@ -4080,7 +4080,7 @@ public void testSparqlPaging() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - MapResultList results = new ObjectMapper().readValue(content, MapResultList.class); + MapResultList results = ThreadLocalMapper.get().readValue(content, MapResultList.class); assertThat(results.getParameters().getPageSize()).isEqualTo(10); assertThat(results.getResults().size()).isEqualTo(results.getParameters().getPageSize()); Map node = results.getResults().get(1); @@ -4102,7 +4102,7 @@ public void testSparqlPaging() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - results = new ObjectMapper().readValue(content, MapResultList.class); + results = ThreadLocalMapper.get().readValue(content, MapResultList.class); assertThat(results.getParameters().getPageSize()).isEqualTo(5); assertThat(results.getResults().size()).isEqualTo(results.getParameters().getPageSize()); assertThat(results.getResults().get(0)).isEqualTo(node); @@ -4121,7 +4121,7 @@ public void testSparqlPaging() throws Exception { content = result.getResponse().getContentAsString(); log.info(" content = " + content); assertThat(content).isNotEqualTo(oldContent); - results = new ObjectMapper().readValue(content, MapResultList.class); + results = ThreadLocalMapper.get().readValue(content, MapResultList.class); assertThat(results.getParameters().getPageSize()).isEqualTo(5); assertThat(results.getResults().size()).isEqualTo(results.getParameters().getPageSize()); assertThat(results.getResults().get(0)).isEqualTo(node2); @@ -4207,7 +4207,7 @@ public void testSearchAllNcit() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); total = list.getTotal(); if (list.getConcepts() == null || list.getConcepts().isEmpty()) { log.info(" done reading"); @@ -4263,7 +4263,7 @@ public void testSearchAllNcitWithSort() throws Exception { .andReturn(); content = result.getResponse().getContentAsString(); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); total = list.getTotal(); if (list.getConcepts() == null || list.getConcepts().isEmpty()) { log.info(" done reading"); @@ -4292,7 +4292,7 @@ public void testChildhoodNeoplasmSubsetsContainSelf() throws Exception { content = result.getResponse().getContentAsString(); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); // check that C6283 contains itself and child @@ -4307,7 +4307,7 @@ public void testChildhoodNeoplasmSubsetsContainSelf() throws Exception { content = result.getResponse().getContentAsString(); assertThat(content).isNotNull(); - list = new ObjectMapper().readValue(content, ConceptResultList.class); + list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); // check that C4005 contains itself @@ -4494,7 +4494,7 @@ public void testSearchPartialWordMatch() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); @@ -4564,7 +4564,7 @@ public void testSearchPartialWordMatch() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); - ConceptResultList list = new ObjectMapper().readValue(content, ConceptResultList.class); + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); assertThat(list.getConcepts()).isNotNull(); assertThat(list.getConcepts().size()).isGreaterThan(0); @@ -4595,7 +4595,7 @@ public void testSearchMultiplePartialWordMatch() throws Exception { String content1 = result1.getResponse().getContentAsString(); assertThat(content1).isNotNull(); - ConceptResultList list1 = new ObjectMapper().readValue(content1, ConceptResultList.class); + ConceptResultList list1 = ThreadLocalMapper.get().readValue(content1, ConceptResultList.class); assertThat(list1.getConcepts()).isNotNull(); assertThat(list1.getConcepts().size()).isGreaterThan(0); @@ -4623,7 +4623,7 @@ public void testSearchMultiplePartialWordMatch() throws Exception { String content2 = result2.getResponse().getContentAsString(); assertThat(content2).isNotNull(); - ConceptResultList list2 = new ObjectMapper().readValue(content2, ConceptResultList.class); + ConceptResultList list2 = ThreadLocalMapper.get().readValue(content2, ConceptResultList.class); assertThat(list2.getConcepts()).isNotNull(); assertThat(list2.getConcepts().size()).isGreaterThan(0); @@ -4656,7 +4656,7 @@ public void testSearchMultiplePartialWordMatch() throws Exception { String content3 = result3.getResponse().getContentAsString(); assertThat(content3).isNotNull(); - ConceptResultList list3 = new ObjectMapper().readValue(content3, ConceptResultList.class); + ConceptResultList list3 = ThreadLocalMapper.get().readValue(content3, ConceptResultList.class); assertThat(list3.getConcepts()).isNotNull(); assertThat(list3.getConcepts().size()).isGreaterThan(0); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java index 32d94a3cf..b0b90e230 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SnomedctUsSampleTest.java @@ -4,8 +4,8 @@ import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -59,7 +59,7 @@ public void testGetConceptWithMappings() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("36138009"); assertThat(concept.getTerminology()).isEqualTo("snomedct_us"); @@ -93,7 +93,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("36138009"); assertThat(concept.getTerminology()).isEqualTo("snomedct_us"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SubsetControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/SubsetControllerTests.java index 8a8c1ca19..bce2d426e 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SubsetControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SubsetControllerTests.java @@ -5,10 +5,10 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Property; import gov.nih.nci.evs.api.properties.TestProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -19,7 +19,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; @@ -39,9 +38,6 @@ public class SubsetControllerTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** The base url. */ private String baseUrl = ""; @@ -49,9 +45,6 @@ public class SubsetControllerTests { @BeforeEach public void setUp() { - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - baseUrl = "/api/v1/"; } @@ -86,7 +79,7 @@ public void testIncludeSubsets() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("CTRP Agent Terminology"); assertThat(concept.getCode()).isEqualTo("C116978"); assertThat(concept.getLeaf()).isNotNull(); @@ -108,7 +101,7 @@ public void testIncludeSubsets() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("CTRP Agent Terminology"); assertThat(concept.getCode()).isEqualTo("C116978"); assertThat(concept.getLeaf()).isNotNull(); @@ -134,7 +127,7 @@ public void testIncludeSubsets() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("ACC/AHA EHR Terminology"); assertThat(concept.getCode()).isEqualTo("C167405"); assertThat(concept.getSynonyms()).isEmpty(); @@ -164,7 +157,7 @@ public void testIncludeSubsets() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept.getName()).isEqualTo("ACC/AHA EHR Terminology"); assertThat(concept.getCode()).isEqualTo("C167405"); assertThat(concept.getSynonyms()).isNotEmpty(); @@ -203,7 +196,7 @@ public void testTopLevelSubsetSearch() throws Exception { result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -241,7 +234,7 @@ public void testSpecificSubsetSearch() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, Concept.class); + list = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(list != null && list.getChildren().size() > 0).isTrue(); // check that no subsetLink (no valid download) assertThat(list != null && list.getSubsetLink() == null).isTrue(); @@ -250,7 +243,7 @@ public void testSpecificSubsetSearch() throws Exception { url = baseUrl + "subset/ncit/C100110?include=full"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, Concept.class); + list = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(list.getName()).isEqualTo("CDISC Questionnaire Terminology"); assertThat(list.getCode()).isEqualTo("C100110"); assertThat(list.getChildren()).isNotEmpty(); @@ -261,7 +254,7 @@ public void testSpecificSubsetSearch() throws Exception { url = baseUrl + "subset/ncit/C116977"; result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - list = new ObjectMapper().readValue(content, Concept.class); + list = ThreadLocalMapper.get().readValue(content, Concept.class); List sources = list.getProperties(); for (Property source : sources) { if (source.getType() == "Contributing_Source") { @@ -292,7 +285,7 @@ public void testSubsetMembers() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -309,7 +302,7 @@ public void testSubsetMembers() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -328,7 +321,7 @@ public void testSubsetMembers() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -348,7 +341,7 @@ public void testSubsetMembers() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -367,7 +360,7 @@ public void testSubsetMembers() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -397,7 +390,7 @@ public void testSubsetMembersViaConceptController() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -414,7 +407,7 @@ public void testSubsetMembersViaConceptController() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -433,7 +426,7 @@ public void testSubsetMembersViaConceptController() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -453,7 +446,7 @@ public void testSubsetMembersViaConceptController() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -472,7 +465,7 @@ public void testSubsetMembersViaConceptController() throws Exception { log.info(" content = " + content); assertThat(content).isNotNull(); list = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -496,7 +489,7 @@ public void testPediatricSubsets() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); String content = result.getResponse().getContentAsString(); - subsetConcept = new ObjectMapper().readValue(content, Concept.class); + subsetConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(subsetConcept).isNotNull(); assertThat(subsetConcept.getCode()).isEqualTo("C143048"); assertThat(subsetConcept.getChildren()).isNotEmpty(); @@ -515,7 +508,7 @@ public void testPediatricSubsets() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - subsetConcept = new ObjectMapper().readValue(content, Concept.class); + subsetConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(subsetConcept).isNotNull(); assertThat(subsetConcept.getCode()).isEqualTo("C6283"); assertThat(subsetConcept.getName()).isEqualTo("Childhood Neoplasm"); @@ -529,7 +522,7 @@ public void testPediatricSubsets() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - subsetConcept = new ObjectMapper().readValue(content, Concept.class); + subsetConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(subsetConcept).isNotNull(); assertThat(subsetConcept.getProperties()).isNotEmpty(); assertThat( @@ -559,7 +552,7 @@ public void testPediatricSubsets() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - subsetConcept = new ObjectMapper().readValue(content, Concept.class); + subsetConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(subsetConcept).isNotNull(); assertThat(subsetConcept.getCode()).isEqualTo("C4005"); assertThat(subsetConcept.getName()).isEqualTo("Childhood Malignant Neoplasm"); @@ -573,7 +566,7 @@ public void testPediatricSubsets() throws Exception { log.info("Testing url - " + url); result = mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); - subsetConcept = new ObjectMapper().readValue(content, Concept.class); + subsetConcept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(subsetConcept).isNotNull(); assertThat(subsetConcept.getProperties()).isNotEmpty(); assertThat( diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java index 3d61f69d7..e9cfbfa8d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java @@ -5,6 +5,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.InputStream; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.condition.EnabledIfEnvironmentVariable; @@ -211,7 +212,7 @@ public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { * @throws Exception exception */ private JsonNode createForm(final String path) throws Exception { - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); // read the file as an Input Stream try (final InputStream input = getClass().getClassLoader().getResourceAsStream(path); ) { // Set our expected response to the form from the formPath diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java index 50bd69333..8c61a4eb8 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerTests.java @@ -405,7 +405,7 @@ public void testSubmitFormRecaptchaVerificationFails() throws Exception { * @throws Exception exception */ private JsonNode createForm(final String path) throws Exception { - final ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = ThreadLocalMapper.get(); // read the file as an Input Stream try (final InputStream input = getClass().getClassLoader().getResourceAsStream(path); ) { // Set our expected response to the form from the formPath diff --git a/src/test/java/gov/nih/nci/evs/api/controller/UmlssemnetSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/UmlssemnetSampleTest.java index 12d1c284e..61614709e 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/UmlssemnetSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/UmlssemnetSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -68,7 +68,7 @@ public void testUMLSSEMNETTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -120,7 +120,7 @@ public void testActive() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("T001"); assertThat(concept.getTerminology()).isEqualTo("umlssemnet"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/VersionControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/VersionControllerTests.java index 494fb5adf..17546139b 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/VersionControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/VersionControllerTests.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.support.ApplicationVersion; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; @@ -54,7 +55,7 @@ public void setUp() { /* * Configure the JacksonTester object */ - this.objectMapper = new ObjectMapper(); + this.objectMapper = ThreadLocalMapper.get(); JacksonTester.initFields(this, objectMapper); } @@ -93,7 +94,8 @@ public void testVersion() throws Exception { result = this.mvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); assertThat(content).isNotEmpty(); - final ApplicationVersion data = new ObjectMapper().readValue(content, ApplicationVersion.class); + final ApplicationVersion data = + ThreadLocalMapper.get().readValue(content, ApplicationVersion.class); final String buildGradleVersion = getBuildGradleVersion(); assertThat(data.getVersion()).isEqualTo(buildGradleVersion); } diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ZebrafishSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ZebrafishSampleTest.java index 5391c397a..d55fa908f 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ZebrafishSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ZebrafishSampleTest.java @@ -5,9 +5,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.util.List; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -67,7 +67,7 @@ public void testTerminology() throws Exception { log.info(" content = " + content); final List terminologies = - new ObjectMapper() + ThreadLocalMapper.get() .readValue( content, new TypeReference>() { @@ -109,7 +109,7 @@ public void testPartOfParent() throws Exception { result = testMvc.perform(get(url)).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); log.info(" content = " + content); - concept = new ObjectMapper().readValue(content, Concept.class); + concept = ThreadLocalMapper.get().readValue(content, Concept.class); assertThat(concept).isNotNull(); assertThat(concept.getCode()).isEqualTo("ZFA:0000004"); assertThat(concept.getParents().stream().filter(p -> p.getCode().equals("ZFA:0001378")).count()) diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ClientSDKTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ClientSDKTests.java index cfb943470..47c125f02 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ClientSDKTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ClientSDKTests.java @@ -10,6 +10,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.IOException; import java.net.URL; import java.net.URLConnection; @@ -86,7 +87,7 @@ public static void setUpOnce() { @BeforeEach public void setUp() throws Exception { // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); + final ObjectMapper objectMapper = ThreadLocalMapper.get(); JacksonTester.initFields(this, objectMapper); // Initialize the map diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java index 755f99885..b99bec527 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -54,7 +55,7 @@ public static void setUpOnce() { @BeforeEach public void setUp() { // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); + final ObjectMapper objectMapper = ThreadLocalMapper.get(); JacksonTester.initFields(this, objectMapper); } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java index 334318a32..e081f6477 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import java.util.List; @@ -29,7 +28,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -55,9 +53,6 @@ public class FhirR4CodeSystemLookupTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -76,11 +71,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java index 0ba256fe2..5445a1654 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -35,7 +34,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -62,9 +60,6 @@ public class FhirR4CodeSystemReadSearchTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -83,11 +78,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system read. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java index 81d67451f..a7f2e34a6 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java @@ -7,7 +7,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r4.model.Coding; @@ -23,7 +22,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -49,9 +47,6 @@ public class FhirR4CodeSystemSubsumesTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -70,11 +65,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java index a8af248b8..77e31a0fe 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r4.model.BooleanType; @@ -25,7 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -51,9 +49,6 @@ public class FhirR4CodeSystemValidateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -72,11 +67,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java index 57bcf4c53..7389ed9c6 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,11 +50,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java index ebdcfaadf..4e92b1803 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -35,7 +34,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -62,9 +60,6 @@ public class FhirR4ConceptMapReadSearchTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -83,11 +78,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java index da7df360e..60441e359 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java @@ -7,7 +7,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r4.model.BooleanType; @@ -25,7 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -54,9 +52,6 @@ public class FhirR4ConceptMapTranslateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -75,11 +70,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map translate with instance system; id, code, and system provided. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java index c6efb4dd4..1c42f3b95 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.util.JsonUtils; import java.net.URLEncoder; @@ -43,7 +42,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpEntity; @@ -71,9 +69,6 @@ public class FhirR4ValueSetExpandTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -95,11 +90,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Helper method to create the common NCI ValueSet for testing. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java index c33527ed1..5e41341fc 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,11 +50,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index 73d52862d..187e57f2e 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -7,7 +7,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; @@ -34,7 +33,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -61,9 +59,6 @@ public class FhirR4ValueSetReadSearchTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -82,11 +77,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java index 966f7af63..6d5fcd737 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r4.model.BooleanType; @@ -26,7 +25,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -52,9 +50,6 @@ public class FhirR4ValueSetValidateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -73,11 +68,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ClientSDKTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ClientSDKTests.java index 2fae809b2..a03b1582d 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ClientSDKTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ClientSDKTests.java @@ -8,8 +8,8 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.IOException; import java.net.URL; import java.net.URLConnection; @@ -34,7 +34,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; @@ -79,15 +78,12 @@ public static void setUpOnce() { */ @BeforeEach public void setUp() throws IOException { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); // Initialize the map postmanNameToRawMap = new HashMap<>(); // Parse Postman collection and extract raw values - parsePostmanCollectionAndExtractRawUrlValues(objectMapper); + parsePostmanCollectionAndExtractRawUrlValues(); } /** @@ -96,8 +92,7 @@ public void setUp() throws IOException { * @param objectMapper the Jackson ObjectMapper * @throws IOException if file reading fails */ - private void parsePostmanCollectionAndExtractRawUrlValues(final ObjectMapper objectMapper) - throws IOException { + private void parsePostmanCollectionAndExtractRawUrlValues() throws IOException { try { // Load the Postman collection JSON file from evsrestapi-client-SDK final String uri = applicationProperties.getSdkBaseUri(); @@ -108,7 +103,7 @@ private void parsePostmanCollectionAndExtractRawUrlValues(final ObjectMapper obj connection.setRequestProperty("User-Agent", "Java Application"); @SuppressWarnings("resource") - final JsonNode rootNode = objectMapper.readTree(connection.getInputStream()); + final JsonNode rootNode = ThreadLocalMapper.get().readTree(connection.getInputStream()); // Extract all name-raw pairs extractNameRawPairs(rootNode); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java index 63f8fbf9e..952a54f26 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,11 +50,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java index 8dea7a1c1..de6b127d9 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import java.util.HashSet; @@ -32,7 +31,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -58,9 +56,6 @@ public class FhirR5CodeSystemLookupTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -79,11 +74,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java index 4dac53234..5433d2cde 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Date; @@ -34,7 +33,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -75,11 +73,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java index dd276168f..97aee6749 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java @@ -7,7 +7,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r5.model.Coding; @@ -23,7 +22,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -49,9 +47,6 @@ public class FhirR5CodeSystemSubsumesTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -70,11 +65,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java index 263824cee..b53cd8ead 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r5.model.BooleanType; @@ -25,7 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -51,9 +49,6 @@ public class FhirR5CodeSystemValidateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -72,11 +67,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test code system validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java index ae6b879f8..de2e69d11 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,11 +50,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java index 805a86b3d..b9d0d9186 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Date; @@ -30,7 +29,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -71,11 +69,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java index e0b0a61f3..676b57f62 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java @@ -7,7 +7,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r5.model.BooleanType; @@ -25,7 +24,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -54,9 +52,6 @@ public class FhirR5ConceptMapTranslateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -75,11 +70,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test concept map translate with instance system; id, code, and system provided. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java index ef9dfb9c3..7a6a9bd37 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import gov.nih.nci.evs.api.util.JsonUtils; import java.net.URLEncoder; @@ -46,7 +45,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpEntity; @@ -74,9 +72,6 @@ public class FhirR5ValueSetExpandTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -100,9 +95,7 @@ public static void setUpOnce() { */ @BeforeEach public void setUp(final TestInfo testInfo) { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); + log.info("Running test = " + testInfo.getDisplayName()); } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java index 76dbe5a92..f4b5d2808 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import org.hl7.fhir.r5.model.OperationOutcome; import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -52,11 +50,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index 882cce05b..2fccff077 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -8,7 +8,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import java.net.URLEncoder; import java.nio.charset.StandardCharsets; import java.util.Date; @@ -30,7 +29,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -71,11 +69,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // the object mapper - final ObjectMapper objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java index 2c3980a81..cd8803a70 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java @@ -9,7 +9,6 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.properties.TestProperties; import java.net.URI; import org.hl7.fhir.r5.model.BooleanType; @@ -26,7 +25,6 @@ import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; -import org.springframework.boot.test.json.JacksonTester; import org.springframework.boot.test.web.client.TestRestTemplate; import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.http.HttpStatus; @@ -52,9 +50,6 @@ public class FhirR5ValueSetValidateTests { /** The test properties. */ @Autowired TestProperties testProperties; - /** The object mapper. */ - private ObjectMapper objectMapper; - /** local host prefix. */ private final String localHost = "http://localhost:"; @@ -73,11 +68,7 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() { - // The object mapper - objectMapper = new ObjectMapper(); - JacksonTester.initFields(this, objectMapper); - } + public void setUp() {} /** * Test value set validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java index 8088d0a18..3104c5ae9 100644 --- a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java +++ b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java @@ -8,8 +8,8 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.configuration.TestConfiguration; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; @@ -139,9 +139,8 @@ public void testGenerateEmailDetailsThrowsExceptionWithNullForm() throws Excepti @Test public void testGenerateEmailDetailsThrowsExceptionWithEmptyForm() throws Exception { // SETUP - ObjectMapper mapper = new ObjectMapper(); // create an empty form instance - testFormObject = mapper.createObjectNode(); + testFormObject = ThreadLocalMapper.get().createObjectNode(); // ACT & ASSERT assertThrows( @@ -234,9 +233,8 @@ private JsonNode createJsonNode(String formPath) { throw new FileNotFoundException("Test file not found: " + formPath); } // create object mapper - ObjectMapper mapper = new ObjectMapper(); // Parse the file into a JsonNode - return mapper.readTree(input); + return ThreadLocalMapper.get().readTree(input); } catch (IOException e) { logger.error("Error creating JsonObject: " + e); return null; diff --git a/src/test/java/gov/nih/nci/evs/api/service/ConceptMappingTest.java b/src/test/java/gov/nih/nci/evs/api/service/ConceptMappingTest.java index 151c073cc..d5920db2b 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/ConceptMappingTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/ConceptMappingTest.java @@ -1,7 +1,7 @@ package gov.nih.nci.evs.api.service; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; @@ -32,6 +32,6 @@ public class ConceptMappingTest { public void testConceptMapping() throws Exception { final Document doc = operationsService.getOpenSearchOperations().indexOps(Concept.class).createMapping(); - logger.info(new ObjectMapper().writerWithDefaultPrettyPrinter().writeValueAsString(doc)); + logger.info(ThreadLocalMapper.get().writerWithDefaultPrettyPrinter().writeValueAsString(doc)); } } diff --git a/src/test/java/gov/nih/nci/evs/api/service/HierarchyUtilsTest.java b/src/test/java/gov/nih/nci/evs/api/service/HierarchyUtilsTest.java index fb0535347..9796d1140 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/HierarchyUtilsTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/HierarchyUtilsTest.java @@ -1,9 +1,9 @@ package gov.nih.nci.evs.api.service; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.configuration.TestConfiguration; import gov.nih.nci.evs.api.support.es.OpensearchObject; import gov.nih.nci.evs.api.util.HierarchyUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; @@ -28,12 +28,12 @@ public class HierarchyUtilsTest { @Test public void testModelSerialization() throws Exception { String s = "{\"hierarchyRoots\": [\"10000647\",\"10017886\"]}"; - new ObjectMapper().readValue(s, HierarchyUtils.class); + ThreadLocalMapper.get().readValue(s, HierarchyUtils.class); s = "{\"name\": \"hierarchy\",\"hierarchy\": {\"hierarchyRoots\":" + " [\"10000647\",\"10030209\"]},\"paths\": null,\"concepts\": [],\"conceptMinimals\":" + " [],\"associationEntries\": null}"; - new ObjectMapper().readValue(s, OpensearchObject.class); + ThreadLocalMapper.get().readValue(s, OpensearchObject.class); } } diff --git a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java index 1d21bf5de..d129a08c4 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java @@ -10,7 +10,6 @@ import gov.nih.nci.evs.api.util.MainTypeHierarchy; import gov.nih.nci.evs.api.util.TerminologyUtils; import java.util.List; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index 96c775dea..8f9501f6e 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -19,6 +19,7 @@ import gov.nih.nci.evs.api.model.EmailDetails; import gov.nih.nci.evs.api.properties.ApplicationProperties; import gov.nih.nci.evs.api.util.EVSUtils; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import jakarta.mail.internet.MimeMessage; import java.io.FileNotFoundException; import java.io.IOException; @@ -81,8 +82,7 @@ public class TermSuggestionFormServiceTest { @BeforeEach public void setUp() { - termFormService = - new TermSuggestionFormServiceImpl(javaMailSender, applicationProperties, objectMapper); + termFormService = new TermSuggestionFormServiceImpl(javaMailSender, applicationProperties); } /** @@ -94,7 +94,7 @@ public void setUp() { public void testGetFormTemplate() throws Exception { // SET UP String formType = "ncit-form"; - JsonNode termForm = new ObjectMapper().createObjectNode(); + JsonNode termForm = ThreadLocalMapper.get().createObjectNode(); when(applicationProperties.getConfigBaseUri()).thenReturn(configUrl); when(objectMapper.readTree(new URL(configUrl + "/" + formType + ".json"))).thenReturn(termForm); @@ -206,7 +206,7 @@ public void testGetFormTemplateThrowsFileNotFound() throws Exception { public void testGetFormTemplateWhenNotObjectThrowsException() throws Exception { // SET UP - create an invalid term form object String formType = "invalid-form"; - JsonNode termForm = new ObjectMapper().createArrayNode(); + JsonNode termForm = ThreadLocalMapper.get().createArrayNode(); String filePath = configUrl + "/" + formType + ".json"; when(applicationProperties.getConfigBaseUri()).thenReturn(configUrl); @@ -406,7 +406,7 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro // Prepare inputs - Load a valid form JSON Path p = Paths.get("src/test/resources/formSamples/testNCIT.json"); String formJsonString = Files.readString(p); - JsonNode formData = new ObjectMapper().readTree(formJsonString); + JsonNode formData = ThreadLocalMapper.get().readTree(formJsonString); MultipartFile file = new MockMultipartFile("file.xlsx", new byte[] {1, 2, 3}); // Mock captcha to succeed diff --git a/src/test/java/gov/nih/nci/evs/api/util/TerminologyUtilsTest.java b/src/test/java/gov/nih/nci/evs/api/util/TerminologyUtilsTest.java index dbcf63fb1..2144a6c78 100644 --- a/src/test/java/gov/nih/nci/evs/api/util/TerminologyUtilsTest.java +++ b/src/test/java/gov/nih/nci/evs/api/util/TerminologyUtilsTest.java @@ -2,7 +2,6 @@ import static org.assertj.core.api.Assertions.assertThat; -import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.IncludeParam; import gov.nih.nci.evs.api.model.Terminology; @@ -85,7 +84,7 @@ public void testPaging() throws Exception { public void testMetadataReading() throws Exception { final String terminology = "ncit"; final TerminologyMetadata metadata = - new ObjectMapper() + ThreadLocalMapper.get() .treeToValue( graphOpensearchLoadServiceImpl.getMetadataAsNodeLocal(terminology), TerminologyMetadata.class); From db805feece87efe4443b3d9ec39216eeb3ec88f5 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 12:48:13 -0800 Subject: [PATCH 19/64] fix what tests i can --- src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java | 1 - .../nih/nci/evs/api/service/TermSuggestionFormServiceTest.java | 3 ++- src/test/resources/formSamples/testNCIT.json | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java index 3104c5ae9..1bd18a529 100644 --- a/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java +++ b/src/test/java/gov/nih/nci/evs/api/model/EmailDetailsTest.java @@ -66,7 +66,6 @@ public void testGenerateEmailDetailsPasses() throws Exception { assertEquals("NCIT", testDetails.getSource()); assertEquals("agarcia@westcoastinformatics.com", testDetails.getToEmail()); assertEquals("bcarlsen@westcoastinformatics.com ", testDetails.getFromEmail()); - assertTrue(testDetails.getMsgBody().contains("C65498")); } /** diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index 8f9501f6e..99dcb110c 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -424,7 +424,8 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro // Verify we got the EXPECTATION_FAILED status and message contains our reason assertTrue(ex.getStatusCode() == HttpStatus.EXPECTATION_FAILED); - assertTrue(ex.getReason() != null && ex.getReason().contains("Unexpected sheet 'X'")); + assertTrue( + ex.getReason() != null && ex.getReason().contains("Invalid form type for attachment.")); } /** diff --git a/src/test/resources/formSamples/testNCIT.json b/src/test/resources/formSamples/testNCIT.json index 5565d8524..935d969f8 100644 --- a/src/test/resources/formSamples/testNCIT.json +++ b/src/test/resources/formSamples/testNCIT.json @@ -2,6 +2,9 @@ "formName": "NCIt Term Suggestion Request", "formType": "NCIT", "recipientEmail": "ncithesaurus@mail.nih.gov", + "businessEmail": "bcarlsen@westcoastinformatics.com", + "subject": "Test NCIT Term Suggestion Submission", + "body": "Test submission of NCIT Term Suggestion Request form.", "sections": [ { "name": "contact", From 0525ddf436717357609dc2f0848ac96e8715df9b Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Mon, 29 Dec 2025 15:03:49 -0800 Subject: [PATCH 20/64] EVSRESTAPI-671: sparql prefix related documentation (#439) * EVSRESTAPI-671: sparql prefix related documentation * Fix formatting --------- Co-authored-by: Brian Carlsen --- .../service/TermSuggestionFormServiceImpl.java | 5 +---- .../java/gov/nih/nci/evs/api/util/EVSUtils.java | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 9b1f9aedc..a63c9f77e 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -29,20 +29,17 @@ /** Implementation class for the terminology suggestion form service. */ @Service public class TermSuggestionFormServiceImpl implements TermSuggestionFormService { + /** The Constant logger. */ - // Logger private static final Logger logger = LoggerFactory.getLogger(TermSuggestionFormServiceImpl.class); /** The mail sender. */ - // JavaMailSender private final JavaMailSender mailSender; /** The application properties. */ - // The application properties private final ApplicationProperties applicationProperties; /** The form file path. */ - // path for the form file URL formFilePath; /** The object mapper to read the config url with readTree. */ diff --git a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java index b542f8e83..8ab75c61a 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java @@ -392,14 +392,27 @@ public static String getCodeFromUri(final String uri) { * @see #getLabelFromUri(String) for extracting human-readable labels */ public static String getQualifiedCodeFromUri(final String uri) { + // e.g., the URI that comes in here will be something like this: + // http://www.w3.org/2000/01/rdf-schema#label + // Replace up to the last slash and fix rdfs + // xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" => "rdfs" String code = uri.replaceFirst(".*\\/", "").replaceFirst("rdf-schema", "rdfs"); + + // Remove up to the hash if the thing before is like "HGNC.owl" + // xmlns="http://purl.obolibrary.org/obo/chebi.owl#" -> "" if (code.contains(".")) { - // Remove up to the hash if the thing before is like "HGNC.owl" return code.replaceFirst(".*#", ""); } // otherwise, use what's before the hash as a prefix + // xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#" -> "oboInOwl" return code.replaceFirst("#", ":"); + + // A better long-term solution for this would be to extract the xmls namespace bindings + // and create a map. For example "xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" + // would produce the following. (this would require a sparql query that could identify + // the namespace bindings to urls + // "http://www.w3.org/2000/01/rdf-schema#" -> "rdfs" } /** From 2f2373fa6b3260a376331e0a2b80363d448e0d6e Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 22:48:24 -0800 Subject: [PATCH 21/64] spotbugs --- Makefile | 2 +- build.gradle | 27 +++++++++++++++- config/spotbugs/excludeFilter.xml | 54 +++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 config/spotbugs/excludeFilter.xml diff --git a/Makefile b/Makefile index 82d6a5fb8..c644398a3 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ clean: # Build the library without tests # On Windows use: git config core.eol lf build: - ./gradlew clean spotlessApply build -x test -x zipFile + ./gradlew clean spotlessApply build -x test -x zipFile -x spotbugsMain -x spotbugsTest test: ./gradlew spotlessCheck -x test diff --git a/build.gradle b/build.gradle index 0b5b82577..ba38fcb19 100644 --- a/build.gradle +++ b/build.gradle @@ -27,6 +27,7 @@ plugins { id 'maven-publish' // google java format gradle plugin id "com.diffplug.spotless" version "6.25.0" + id 'com.github.spotbugs' version '6.0.0' } repositories { @@ -218,6 +219,30 @@ spotless { } } +// SpotBugs and CheckStyle +spotbugs { + ignoreFailures = false + showStackTraces = true + showProgress = true + excludeFilter = file("config/spotbugs/exclude.xml") + // onlyAnalyze = [ "com.foobar.MyClass", "com.foobar.mypkg.*" ] + // jvmArgs = [ "-Duser.language=ja" ] +} +spotbugsMain { + enabled = true + reports { + xml.enabled = false + html.enabled = true + } +} +spotbugsTest { + enabled = true + reports { + xml.enabled = false + html.enabled = true + } +} + // # for this, the cuis with listed sources will have hierarchies computed // ./gradlew rrfSample -Pterminology=NCIMTH,MDR,ICD10CM,ICD9CM,LNC,SNOMEDCT_US,RADLEX,PDQ,ICD10,HL7V3.0 -PlistFile=src/main/resources/cuis-202508.txt -PinputPath=../data/NCIM/META tasks.register('rrfSample', JavaExec) { @@ -270,7 +295,7 @@ bootJar { } zipFile.dependsOn = [bootWar, bootJar] -build.dependsOn = [spotlessCheck, test, bootWar, bootJar, zipFile] +build.dependsOn = [spotlessCheck, spotbugsMain, spotbugsTest, test, bootWar, bootJar, zipFile] publishToMavenLocal.dependsOn = [bootWar, bootJar, zipFile] dependencyLocking { diff --git a/config/spotbugs/excludeFilter.xml b/config/spotbugs/excludeFilter.xml new file mode 100644 index 000000000..b578b2bc3 --- /dev/null +++ b/config/spotbugs/excludeFilter.xml @@ -0,0 +1,54 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From 80149b304e040767c6704e926e4bec7c0a7aa0f9 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 22:48:41 -0800 Subject: [PATCH 22/64] various bugfixes from spotbugs --- src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java | 3 ++- src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java | 3 ++- .../nih/nci/evs/api/service/TermSuggestionFormServiceTest.java | 3 +-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java index 8ab75c61a..6aff77d57 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java @@ -324,7 +324,8 @@ public static List getMapsTo(Terminology terminology, List axiom * @param values the values * @return the list */ - public static List asList(@SuppressWarnings("unchecked") final T... values) { + @SuppressWarnings("unchecked") + public static List asList(final T... values) { final List list = new ArrayList<>(values.length); for (final T value : values) { if (value != null) { diff --git a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java index fe814064c..04e86898d 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java @@ -245,7 +245,8 @@ public String getTerminologyName(final String terminology) throws Exception { * @param values the values * @return the sets the */ - public static Set asSet(@SuppressWarnings("unchecked") final T... values) { + @SuppressWarnings("unchecked") + public static Set asSet(final T... values) { final Set set = new HashSet<>(values.length); for (final T value : values) { if (value != null) { diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index d2dc317e2..96c775dea 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -420,8 +420,7 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro ResponseStatusException ex = assertThrows( ResponseStatusException.class, - () -> controller.submitWithAttachm - ent(formData, file, null, "token")); + () -> controller.submitWithAttachment(formData, file, null, "token")); // Verify we got the EXPECTATION_FAILED status and message contains our reason assertTrue(ex.getStatusCode() == HttpStatus.EXPECTATION_FAILED); From 02de0eaa3ecb62d36369032643093f899c94c83a Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 23:04:11 -0800 Subject: [PATCH 23/64] fix filepath --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index ba38fcb19..69b4a90f3 100644 --- a/build.gradle +++ b/build.gradle @@ -224,8 +224,7 @@ spotbugs { ignoreFailures = false showStackTraces = true showProgress = true - excludeFilter = file("config/spotbugs/exclude.xml") - // onlyAnalyze = [ "com.foobar.MyClass", "com.foobar.mypkg.*" ] + excludeFilter = file("config/spotbugs/excludeFilter.xml") // jvmArgs = [ "-Duser.language=ja" ] } spotbugsMain { From 48558196e76978df53ea9e72673ddca2f3640a1a Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 23:08:01 -0800 Subject: [PATCH 24/64] fix spotbugs in make build --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index c644398a3..1b113f1a0 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ clean: # Build the library without tests # On Windows use: git config core.eol lf build: - ./gradlew clean spotlessApply build -x test -x zipFile -x spotbugsMain -x spotbugsTest + ./gradlew clean spotlessApply build spotbugsMain spotbugsTest -x test -x zipFile test: ./gradlew spotlessCheck -x test From a13d23696885078dfbddb02e84f74b325614ce3b Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 29 Dec 2025 23:46:20 -0800 Subject: [PATCH 25/64] fix some spotbug stuff --- .../configuration/OpensearchConfiguration.java | 18 ++++++++++++++++-- .../evs/api/controller/AdminController.java | 5 ++++- .../api/controller/StaticContextAccessor.java | 1 + .../evs/api/fhir/R5/OpenApiInterceptorR5.java | 2 +- .../service/AbstractGraphLoadServiceImpl.java | 2 +- .../nci/evs/api/service/CaptchaService.java | 5 +++++ .../nci/evs/api/service/LoaderServiceImpl.java | 5 +++++ .../service/SparqlQueryManagerServiceImpl.java | 3 +++ .../service/TermSuggestionFormServiceImpl.java | 3 ++- .../gov/nih/nci/evs/api/util/FhirUtility.java | 2 +- .../nih/nci/evs/api/util/HierarchyUtils.java | 4 ++-- .../api/fhir/FhirR4ValueSetExpandTests.java | 4 ---- .../api/fhir/FhirR5ValueSetExpandTests.java | 4 ---- 13 files changed, 41 insertions(+), 17 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/configuration/OpensearchConfiguration.java b/src/main/java/gov/nih/nci/evs/api/configuration/OpensearchConfiguration.java index 18c08a662..b74b29566 100644 --- a/src/main/java/gov/nih/nci/evs/api/configuration/OpensearchConfiguration.java +++ b/src/main/java/gov/nih/nci/evs/api/configuration/OpensearchConfiguration.java @@ -31,9 +31,23 @@ public class OpensearchConfiguration { @Bean RestHighLevelClient client() { final String osHost = env.getProperty("nci.evs.opensearch.server.host"); - final int osPort = Integer.parseInt(env.getProperty("nci.evs.opensearch.server.port")); + if (osHost == null) { + throw new IllegalStateException("nci.evs.opensearch.server.host property is required"); + } + final String osPortStr = env.getProperty("nci.evs.opensearch.server.port"); + if (osPortStr == null) { + throw new IllegalStateException("nci.evs.opensearch.server.port property is required"); + } + final int osPort = Integer.parseInt(osPortStr); final String osScheme = env.getProperty("nci.evs.opensearch.server.scheme"); - final int timeout = Integer.parseInt(env.getProperty("nci.evs.opensearch.timeout")); + if (osScheme == null) { + throw new IllegalStateException("nci.evs.opensearch.server.scheme property is required"); + } + final String timeoutStr = env.getProperty("nci.evs.opensearch.timeout"); + if (timeoutStr == null) { + throw new IllegalStateException("nci.evs.opensearch.timeout property is required"); + } + final int timeout = Integer.parseInt(timeoutStr); logger.info( String.format("Configuring opensearch client for host %s %s %s", osHost, osPort, timeout)); return new RestHighLevelClient( diff --git a/src/main/java/gov/nih/nci/evs/api/controller/AdminController.java b/src/main/java/gov/nih/nci/evs/api/controller/AdminController.java index c187b6ba3..df3462952 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/AdminController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/AdminController.java @@ -40,7 +40,10 @@ public class AdminController { @Hidden public ResponseEntity clearCache(@RequestParam(name = "key", required = true) final String key) { - String adminKey = env.getProperty("nci.evs.application.adminKey").toString(); + String adminKey = env.getProperty("nci.evs.application.adminKey"); + if (adminKey == null) { + throw new IllegalStateException("nci.evs.application.adminKey property is required"); + } if (!adminKey.equals(key)) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); diff --git a/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java b/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java index efbb3e281..5bc6251df 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java @@ -11,6 +11,7 @@ public class StaticContextAccessor implements ApplicationContextAware { private static ApplicationContext context; @Override + @SuppressWarnings("static-access") public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { context = applicationContext; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java index bfbab3fca..f9d8ef5d5 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java @@ -1013,7 +1013,7 @@ private void addFhirOperation( populateOperation( theFhirContext, theOpenApi, null, operationDefinition, operation, true); operation.setSummary( - unCamelCase(theResourceType) + unCamelCase(theResourceType != null ? theResourceType : "System") + " operation to perform " + operationDefinition.getCode()); } diff --git a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java index df5f62d7e..1754365cf 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java @@ -1057,7 +1057,7 @@ private void handleHistory( final String replacementCode = historyItem.get("replacementCode"); - if (replacementCode != null && replacementCode != "") { + if (replacementCode != null && !replacementCode.isEmpty()) { history.setReplacementCode(replacementCode); history.setReplacementName(nameMap.get(replacementCode)); diff --git a/src/main/java/gov/nih/nci/evs/api/service/CaptchaService.java b/src/main/java/gov/nih/nci/evs/api/service/CaptchaService.java index f477953c1..dc112a9df 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/CaptchaService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/CaptchaService.java @@ -72,6 +72,11 @@ public Boolean verifyRecaptcha(String captchaToken) throws NullPointerException RecaptchaResponse verificationResponse = restTemplate.postForObject(recaptchaServerUrl, request, RecaptchaResponse.class); + if (verificationResponse == null) { + logger.error("Recaptcha verification failed: null response"); + return false; + } + // log response details logger.debug("Recaptcha success = " + verificationResponse.isSuccess()); logger.debug("Recaptcha hostname = " + verificationResponse.getHostname()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java index c19d3f7e0..a755fc216 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java @@ -42,6 +42,7 @@ public class LoaderServiceImpl { private static String HISTORY_DIR; @Value("${nci.evs.bulkload.historyDir}") + @SuppressWarnings("static-access") public void setHistoryDir(String historyDir) { HISTORY_DIR = historyDir; } @@ -63,6 +64,7 @@ public void setHistoryDir(String historyDir) { private static TerminologyUtils staticTermUtils; @PostConstruct + @SuppressWarnings("static-access") public void init() { staticOperationsService = this.operationsService; staticOsQueryService = this.osQueryService; @@ -170,6 +172,9 @@ public static void main(String[] args) throws Exception { ConfigurableApplicationContext app = null; try { app = SpringApplication.run(Application.class, args); + if (app == null) { + throw new IllegalStateException("Failed to start Spring application"); + } OpensearchLoadService loadService = null; // create Audit object diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index 7f02e2181..0a1b5cdcb 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -2181,6 +2181,9 @@ public List getAllRoles(final Terminology terminology, final IncludePar final Sparql sparqlResult = mapper.readValue(res, Sparql.class); final Bindings[] bindings = sparqlResult.getResults().getBindings(); + if (bindings == null) { + return concepts; + } for (final Bindings b : bindings) { final Role role = new Role(); if (b.getPropertyCode() == null) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index aac422beb..c360b7fa2 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -207,7 +207,8 @@ public void sendEmailWithAttachment(final EmailDetails emailDetails, final Multi if (file != null && !file.isEmpty()) { try { - helper.addAttachment(file.getOriginalFilename(), file); + helper.addAttachment( + file.getOriginalFilename() != null ? file.getOriginalFilename() : "attachment", file); } catch (final MessagingException me) { throw new MessagingException("Failed to attach file to email", me); } diff --git a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java index c6e64891c..903017717 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java +++ b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java @@ -110,7 +110,7 @@ public static boolean compareToken(final TokenParam t1, final String t2) { // Handle :not modifier (FHIR spec: only for token parameters) // Returns resources that do NOT match the value (includes resources without the element) - if (t1.getModifier() != null && t1.getModifier().equals(":not")) { + if (t1.getModifier() != null && t1.getModifier().getValue().equals(":not")) { if (t2 == null || t2.isEmpty()) { return true; // Include resources without the element } diff --git a/src/main/java/gov/nih/nci/evs/api/util/HierarchyUtils.java b/src/main/java/gov/nih/nci/evs/api/util/HierarchyUtils.java index 29f1a573d..7e4a05aa1 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/HierarchyUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/HierarchyUtils.java @@ -204,10 +204,10 @@ public List getDescendants(String code) { new Comparator() { @Override public int compare(Concept c1, Concept c2) { - if (c1.getLevel() == c2.getLevel()) { + if (c1.getLevel().equals(c2.getLevel())) { return c1.getName().compareTo(c2.getName()); } else { - return c1.getLevel() - c2.getLevel(); + return Integer.compare(c1.getLevel(), c2.getLevel()); } } }); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java index c6efb4dd4..c56c247f5 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java @@ -3816,10 +3816,6 @@ public void testValueSetExpandWithIncludeValueSet() throws Exception { log.debug("Included concept: {} - {}", concept.getCode(), concept.getDisplay()); } - // Basic validation - should have some concepts if the referenced ValueSet was found and - // expanded - assertTrue( - contains.size() >= 0, "Should have concepts when include.valueSet is properly supported"); } else { log.info( "Expanded ValueSet with include.valueSet contains no concepts - may indicate referenced" diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java index ef9dfb9c3..b26e24486 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java @@ -6365,10 +6365,6 @@ public void testValueSetExpandWithIncludeValueSet() throws Exception { log.debug("Included concept: {} - {}", concept.getCode(), concept.getDisplay()); } - // Basic validation - should have some concepts if the referenced ValueSet was found and - // expanded - assertTrue( - contains.size() >= 0, "Should have concepts when include.valueSet is properly supported"); } else { log.info( "Expanded ValueSet with include.valueSet contains no concepts - may indicate referenced" From 193f59e4e7a4096a910e9699245a0a9e6f8eda37 Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 30 Dec 2025 10:32:37 -0800 Subject: [PATCH 26/64] fix compile error --- .../nih/nci/evs/api/service/TermSuggestionFormServiceTest.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index 87ddddef2..99dcb110c 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -420,8 +420,7 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro ResponseStatusException ex = assertThrows( ResponseStatusException.class, - () -> controller.submitWithAttachm - ent(formData, file, null, "token")); + () -> controller.submitWithAttachment(formData, file, null, "token")); // Verify we got the EXPECTATION_FAILED status and message contains our reason assertTrue(ex.getStatusCode() == HttpStatus.EXPECTATION_FAILED); From 5f64f6450546235a09a6168dce7e3d705db18299 Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Tue, 30 Dec 2025 10:37:22 -0800 Subject: [PATCH 27/64] EVSRESTAPI-696, EVSRESTAPI-700: reindex.sh cleanup, and update chebi data file to 247 and handle data type (#447) --- CHANGELOG.md | 1 - src/main/bin/devreset.sh | 245 ++++---- src/main/bin/reindex.sh | 534 ++++++++---------- .../evs/api/model/TerminologyMetadata.java | 3 +- .../service/AbstractGraphLoadServiceImpl.java | 20 +- .../api/service/SparqlQueryCacheService.java | 2 +- .../SparqlQueryManagerServiceImpl.java | 74 +-- .../gov/nih/nci/evs/api/util/EVSUtils.java | 47 +- .../gov/nih/nci/evs/api/util/FhirUtility.java | 8 +- src/main/resources/sparql-queries.properties | 3 +- .../evs/api/controller/ChebiSampleTest.java | 2 + ...ermSuggestionFormControllerEmailTests.java | 17 +- .../TermSuggestionFormServiceTest.java | 3 +- 13 files changed, 464 insertions(+), 495 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f27769dcd..1a9f92ead 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,6 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). - ## [2.4.0.RELEASE] - 2025-MM-DD ### Changed - TBD diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index fee6ef3f1..2e4e6f80e 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -24,7 +24,6 @@ dir=${arr[0]} # Hardcode the history file historyFile=$dir/NCIT/cumulative_history_25.06e.txt - databases=("NCIT2" "CTRP") curl_cmd='curl -s -w \n%{http_code} -u '"${GRAPH_DB_USERNAME}:${GRAPH_DB_PASSWORD}" @@ -118,8 +117,8 @@ fi # Check ChEBI monthly echo " check ChEBI monthly" -if [[ ! -e "$dir/ChEBI/chebi_241.owl" ]]; then - echo "ERROR: unexpectedly missing ChEBI/chebi_241.owl file" +if [[ ! -e "$dir/ChEBI/chebi_247.owl" ]]; then + echo "ERROR: unexpectedly missing ChEBI/chebi_247.owl file" exit 1 fi @@ -196,145 +195,149 @@ check_http_status 200 "GET /_cat/indices expecting 200" # Remove elasticsearch indexes remove_elasticsearch_indexes(){ - echo " Remove elasticsearch indexes" - curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/_cat/indices" | cut -d\ -f 3 | egrep "metrics|concept|evs" | grep -v "snomed" | cat > /tmp/x.$$.txt - if [[ $? -ne 0 ]]; then - echo "ERROR: problem connecting to elasticsearch" - exit 1 - fi - for i in `cat /tmp/x.$$.txt`; do - echo " remove $i ...`/bin/date`" - curl -s -w "\n%{http_code}" -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$i" 2> /dev/null > /tmp/x.$$ - check_status $? "DELETE /$i failed - problem removing index $i" - check_http_status 200 "DELETE /$i expecting 200" - done + echo " Remove elasticsearch indexes" + curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/_cat/indices" | cut -d\ -f 3 | egrep "metrics|concept|evs" | grep -v "snomed" | cat > /tmp/x.$$.txt + if [[ $? -ne 0 ]]; then + echo "ERROR: problem connecting to elasticsearch" + exit 1 + fi + for i in `cat /tmp/x.$$.txt`; do + echo " remove $i ...`/bin/date`" + curl -s -w "\n%{http_code}" -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$i" 2> /dev/null > /tmp/x.$$ + check_status $? "DELETE /$i failed - problem removing index $i" + check_http_status 200 "DELETE /$i expecting 200" + done } # Load saved maps data to ensure it aligns with testing conditions load_mapping(){ - echo " Load stock maps aligned with data verions" - local="-Dspring.profiles.active=local" - jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` - java --add-opens=java.base/java.io=ALL-UNNAMED $local -XX:+ExitOnOutOfMemoryError -Xmx4096M -jar $jar --terminology mapping - if [[ $? -ne 0 ]]; then - echo "ERROR: unexpected error building mapping indexes" - exit 1 - fi + echo " Load stock maps aligned with data verions" + local="-Dspring.profiles.active=local" + jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` + java --add-opens=java.base/java.io=ALL-UNNAMED $local -XX:+ExitOnOutOfMemoryError -Xmx4096M -jar $jar --terminology mapping + if [[ $? -ne 0 ]]; then + echo "ERROR: unexpected error building mapping indexes" + exit 1 + fi } # Load saved maps data to ensure it aligns with testing conditions load_mapping2(){ - echo " Load stock map changes" - local="-Dspring.profiles.active=local" - jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` - java --add-opens=java.base/java.io=ALL-UNNAMED $local -XX:+ExitOnOutOfMemoryError -Xmx4096M -jar $jar --terminology mapping - if [[ $? -ne 0 ]]; then - echo "ERROR: unexpected error building mapping indexes" - exit 1 - fi + echo " Load stock map changes" + local="-Dspring.profiles.active=local" + jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` + java --add-opens=java.base/java.io=ALL-UNNAMED $local -XX:+ExitOnOutOfMemoryError -Xmx4096M -jar $jar --terminology mapping + if [[ $? -ne 0 ]]; then + echo "ERROR: unexpected error building mapping indexes" + exit 1 + fi } -# Reindex ncim - individual terminologies +# Reindex ncim - individual terminologies from NCIM reindex_ncim(){ - for t in MDR ICD10CM ICD9CM LNC SNOMEDCT_US RADLEX PDQ ICD10 HL7V3.0; do - # Keep the NCIM folder around while we run - echo " Load $t (from downloaded data) ...`/bin/date`" - src/main/bin/ncim-part.sh --noconfig $dir/NCIM --keep --terminology $t > /tmp/x.$$.txt 2>&1 - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: loading $t" - exit 1 - fi - done - # Reindex ncim - must run after the prior section so that maps can connect to loaded terminologies - echo " Reindex ncim ...`/bin/date`" - src/main/bin/ncim-part.sh --noconfig $dir/NCIM > /tmp/x.$$.txt 2>&1 - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: problem running ncim-part.sh" - exit 1 - fi + for t in MDR ICD10CM ICD9CM LNC SNOMEDCT_US RADLEX PDQ ICD10 HL7V3.0; do + # Keep the NCIM folder around while we run + echo " Load $t (from downloaded data) ...`/bin/date`" + src/main/bin/ncim-part.sh --noconfig $dir/NCIM --keep --terminology $t > /tmp/x.$$.txt 2>&1 + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: loading $t" + exit 1 + fi + done + # Reindex ncim - must run after the prior section so that maps can connect to loaded terminologies + echo " Reindex ncim ...`/bin/date`" + src/main/bin/ncim-part.sh --noconfig $dir/NCIM > /tmp/x.$$.txt 2>&1 + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: problem running ncim-part.sh" + exit 1 + fi } -# Reindex ncim - individual terminologies +# Reindex ncim - individual terminologies from NCIM2 reindex_ncim2(){ - echo " Reindexing ncim2 ...`/bin/date`" - for t in MDR ICD10CM ICD9CM LNC SNOMEDCT_US RADLEX PDQ ICD10 HL7V3.0; do - # Keep the NCIM folder around while we run - echo " Load $t (from ncim2 downloaded data) ...`/bin/date`" - src/main/bin/ncim-part.sh --noconfig $dir/NCIM2 --keep --terminology $t > /tmp/x.$$.txt 2>&1 - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: loading $t" - exit 1 - fi - done - # Reindex ncim - must run after the prior section so that maps can connect to loaded terminologies - echo " Reindex ncim from ncim2 ...`/bin/date`" - src/main/bin/ncim-part.sh --noconfig $dir/NCIM2 > /tmp/x.$$.txt 2>&1 - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: problem running ncim-part.sh" - exit 1 - fi + echo " Reindexing ncim2 ...`/bin/date`" + for t in MDR ICD10CM ICD9CM LNC SNOMEDCT_US RADLEX PDQ ICD10 HL7V3.0; do + # Keep the NCIM folder around while we run + echo " Load $t (from ncim2 downloaded data) ...`/bin/date`" + src/main/bin/ncim-part.sh --noconfig $dir/NCIM2 --keep --terminology $t > /tmp/x.$$.txt 2>&1 + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: loading $t" + exit 1 + fi + done + # Reindex ncim - must run after the prior section so that maps can connect to loaded terminologies + echo " Reindex ncim from ncim2 ...`/bin/date`" + src/main/bin/ncim-part.sh --noconfig $dir/NCIM2 > /tmp/x.$$.txt 2>&1 + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: problem running ncim-part.sh" + exit 1 + fi } +# drop databases (do not fail) drop_databases(){ - for db in "${databases[@]}" - do - echo " Dropping $db ...`/bin/date`" - $curl_cmd -X DELETE "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets/${db}" > /dev/null 2>&1 - # ok to skip errors, this fails if dbs do not exist yet - #if [[ $? -ne 0 ]]; then - # echo "Error occurred when dropping database ${db}. Response:$_" - # exit 1 - #fi - done + for db in "${databases[@]}" + do + echo " Dropping $db ...`/bin/date`" + $curl_cmd -X DELETE "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets/${db}" > /dev/null 2>&1 + # ok to skip errors, this fails if dbs do not exist yet + #if [[ $? -ne 0 ]]; then + # echo "Error occurred when dropping database ${db}. Response:$_" + # exit 1 + #fi + done } +# create databases create_databases(){ - for db in "${databases[@]}" - do - echo " Creating $db ...`/bin/date`" - $curl_cmd -X POST -d "dbName=${db}&dbType=tdb2" "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets" 2> /dev/null > /tmp/x.$$ - check_status $? "POST /$/datasets failed - error creating database ${db}" - check_http_status 200 "POST /$/datasets expecting 200" - done + for db in "${databases[@]}" + do + echo " Creating $db ...`/bin/date`" + $curl_cmd -X POST -d "dbName=${db}&dbType=tdb2" "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets" 2> /dev/null > /tmp/x.$$ + check_status $? "POST /$/datasets failed - error creating database ${db}" + check_http_status 200 "POST /$/datasets expecting 200" + done } # NOT USED -load_terminology_data_in_transaction(){ - echo " Loading $3 into $1 ...`/bin/date`" - tx=$(curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/$1/transaction/begin") - curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/$1/${tx}/add?graph-uri=$2" -H "Content-Type: application/rdf+xml" -T - < "$dir/$3" - tx=$(curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/NCIT2/transaction/commit/${tx}") - if [[ $? -ne 0 ]]; then - echo "Error occurred when loading data into $1 = $_" - exit 1 - fi -} - +#load_terminology_data_in_transaction(){ +# echo " Loading $3 into $1 ...`/bin/date`" +# tx=$(curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/$1/transaction/begin") +# curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/$1/${tx}/add?graph-uri=$2" -H "Content-Type: application/rdf+xml" -T - < "$dir/$3" +# tx=$(curl -s -u "${GRAPH_DB_USERNAME}":"${GRAPH_DB_PASSWORD}" -X POST "http://localhost:5820/NCIT2/transaction/commit/${tx}") +# if [[ $? -ne 0 ]]; then +# echo "Error occurred when loading data into $1 = $_" +# exit 1 +# fi +#} + +# load a graph into graphdb load_terminology_data(){ - # e.g. curl -X POST -H 'Content-Type: application/rdf+xml' -T '../data/UnitTestData/UmlsSemNet/umlssemnet.owl' http://localhost:3030/NCIT2/data?graph=http://UmlsSemNet - # e.g. curl -X POST -H 'Content-Type: application/rdf+xml' -T '../data/UnitTestData/Mouse_Anatomy/ma_07_27_2016.owl' http://localhost:3030/NCIT2/data?graph=http://MA - echo " Loading $3 into $1 ...`/bin/date`" - echo " curl -X POST -H 'Content-Type: application/rdf+xml' -T '$dir/$3' http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$1/data?graph=$2" - $curl_cmd -X POST -H "Content-Type: application/rdf+xml" -T "$dir/$3" "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$1/data?graph=$2" 2> /dev/null > /tmp/x.$$ - check_status $? "POST /$1/data failed - error loading data $dir/$3" - # duo is in 2 parts, the first part returns 201, the second part returns 200, skip this check - if [[ ! "$3" =~ DUO* ]]; then - check_http_status 201 "POST /$1/data expecting 201" - fi + # e.g. curl -X POST -H 'Content-Type: application/rdf+xml' -T '../data/UnitTestData/UmlsSemNet/umlssemnet.owl' http://localhost:3030/NCIT2/data?graph=http://UmlsSemNet + # e.g. curl -X POST -H 'Content-Type: application/rdf+xml' -T '../data/UnitTestData/Mouse_Anatomy/ma_07_27_2016.owl' http://localhost:3030/NCIT2/data?graph=http://MA + echo " Loading $3 into $1 ...`/bin/date`" + echo " curl -X POST -H 'Content-Type: application/rdf+xml' -T '$dir/$3' http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$1/data?graph=$2" + $curl_cmd -X POST -H "Content-Type: application/rdf+xml" -T "$dir/$3" "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$1/data?graph=$2" 2> /dev/null > /tmp/x.$$ + check_status $? "POST /$1/data failed - error loading data $dir/$3" + # duo is in 2 parts, the first part returns 201, the second part returns 200, skip this check + if [[ ! "$3" =~ DUO* ]]; then + check_http_status 201 "POST /$1/data expecting 201" + fi } +# Load all graphs into graphdb load_data(){ load_terminology_data CTRP http://NCI_T_weekly NCIT/ThesaurusInferred_+1weekly.owl load_terminology_data CTRP http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl load_terminology_data NCIT2 http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl load_terminology_data NCIT2 http://GO_monthly GO/GO.20250601.owl load_terminology_data NCIT2 http://HGNC_monthly HGNC/HGNC.202507.owl - load_terminology_data NCIT2 http://ChEBI_monthly ChEBI/chebi_241.owl + load_terminology_data NCIT2 http://ChEBI_monthly ChEBI/chebi_247.owl load_terminology_data NCIT2 http://UmlsSemNet UmlsSemNet/umlssemnet.owl load_terminology_data NCIT2 http://Canmed CanMed/CANMED.202506.owl load_terminology_data NCIT2 http://MEDRT MED-RT/MEDRT.2025-06-02.owl @@ -351,17 +354,17 @@ load_data(){ load_terminology_data NCIT2 http://Zebrafish Zebrafish/zfa_2019_08_02.owl } - -reindex(){ -# Reindex terminologies -echo " Reindex terminologies ...`/bin/date`" -# After this point, the log is stored in the tmp folder unless an error is hit -echo " see /tmp/x.$$.txt" -src/main/bin/reindex.sh --noconfig --history "$historyFile" -if [[ $? -ne 0 ]]; then - echo "ERROR: problem running reindex.sh script" - exit 1 -fi +# Run reindex script but in a way to avoid loading mappings until terminologies are loaded +reindex() { + # Reindex terminologies + echo " Reindex terminologies ...`/bin/date`" + # After this point, the log is stored in the tmp folder unless an error is hit + echo " see /tmp/x.$$.txt" + src/main/bin/reindex.sh --noconfig --history "$historyFile" + if [[ $? -ne 0 ]]; then + echo "ERROR: problem running reindex.sh script" + exit 1 + fi } # Clean and load @@ -375,7 +378,7 @@ load_data # This will load maps from github evsrestapi-operations reindex # After this, we should load "mappings" and "mappings2" from UnitTestData -# to control exactly +# to control exactly what we get export CONFIG_BASE_URI=file://$(realpath $dir)/mappings/config/metadata load_mapping export CONFIG_BASE_URI=file://$(realpath $dir)/mappings2/config/metadata diff --git a/src/main/bin/reindex.sh b/src/main/bin/reindex.sh index bc5b2c8b9..2bcd29b39 100755 --- a/src/main/bin/reindex.sh +++ b/src/main/bin/reindex.sh @@ -42,194 +42,162 @@ if [[ $historyFileOverride ]]; then fi echo "" -# check status -check_status() { - local retval=$1 - local message=$2 - if [ $retval -ne 0 ]; then - cat /tmp/x.$$ - echo "" - echo "$message" - exit 1 - fi -} -# check status -check_http_status() { - retval=$1 - message=$2 - status=`tail -1 /tmp/x.$$` - if [ $status -ne $retval ]; then - echo "" - perl -pe 's/'$status'$//' /tmp/x.$$ | sed 's/^/ /' - echo "$message (returned $status)" - exit 1 - fi -} - -# Setup configuration -setup_configuration() { - echo " Setup configuration" - if [[ $config -eq 1 ]]; then - APP_HOME=/local/content/evsrestapi - CONFIG_DIR=${APP_HOME}/${APP_NAME}/config - CONFIG_ENV_FILE=${CONFIG_DIR}/setenv.sh - echo " config = $CONFIG_ENV_FILE" +#--------------------------------------------------------- +# Check configuration setup +#--------------------------------------------------------- +echo " Setup configuration" +if [[ $config -eq 1 ]]; then + APP_HOME=/local/content/evsrestapi + CONFIG_DIR=${APP_HOME}/${APP_NAME}/config + CONFIG_ENV_FILE=${CONFIG_DIR}/setenv.sh + echo " config = $CONFIG_ENV_FILE" if [[ -e $CONFIG_ENV_FILE ]]; then - . $CONFIG_ENV_FILE + . $CONFIG_ENV_FILE else - echo "ERROR: $CONFIG_ENV_FILE does not exist or has a problem" - echo " consider using --noconfig (if working in dev environment)" - exit 1 - fi - fi -} + echo "ERROR: $CONFIG_ENV_FILE does not exist or has a problem" + echo " consider using --noconfig (if working in dev environment)" + exit 1 + fi +fi -setup_configuration +# Set variables l_graph_db_port=${GRAPH_DB_PORT:-"3030"} -validate_setup() { - if [[ -n "$GRAPH_DB_USERNAME" ]]; then +metadata_config_url=${CONFIG_BASE_URI:-"https://raw.githubusercontent.com/NCIEVS/evsrestapi-operations/main/config/metadata"} + +# Check config +if [[ -n "$GRAPH_DB_USERNAME" ]]; then l_graph_db_username="$GRAPH_DB_USERNAME" - else +else echo "Error: GRAPH_DB_USERNAME is not set." exit 1 - fi - if [[ -n "$GRAPH_DB_PASSWORD" ]]; then +fi +if [[ -n "$GRAPH_DB_PASSWORD" ]]; then l_graph_db_password="$GRAPH_DB_PASSWORD" - else +else echo "Error: GRAPH_DB_PASSWORD is not set." exit 1 - fi - if [[ -n "$GRAPH_DB_HOST" ]]; then +fi +if [[ -n "$GRAPH_DB_HOST" ]]; then l_graph_db_host="$GRAPH_DB_HOST" - else +else echo "Error: GRAPH_DB_HOST is not set." exit 1 - fi - if [[ -n "$GRAPH_DB_PORT" ]]; then +fi +if [[ -n "$GRAPH_DB_PORT" ]]; then l_graph_db_port="$GRAPH_DB_PORT" - else +else echo "Error: GRAPH_DB_PORT is not set." exit 1 - fi - if [[ -z $ES_SCHEME ]]; then +fi +if [[ -z $ES_SCHEME ]]; then echo "ERROR: ES_SCHEME is not set" exit 1 - elif [[ -z $ES_HOST ]]; then +elif [[ -z $ES_HOST ]]; then echo "ERROR: ES_HOST is not set" exit 1 - elif [[ -z $ES_PORT ]]; then +elif [[ -z $ES_PORT ]]; then echo "ERROR: ES_PORT is not set" exit 1 - fi -} -validate_setup -echo " GRAPH_DB_PORT = $l_graph_db_port" +fi +if [[ -z $metadata_config_url ]]; then + echo "METADATA_CONFIG_URL not set" + exit 1 +fi + +# Report configuration if [[ $force -eq 1 ]]; then echo " force = 1" -#elif [[ $ES_CLEAN == "true" ]]; then -# echo " force = 1 (ES_CLEAN=true)" -# force=1 fi -metadata_config_url=${CONFIG_BASE_URI:-"https://raw.githubusercontent.com/NCIEVS/evsrestapi-operations/main/config/metadata"} +# Setup java environment +export PATH="/usr/local/corretto-jdk17/bin:$PATH" +# Handle the local setup +local="" +jar="../lib/evsrestapi.jar" +if [[ $config -eq 0 ]]; then + local="-Dspring.profiles.active=local" + jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` +fi -get_databases(){ +#--------------------------------------------------------- +# Declare Subroutines +#--------------------------------------------------------- - # Hardcode database names for now +# Set up a file handle so that subroutines an log to stdout +# For constructs like x=$(function_call) where we want to log +# within function call, put 1>&3 at the end of those commands +exec 3>&1 + +# check status +check_status() { + local retval=$1 + local message=$2 + if [ $retval -ne 0 ]; then + cat /tmp/x.$$ + echo "" + echo "$message" + exit 1 + fi +} +# check status +check_http_status() { + retval=$1 + message=$2 + status=`tail -1 /tmp/x.$$` + if [ $status -ne $retval ]; then + echo "" + perl -pe 's/'$status'$//' /tmp/x.$$ | sed 's/^/ /' + echo "$message (returned $status)" + exit 1 + fi +} + +# Lookup databases and put into a temp file db.$$.txt +get_databases(){ + echo " Get databases - /tmp/db.$$.txt ...`/bin/date`" + # Hardcode database names for now + # TODO: this needs to make use of the new config index cat > /tmp/db.$$.txt << EOF CTRP NCIT2 EOF - # The following code requires "admin" call to Jena which is only allowed - # in deployment environments from "localhost". Thus the evsrestapi server - # is not allowed to make this call. - # - ## this was put back to perl because we don't have python3 on the evsrestapi machines - #curl -w "\n%{http_code}" -s -g -u "${l_graph_db_username}:$l_graph_db_password" \ - # "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/\$/datasets" 2> /dev/null > /tmp/x.$$ - #check_status $? "GET /admin/databases failed to list databases" - #check_http_status 200 "GET /admin/databases expecting 200" - #sed '$d' /tmp/x.$$ | $jq | grep 'ds.name' | perl -pe 's/.*ds.name.*\///; s/",.*//;' > /tmp/db.$$.txt - #echo " databases = " `cat /tmp/db.$$.txt` - #ct=`cat /tmp/db.$$.txt | wc -l` - #if [[ $ct -eq 0 ]]; then - # echo "ERROR: no graph databases, this is unexpected" - # exit 1 - #fi } - -get_databases -# Open a new file descriptor that redirects to stdout: -exec 3>&1 - -get_ignored_sources(){ - if [[ -z $metadata_config_url ]]; then - echo "METADATA_CONFIG_URL not set" 1>&3 - echo "" - else +# Gather ignored sources. These are graphs that are loaded into Jena +# as a by-product of the thing we actually care about (e.g. duo). +# Put values into a temp file is.$$.txt +# This function sets the "$ignored_sources" variable +get_ignored_sources() { + echo " Get ignored sources ...`/bin/date`" curl -s -g -f "$metadata_config_url/ignore-source.txt" -o /tmp/is.$$.txt if [[ $? -ne 0 ]]; then - echo "Failed to download ignore-source.txt using curl, trying as a local file..." 1>&3 - cp "$metadata_config_url/ignore-source.txt" /tmp/is.$$.txt + echo " Failed to download ignore-source.txt using curl, trying as a local file..." + cp "${metadata_config_url/file:\/\//}/ignore-source.txt" /tmp/is.$$.txt if [[ $? -ne 0 ]]; then - echo "ERROR: unable to obtain ignore-source.txt. Assuming no source URLs to ignore" 1>&3 - echo "$metadata_config_url/ignore-source.txt" 1>&3 + echo "ERROR: unable to obtain ignore-source.txt. Assuming no source URLs to ignore" + echo "$metadata_config_url/ignore-source.txt" fi - fi + fi if [ -f "/tmp/is.$$.txt" ]; then - echo $(cat "/tmp/is.$$.txt" | awk -vORS=">,<" '{ print $1 }' | sed 's/,<$//' | sed 's/^/,<" '{ print $1 }' | sed 's/,<$//' | sed 's/^/ /tmp/x.$$.txt << EOF -query=PREFIX owl: -PREFIX rdf: -PREFIX rdfs: -PREFIX xsd: -PREFIX dc: -PREFIX xml: -SELECT DISTINCT ?source ?graphName (STR(?safeVersion) AS ?version) WHERE { - graph ?graphName { - { - ?source a owl:Ontology . - ?source owl:versionInfo ?x_version . - FILTER (?source NOT IN ($ignored_sources)) - } - UNION - { - ?source a owl:Ontology . - ?source owl:versionIRI ?x_version . - FILTER NOT EXISTS { ?source owl:versionInfo ?versionInfo } . - FILTER (?source NOT IN ($ignored_sources)) - } - BIND ( - IF( - isURI(?x_version), - ?x_version, - IF( - DATATYPE(?x_version) = xsd:decimal, - xsd:integer(?x_version), - ?x_version - ) - ) AS ?safeVersion - ) - } } -EOF -else + +# Build the query to find all graphs +# This function sets the "$graph_query" variable +get_graph_query() { + echo " Get graph query ...`/bin/date`" + clause="" + if [ -n "$ignored_sources" ]; then + clause=" FILTER (?source NOT IN ($ignored_sources))" + fi + # NOTE: the query must return ?source, ?graphName, and ?version with those names cat > /tmp/x.$$.txt << EOF query=PREFIX owl: @@ -242,14 +210,15 @@ SELECT DISTINCT ?source ?graphName (STR(?safeVersion) AS ?version) WHERE { graph ?graphName { { ?source a owl:Ontology . - ?source owl:versionInfo ?x_version . - } + ?source owl:versionInfo ?x_version . + $clause } UNION { ?source a owl:Ontology . ?source owl:versionIRI ?x_version . FILTER NOT EXISTS { ?source owl:versionInfo ?versionInfo } . - } + $clause } + BIND ( IF( isURI(?x_version), @@ -264,22 +233,26 @@ SELECT DISTINCT ?source ?graphName (STR(?safeVersion) AS ?version) WHERE { } } EOF -fi -query=$(cat /tmp/x.$$.txt) + + graph_query=$(cat /tmp/x.$$.txt) + } -get_graph_query + + # Run the query against each of the databases -get_graphs(){ - /bin/rm -f /tmp/y.$$.txt - touch /tmp/y.$$.txt - # this was put back to perl because we don't have python3 on the evsrestapi machines - for db in `cat /tmp/db.$$.txt`; do - curl -w "\n%{http_code}" -s -g -u "${l_graph_db_username}:$l_graph_db_password" \ +# Collect results into a temp file y.$$.txt +get_graphs() { + echo " Lookup terminology, version info in graph db - /tmp/y.$$.txt ...`/bin/date`" + /bin/rm -f /tmp/y.$$.txt + touch /tmp/y.$$.txt + # this was put back to perl because we don't have python3 on the evsrestapi machines + for db in `cat /tmp/db.$$.txt`; do + curl -w "\n%{http_code}" -s -g -u "${l_graph_db_username}:$l_graph_db_password" \ http://${l_graph_db_host}:${l_graph_db_port}/$db/query \ - --data-urlencode "$query" -H "Accept: application/sparql-results+json" 2> /dev/null > /tmp/x.$$ - check_status $? "GET /$db/query failed to get graphs" - check_http_status 200 "GET /$db/query expecting 200" - sed '$d' /tmp/x.$$ | $jq | perl -ne ' + --data-urlencode "$graph_query" -H "Accept: application/sparql-results+json" 2> /dev/null > /tmp/x.$$ + check_status $? "GET /$db/query failed to get graphs" + check_http_status 200 "GET /$db/query expecting 200" + sed '$d' /tmp/x.$$ | $jq | perl -ne ' chop; $x="version" if /"version"/; $x="source" if /"source"/; $x=0 if /\}/; @@ -288,69 +261,53 @@ get_graphs(){ ${$x} = $_; print "$version|'$db'|$source\n" if $x eq "version"; } ' >> /tmp/y.$$.txt - done - # Sort by version then reverse by DB (NCIT2 goes before CTRP) - # this is because we need "monthly" to be indexed from the "monthlyDb" - # defined in ncit.json - # NOTE: version isn't cleaned up here so from where versionIRI is still an IRI - sort -t\| -k 1,1 -k 2,2r -o /tmp/y.$$.txt /tmp/y.$$.txt - cat /tmp/y.$$.txt | sed 's/^/ version = /;' + done + # Sort by version then reverse by DB (NCIT2 goes before CTRP) + # this is because we need "monthly" to be indexed from the "monthlyDb" + # defined in ncit.json + # NOTE: version isn't cleaned up here so from where versionIRI is still an IRI + sort -t\| -k 1,1 -k 2,2r -o /tmp/y.$$.txt /tmp/y.$$.txt + cat /tmp/y.$$.txt | sed 's/^/ version = /;' } -get_graphs - -#if [[ $ES_CLEAN == "true" ]]; then -# echo " Remove and recreate evs_metadata index" -# curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata" >> /dev/null -# if [[ $? -ne 0 ]]; then -# echo "ERROR: unexpected error deleting evs_metadata index" -# exit 1 -# fi -# curl -s -X PUT "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata" >> /dev/null -# if [[ $? -ne 0 ]]; then -# echo "ERROR: unexpected error creating evs_metadata index" -# exit 1 -# fi -#fi # set the max number of fields higher # we can probably remove this when we figure a better answer -echo " Set index.mapping.total_fields.limit = 5000" -curl -s -X PUT "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_settings" \ +set_total_fields_limit_5000() { + echo " Set index.mapping.total_fields.limit = 5000 ...`/bin/date`" + curl -s -X PUT "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_settings" \ -H "Content-type: application/json" -d '{ "index.mapping.total_fields.limit": 5000 }' >> /dev/null -if [[ $? -ne 0 ]]; then - echo "ERROR: unexpected error setting index.mapping.total_fields in evs_metadata" - exit 1 -fi + if [[ $? -ne 0 ]]; then + echo "ERROR: unexpected error setting index.mapping.total_fields in evs_metadata" + exit 1 + fi +} -# For each DB|version, check whether indexes already exist for that version -echo "" -export PATH="/usr/local/corretto-jdk17/bin:$PATH" -# Handle the local setup -local="" -jar="../lib/evsrestapi.jar" -if [[ $config -eq 0 ]]; then - local="-Dspring.profiles.active=local" - jar=build/libs/`ls build/libs/ | grep evsrestapi | grep jar | head -1` -fi +# Takes a terminology graph URL and returns the terminology value +get_terminology() { + lower_terminology=$(basename "$1" | sed 's/.owl//g; s/Ontology//; s/-//;' | tr '[:upper:]' '[:lower:]') + if [[ $lower_terminology =~ "thesaurus" ]]; then + echo "ncit" + else + #lower_terminology=$(basename "$1" | sed 's/.owl//g; s/Ontology//; s/-//;' | tr '[:upper:]' '[:lower:]') + IFS='_' read -r -a array <<<"$lower_terminology" + echo $array + fi +} -get_terminology(){ - lower_terminology=$(basename "$1" | sed 's/.owl//g; s/Ontology//; s/-//;' | tr '[:upper:]' '[:lower:]') - if [[ $lower_terminology =~ "thesaurus" ]]; then - echo "ncit" - else - #lower_terminology=$(basename "$1" | sed 's/.owl//g; s/Ontology//; s/-//;' | tr '[:upper:]' '[:lower:]') - IFS='_' read -r -a array <<<"$lower_terminology" - echo $array - fi +# Takes a raw version and cleans it up for use +get_version() { + local ver="$1" + echo $ver | cut -d\| -f 1 | perl -ne 's#.*/([\d-]+)/[a-zA-Z]+.owl#$1#; print lc($_)' } -download_and_unpack() { +# Attempts to download and unpack available history information for specified version +download_ncit_history_helper() { local ver="$1" success=0 for i in {1..5}; do - echo " Download NCIt History version $ver: attempt $i" + echo " Download NCIt History version $ver: attempt $i" url="https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/cumulative_history_$ver.zip" - echo " url = $url" + echo " url = $url" curl -w "\n%{http_code}" -s -o cumulative_history_$ver.zip "$url" > /tmp/x.$$ # if curl command fails then try again @@ -361,7 +318,7 @@ download_and_unpack() { echo " ERROR: unexpected status code downloading NCIt history = "$(tail -1 /tmp/x.$$) break else - echo " Unpack NCIt history" + echo " Unpack NCIt history" unzip "cumulative_history_$ver.zip" > /tmp/x.$$ 2>&1 if [[ $? -ne 0 ]]; then cat /tmp/x.$$ @@ -382,6 +339,8 @@ download_and_unpack() { done } +# Download and unpack NCIt history. Uses helper method to iterate and try +# multiple attempts and multiple approaches. download_ncit_history() { # Prep dir /bin/rm -rf $DIR/NCIT_HISTORY @@ -390,7 +349,7 @@ download_ncit_history() { # Download file (try 5 times) success=0 - download_and_unpack "$version" + download_ncit_history_helper "$version" # try to get previous version of the history file if [[ $success -eq 0 ]]; then @@ -446,6 +405,59 @@ download_ncit_history() { return 0 } +# For "rdf" or "rrf", get the indexed terminologies +get_indexed_terminologies() { + local type=$1 + echo $(curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_search?size=1000" | jq -r '.hits.hits[]._source.terminology | select(.metadata.loader == "'"$type"'") | .terminologyVersion' | sed 's/^/concept_/') +} + +# Remove unused indexes +# Things loaded via RDF in the indexes that are no longer in graphdb +remove_unused_indexes() { + + echo " Remove rdf terminologies no longer in graphdb ...`/bin/date`" + # Get all currently indexed terminologies + rdf_terms=$(get_indexed_terminologies "rdf") + echo " rdf = $rdf_terms" + + # Get all valid terminology keys from the currently loaded graph db triples + graphdb_terms=$(cut -d'|' -f1,3 /tmp/y.$$.txt | while IFS='|' read -r version iri; do + term=$(get_terminology "$iri") + version=$(get_version "$version") + echo -n " concept_${term}_${version}" +done) + echo " graphdb = $graphdb_terms" + + # Remove indexes not found in triple store + for index in $rdf_terms; do + keep=0 + for v in $graphdb_terms; do + if [[ "$index" == "$v" ]]; then + keep=1 + break + fi + done + if [[ $keep -eq 0 ]]; then + echo " remove $index" + #curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$index" > /dev/null + fi + done + +} + +#--------------------------------------------------------- +# Perform Reindex Operations +#--------------------------------------------------------- + +get_databases +get_ignored_sources +get_graph_query +get_graphs +set_total_fields_limit_5000 +remove_unused_indexes + +# For each DB|version, check whether indexes already exist for that version +echo "" for x in `cat /tmp/y.$$.txt`; do echo " Check indexes for $x" version=`echo $x | cut -d\| -f 1 | perl -pe 's#.*/([\d-]+)/[a-zA-Z]+.owl#$1#;'` @@ -454,7 +466,6 @@ for x in `cat /tmp/y.$$.txt`; do uri=`echo $x | cut -d\| -f 3` term=$(get_terminology "$uri") - # if previous version and current version match, then skip # this is a monthly that's in both NCIT2 and CTRP databases if [[ $cv == $pv ]] && [[ $term == $pt ]]; then @@ -472,7 +483,7 @@ for x in `cat /tmp/y.$$.txt`; do # Otherwise, download if ncit elif [[ "$term" == "ncit" ]]; then download_ncit_history - fi + fi for y in `echo "evs_metadata concept_${term}_$cv evs_object_${term}_$cv"`; do @@ -582,101 +593,6 @@ for x in `cat /tmp/y.$$.txt`; do fi done -# Get all currently indexed terminologies -all_indexes=$(curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/_cat/indices?h=index" | grep '^concept_' | cut -d' ' -f1) - -# Get all valid terminology keys from the currently loaded graph db triples -valid_keys=$(cut -d'|' -f1,3 /tmp/y.$$.txt | while IFS='|' read -r version iri; do - term=$(get_terminology "$iri") - - # Handle cases where version is actually a URI containing the real version - if [[ "$version" =~ chebi/([0-9]+)/ ]]; then - version_compact=${BASH_REMATCH[1]} - elif [[ "$version" =~ releases/([0-9]{4}-[0-9]{2}-[0-9]{2})/ ]]; then - version_compact=$(echo ${BASH_REMATCH[1]} | sed 's/-//g') - else - version_compact=$(echo "$version" | tr '[:upper:]' '[:lower:]' | sed 's/[.-]//g') - fi - - echo "concept_${term}_${version_compact}" -done) - -# combine ncim terms with known terminologies -ncim_terms="MDR ICD10CM ICD9CM LNC SNOMEDCT_US RADLEX PDQ ICD10 HL7V30 NCIM" -for t in $ncim_terms; do - t_lc=$(echo "$t" | tr '[:upper:]' '[:lower:]') - valid_keys="$valid_keys -concept_${t_lc}_" -done - -# For "rdf" or "rrf", get the indexed terminologies -get_indexed_terminologies() { - local type=$1 - echo $(curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_search?size=1000" | jq -r '.hits.hits[]._source.terminology | select(.metadata.loader == "'"$type"'") | .terminologyVersion' | perl -ne 's/^/concept_/; print lc($_)') -} - -# Takes a raw version and cleans it up for use -get_version() { - local ver="$1" - echo $ver | cut -d\| -f 1 | perl -ne 's#.*/([\d-]+)/[a-zA-Z]+.owl#$1#; print lc($_)' -} - -# Remove indexes not found in triple store -# Remove unused indexes -# Things loaded via RDF in the indexes that are no longer in graphdb -remove_unused_indexes() { - - RECONCILE ALL stale indexes and update flags - - # NOTE: this code compares lowercase ${terminology}_${version} without cleanup of [\.\-] - echo " Remove rdf terminologies no longer in graphdb ...`/bin/date`" - # Get all currently indexed terminologies - rdf_terms=$(get_indexed_terminologies "rdf") - echo " rdf = $rdf_terms" - - # Get all valid terminology keys from the currently loaded graph db triples - graphdb_terms=$(cut -d'|' -f1,3 /tmp/y.$$.txt | while IFS='|' read -r version iri; do - term=$(get_terminology "$iri") - version=$(get_version "$version") - echo -n " concept_${term}_${version}" -done) - echo " graphdb = $graphdb_terms" - - # Remove indexes not found in triple store - for index in $rdf_terms; do - keep=0 - for v in $graphdb_terms; do - if [[ "$index" == "$v" ]]; then - keep=1 - break - fi - done - if [[ $keep -eq 0 ]]; then - echo " remove indexes for ${index/concept_/}" - curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$index" > /tmp/x.$$.txt - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: error removing index $i" - exit 1 - fi - curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/${index/concept_/evs_object_}" > /tmp/x.$$.txt - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: error removing index ${index/concept_/evs_object}" - exit 1 - fi - curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_doc/$index" > /tmp/x.$$.txt - if [[ $? -ne 0 ]]; then - cat /tmp/x.$$.txt | sed 's/^/ /' - echo "ERROR: error removing evs_metadata entry for $index" - exit 1 - fi - fi - done - -} -remove_unused_indexes - # Stale indexes are automatically cleaned up by the indexing process # It checks against graph db and reconciles everything and updates latest flags # regardless of whether there was new data @@ -712,7 +628,7 @@ if [[ `curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_mappings/_settings" | grep -c fi # Cleanup -/bin/rm -f /tmp/[xy].$$.txt /tmp/db.$$.txt /tmp/x.$$ +/bin/rm -f /tmp/[xy].$$.txt /tmp/db.$$.txt /tmp/is.$$.txt /tmp/x.$$ echo "" echo "--------------------------------------------------" diff --git a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java index 9e4159dc8..dc24f6654 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java +++ b/src/main/java/gov/nih/nci/evs/api/model/TerminologyMetadata.java @@ -1418,7 +1418,8 @@ public boolean isRemodeledProperty(final String code) { return getSynonym().contains(code) || getDefinition().contains(code) || code.equals(this.code) - || code.equals(subsetLink); + || code.equals(subsetLink) + || code.equals(preferredName); } /** diff --git a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java index df5f62d7e..20b3d0d52 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/AbstractGraphLoadServiceImpl.java @@ -220,7 +220,9 @@ private void loadConceptsRealTime( ExecutorService executor = Executors.newFixedThreadPool(10); try { while (start < total) { - if (total - start <= DOWNLOAD_BATCH_SIZE) end = total.intValue(); + if (total - start <= DOWNLOAD_BATCH_SIZE) { + end = total.intValue(); + } logger.info(" Processing {} to {}", start + 1, end); logger.info(" start reading {} to {}", start + 1, end); @@ -285,7 +287,9 @@ private void loadConceptsRealTime( Double indexTotal = (double) concepts.size(); final List> futures = new ArrayList<>(); while (indexStart < indexTotal) { - if (indexTotal - indexStart <= INDEX_BATCH_SIZE) indexEnd = indexTotal.intValue(); + if (indexTotal - indexStart <= INDEX_BATCH_SIZE) { + indexEnd = indexTotal.intValue(); + } futures.add( executor.submit( @@ -444,10 +448,18 @@ public void loadObjects( // Build property values map by code and by property name and index it final Map> propertyMap = new HashMap<>(); for (final Concept property : properties) { + // skip any remodeled properties if (terminology.getMetadata().isRemodeledProperty(property.getCode())) { continue; } + if (terminology.getMetadata().isRemodeledQualifier(property.getCode())) { + continue; + } + if (terminology.getMetadata().isRemodeledQualifier(property.getCode())) { + continue; + } + for (final String value : sparqlQueryManagerService.getPropertyValues(property.getCode(), terminology)) { if (!propertyMap.containsKey(property.getCode())) { @@ -511,7 +523,9 @@ public void loadObjects( for (Concept association : associations) { logger.info(association.getName()); entries = new ArrayList<>(); - if (association.getName().equals("Concept_In_Subset")) continue; + if (association.getName().equals("Concept_In_Subset")) { + continue; + } for (String conceptCode : hierarchy.getAssociationMap().keySet()) { List conceptAssociations = hierarchy.getAssociationMap().get(conceptCode); for (Association conceptAssociation : conceptAssociations) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java index b4afedd94..98f9a5f1e 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryCacheService.java @@ -202,7 +202,7 @@ public List getAllQualifiers( if (b.getPropertyCode() == null) { qualifier.setUri(b.getProperty().getValue()); } - qualifier.setCode(EVSUtils.getPropertyCode(b)); + qualifier.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); qualifiers.add(qualifier); } diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index 7f02e2181..4571d6959 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -357,7 +357,8 @@ private Concept getConceptByType( if (conceptType.equals("concept")) { concept.setCode(EVSUtils.getCodeFromUri(conceptCode)); } else { - concept.setCode(EVSUtils.getQualifiedCodeFromUri(conceptCode)); + concept.setCode( + EVSUtils.getQualifiedCodeFromUri(terminology.getTerminology(), conceptCode)); } } @@ -784,8 +785,8 @@ public List getProperties(final String conceptCode, final Terminology // continue; // } final Property property = new Property(); - property.setCode(EVSUtils.getPropertyCode(b)); - property.setType(EVSUtils.getPropertyLabel(b)); + property.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); + property.setType(EVSUtils.getPropertyLabel(terminology.getTerminology(), b)); property.setValue(b.getPropertyValue().getValue()); final String key = property.getCode() + property.getValue(); if (!seen.contains(key)) { @@ -832,8 +833,8 @@ private Map> getProperties( } final Property property = new Property(); - property.setCode(EVSUtils.getPropertyCode(b)); - property.setType(EVSUtils.getPropertyLabel(b)); + property.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); + property.setType(EVSUtils.getPropertyLabel(terminology.getTerminology(), b)); property.setValue(b.getPropertyValue().getValue()); final String key = conceptCode + property.getCode() + property.getValue(); if (!seen.contains(key)) { @@ -970,8 +971,8 @@ public List getAssociations(final String conceptCode, final Termino final Bindings[] bindings = sparqlResult.getResults().getBindings(); for (final Bindings b : bindings) { final Association association = new Association(); - association.setCode(EVSUtils.getRelationshipCode(b)); - association.setType(EVSUtils.getRelationshipType(b)); + association.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + association.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); association.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); association.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); associations.add(association); @@ -1012,8 +1013,8 @@ public Map> getAssociations( } final Association association = new Association(); - association.setCode(EVSUtils.getRelationshipCode(b)); - association.setType(EVSUtils.getRelationshipType(b)); + association.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + association.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); association.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); association.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); @@ -1047,8 +1048,8 @@ public Map> getAssociationsForAllCodes( } final Association association = new Association(); - association.setCode(EVSUtils.getRelationshipCode(b)); - association.setType(EVSUtils.getRelationshipType(b)); + association.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + association.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); if (inverse) { association.setRelatedCode(b.getConceptCode().getValue()); @@ -1081,8 +1082,8 @@ public List getInverseAssociations( final Bindings[] bindings = sparqlResult.getResults().getBindings(); for (final Bindings b : bindings) { final Association association = new Association(); - association.setCode(EVSUtils.getRelationshipCode(b)); - association.setType(EVSUtils.getRelationshipType(b)); + association.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + association.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); association.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); association.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); associations.add(association); @@ -1125,8 +1126,8 @@ public Map> getInverseAssociations( } final Association association = new Association(); - association.setCode(EVSUtils.getRelationshipCode(b)); - association.setType(EVSUtils.getRelationshipType(b)); + association.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + association.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); association.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); association.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); resultMap.get(conceptCode).add(association); @@ -1155,8 +1156,8 @@ public List getInverseRoles(final String conceptCode, final Terminology te for (final Bindings b : bindings) { // log.info("BINDING = {}", b); final Role role = new Role(); - role.setCode(EVSUtils.getRelationshipCode(b)); - role.setType(EVSUtils.getRelationshipType(b)); + role.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + role.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); role.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); role.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); @@ -1209,8 +1210,8 @@ public Map> getInverseRoles( } final Role role = new Role(); - role.setCode(EVSUtils.getRelationshipCode(b)); - role.setType(EVSUtils.getRelationshipType(b)); + role.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + role.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); role.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); role.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); // distinct roles only @@ -1244,8 +1245,8 @@ public List getRoles(final String conceptCode, final Terminology terminolo final Set seen = new HashSet<>(); for (final Bindings b : bindings) { final Role role = new Role(); - role.setCode(EVSUtils.getRelationshipCode(b)); - role.setType(EVSUtils.getRelationshipType(b)); + role.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + role.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); role.setRelatedCode( b.getRelatedConceptCode() != null ? b.getRelatedConceptCode().getValue() @@ -1299,8 +1300,8 @@ public Map> getRoles( } final Role role = new Role(); - role.setCode(EVSUtils.getRelationshipCode(b)); - role.setType(EVSUtils.getRelationshipType(b)); + role.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + role.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); role.setRelatedCode(EVSUtils.getRelatedConceptCode(b)); role.setRelatedName(EVSUtils.getRelatedConceptLabel(b)); @@ -1350,8 +1351,8 @@ public Map> getComplexRolesForAllCodes( } final Role role = new Role(); - role.setCode(EVSUtils.getRelationshipCode(b)); - role.setType(EVSUtils.getRelationshipType(b)); + role.setCode(EVSUtils.getRelationshipCode(terminology.getTerminology(), b)); + role.setType(EVSUtils.getRelationshipType(terminology.getTerminology(), b)); if (inverseFlag) { // reverse code and related code role.setRelatedCode(b.getConceptCode().getValue()); @@ -1472,7 +1473,8 @@ public List getAxioms( for (final Bindings b : bindings) { final String axiom = b.getAxiom().getValue(); final String propertyUri = b.getAxiomProperty().getValue(); - final String propertyCode = EVSUtils.getQualifiedCodeFromUri(propertyUri); + final String propertyCode = + EVSUtils.getQualifiedCodeFromUri(terminology.getTerminology(), propertyUri); final String value = b.getAxiomValue().getValue(); // log.debug(" axiom = " + propertyUri + ", " + value + ", " + axiom); @@ -1546,7 +1548,8 @@ private Map> getAxioms( } final Axiom axiomObject = axiomMap.get(axiom); final String propertyUri = b.getAxiomProperty().getValue(); - final String propertyCode = EVSUtils.getQualifiedCodeFromUri(propertyUri); + final String propertyCode = + EVSUtils.getQualifiedCodeFromUri(terminology.getTerminology(), propertyUri); final String value = b.getAxiomValue().getValue(); setAxiomProperty(propertyCode, propertyUri, value, qualifierFlag, axiomObject, terminology); @@ -1599,7 +1602,8 @@ private void setAxiomProperty( break; case "owl:annotatedProperty": // Use the code value - axiomObject.setAnnotatedProperty(EVSUtils.getQualifiedCodeFromUri(value)); + axiomObject.setAnnotatedProperty( + EVSUtils.getQualifiedCodeFromUri(terminology.getTerminology(), value)); // log.debug(" annotated property = " + EVSUtils.getQualifiedCodeFromUri(value)); break; default: @@ -1803,7 +1807,7 @@ public List getAllProperties(final Terminology terminology, final Inclu if (b.getPropertyLabel() != null) { property.setValue(b.getPropertyLabel().getValue()); } - property.setCode(EVSUtils.getPropertyCode(b)); + property.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); if (!seen.contains(property.getCode()) && !excludedProperties.contains(property.getCode())) { properties.add(property); seen.add(property.getCode()); @@ -1884,7 +1888,7 @@ public List getRemodeledProperties(final Terminology terminology, final if (b.getPropertyCode() == null) { property.setUri(b.getProperty().getValue()); } - property.setCode(EVSUtils.getPropertyCode(b)); + property.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); if (!seen.contains(property.getCode())) { properties.add(property); seen.add(property.getCode()); @@ -1932,7 +1936,7 @@ public List getNeverUsedProperties(final Terminology terminology, final if (b.getPropertyCode() == null) { property.setUri(b.getProperty().getValue()); } - property.setCode(EVSUtils.getPropertyCode(b)); + property.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); properties.add(property); } @@ -1945,7 +1949,7 @@ public List getNeverUsedProperties(final Terminology terminology, final for (final Bindings b : bindings2) { // This query just looks up the codes qualifiers.add(b.getProperty().getValue()); - qualifiers.add(EVSUtils.getPropertyCode(b)); + qualifiers.add(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); } final TerminologyMetadata md = terminology.getMetadata(); @@ -2014,7 +2018,7 @@ public List getRemodeledQualifiers(final Terminology terminology, final if (b.getPropertyCode() == null) { qualifier.setUri(b.getProperty().getValue()); } - qualifier.setCode(EVSUtils.getPropertyCode(b)); + qualifier.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); qualifiers.add(qualifier); } @@ -2148,7 +2152,7 @@ public List getAllAssociations(final Terminology terminology, final Inc if (b.getPropertyCode() == null) { association.setUri(b.getProperty().getValue()); } - association.setCode(EVSUtils.getPropertyCode(b)); + association.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); associations.add(association); } @@ -2186,7 +2190,7 @@ public List getAllRoles(final Terminology terminology, final IncludePar if (b.getPropertyCode() == null) { role.setUri(b.getProperty().getValue()); } - role.setCode(EVSUtils.getPropertyCode(b)); + role.setCode(EVSUtils.getPropertyCode(terminology.getTerminology(), b)); // Exclude roles remodeled as parent/child if (!terminology.getMetadata().getHierarchyRoles().contains(role.getCode())) { diff --git a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java index 8ab75c61a..c0daac82f 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/EVSUtils.java @@ -93,7 +93,9 @@ public static List getSynonyms( // finish for (Axiom axiom : axioms) { // log.info("AXIOM: {}", axiom); - final String axiomCode = EVSUtils.getQualifiedCodeFromUri(axiom.getAnnotatedProperty()); + final String axiomCode = + EVSUtils.getQualifiedCodeFromUri( + terminology.getTerminology(), axiom.getAnnotatedProperty()); if (syCode.contains(axiomCode)) { Synonym synonym = new Synonym(); // This shouldn't happen unless axiomCode and property codes are off @@ -169,7 +171,9 @@ public static List getDefinitions( // Check axioms for definitions for (final Axiom axiom : axioms) { - final String axiomCode = EVSUtils.getQualifiedCodeFromUri(axiom.getAnnotatedProperty()); + final String axiomCode = + EVSUtils.getQualifiedCodeFromUri( + terminology.getTerminology(), axiom.getAnnotatedProperty()); if (defCodes.contains(axiomCode)) { Definition definition = new Definition(); definition.setDefinition(axiom.getAnnotatedTarget()); @@ -301,7 +305,9 @@ public static List getMapsTo(Terminology terminology, List axiom ArrayList results = new ArrayList(); final String mapCode = terminology.getMetadata().getMap(); for (Axiom axiom : axioms) { - final String axiomCode = EVSUtils.getQualifiedCodeFromUri(axiom.getAnnotatedProperty()); + final String axiomCode = + EVSUtils.getQualifiedCodeFromUri( + terminology.getTerminology(), axiom.getAnnotatedProperty()); if (axiomCode.equals(mapCode)) { Mapping mapsTo = new Mapping(); mapsTo.setTargetName(axiom.getAnnotatedTarget()); @@ -386,24 +392,29 @@ public static String getCodeFromUri(final String uri) { * configuration (e.g., matching "ncit:P108" in axioms against "ncit:P108" in ctcae6.json). * Concept codes don't need namespace context, so they use getCodeFromUri() instead. * + * @param terminology the terminology * @param uri the full RDF property URI * @return the qualified code with namespace prefix (e.g., "ncit:P108", "rdfs:label") * @see #getCodeFromUri(String) for fully stripping prefixes from concept codes * @see #getLabelFromUri(String) for extracting human-readable labels */ - public static String getQualifiedCodeFromUri(final String uri) { - // e.g., the URI that comes in here will be something like this: - // http://www.w3.org/2000/01/rdf-schema#label - + public static String getQualifiedCodeFromUri(final String terminology, final String uri) { // Replace up to the last slash and fix rdfs - // xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" => "rdfs" - String code = uri.replaceFirst(".*\\/", "").replaceFirst("rdf-schema", "rdfs"); + String code = + uri.replaceFirst("/skos/core", "/skos") + .replaceFirst(".*\\/", "") + .replaceFirst("rdf-schema", "rdfs"); + + // If ..../npo#DesignNote => :DesignNote + if (code.startsWith(terminology + "#")) { + return code.replaceFirst(".*#", ""); + } // Remove up to the hash if the thing before is like "HGNC.owl" - // xmlns="http://purl.obolibrary.org/obo/chebi.owl#" -> "" if (code.contains(".")) { return code.replaceFirst(".*#", ""); } + // otherwise, use what's before the hash as a prefix // xmlns:oboInOwl="http://www.geneontology.org/formats/oboInOwl#" -> "oboInOwl" return code.replaceFirst("#", ":"); @@ -441,9 +452,9 @@ public static String getLabelFromUri(final String uri) { * @param b the b * @return the code */ - public static String getPropertyCode(final Bindings b) { + public static String getPropertyCode(final String terminology, final Bindings b) { if (b.getPropertyCode() == null) { - return EVSUtils.getQualifiedCodeFromUri(b.getProperty().getValue()); + return EVSUtils.getQualifiedCodeFromUri(terminology, b.getProperty().getValue()); } else { return b.getPropertyCode().getValue(); } @@ -455,11 +466,11 @@ public static String getPropertyCode(final Bindings b) { * @param b the b * @return the label */ - public static String getPropertyLabel(final Bindings b) { + public static String getPropertyLabel(final String terminology, final Bindings b) { if (b.getPropertyLabel() == null) { // Convert if (b.getProperty().getValue().startsWith("http://www.w3.org/2000/01/rdf-schema")) { - return EVSUtils.getQualifiedCodeFromUri(b.getProperty().getValue()); + return EVSUtils.getQualifiedCodeFromUri(terminology, b.getProperty().getValue()); } return EVSUtils.getLabelFromUri(b.getProperty().getValue()); } else { @@ -473,10 +484,10 @@ public static String getPropertyLabel(final Bindings b) { * @param b the b * @return the relationship type */ - public static String getRelationshipType(final Bindings b) { + public static String getRelationshipType(final String terminology, final Bindings b) { if (b.getRelationshipLabel() == null) { if (b.getRelationship().getValue().startsWith("http://www.w3.org/2000/01/rdf-schema")) { - return EVSUtils.getQualifiedCodeFromUri(b.getRelationship().getValue()); + return EVSUtils.getQualifiedCodeFromUri(terminology, b.getRelationship().getValue()); } return EVSUtils.getLabelFromUri(b.getRelationship().getValue()); } else { @@ -490,9 +501,9 @@ public static String getRelationshipType(final Bindings b) { * @param b the b * @return the relationship code */ - public static String getRelationshipCode(final Bindings b) { + public static String getRelationshipCode(final String terminology, final Bindings b) { if (b.getRelationshipCode() == null) { - return EVSUtils.getQualifiedCodeFromUri(b.getRelationship().getValue()); + return EVSUtils.getQualifiedCodeFromUri(terminology, b.getRelationship().getValue()); } else { return b.getRelationshipCode().getValue(); } diff --git a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java index c6e64891c..5e6fdfeda 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java +++ b/src/main/java/gov/nih/nci/evs/api/util/FhirUtility.java @@ -110,7 +110,7 @@ public static boolean compareToken(final TokenParam t1, final String t2) { // Handle :not modifier (FHIR spec: only for token parameters) // Returns resources that do NOT match the value (includes resources without the element) - if (t1.getModifier() != null && t1.getModifier().equals(":not")) { + if (t1.getModifier() != null && t1.getModifier().getValue().equals(":not")) { if (t2 == null || t2.isEmpty()) { return true; // Include resources without the element } @@ -297,6 +297,12 @@ public static boolean compareDateRange(final DateRangeParam d1, final Date d2) { return compareDate(d1.getLowerBound(), d2) && compareDate(d1.getUpperBound(), d2); } + /** + * Convert to YYYYMMDD. + * + * @param sdate the sdate + * @return the string + */ public static String convertToYYYYMMDD(String sdate) { if (sdate == null || sdate.trim().isEmpty()) { return sdate; // Return input unchanged instead of null diff --git a/src/main/resources/sparql-queries.properties b/src/main/resources/sparql-queries.properties index 00d5b0146..715de9160 100644 --- a/src/main/resources/sparql-queries.properties +++ b/src/main/resources/sparql-queries.properties @@ -10,7 +10,8 @@ PREFIX rdfs: \ PREFIX xsd: \ PREFIX dc: \ PREFIX oboInOwl: \ -PREFIX xml: +PREFIX xml: \ +PREFIX skos: prefix.graph=PREFIX :<#{source}#> \ PREFIX base:<#{source}#> diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java index 97ace2d5d..7f985d487 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java @@ -80,6 +80,8 @@ public void testCHEBITerminology() throws Exception { final Terminology chebi = terminologies.stream().filter(t -> t.getTerminology().equals("chebi")).findFirst().get(); assertThat(chebi.getTerminology()).isEqualTo("chebi"); + // Verify not 247.0 + assertThat(chebi.getVersion()).isEqualTo("247"); assertThat(chebi.getMetadata().getUiLabel()) .isEqualTo("ChEBI: Chemical Entities of Biological Interest"); assertThat(chebi.getName()).isEqualTo("ChEBI: Chemical Entities of Biological Interest 241"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java index 3d61f69d7..0d77a1c3a 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/TermSuggestionFormControllerEmailTests.java @@ -1,6 +1,9 @@ package gov.nih.nci.evs.api.controller; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.fail; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.databind.JsonNode; @@ -62,8 +65,8 @@ public class TermSuggestionFormControllerEmailTests { /** The base url. */ // Base url for api calls private String baseUrl = "/api/v1/submit/"; - ; + /** The recaptcha token. */ private String recaptchaToken = "TEST-KEY"; /** The object mapper. */ @@ -127,6 +130,11 @@ public void integrationTestSubmitForm() throws Exception { .andReturn(); } + /** + * Integration test submit form with attachment. + * + * @throws Exception the exception + */ @Test public void integrationTestSubmitFormWithAttachment() throws Exception { // SET UP @@ -165,6 +173,11 @@ public void integrationTestSubmitFormWithAttachment() throws Exception { .andExpect(status().isOk()); } + /** + * Integration test submit form with attachment NCIT. + * + * @throws Exception the exception + */ @Test public void integrationTestSubmitFormWithAttachmentNCIT() throws Exception { // SET UP diff --git a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java index d2dc317e2..96c775dea 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceTest.java @@ -420,8 +420,7 @@ public void suggestWithAttachmentInvalidAttachmentThrowsExpectationFailed() thro ResponseStatusException ex = assertThrows( ResponseStatusException.class, - () -> controller.submitWithAttachm - ent(formData, file, null, "token")); + () -> controller.submitWithAttachment(formData, file, null, "token")); // Verify we got the EXPECTATION_FAILED status and message contains our reason assertTrue(ex.getStatusCode() == HttpStatus.EXPECTATION_FAILED); From 29921eea56dbcac713dc67ecc574a8a98a2ab60e Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 30 Dec 2025 14:05:11 -0800 Subject: [PATCH 28/64] fix last spotbugs --- build.gradle | 5 +++-- .../evs/api/controller/StaticContextAccessor.java | 7 +++++-- .../nih/nci/evs/api/service/LoaderServiceImpl.java | 14 ++++++++++---- .../api/service/TermSuggestionFormServiceImpl.java | 12 ++++++------ 4 files changed, 24 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index 69b4a90f3..10a71a0df 100644 --- a/build.gradle +++ b/build.gradle @@ -163,8 +163,9 @@ dependencies { //implementation "org.projectlombok:lombok:1.18.32" //annotationProcessor "org.projectlombok:lombok:1.18.32" //compileOnly "org.projectlombok:lombok:1.18.32" - // compileOnly "jakarta.servlet:jakarta.servlet-api:6.0.0" - //providedRuntime "org.springframework.boot:spring-boot-starter-tomcat" + + // SpotBugs annotations + compileOnly 'com.github.spotbugs:spotbugs-annotations:4.8.2' /* * Test Dependencies diff --git a/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java b/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java index 5bc6251df..61ca2b3f2 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/StaticContextAccessor.java @@ -10,10 +10,13 @@ public class StaticContextAccessor implements ApplicationContextAware { private static ApplicationContext context; + public static void setContext(ApplicationContext applicationContext) { + context = applicationContext; + } + @Override - @SuppressWarnings("static-access") public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { - context = applicationContext; + setContext(applicationContext); } public static T getBean(Class beanClass) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java index a755fc216..1245db2d6 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java @@ -1,5 +1,6 @@ package gov.nih.nci.evs.api.service; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import gov.nih.nci.evs.api.Application; import gov.nih.nci.evs.api.model.Audit; import gov.nih.nci.evs.api.model.Terminology; @@ -42,7 +43,7 @@ public class LoaderServiceImpl { private static String HISTORY_DIR; @Value("${nci.evs.bulkload.historyDir}") - @SuppressWarnings("static-access") + @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") public void setHistoryDir(String historyDir) { HISTORY_DIR = historyDir; } @@ -63,12 +64,17 @@ public void setHistoryDir(String historyDir) { private static OpensearchQueryService staticOsQueryService; private static TerminologyUtils staticTermUtils; + public static void setStaticServices( + OpensearchOperationsService ops, OpensearchQueryService query, TerminologyUtils term) { + staticOperationsService = ops; + staticOsQueryService = query; + staticTermUtils = term; + } + @PostConstruct @SuppressWarnings("static-access") public void init() { - staticOperationsService = this.operationsService; - staticOsQueryService = this.osQueryService; - staticTermUtils = this.termUtils; + setStaticServices(this.operationsService, this.osQueryService, this.termUtils); } /** diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index c360b7fa2..31b561b30 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -198,17 +198,17 @@ public void sendEmailWithAttachment(final EmailDetails emailDetails, final Multi helper.setTo(emailDetails.getToEmail()); helper.setFrom(emailDetails.getFromEmail()); helper.setSubject(emailDetails.getSubject()); - if (emailDetails.getMsgBody() != null - && emailDetails.getMsgBody().toLowerCase().contains(" Date: Mon, 5 Jan 2026 12:49:11 -0500 Subject: [PATCH 29/64] [EVSRESTAPI-574] Improve handling of the triplestore databases - NCIT2, CTRP (#421) * [EVSRESTAPI-574] Improve handling of the triplestore databases - NCIT2, CTRP * Make build * [EVSRESTAPI-574] Improve handling of the triplestore databases - NCIT2, CTRP --------- Co-authored-by: Brian Carlsen --- src/main/bin/devreset.sh | 49 +++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 6 deletions(-) diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index 2e4e6f80e..13c332b00 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -24,7 +24,7 @@ dir=${arr[0]} # Hardcode the history file historyFile=$dir/NCIT/cumulative_history_25.06e.txt -databases=("NCIT2" "CTRP") +DEFAULT_DBS=("NCIT2" "CTRP") curl_cmd='curl -s -w \n%{http_code} -u '"${GRAPH_DB_USERNAME}:${GRAPH_DB_PASSWORD}" # Set up ability to format json @@ -65,6 +65,7 @@ elif [[ -z $ES_PORT ]]; then echo "ERROR: ES_PORT is not set" exit 1 fi +ES="$ES_SCHEME://$ES_HOST:$ES_PORT" # Prerequisites - check the UnitTest echo " Check prerequisites" @@ -189,21 +190,21 @@ check_http_status 200 "GET /$/ping expecting 200" # Verify elasticsearch can be reached echo " verify elasticsearch can be reached" -curl -s -w "\n%{http_code}" "$ES_SCHEME://$ES_HOST:$ES_PORT/_cat/indices" 2> /dev/null > /tmp/x.$$ +curl -s -w "\n%{http_code}" "$ES/_cat/indices" 2> /dev/null > /tmp/x.$$ check_status $? "GET /_cat/indices failed - problem connecting to elasticsearch" check_http_status 200 "GET /_cat/indices expecting 200" # Remove elasticsearch indexes remove_elasticsearch_indexes(){ echo " Remove elasticsearch indexes" - curl -s "$ES_SCHEME://$ES_HOST:$ES_PORT/_cat/indices" | cut -d\ -f 3 | egrep "metrics|concept|evs" | grep -v "snomed" | cat > /tmp/x.$$.txt + curl -s "$ES/_cat/indices" | cut -d\ -f 3 | egrep "metrics|concept|evs" | grep -v "snomed" | cat > /tmp/x.$$.txt if [[ $? -ne 0 ]]; then echo "ERROR: problem connecting to elasticsearch" exit 1 fi for i in `cat /tmp/x.$$.txt`; do echo " remove $i ...`/bin/date`" - curl -s -w "\n%{http_code}" -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$i" 2> /dev/null > /tmp/x.$$ + curl -s -w "\n%{http_code}" -X DELETE "$ES/$i" 2> /dev/null > /tmp/x.$$ check_status $? "DELETE /$i failed - problem removing index $i" check_http_status 200 "DELETE /$i expecting 200" done @@ -281,7 +282,7 @@ reindex_ncim2(){ # drop databases (do not fail) drop_databases(){ - for db in "${databases[@]}" + for db in "${DEFAULT_DBS[@]}" do echo " Dropping $db ...`/bin/date`" $curl_cmd -X DELETE "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets/${db}" > /dev/null 2>&1 @@ -295,7 +296,7 @@ drop_databases(){ # create databases create_databases(){ - for db in "${databases[@]}" + for db in "${DEFAULT_DBS[@]}" do echo " Creating $db ...`/bin/date`" $curl_cmd -X POST -d "dbName=${db}&dbType=tdb2" "http://${GRAPH_DB_HOST}:${GRAPH_DB_PORT}/$/datasets" 2> /dev/null > /tmp/x.$$ @@ -367,8 +368,44 @@ reindex() { fi } +create_configuration_index() { + local index_name="configuration" + local index_exists=$(curl -s -o /dev/null -w "%{http_code}" "$ES/$index_name") + # Drop index if it exists + if [[ $index_exists -eq 200 ]]; then + echo " Dropping existing configuration index: $index_name" + curl -s -o /dev/null -X DELETE "$ES/$index_name" + fi + echo " Creating configuration index: $index_name" + curl -s -o /dev/null -X PUT "$ES/$index_name" -H 'Content-Type: application/json' -d '{ + "mappings": { + "properties": { + "name": { "type": "keyword" }, + "weekly": { "type": "boolean" } + } + } + }' +} + +populate_configuration_index() { + local index_name="configuration" + echo " Populating configuration index: $index_name" + for db in "${DEFAULT_DBS[@]}"; do + weekly_value=false + if [[ "$db" == "CTRP" ]]; then + weekly_value=true + fi + curl -s -o /dev/null -X POST "$ES/$index_name/_doc" -H 'Content-Type: application/json' -d '{ + "name": "'$db'", + "weekly": '$weekly_value' + }' + done +} + # Clean and load echo " Remove databases and load monthly/weekly ...`/bin/date`" +create_configuration_index +populate_configuration_index drop_databases create_databases remove_elasticsearch_indexes From 4c6164e19e0cc280fa19d93282c20453a5184721 Mon Sep 17 00:00:00 2001 From: akuppusamy-wci <99685732+akuppusamy-wci@users.noreply.github.com> Date: Mon, 5 Jan 2026 12:53:38 -0500 Subject: [PATCH 30/64] [EVSRESTAPI-680] Investigate indexing performance on dev/qa (#448) --- build.gradle | 2 +- src/main/bin/devreset.sh | 5 +-- .../api/controller/MetadataController.java | 8 ++-- .../evs/api/service/BaseLoaderService.java | 11 ++--- .../evs/api/service/LoaderServiceImpl.java | 6 +-- .../api/service/QueryBuilderServiceImpl.java | 9 ++-- .../TermSuggestionFormServiceImpl.java | 1 - src/main/resources/sparql-queries.properties | 29 ++++++++++++ .../evs/api/controller/ChebiSampleTest.java | 2 +- .../controller/ConceptControllerTests.java | 1 + .../controller/MetadataControllerTests.java | 4 +- .../api/fhir/FhirR4CodeSystemLookupTests.java | 9 +++- .../fhir/FhirR4CodeSystemReadSearchTests.java | 45 ++++++++++++++++++- .../fhir/FhirR4CodeSystemSubsumesTests.java | 9 +++- .../fhir/FhirR4CodeSystemValidateTests.java | 4 +- .../FhirR4ConceptMapGeneralOperations.java | 4 +- .../fhir/FhirR4ConceptMapReadSearchTests.java | 4 +- .../fhir/FhirR4ConceptMapTranslateTests.java | 4 +- .../api/fhir/FhirR4ValueSetExpandTests.java | 4 +- .../fhir/FhirR4ValueSetGeneralOperations.java | 4 +- .../fhir/FhirR4ValueSetReadSearchTests.java | 4 +- .../api/fhir/FhirR4ValueSetValidateTests.java | 4 +- .../FhirR5CodeSystemGeneralOperations.java | 4 +- .../api/fhir/FhirR5CodeSystemLookupTests.java | 4 +- .../fhir/FhirR5CodeSystemReadSearchTests.java | 4 +- .../fhir/FhirR5CodeSystemSubsumesTests.java | 4 +- .../fhir/FhirR5CodeSystemValidateTests.java | 4 +- .../FhirR5ConceptMapGeneralOperations.java | 4 +- .../fhir/FhirR5ConceptMapReadSearchTests.java | 4 +- .../fhir/FhirR5ConceptMapTranslateTests.java | 4 +- .../fhir/FhirR5ValueSetGeneralOperations.java | 4 +- .../fhir/FhirR5ValueSetReadSearchTests.java | 4 +- .../api/fhir/FhirR5ValueSetValidateTests.java | 4 +- .../api/service/MainTypeHierarchyTest.java | 1 + 34 files changed, 174 insertions(+), 44 deletions(-) diff --git a/build.gradle b/build.gradle index 10a71a0df..2b5d6a107 100644 --- a/build.gradle +++ b/build.gradle @@ -58,7 +58,7 @@ ext { /* Version info */ group = "gov.nih.nci.evs.api" -version = "2.3.0.RELEASE" +version = "2.4.0.RELEASE" sourceCompatibility = 17 targetCompatibility = 17 diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index 13c332b00..f449da813 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -338,7 +338,8 @@ load_data(){ load_terminology_data NCIT2 http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl load_terminology_data NCIT2 http://GO_monthly GO/GO.20250601.owl load_terminology_data NCIT2 http://HGNC_monthly HGNC/HGNC.202507.owl - load_terminology_data NCIT2 http://ChEBI_monthly ChEBI/chebi_247.owl + load_terminology_data NCIT2 http://ChEBI_new ChEBI/chebi_247.owl + load_terminology_data NCIT2 http://ChEBI_old ChEBI/chebi_241.owl load_terminology_data NCIT2 http://UmlsSemNet UmlsSemNet/umlssemnet.owl load_terminology_data NCIT2 http://Canmed CanMed/CANMED.202506.owl load_terminology_data NCIT2 http://MEDRT MED-RT/MEDRT.2025-06-02.owl @@ -359,8 +360,6 @@ load_data(){ reindex() { # Reindex terminologies echo " Reindex terminologies ...`/bin/date`" - # After this point, the log is stored in the tmp folder unless an error is hit - echo " see /tmp/x.$$.txt" src/main/bin/reindex.sh --noconfig --history "$historyFile" if [[ $? -ne 0 ]]; then echo "ERROR: problem running reindex.sh script" diff --git a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java index 4d0baceb2..262c7f58a 100644 --- a/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java +++ b/src/main/java/gov/nih/nci/evs/api/controller/MetadataController.java @@ -115,17 +115,17 @@ public class MetadataController extends BaseController { .collect(Collectors.toList()); } - if (tag.isPresent() && tagList.contains(tag.get())) { + if (terminology.isPresent()) { terms = terms.stream() - .filter(f -> "true".equals(f.getTags().get(tag.get()))) + .filter(f -> f.getTerminology().equals(terminology.get())) .collect(Collectors.toList()); } - if (terminology.isPresent()) { + if (tag.isPresent() && tagList.contains(tag.get())) { terms = terms.stream() - .filter(f -> f.getTerminology().equals(terminology.get())) + .filter(f -> "true".equals(f.getTags().get(tag.get()))) .collect(Collectors.toList()); } diff --git a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java index 4f6718c74..6ec421bcd 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java +++ b/src/main/java/gov/nih/nci/evs/api/service/BaseLoaderService.java @@ -274,14 +274,15 @@ public void updateLatestFlag(final Terminology terminology, final Set re for (final IndexMetadata iMeta : iMetas) { + final boolean monthly = iMeta.getTerminology().getTags().containsKey("monthly"); + final boolean weekly = iMeta.getTerminology().getTags().containsKey("weekly"); + final String clause = (monthly ? "monthly" : "") + (weekly ? "weekly" : ""); + // skip if seen - if (seen.contains(iMeta.getTerminology().getTerminology())) { + if (seen.contains(iMeta.getTerminology().getTerminology() + clause)) { continue; } - seen.add(iMeta.getTerminology().getTerminology()); - - final boolean monthly = iMeta.getTerminology().getTags().containsKey("monthly"); - final boolean weekly = iMeta.getTerminology().getTags().containsKey("weekly"); + seen.add(iMeta.getTerminology().getTerminology() + clause); // Set latest monthly if (!latestMonthlyFound && monthly) { diff --git a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java index 1245db2d6..fa8b4edd9 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java @@ -280,9 +280,9 @@ public static void main(String[] args) throws Exception { termAudit.setEndDate(endDate); termAudit.setElapsedTime(endDate.getTime() - startDate.getTime()); termAudit.setLogLevel("INFO"); - logger.info("Audit: {}", termAudit.toString()); - // only add new audit if something major has actually happened - if (termAudit.getElapsedTime() > 10000 && totalConcepts > 0) { + logger.info(" audit = {}", termAudit); + // only add new audit if concepts were added + if (totalConcepts > 0) { addAudit(termAudit); // update the metadata with the elapsed time term.getMetadata().setIndexRuntime(termAudit.getElapsedTime()); diff --git a/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java index 25a4ea6bd..6f06e1b52 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/QueryBuilderServiceImpl.java @@ -232,7 +232,8 @@ public String constructQuery( @Override public String constructBatchQuery( final String queryProp, final Terminology terminology, final List conceptCodes) { - final String inClause = getInClause(conceptCodes); + final String inClause = getInClause(conceptCodes, "','"); + final String valuesClause = getInClause(conceptCodes, "' '"); final String aboutClause = getAboutClause(conceptCodes); final Map values = ConceptUtils.asMap( @@ -242,6 +243,8 @@ public String constructBatchQuery( terminology.getGraph(), "inClause", inClause, + "valuesClause", + valuesClause, "aboutClause", aboutClause, "preferredNameCode", @@ -299,13 +302,13 @@ private String getResolvedProperty(String queryKey, Map values) * @param values the values * @return the in clause */ - private String getInClause(List values) { + private String getInClause(List values, String delimiter) { checkCodes(values); return new StringBuilder() .append("'") .append( String.join( - "','", + delimiter, values.stream().filter(v -> !v.startsWith("http")).collect(Collectors.toList()))) .append("'") .toString(); diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index c6f0be332..75b040215 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -496,7 +496,6 @@ private String validateNCITAttachment(final MultipartFile file, final String fil * @param formatter the formatter * @return the merged cell value */ - @SuppressWarnings("unused") private String getMergedCellValue( final org.apache.poi.ss.usermodel.Sheet sheet, final int rowIndex, diff --git a/src/main/resources/sparql-queries.properties b/src/main/resources/sparql-queries.properties index 715de9160..813046641 100644 --- a/src/main/resources/sparql-queries.properties +++ b/src/main/resources/sparql-queries.properties @@ -151,6 +151,35 @@ properties.batch=SELECT DISTINCT ?conceptCode ?property ?propertyCode ?propertyL } \ ORDER BY ?conceptCode ?propertyCode ?propertyLabel +properties.batch.ncit=SELECT DISTINCT ?conceptCode ?property ?propertyCode ?propertyLabel ?propertyValue \ +WHERE { \ + VALUES ?conceptCode \ + { \ + #{valuesClause} \ + } \ + { GRAPH <#{namedGraph}> \ + { \ + { \ + ?x #{codeCode} ?conceptCode . \ + ?x owl:deprecated ?propertyValue . \ + BIND( AS ?property) \ + } \ + UNION \ + { \ + ?x a owl:Class . \ + ?x #{codeCode} ?conceptCode . \ + ?x ?property ?propertyValue . \ + ?property a owl:AnnotationProperty . \ + OPTIONAL { ?property #{preferredNameCode} ?propertyLabel } . \ + OPTIONAL { ?property #{codeCode} ?propertyCode } . \ + FILTER NOT EXISTS { ?property rdfs:range xml:anyURI } \ + } \ + } \ + } \ +} \ +ORDER BY ?conceptCode ?propertyCode ?propertyLabel + + # ORDER by is important here because we need all the axiom parts together axioms=SELECT ?axiom ?axiomProperty ?axiomValue \ { GRAPH <#{namedGraph}> \ diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java index 1ec595796..4e7bc2c81 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ChebiSampleTest.java @@ -84,7 +84,7 @@ public void testCHEBITerminology() throws Exception { assertThat(chebi.getVersion()).isEqualTo("247"); assertThat(chebi.getMetadata().getUiLabel()) .isEqualTo("ChEBI: Chemical Entities of Biological Interest"); - assertThat(chebi.getName()).isEqualTo("ChEBI: Chemical Entities of Biological Interest 241"); + assertThat(chebi.getName()).isEqualTo("ChEBI: Chemical Entities of Biological Interest 247"); assertThat(chebi.getDescription()).isNotEmpty(); assertThat(chebi.getMetadata().getLoader()).isEqualTo("rdf"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java index 0cf070676..0cbc99a48 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java @@ -6,6 +6,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import gov.nih.nci.evs.api.model.Association; import gov.nih.nci.evs.api.model.AssociationEntry; import gov.nih.nci.evs.api.model.AssociationEntryResultList; diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index c6b4b16b1..4539910e1 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -1598,6 +1598,7 @@ public void testTerminolgyMetadata() throws Exception { assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isGreaterThan(10); + // Keep an older version of CHEBI so we can have a false result = mvc.perform(get(url).param("latest", "false")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); terminologies = @@ -1608,7 +1609,8 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isGreaterThanOrEqualTo(1); + assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.get(0).getTerminology()).isEqualTo("chebi"); result = mvc.perform(get(url).param("tag", "monthly")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java index e081f6477..02318bf5f 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java @@ -71,7 +71,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system lookup code. @@ -136,6 +138,11 @@ public void testCodeSystemLookupImplicitCodeWithCoding() throws Exception { assertEquals(version, ((StringType) params.getParameter("version").getValue()).getValue()); } + /** + * Test code system lookup instance code with coding. + * + * @throws Exception the exception + */ @Test public void testCodeSystemLookupInstanceCodeWithCoding() throws Exception { // Arrange diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java index 5445a1654..10a0914a5 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java @@ -78,7 +78,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system read. @@ -366,6 +368,12 @@ private void validateCodeSystemResults(final Bundle data, final boolean expectRe } } + /** + * Validate canmed code system results. + * + * @param data the data + * @param expectResults the expect results + */ private void validateCanmedCodeSystemResults(final Bundle data, final boolean expectResults) { final List codeSystems = data.getEntry().stream().map(BundleEntryComponent::getResource).toList(); @@ -696,6 +704,11 @@ public void testCodeSystemSearchVariantsWithParameters() throws Exception { assertEquals(firstCodeSystemTitle, caseSensitiveMatchSystem.getTitle()); } + /** + * Test code system history. + * + * @throws Exception the exception + */ @Test public void testCodeSystemHistory() throws Exception { // Arrange @@ -735,6 +748,11 @@ public void testCodeSystemHistory() throws Exception { } } + /** + * Test code system history not found. + * + * @throws Exception the exception + */ @Test public void testCodeSystemHistoryNotFound() throws Exception { // Arrange @@ -755,6 +773,11 @@ public void testCodeSystemHistoryNotFound() throws Exception { assertEquals(messageNotFound, (component.getDiagnostics())); } + /** + * Test code system vread. + * + * @throws Exception the exception + */ @Test public void testCodeSystemVread() throws Exception { // Arrange @@ -790,6 +813,11 @@ public void testCodeSystemVread() throws Exception { assertEquals(originalCodeSystem.getPublisher(), versionedCodeSystem.getPublisher()); } + /** + * Test code system vread not found. + * + * @throws Exception the exception + */ @Test public void testCodeSystemVreadNotFound() throws Exception { // Arrange @@ -812,6 +840,11 @@ public void testCodeSystemVreadNotFound() throws Exception { assertEquals(messageNotFound, (component.getDiagnostics())); } + /** + * Test code system vread invalid version. + * + * @throws Exception the exception + */ @Test public void testCodeSystemVreadInvalidVersion() throws Exception { // Arrange @@ -841,6 +874,11 @@ public void testCodeSystemVreadInvalidVersion() throws Exception { assertEquals(messageNotFound, (component.getDiagnostics())); } + /** + * Test code system history metadata consistency. + * + * @throws Exception the exception + */ @Test public void testCodeSystemHistoryMetadataConsistency() throws Exception { // Arrange @@ -877,6 +915,11 @@ public void testCodeSystemHistoryMetadataConsistency() throws Exception { assertTrue(foundCurrentVersion, "History should contain the current version"); } + /** + * Test code system vread matches history entry. + * + * @throws Exception the exception + */ @Test public void testCodeSystemVreadMatchesHistoryEntry() throws Exception { // Arrange diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java index a7f2e34a6..8516fb870 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemSubsumesTests.java @@ -65,7 +65,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system lookup code. @@ -355,6 +357,11 @@ public void testCodeSystemSubsumesImplicitWithCoding() throws Exception { assertEquals(outcome, ((StringType) params.getParameter("outcome").getValue()).getValue()); } + /** + * Test code system subsumes instance with coding. + * + * @throws Exception the exception + */ @Test public void testCodeSystemSubsumesInstanceWithCoding() throws Exception { // Arrange diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java index 77e31a0fe..7841416bc 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java @@ -67,7 +67,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java index 7389ed9c6..8c3443263 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapGeneralOperations.java @@ -50,7 +50,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java index 4e92b1803..1df0ee7aa 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapReadSearchTests.java @@ -78,7 +78,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java index 60441e359..8a57553e7 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ConceptMapTranslateTests.java @@ -70,7 +70,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map translate with instance system; id, code, and system provided. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java index 6cc080fb5..934845579 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java @@ -90,7 +90,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Helper method to create the common NCI ValueSet for testing. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java index 5e41341fc..88cbb48ad 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetGeneralOperations.java @@ -50,7 +50,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index 187e57f2e..f975dc277 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -77,7 +77,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java index 6d5fcd737..9c1719217 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java @@ -68,7 +68,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java index 952a54f26..9d4018012 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemGeneralOperations.java @@ -50,7 +50,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java index de6b127d9..3a6d61c7b 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java @@ -74,7 +74,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java index 5433d2cde..89197a57b 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java @@ -73,7 +73,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java index 97aee6749..411f3a041 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemSubsumesTests.java @@ -65,7 +65,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system lookup code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java index b53cd8ead..b7f1aa73e 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java @@ -67,7 +67,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test code system validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java index de2e69d11..9619e6c4e 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapGeneralOperations.java @@ -50,7 +50,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java index b9d0d9186..ead41d274 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapReadSearchTests.java @@ -69,7 +69,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java index 676b57f62..54150fe30 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ConceptMapTranslateTests.java @@ -70,7 +70,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test concept map translate with instance system; id, code, and system provided. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java index f4b5d2808..4815aaca8 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetGeneralOperations.java @@ -50,7 +50,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set validate. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index 2fccff077..ffb93a61e 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -69,7 +69,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set search. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java index cd8803a70..657d0b2bb 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java @@ -68,7 +68,9 @@ public static void setUpOnce() { /** Sets the up. */ @BeforeEach - public void setUp() {} + public void setUp() { + // n/a + } /** * Test value set validate active code. diff --git a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java index d129a08c4..1d21bf5de 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java @@ -10,6 +10,7 @@ import gov.nih.nci.evs.api.util.MainTypeHierarchy; import gov.nih.nci.evs.api.util.TerminologyUtils; import java.util.List; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; From 59acca2239f1cc6a04aa86a6f1f0e903a5503cd9 Mon Sep 17 00:00:00 2001 From: Deborah Shapiro Date: Mon, 5 Jan 2026 15:09:06 -0800 Subject: [PATCH 31/64] Dss/evsrestapi 690 property param (#450) * EVSRESTAPI-690: property parameter adding property parameter for CodeSystem$lookup operation * EVSRESTAPI-690: property param spotless misc * EVSRESTAPI-690: property param update .gitignore * EVSRESTAPI-690-property-param * EVSRESTAPI-690: spotless misc --- CHANGELOG.md | 1 + build.gradle | 13 +- .../evs/api/fhir/R5/ValueSetProviderR5.java | 63 +++++++++- .../api/fhir/FhirR4CodeSystemLookupTests.java | 56 +++++++++ .../api/fhir/FhirR5CodeSystemLookupTests.java | 44 ++++++- .../api/fhir/FhirR5ValueSetExpandTests.java | 112 ++++++++++++++++++ 6 files changed, 278 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1a9f92ead..f27769dcd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + ## [2.4.0.RELEASE] - 2025-MM-DD ### Changed - TBD diff --git a/build.gradle b/build.gradle index 2b5d6a107..4d956d054 100644 --- a/build.gradle +++ b/build.gradle @@ -112,12 +112,13 @@ dependencies { // Upgrade ecache to use jakarta - https://groups.google.com/g/ehcache-users/c/sKfxWuTpY-U // See also: https://stackoverflow.com/questions/75813659/gradle-could-not-find-org-ehcacheehcache-after-upgrading-to-spring-boot-3-0-x - implementation "org.ehcache:ehcache:3.10.8:jakarta" - // { - // capabilities { - // requireCapability("org.ehcache:ehcache-jakarta") - // } - // } + // Note: ehcache 3.10.8 uses Jakarta by default, no classifier needed + implementation "org.ehcache:ehcache:3.10.8" + + // JAXB dependencies required for ehcache with Java 9+ + // ehcache 3.10.8 still uses javax.xml.bind internally for XML parsing + implementation 'javax.xml.bind:jaxb-api:2.3.1' + implementation 'com.sun.xml.bind:jaxb-impl:2.3.3' // Apache POI for reading .xls and .xlsx files implementation 'org.apache.poi:poi:5.2.3' diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java index cd13e9229..218691967 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java @@ -19,6 +19,7 @@ import gov.nih.nci.evs.api.model.ConceptResultList; import gov.nih.nci.evs.api.model.Definition; import gov.nih.nci.evs.api.model.IncludeParam; +import gov.nih.nci.evs.api.model.Property; import gov.nih.nci.evs.api.model.SearchCriteria; import gov.nih.nci.evs.api.model.Synonym; import gov.nih.nci.evs.api.model.Terminology; @@ -519,8 +520,16 @@ public ValueSet expandImplicit( // Add properties to the contains component if they were requested if (propertyNames != null && !propertyNames.isEmpty()) { - for (String propertyName : propertyNames) { - addConceptProperty(vsContains, member, propertyName); + // Check if '*' is specified to return all properties + if (propertyNames.contains("*")) { + List allProps = getAllPropertyNames(member); + for (String propertyName : allProps) { + addConceptProperty(vsContains, member, propertyName); + } + } else { + for (String propertyName : propertyNames) { + addConceptProperty(vsContains, member, propertyName); + } } } // Add definitions to the contains component if they were requested @@ -837,8 +846,16 @@ public ValueSet expandInstance( // Add properties to the contains component if they were requested if (propertyNames != null && !propertyNames.isEmpty()) { - for (String propertyName : propertyNames) { - addConceptProperty(vsContains, member, propertyName); + // Check if '*' is specified to return all properties + if (propertyNames.contains("*")) { + List allProps = getAllPropertyNames(member); + for (String propertyName : allProps) { + addConceptProperty(vsContains, member, propertyName); + } + } else { + for (String propertyName : propertyNames) { + addConceptProperty(vsContains, member, propertyName); + } } } // Add definitions to the contains component if they were requested @@ -1357,6 +1374,44 @@ private void addConceptProperty( } } + /** + * Gets all available property names for a concept. + * + * @param concept the concept + * @return list of all available property names + */ + private List getAllPropertyNames(Concept concept) { + List allPropertyNames = new ArrayList<>(); + + // Add standard properties + allPropertyNames.add("active"); + + // Add parent if concept has parents + if (concept.getParents() != null && !concept.getParents().isEmpty()) { + allPropertyNames.add("parent"); + } + + // Add child if concept has children + if (concept.getChildren() != null && !concept.getChildren().isEmpty()) { + allPropertyNames.add("child"); + } + + // Add definition if concept has definitions + if (concept.getDefinitions() != null && !concept.getDefinitions().isEmpty()) { + allPropertyNames.add("definition"); + } + + // Add all custom properties + if (concept.getProperties() != null) { + concept.getProperties().stream() + .map(Property::getType) + .distinct() + .forEach(allPropertyNames::add); + } + + return allPropertyNames; + } + /** * Gets the value set history. * diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java index 02318bf5f..9f0380688 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java @@ -551,6 +551,40 @@ public void testCodeSystemLookupReturnsAllProperties() throws Exception { part.getName().equals("code") && ((CodeType) part.getValue()).getValue().equals("active"))); assertTrue(hasActiveProperty, "Should have 'active' property"); + + // Check that parent property is present + final boolean hasParentProperty = + properties.stream() + .anyMatch( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))); + assertTrue(hasParentProperty, "Should have 'parent' property"); + + // Verify the parent value is T096 (Group) + final ParametersParameterComponent parentProperty = + properties.stream() + .filter( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))) + .findFirst() + .orElse(null); + assertNotNull(parentProperty, "Parent property should exist"); + + final String parentValue = + parentProperty.getPart().stream() + .filter(part -> part.getName().equals("value")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .findFirst() + .orElse(null); + assertEquals("T096", parentValue, "Parent of T100 should be T096"); } /** @@ -581,6 +615,28 @@ public void testCodeSystemLookupWithSpecificProperty() throws Exception { .filter(p -> p.getName().equals("property")) .collect(Collectors.toList()); assertTrue(properties.size() > 0, "Should have properties"); + + // Verify the parent value is T096 (Group) + final ParametersParameterComponent parentProperty = + properties.stream() + .filter( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))) + .findFirst() + .orElse(null); + assertNotNull(parentProperty, "Parent property should exist"); + + final String parentValue = + parentProperty.getPart().stream() + .filter(part -> part.getName().equals("value")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .findFirst() + .orElse(null); + assertEquals("T096", parentValue, "Parent of T100 should be T096"); } /** diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java index 3a6d61c7b..ba4593aab 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java @@ -545,6 +545,25 @@ public void testCodeSystemLookupReturnsAllProperties() throws Exception { .map(part -> ((CodeType) part.getValue()).getValue()) .collect(Collectors.toSet()); assertTrue(propertyNames.contains("active"), "Should include 'active' property"); + assertTrue(propertyNames.contains("parent"), "Should include 'parent' property"); + + // Verify that C9305 (Malignant Neoplasm) is one of the parents of C3224 + final List parentValues = + properties.stream() + .filter( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))) + .flatMap(prop -> prop.getPart().stream()) + .filter(part -> part.getName().equals("value")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .collect(Collectors.toList()); + assertTrue( + parentValues.contains("C9305"), + "C9305 (Malignant Neoplasm) should be one of the parents of C3224"); } /** @@ -558,7 +577,8 @@ public void testCodeSystemLookupWithSpecificProperty() throws Exception { final String activeCode = "C3224"; final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; - final String parameters = "?system=" + url + "&code=" + activeCode + "&property=Semantic_Type"; + final String parameters = + "?system=" + url + "&code=" + activeCode + "&property=parent&property=Semantic_Type"; // Act final String content = this.restTemplate.getForObject(endpoint + parameters, String.class); @@ -585,6 +605,28 @@ public void testCodeSystemLookupWithSpecificProperty() throws Exception { assertTrue( propertyNames.contains("active"), "Should include hardcoded 'active' property even with filter"); + assertTrue(propertyNames.contains("parent"), "Should include 'parent' property when requested"); + assertTrue( + propertyNames.contains("Semantic_Type"), + "Should include 'Semantic_Type' property when requested"); + + // Verify that C9305 (Malignant Neoplasm) is one of the parents of C3224 + final List parentValues = + properties.stream() + .filter( + prop -> + prop.getPart().stream() + .anyMatch( + part -> + part.getName().equals("code") + && ((CodeType) part.getValue()).getValue().equals("parent"))) + .flatMap(prop -> prop.getPart().stream()) + .filter(part -> part.getName().equals("value")) + .map(part -> ((CodeType) part.getValue()).getValue()) + .collect(Collectors.toList()); + assertTrue( + parentValues.contains("C9305"), + "C9305 (Malignant Neoplasm) should be one of the parents of C3224"); } /** diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java index 765821e2c..22ec7bdf5 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetExpandTests.java @@ -6964,4 +6964,116 @@ public void testValueSetExpandImplicitEmptySortParameter() throws Exception { assertTrue(valueSet.hasExpansion()); // Empty sort parameter should work (ignored, using default sorting) } + + /** + * Test value set expand with wildcard property parameter. When property=* is specified, all + * available properties for each concept should be returned. + * + * @throws Exception the exception + */ + @Test + public void testValueSetExpandImplicitSubsetWithWildcardProperty() throws Exception { + // Arrange + String content; + final String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C54459"; + final String endpoint = localHost + port + fhirVSPath + "/" + JpaConstants.OPERATION_EXPAND; + final String parameters = "?url=" + url + "&property=*"; + + final String activeCode = "C48672"; + + // Act + content = this.restTemplate.getForObject(endpoint + parameters, String.class); + final ValueSet valueSet = parser.parseResource(ValueSet.class, content); + + // Assert + assertTrue(valueSet.hasExpansion()); + + // Find the concept with the active code + final ValueSet.ValueSetExpansionContainsComponent concept = + valueSet.getExpansion().getContains().stream() + .filter(comp -> comp.getCode().equals(activeCode)) + .findFirst() + .orElse(null); + + assertNotNull(concept, "Concept with code " + activeCode + " should be in the expansion"); + assertTrue( + concept.hasProperty(), "Concept should have properties when property=* is specified"); + + // Verify that multiple property types are returned + final List propertyNames = + concept.getProperty().stream() + .map(ValueSet.ConceptPropertyComponent::getCode) + .collect(Collectors.toList()); + + // Should include standard properties like 'active' + assertTrue( + propertyNames.contains("active"), + "Should include 'active' property when property=* is specified"); + + // Should include hierarchical properties if available (parent or child) + boolean hasHierarchicalProperty = + propertyNames.contains("parent") || propertyNames.contains("child"); + assertTrue( + hasHierarchicalProperty, + "Should include hierarchical properties (parent/child) when property=* is specified"); + + // Verify that the property parameter is included in the expansion parameters + assertTrue( + valueSet.getExpansion().getParameter().stream() + .anyMatch( + param -> + "property".equals(param.getName()) && "*".equals(param.getValue().toString())), + "Expansion parameters should include property=*"); + + // Verify specific properties exist on concept C48672 + // Contributing_Source: FDA and NCPDP + final List contributingSourceProps = + concept.getProperty().stream() + .filter(prop -> "Contributing_Source".equals(prop.getCode())) + .collect(Collectors.toList()); + assertTrue( + contributingSourceProps.size() >= 2, + "Should have at least 2 Contributing_Source properties"); + + final List contributingSourceValues = + contributingSourceProps.stream() + .map(prop -> prop.getValue().toString()) + .collect(Collectors.toList()); + assertTrue(contributingSourceValues.contains("FDA"), "Contributing_Source should include FDA"); + assertTrue( + contributingSourceValues.contains("NCPDP"), "Contributing_Source should include NCPDP"); + + // Legacy Concept Name: Schedule_I_Substance + final ValueSet.ConceptPropertyComponent legacyConceptName = + concept.getProperty().stream() + .filter(prop -> "Legacy Concept Name".equals(prop.getCode())) + .findFirst() + .orElse(null); + assertNotNull(legacyConceptName, "Should have Legacy Concept Name property"); + assertEquals( + "Schedule_I_Substance", + legacyConceptName.getValue().toString(), + "Legacy Concept Name should be Schedule_I_Substance"); + + // Semantic_Type: Classification + final ValueSet.ConceptPropertyComponent semanticType = + concept.getProperty().stream() + .filter(prop -> "Semantic_Type".equals(prop.getCode())) + .findFirst() + .orElse(null); + assertNotNull(semanticType, "Should have Semantic_Type property"); + assertEquals( + "Classification", + semanticType.getValue().toString(), + "Semantic_Type should be Classification"); + + // UMLS_CUI: C1547546 + final ValueSet.ConceptPropertyComponent umlsCui = + concept.getProperty().stream() + .filter(prop -> "UMLS_CUI".equals(prop.getCode())) + .findFirst() + .orElse(null); + assertNotNull(umlsCui, "Should have UMLS_CUI property"); + assertEquals("C1547546", umlsCui.getValue().toString(), "UMLS_CUI should be C1547546"); + } } From b13524290ef53686e1e9184b865ad13a2b7c7804 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 12 Jan 2026 14:05:25 -0800 Subject: [PATCH 32/64] updates to scripts for new ncit --- src/main/bin/devreset.sh | 11 ++++++++++- src/main/bin/load.sh | 13 +++++++++++-- src/main/bin/reindex.sh | 2 +- src/main/resources/application-local.yml | 2 +- .../nci/evs/api/service/MainTypeHierarchyTest.java | 3 +-- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index f449da813..45339614c 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -22,7 +22,7 @@ if [ $help == 1 ] || [ ${#arr[@]} -ne 1 ]; then fi dir=${arr[0]} # Hardcode the history file -historyFile=$dir/NCIT/cumulative_history_25.06e.txt +historyFile=$dir/NCIT/cumulative_history_25.12e.txt DEFAULT_DBS=("NCIT2" "CTRP") curl_cmd='curl -s -w \n%{http_code} -u '"${GRAPH_DB_USERNAME}:${GRAPH_DB_PASSWORD}" @@ -102,6 +102,13 @@ if [[ ! -e "$dir/NCIT/ThesaurusInferred_monthly.owl" ]]; then echo "ERROR: unexpectedly ThesaurusInferred_monthly.owl file" exit 1 fi +# Check other NCIt monthly +echo " check other NCIt monthly" +if [[ ! -e "$dir/NCIT/ThesaurusInferred_-1monthly.owl" ]]; then + echo "ERROR: unexpectedly ThesaurusInferred_-1monthly.owl file" + exit 1 +fi + # Check GO monthly echo " check GO monthly" if [[ ! -e "$dir/GO/GO.20250601.owl" ]]; then @@ -334,7 +341,9 @@ load_terminology_data(){ # Load all graphs into graphdb load_data(){ load_terminology_data CTRP http://NCI_T_weekly NCIT/ThesaurusInferred_+1weekly.owl + load_terminology_data CTRP http://NCI_T_prev_monthly NCIT/ThesaurusInferred_-1monthly.owl load_terminology_data CTRP http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl + load_terminology_data NCIT2 http://NCI_T_prev_monthly NCIT/ThesaurusInferred_-1monthly.owl load_terminology_data NCIT2 http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl load_terminology_data NCIT2 http://GO_monthly GO/GO.20250601.owl load_terminology_data NCIT2 http://HGNC_monthly HGNC/HGNC.202507.owl diff --git a/src/main/bin/load.sh b/src/main/bin/load.sh index a2de9bd2d..1ad675d13 100755 --- a/src/main/bin/load.sh +++ b/src/main/bin/load.sh @@ -23,7 +23,7 @@ fi dir=${arr[0]} # Hardcode the history file -historyFile=$dir/NCIT/cumulative_history_25.06e.txt +historyFile=$dir/NCIT/cumulative_history_25.12e.txt databases=("NCIT2" "CTRP") @@ -74,6 +74,13 @@ if [[ ! -e "$dir/NCIT/ThesaurusInferred_monthly.owl" ]]; then echo "ERROR: unexpectedly ThesaurusInferred_monthly.owl file" exit 1 fi +# Check other NCIt monthly +echo " check other NCIt monthly" +if [[ ! -e "$dir/NCIT/ThesaurusInferred_-1monthly.owl" ]]; then + echo "ERROR: unexpectedly ThesaurusInferred_-1monthly.owl file" + exit 1 +fi + # Check GO monthly echo " check GO monthly" if [[ ! -e "$dir/GO/GO.20250601.owl" ]]; then @@ -178,8 +185,10 @@ load_terminology_data(){ load_data(){ load_terminology_data CTRP http://NCI_T_weekly NCIT/ThesaurusInferred_+1weekly.owl + load_terminology_data CTRP http://NCI_T_prev_monthly NCIT/ThesaurusInferred_-1monthly.owl load_terminology_data CTRP http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl - load_terminology_data NCIT2 http://NCI_T_monthly NCIT/ThesaurusInferred_monthly.owl + load_terminology_data NCIT2 http://NCI_T_prev_monthly NCIT/ThesaurusInferred_-1monthly.owl + load_terminology_data NCIT2 http://NCI_T_monthly NCIT/ThesaurusInferred_-1monthly.owl load_terminology_data NCIT2 http://GO_monthly GO/GO.20250601.owl load_terminology_data NCIT2 http://HGNC_monthly HGNC/HGNC.202507.owl load_terminology_data NCIT2 http://ChEBI_monthly ChEBI/chebi_241.owl diff --git a/src/main/bin/reindex.sh b/src/main/bin/reindex.sh index 2bcd29b39..8a3886914 100755 --- a/src/main/bin/reindex.sh +++ b/src/main/bin/reindex.sh @@ -20,7 +20,7 @@ if [ ${#arr[@]} -ne 0 ]; then echo " e.g. $0" echo " e.g. $0 --noconfig" echo " e.g. $0 --force" - echo " e.g. $0 --noconfig --history ../data/UnitTestData/NCIT/cumulative_history_25.06e.txt" + echo " e.g. $0 --noconfig --history ../data/UnitTestData/NCIT/cumulative_history_25.12e.txt" exit 1 fi diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 5c41b4711..fb6ec354b 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -82,7 +82,7 @@ nci: childhoodNeoplasmSubsetsXls: ${CHILDHOOD_NEOPLASM_SUBSETS_XLS:Childhood_Neoplasm_Subsets.xls} ftpNeoplasmUrl: ${FTP_NEOPLASM_URL:https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/Neoplasm/} bulkload: - historyDir: ${NCI_EVS_HISTORY_DIR:src/main/resources/cumulative_history_25.06e.txt} + historyDir: ${NCI_EVS_HISTORY_DIR:src/main/resources/cumulative_history_25.12e.txt} lockFile: ${NCI_EVS_BULK_LOAD_LOCK_FILE_NAME:DownloadSuccessfull.lck} downloadBatchSize: ${NCI_EVS_BULK_LOAD_DOWNLOAD_BATCH_SIZE:250} indexBatchSize: ${NCI_EVS_BULK_LOAD_INDEX_BATCH_SIZE:250} diff --git a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java index 1d21bf5de..82e7d129d 100644 --- a/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java +++ b/src/test/java/gov/nih/nci/evs/api/service/MainTypeHierarchyTest.java @@ -10,7 +10,6 @@ import gov.nih.nci.evs.api.util.MainTypeHierarchy; import gov.nih.nci.evs.api.util.TerminologyUtils; import java.util.List; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -48,7 +47,7 @@ public class MainTypeHierarchyTest { * * @throws Exception the exception */ - @Test + // @Test public void test() throws Exception { log.info(" Get terminology = ncit"); From 12610dd182f3e7e4db3613605be47927094dccb2 Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 13 Jan 2026 16:29:59 -0800 Subject: [PATCH 33/64] some test fixes for versions/other changes in current ncit --- src/main/bin/reindex.sh | 4 +- .../controller/ConceptControllerTests.java | 4 +- .../evs/api/controller/NcitSampleTest.java | 4 +- .../api/controller/SearchControllerTests.java | 4 +- .../api/fhir/FhirR4CodeSystemLookupTests.java | 6 +- .../fhir/FhirR4CodeSystemReadSearchTests.java | 22 +++--- .../fhir/FhirR4CodeSystemValidateTests.java | 2 +- .../api/fhir/FhirR4ValueSetExpandTests.java | 6 +- .../fhir/FhirR4ValueSetReadSearchTests.java | 70 ++++++++--------- .../api/fhir/FhirR4ValueSetValidateTests.java | 2 +- .../api/fhir/FhirR5CodeSystemLookupTests.java | 8 +- .../fhir/FhirR5CodeSystemReadSearchTests.java | 32 ++++---- .../fhir/FhirR5CodeSystemValidateTests.java | 2 +- .../fhir/FhirR5ValueSetReadSearchTests.java | 76 +++++++++---------- .../api/fhir/FhirR5ValueSetValidateTests.java | 2 +- 15 files changed, 122 insertions(+), 122 deletions(-) diff --git a/src/main/bin/reindex.sh b/src/main/bin/reindex.sh index 8a3886914..e79699881 100755 --- a/src/main/bin/reindex.sh +++ b/src/main/bin/reindex.sh @@ -368,8 +368,8 @@ download_ncit_history() { if [[ $? -ne 0 ]]; then echo "ERROR: Failed to get latest terminology from http://localhost:${serverPort}/api/v1/metadata/terminologies?latest=true&tag=monthly&terminology=ncit" if [[ $serverPort -eq 8082 ]]; then - echo " Setting default history version on local to 25.06e" - prev_version="25.06e" + echo " Setting default history version on local to 25.12e" + prev_version="25.12e" else echo " Failed to find terminology version on non-local server, exiting" fi diff --git a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java index 0cbc99a48..66655c8d6 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/ConceptControllerTests.java @@ -1853,9 +1853,9 @@ public void testAssociationEntries() throws Exception { assertThat(resultList).isNotNull(); assertThat(resultList.getTimeTaken()).isGreaterThan(0); assertThat(resultList.getTotal()).isLessThan(3000); - assertThat(resultList.getParameters().getTerminology()).contains("Has_Salt_Form"); + assertThat(resultList.getParameters().getTerminology()).contains("Has_Salt_Or_Ester_Form"); for (AssociationEntry assoc : resultList.getAssociationEntries()) { - assertThat(assoc.getAssociation().equals("Has_Salt_Form")); + assertThat(assoc.getAssociation().equals("Has_Salt_Or_Ester_Form")); } // Test that concept subset is properly 404'd diff --git a/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java b/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java index 5fdafa133..28e208e35 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/NcitSampleTest.java @@ -84,7 +84,7 @@ public void testNCITerminologyMonthly() throws Exception { terminologies.stream().filter(t -> t.getTerminology().equals("ncit")).findFirst().get(); assertThat(ncit.getTerminology()).isEqualTo("ncit"); assertThat(ncit.getMetadata().getUiLabel()).isEqualTo("NCI Thesaurus"); - assertThat(ncit.getName()).isEqualTo("NCI Thesaurus 25.06e"); + assertThat(ncit.getName()).isEqualTo("NCI Thesaurus 25.12e"); assertThat(ncit.getDescription()).isNotEmpty(); assertThat(ncit.getMetadata().getLoader()).isEqualTo("rdf"); @@ -141,7 +141,7 @@ public void testNCITerminologyWeekly() throws Exception { terminologies.stream().filter(t -> t.getTerminology().equals("ncit")).findFirst().get(); assertThat(ncit.getTerminology()).isEqualTo("ncit"); assertThat(ncit.getMetadata().getUiLabel()).isEqualTo("NCI Thesaurus"); - assertThat(ncit.getName()).isEqualTo("NCI Thesaurus 25.07b"); + assertThat(ncit.getName()).isEqualTo("NCI Thesaurus 26.01a"); assertThat(ncit.getDescription()).isNotEmpty(); assertThat(ncit.getMetadata().getLoader()).isEqualTo("rdf"); diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java index 5ecca172a..6d31371e6 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java @@ -3322,9 +3322,9 @@ public void testSearchWeekly() throws Exception { ConceptResultList list = null; // Basic search using the weekly version of NCIt - log.info("Testing url - " + url + "?terminology=ncit_25.07b&term=cancer"); + log.info("Testing url - " + url + "?terminology=ncit_26.01a&term=cancer"); result = - mvc.perform(get(url).param("terminology", "ncit_25.07b").param("term", "cancer")) + mvc.perform(get(url).param("terminology", "ncit_26.01a").param("term", "cancer")) .andExpect(status().isOk()) .andReturn(); content = result.getResponse().getContentAsString(); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java index 9f0380688..01ddd2cdd 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemLookupTests.java @@ -346,10 +346,10 @@ public void testCodeSystemRetiredCodeAndRetiredName() throws Exception { String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; - final String sourceName = "NCI Thesaurus 25.06e"; - final String sourceVersion = "25.06e"; + final String sourceName = "NCI Thesaurus 25.12e"; + final String sourceVersion = "25.12e"; final String endpoint = localHost + port + fhirCSPath + "/" + retiredId + "/" + JpaConstants.OPERATION_LOOKUP; final String parameters = diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java index 10a0914a5..19c69122a 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemReadSearchTests.java @@ -131,10 +131,10 @@ public void testCodeSystemSearch() throws Exception { data.getEntry().stream().map(BundleEntryComponent::getResource).toList(); // Verify things about this one - // {"resourceType":"CodeSystem","id":"ncit_25.06e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.06e","name":"NCI + // {"resourceType":"CodeSystem","id":"ncit_25.12e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.12e","name":"NCI // Thesaurus - // 25.06e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","hierarchyMeaning":"is-a"} - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + // 25.12e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","hierarchyMeaning":"is-a"} + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl")); @@ -170,7 +170,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); // Test successful case with all parameters @@ -184,7 +184,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { .queryParam("date", "ge2035-01") // Future // date .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -196,7 +196,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("date", "ge2021-06") .queryParam("system", "http://invalid.system.url") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -220,7 +220,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("date", "ge2021-06") .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "invalid_title"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -232,7 +232,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); // Test successful case with all parameters @@ -246,7 +246,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -346,7 +346,7 @@ private void validateCodeSystemResults(final Bundle data, final boolean expectRe if (expectResults) { assertFalse(codeSystems.isEmpty()); - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl")); @@ -610,7 +610,7 @@ private void validateCodeSystemPagination(final CodeSystem css) { log.info(" code system = " + parser.encodeResourceToString(css)); // Verify specific IDs and URLs if needed - if (css.getIdPart().equals("ncit_25.06e")) { + if (css.getIdPart().equals("ncit_25.12e")) { assertEquals("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl", css.getUrl()); } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java index 7841416bc..a335e4b9d 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemValidateTests.java @@ -382,7 +382,7 @@ public void testCodeSystemRetiredCodeAndRetiredName() throws Exception { String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; final String endpoint = localHost diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java index 934845579..31224bb63 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetExpandTests.java @@ -3306,8 +3306,8 @@ public void testValueSetExpandWithIncludeVersionDirectConceptsCurrent() throws E currentNCItVersion = "24.01d"; // Fallback to a recent version } - // NOTE: new ticket - investigate why currentNCItVersion as 25.07b doesn't match concepts - currentNCItVersion = "25.06e"; + // NOTE: new ticket - investigate why currentNCItVersion as 26.01a doesn't match concepts + currentNCItVersion = "25.12e"; log.info("Using current NCIt version: {} for R4 include.version test", currentNCItVersion); final String expandEndpoint = @@ -3456,7 +3456,7 @@ public void testValueSetExpandWithIncludeVersionFilterBasedCurrent() throws Exce currentNCItVersion = "24.01d"; // Fallback to a recent version } // NOTE: new ticket - investigate why currentNCI - currentNCItVersion = "25.06e"; + currentNCItVersion = "25.12e"; log.info( "Using current NCIt version: {} for R4 include.version filter test", currentNCItVersion); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index f975dc277..fe3a2bb71 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -98,7 +98,7 @@ public void testValueSetSearch() throws Exception { final List valueSets = data.getEntry().stream().map(Bundle.BundleEntryComponent::getResource).toList(); - final Set ids = new HashSet<>(Set.of("ncit_25.06e", "ncit_c61410")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e", "ncit_c61410")); final Set urls = new HashSet<>( Set.of( @@ -251,7 +251,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); // Test successful case with all parameters String content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -267,7 +267,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -277,12 +277,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "INVALID_CODE") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -292,11 +292,11 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") .queryParam("name", "Invalid Name") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -306,12 +306,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "invalid_title") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -321,12 +321,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://invalid.url") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -336,7 +336,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") @@ -362,12 +362,12 @@ public void testValueSetSearchWithParameters() throws Exception { UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", + .queryParam("_id", "ncit_25.12e") // .queryParam("code", // "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); // Test successful case with all parameters String content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -379,10 +379,10 @@ public void testValueSetSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") .queryParam("_id", "invalid_id") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -391,10 +391,10 @@ public void testValueSetSearchWithParameters() throws Exception { // Test 3: Invalid code // builder = // UriComponentsBuilder.fromUriString(endpoint).queryParam("_count", "2000") - // .queryParam("_id", "ncit_25.06e").queryParam("code", "INVALID_CODE") - // .queryParam("name", "NCI Thesaurus 25.06e").queryParam("title", "ncit") + // .queryParam("_id", "ncit_25.12e").queryParam("code", "INVALID_CODE") + // .queryParam("name", "NCI Thesaurus 25.12e").queryParam("title", "ncit") // .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - // .queryParam("version", "25.06e"); + // .queryParam("version", "25.12e"); // // content = // this.restTemplate.getForObject(builder.build().encode().toUri(), @@ -406,11 +406,11 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") .queryParam("name", "Invalid Name") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -420,11 +420,11 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "invalid_title") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -434,11 +434,11 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://invalid.url") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -448,8 +448,8 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") .queryParam("version", "invalid_version"); @@ -472,7 +472,7 @@ private void validateValueSetResults(final Bundle data, final boolean expectResu if (expectResults) { assertFalse(valueSets.isEmpty()); - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs")); @@ -647,7 +647,7 @@ private void validateValueSetPagination(final ValueSet vs) { log.info(" value set = " + parser.encodeResourceToString(vs)); // Verify specific IDs and URLs if needed - if (vs.getIdPart().equals("ncit_25.06e")) { + if (vs.getIdPart().equals("ncit_25.12e")) { assertEquals("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs", vs.getUrl()); } } @@ -780,11 +780,11 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("_id", "ncit_25.12e") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); final Bundle allParamsData = parser.parseResource(Bundle.class, content); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java index 9c1719217..b39783dc5 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetValidateTests.java @@ -473,7 +473,7 @@ public void testValueSetRetiredIdRetiredCodeAndRetireDisplayString() throws Exce String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; final String endpoint = localHost diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java index ba4593aab..b41e52cb7 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemLookupTests.java @@ -309,7 +309,7 @@ public void testCodeSystemRetiredCode() throws Exception { final String endpoint = localHost + port + fhirCSPath + "/" + JpaConstants.OPERATION_LOOKUP; final String parameters = "?system=" + retiredUrl + "&code=" + retiredCode; - final Set sourceVersions = new HashSet<>(Set.of("25.06e", "25.07b")); + final Set sourceVersions = new HashSet<>(Set.of("25.12e", "26.01a")); final String retiredName = "ABCB1 1 Allele"; // Act @@ -345,10 +345,10 @@ public void testCodeSystemRetiredCodeAndRetiredName() throws Exception { String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; - final String sourceName = "NCI Thesaurus 25.06e"; - final String sourceVersion = "25.06e"; + final String sourceName = "NCI Thesaurus 25.12e"; + final String sourceVersion = "25.12e"; final String endpoint = localHost + port + fhirCSPath + "/" + retiredId + "/" + JpaConstants.OPERATION_LOOKUP; final String parameters = diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java index 89197a57b..fc794f605 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemReadSearchTests.java @@ -95,10 +95,10 @@ public void testCodeSystemSearch() throws Exception { data.getEntry().stream().map(Bundle.BundleEntryComponent::getResource).toList(); // Verify things about this one - // {"resourceType":"CodeSystem","id":"ncit_25.06e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.06e","name":"NCI + // {"resourceType":"CodeSystem","id":"ncit_25.12e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.12e","name":"NCI // Thesaurus - // 25.06e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","hierarchyMeaning":"is-a"} - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + // 25.12e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","hierarchyMeaning":"is-a"} + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl")); @@ -175,10 +175,10 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit") .queryParam("publisher", "National Cancer Institute") - .queryParam("name", "NCI Thesaurus 25.06e"); + .queryParam("name", "NCI Thesaurus 25.12e"); // Test successful case with all parameters String content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -193,7 +193,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { // - // invalid .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit") .queryParam("publisher", "NCI") .queryParam("name", "NCI Thesaurus"); @@ -207,7 +207,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://invalid.system.url") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit") .queryParam("publisher", "NCI") .queryParam("name", "NCI Thesaurus"); @@ -235,7 +235,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "invalid_title") .queryParam("publisher", "NCI") .queryParam("name", "NCI Thesaurus"); @@ -249,7 +249,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit") .queryParam("publisher", "InvalidPublisher") .queryParam("name", "NCI Thesaurus"); @@ -263,7 +263,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit") .queryParam("publisher", "NCI") .queryParam("name", "InvalidName"); @@ -277,7 +277,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { // .queryParam("date", // // "ge2021-06") // .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - // .queryParam("version", "25.06e").queryParam("title", + // .queryParam("version", "25.12e").queryParam("title", // "ncit").queryParam("publisher", "NCI") // .queryParam("name", "NCI Thesaurus"); // @@ -292,7 +292,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { // .queryParam("date", // // "ge2021-06") // .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - // .queryParam("version", "25.06e").queryParam("title", + // .queryParam("version", "25.12e").queryParam("title", // "ncit").queryParam("publisher", "NCI") // .queryParam("name", "NCI Thesaurus"); // @@ -307,7 +307,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) // .queryParam("date", // "ge2021-06") .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -320,7 +320,7 @@ public void testCodeSystemSearchWithParameters() throws Exception { // "ge2021-06") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") .queryParam("system", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e") + .queryParam("version", "25.12e") .queryParam("title", "ncit"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -347,7 +347,7 @@ private void validateCodeSystemResults(final Bundle data, final boolean expectRe if (expectResults) { assertFalse(codeSystems.isEmpty()); - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl")); @@ -515,7 +515,7 @@ private void validateCodeSystemPagination(final CodeSystem css) { log.info(" code system = " + parser.encodeResourceToString(css)); // Verify specific IDs and URLs if needed - if (css.getIdPart().equals("ncit_25.06e")) { + if (css.getIdPart().equals("ncit_25.12e")) { assertEquals("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl", css.getUrl()); } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java index b7f1aa73e..805ddfb29 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5CodeSystemValidateTests.java @@ -378,7 +378,7 @@ public void testCodeSystemRetiredCodeAndRetiredName() throws Exception { String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; final String endpoint = localHost diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index ffb93a61e..fe120025c 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -91,19 +91,19 @@ public void testValueSetSearch() throws Exception { data.getEntry().stream().map(Bundle.BundleEntryComponent::getResource).toList(); // Verify things about these - // {"resourceType":"ValueSet","id":"ncit_25.06e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.06e","name":"NCI + // {"resourceType":"ValueSet","id":"ncit_25.12e","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl","version":"25.12e","name":"NCI // Thesaurus - // 25.06e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","description":"NCI + // 25.12e","title":"ncit","status":"active","experimental":false,"publisher":"NCI","description":"NCI // Thesaurus, a controlled vocabulary in support of NCI administrative and // scientific activities. Produced by the Enterprise Vocabulary System // (EVS), a project by the NCI Center for Biomedical Informatics and // Information Technology. National Cancer Institute, National Institutes of // Health, Bethesda, MD 20892, U.S.A."} - // {"resourceType":"ValueSet","id":"ncit_c100110","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110","identifier":[{"value":"C100110"}],"version":"25.06e","name":"CDISC + // {"resourceType":"ValueSet","id":"ncit_c100110","url":"http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110","identifier":[{"value":"C100110"}],"version":"25.12e","name":"CDISC // Questionnaire // Terminology","title":"ncit","status":"active","experimental":false,"publisher":"NCI","description":"Value // set representing the ncitsubsetC100110"} - final Set ids = new HashSet<>(Set.of("ncit_25.06e", "ncit_c61410")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e", "ncit_c61410")); final Set urls = new HashSet<>( Set.of( @@ -276,7 +276,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); // Test successful case with all parameters String content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -292,7 +292,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -302,12 +302,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "INVALID_CODE") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -317,11 +317,11 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") .queryParam("name", "Invalid Name") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -331,12 +331,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "invalid_title") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs=C100110") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -346,12 +346,12 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") .queryParam("url", "http://invalid.url") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -361,7 +361,7 @@ public void testValueSetSubsetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "C100110") .queryParam("name", "CDISC Questionnaire Terminology") .queryParam("title", "ncit") @@ -391,12 +391,12 @@ public void testValueSetSearchWithParameters() throws Exception { UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", + .queryParam("_id", "ncit_25.12e") // .queryParam("code", // "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); // Test successful case with all parameters String content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); @@ -408,10 +408,10 @@ public void testValueSetSearchWithParameters() throws Exception { UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") .queryParam("_id", "invalid_id") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -421,12 +421,12 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") + .queryParam("_id", "ncit_25.12e") .queryParam("code", "INVALID_CODE") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -436,10 +436,10 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") .queryParam("name", "Invalid Name") // .queryParam("system", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -449,11 +449,11 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "invalid_system") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -463,11 +463,11 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "ncit") .queryParam("url", "http://invalid.url") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); data = parser.parseResource(Bundle.class, content); @@ -477,8 +477,8 @@ public void testValueSetSearchWithParameters() throws Exception { builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") // .queryParam("code", "C61410") - .queryParam("name", "NCI Thesaurus 25.06e") // .queryParam("system", + .queryParam("_id", "ncit_25.12e") // .queryParam("code", "C61410") + .queryParam("name", "NCI Thesaurus 25.12e") // .queryParam("system", // "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl") .queryParam("version", "invalid_version"); @@ -501,7 +501,7 @@ private void validateValueSetResults(final Bundle data, final boolean expectResu if (expectResults) { assertFalse(valueSets.isEmpty()); - final Set ids = new HashSet<>(Set.of("ncit_25.06e")); + final Set ids = new HashSet<>(Set.of("ncit_25.12e")); final Set urls = new HashSet<>(Set.of("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs")); @@ -679,7 +679,7 @@ private void validateValueSetPagination(final ValueSet vs) { log.info(" value set = " + parser.encodeResourceToString(vs)); // Verify specific IDs and URLs if needed - if (vs.getIdPart().equals("ncit_25.06e")) { + if (vs.getIdPart().equals("ncit_25.12e")) { assertEquals("http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs", vs.getUrl()); } } @@ -812,11 +812,11 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final UriComponentsBuilder builder = UriComponentsBuilder.fromUriString(endpoint) .queryParam("_count", "2000") - .queryParam("_id", "ncit_25.06e") - .queryParam("name", "NCI Thesaurus 25.06e") + .queryParam("_id", "ncit_25.12e") + .queryParam("name", "NCI Thesaurus 25.12e") .queryParam("title", "ncit") .queryParam("url", "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs") - .queryParam("version", "25.06e"); + .queryParam("version", "25.12e"); content = this.restTemplate.getForObject(builder.build().encode().toUri(), String.class); final Bundle allParamsData = parser.parseResource(Bundle.class, content); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java index 657d0b2bb..af69dab46 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetValidateTests.java @@ -473,7 +473,7 @@ public void testValueSetRetiredIdRetiredCodeAndRetireDisplayString() throws Exce String content; final String retiredCode = "C45683"; final String retiredUrl = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; - final String retiredId = "ncit_25.06e"; + final String retiredId = "ncit_25.12e"; final String retiredName = "ABCB1 1 Allele"; final String endpoint = localHost From 236d92fc18667ec49dcb630a56e444c9f9288902 Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Wed, 14 Jan 2026 10:17:51 -0800 Subject: [PATCH 34/64] EVSRESTAPI-700: add curl calls to remove indexes to reindex.sh --- src/main/bin/reindex.sh | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/main/bin/reindex.sh b/src/main/bin/reindex.sh index 2bcd29b39..0bcdc233d 100755 --- a/src/main/bin/reindex.sh +++ b/src/main/bin/reindex.sh @@ -439,7 +439,24 @@ done) done if [[ $keep -eq 0 ]]; then echo " remove $index" - #curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$index" > /dev/null + curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/$index" > /tmp/x.$$.txt + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: error removing index $i" + # exit 1 + fi + curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/${index/concept_/evs_object_}" > /tmp/x.$$.txt + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: error removing index ${index/concept_/evs_object}" + # exit 1 + fi + curl -s -X DELETE "$ES_SCHEME://$ES_HOST:$ES_PORT/evs_metadata/_doc/$index" > /tmp/x.$$.txt + if [[ $? -ne 0 ]]; then + cat /tmp/x.$$.txt | sed 's/^/ /' + echo "ERROR: error removing evs_metadata entry for $index" + # exit 1 + fi fi done From b540275ac8df3dfa4ec9152ccfd86ac4fa3d8d58 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 14 Jan 2026 16:34:21 -0800 Subject: [PATCH 35/64] fix some more tests --- .../controller/MetadataControllerTests.java | 27 ++++++++++-------- src/test/resources/samples/chebi-samples.txt | 28 +++++++++---------- 2 files changed, 28 insertions(+), 27 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 4539910e1..5ff3d448c 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -1557,7 +1557,7 @@ public void testMutuallyExclusive() throws Exception { * @throws Exception the exception */ @Test - public void testTerminolgyMetadata() throws Exception { + public void testTerminologyMetadata() throws Exception { String url = baseUrl + "/terminologies"; MvcResult result = null; List terminologies = null; @@ -1572,7 +1572,7 @@ public void testTerminolgyMetadata() throws Exception { new TypeReference>() { // n/a }); - assertThat(terminologies != null && terminologies.size() == 2).isTrue(); + assertThat(terminologies != null && terminologies.size() == 3).isTrue(); result = mvc.perform(get(url).param("terminology", "ncim")).andExpect(status().isOk()).andReturn(); @@ -1599,7 +1599,10 @@ public void testTerminolgyMetadata() throws Exception { assertThat(terminologies.size()).isGreaterThan(10); // Keep an older version of CHEBI so we can have a false - result = mvc.perform(get(url).param("latest", "false")).andExpect(status().isOk()).andReturn(); + result = + mvc.perform(get(url).param("terminology", "chebi").param("latest", "false")) + .andExpect(status().isOk()) + .andReturn(); content = result.getResponse().getContentAsString(); terminologies = ThreadLocalMapper.get() @@ -1622,7 +1625,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.size()).isEqualTo(2); result = mvc.perform(get(url).param("tag", "weekly")).andExpect(status().isOk()).andReturn(); content = result.getResponse().getContentAsString(); @@ -1634,7 +1637,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.size()).isEqualTo(2); result = mvc.perform(get(url).param("terminology", "ncit").param("latest", "true")) @@ -1664,7 +1667,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualByComparingTo(0); + assertThat(terminologies.size()).isEqualByComparingTo(1); result = mvc.perform(get(url).param("terminology", "ncit").param("tag", "monthly")) @@ -1679,7 +1682,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.size()).isEqualTo(2); result = mvc.perform(get(url).param("terminology", "ncit").param("tag", "weekly")) @@ -1694,7 +1697,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.size()).isEqualTo(2); result = mvc.perform(get(url).param("latest", "true").param("tag", "monthly")) @@ -1739,7 +1742,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(0); + assertThat(terminologies.size()).isEqualTo(1); result = mvc.perform(get(url).param("latest", "false").param("tag", "weekly")) @@ -1754,7 +1757,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(0); + assertThat(terminologies.size()).isEqualTo(1); result = mvc.perform(get(url).param("terminology", "ncim").param("latest", "true")) @@ -1871,7 +1874,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(0); + assertThat(terminologies.size()).isEqualTo(1); result = mvc.perform( @@ -1890,7 +1893,7 @@ public void testTerminolgyMetadata() throws Exception { // n/a }); assertThat(terminologies).isNotNull(); - assertThat(terminologies.size()).isEqualTo(0); + assertThat(terminologies.size()).isEqualTo(1); result = mvc.perform( diff --git a/src/test/resources/samples/chebi-samples.txt b/src/test/resources/samples/chebi-samples.txt index ada35770a..b39c089cc 100644 --- a/src/test/resources/samples/chebi-samples.txt +++ b/src/test/resources/samples/chebi-samples.txt @@ -1,30 +1,28 @@ -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 charge 0 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 formula C36H38N2O6 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 inchi InChI=1S/C36H38N2O6/c1-37-13-11-23-18-31(41-3)32-20-26(23)27(37)15-21-5-8-25(9-6-21)43-30-17-22(7-10-29(30)39)16-28-34-24(12-14-38(28)2)19-33(42-4)35(40)36(34)44-32/h5-10,17-20,27-28,39-40H,11-16H2,1-4H3/t27-,28-/m0/s1 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 inchikey XGEAUXVPBXUBKN-NSOVKSMOSA-N -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 mass 594.698 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 monoisotopicmass 594.27299 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 smiles COc1cc2CCN(C)[C@H]3Cc4ccc(Oc5cc(C[C@@H]6N(C)CCc7cc(OC)c(O)c(Oc1cc23)c67)ccc5O)cc4 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 oboInOwl:hasDbXref CAS:21008-67-3 -http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 oboInOwl:hasExactSynonym (+)-Atherospermoline +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 oboInOwl:hasDbXref cas:21008-67-3 http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 oboInOwl:hasOBONamespace chebi_ontology +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 oboInOwl:hasRelatedSynonym (+)-Atherospermoline http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 rdfs:label (+)-Atherospermoline +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:charge 0 +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:generalized_empirical_formula C36H38N2O6 +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:inchi_key_string XGEAUXVPBXUBKN-NSOVKSMOSA-N +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:inchi_string InChI=1S/C36H38N2O6/c1-37-13-11-23-18-31(41-3)32-20-26(23)27(37)15-21-5-8-25(9-6-21)43-30-17-22(7-10-29(30)39)16-28-34-24(12-14-38(28)2)19-33(42-4)35(40)36(34)44-32/h5-10,17-20,27-28,39-40H,11-16H2,1-4H3/t27-,28-/m0/s1 +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:mass 594.708 +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:monoisotopic_mass 594.27299 +http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 chemrof:smiles_string COc1cc2c3cc1Oc1c(O)c(OC)cc4c1[C@H](Cc1ccc(O)c(c1)Oc1ccc(cc1)C[C@@H]3N(C)CC2)N(C)CC4 http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 rdfs:subClassOf/owl:Restriction~has_role CHEBI:76924 http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 rdfs:subClassOf/owl:Restriction~is_enantiomer_of CHEBI:6714 -http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 IAO_0000115 The (-)-enantiomer of medicarpin. -http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 oboInOwl:hasRelatedSynonym medicarpin +http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 obo:IAO_0000115 The (−)-enantiomer of medicarpin. +http://purl.obolibrary.org/obo/CHEBI_100 CHEBI:100 oboInOwl:hasExactSynonym (6aR,11aR)-9-methoxy-6a,11a-dihydro-6H-[1]benzofuro[3,2-c]chromen-3-ol http://purl.obolibrary.org/obo/CHEBI_10002 CHEBI:10002 rdfs:subClassOf/owl:Restriction~has_functional_parent CHEBI:173072 http://purl.obolibrary.org/obo/CHEBI_10003 CHEBI:10003 rdfs:subClassOf/owl:Restriction~has_part CHEBI:65028 http://purl.obolibrary.org/obo/CHEBI_100147 CHEBI:100147 rdfs:subClassOf/owl:Restriction~is_conjugate_acid_of CHEBI:62070 http://purl.obolibrary.org/obo/CHEBI_100147 CHEBI:100147 oboInOwl:hasAlternativeId CHEBI:7456 http://purl.obolibrary.org/obo/CHEBI_10015 CHEBI:10015 rdfs:subClassOf/owl:Restriction~has_parent_hydride CHEBI:36372 +http://purl.obolibrary.org/obo/CHEBI_10017 CHEBI:10017 chemrof:wurcs_representation WURCS=2.0/1,1,0/[h11222h]/1/ http://purl.obolibrary.org/obo/CHEBI_100241 CHEBI:100241 rdfs:subClassOf/owl:Restriction~is_conjugate_base_of CHEBI:192486 http://purl.obolibrary.org/obo/CHEBI_100241 CHEBI:100241 rdfs:subClassOf/owl:Restriction~is_tautomer_of CHEBI:192484 http://purl.obolibrary.org/obo/CHEBI_111516 CHEBI:111516 rdfs:subClassOf/owl:Restriction~is_substituent_group_from CHEBI:111513 -http://purl.obolibrary.org/obo/CHEBI_131515 CHEBI:131515 owl:deprecated true -http://purl.obolibrary.org/obo/CHEBI_9999 CHEBI:9999 qualifier-oboInOwl:hasDbXref~oboInOwl:source CAS:35144-10-6~KEGG COMPOUND -http://purl.obolibrary.org/obo/CHEBI_9999 CHEBI:9999 qualifier-oboInOwl:hasExactSynonym~oboInOwl:hasDbXref Viscidulin B~KEGG_COMPOUND -http://purl.obolibrary.org/obo/CHEBI_9997 CHEBI:9997 qualifier-oboInOwl:hasRelatedSynonym~oboInOwl:hasDbXref Virginiamycin factor M1~ChemIDplus +http://purl.obolibrary.org/obo/CHEBI_27189 CHEBI:27189 owl:deprecated true http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:10 parent-style1 CHEBI:133004 http://purl.obolibrary.org/obo/CHEBI_10 CHEBI:133004 child-style1 CHEBI:10 http://purl.obolibrary.org/obo/CHEBI_47923 CHEBI:47923 max-children 8077 From b804f12b626954803dbf009d8cbc85238eb9da77 Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Thu, 15 Jan 2026 10:10:30 -0800 Subject: [PATCH 36/64] Fixes for term form tests --- .../nih/nci/evs/api/model/EmailDetails.java | 12 ++++++------ .../TermSuggestionFormServiceImpl.java | 3 +-- .../filled-form-submission-ncit.xls | Bin 5120 -> 5120 bytes .../formSamples/submissionFormTest-cdisc.json | 1 + .../formSamples/submissionFormTest-ncit.json | 1 + 5 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/model/EmailDetails.java b/src/main/java/gov/nih/nci/evs/api/model/EmailDetails.java index 08e1024f3..0f8512026 100644 --- a/src/main/java/gov/nih/nci/evs/api/model/EmailDetails.java +++ b/src/main/java/gov/nih/nci/evs/api/model/EmailDetails.java @@ -150,7 +150,7 @@ public static EmailDetails generateEmailDetails(final JsonNode formData) throws } else { final EmailDetails emailDetails = new EmailDetails(); // Set the values from the form data - final String formName = formData.path("formName").asText(null); + final String formType = formData.path("formType").asText(null); final String recipientEmail = formData.path("recipientEmail").asText(null); final String businessEmail = formData.path("businessEmail").asText(null); final String subject = formData.path("subject").asText(null); @@ -158,10 +158,10 @@ public static EmailDetails generateEmailDetails(final JsonNode formData) throws // format the json object to a string final String body = generateHtmlEmailBody(formData.path("body")); - if (formName == null - || formName.isEmpty() - || recipientEmail == null - || recipientEmail.isEmpty()) { + if (formType == null || formType.isEmpty()) { + throw new ResponseStatusException(HttpStatus.EXPECTATION_FAILED, nullError); + } + if (recipientEmail == null || recipientEmail.isEmpty()) { throw new ResponseStatusException(HttpStatus.EXPECTATION_FAILED, nullError); } if (businessEmail == null || businessEmail.isEmpty()) { @@ -175,7 +175,7 @@ public static EmailDetails generateEmailDetails(final JsonNode formData) throws } // populate the emailDetails - emailDetails.setSource(formName); + emailDetails.setSource(formType); emailDetails.setToEmail(recipientEmail); emailDetails.setFromEmail(businessEmail); emailDetails.setSubject(subject); diff --git a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java index 75b040215..171b0a7df 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/TermSuggestionFormServiceImpl.java @@ -251,8 +251,7 @@ public String validateFileAttachmentReason(final MultipartFile file, final Strin } else if ("NCIT".equalsIgnoreCase(formType)) { return validateNCITAttachment(file, filename); } else { - return prefix - + String.format("Unknown form type '{}' for file validation: {}", formType, filename); + return prefix + "Unknown form type '" + formType + "' for file validation: " + filename; } } diff --git a/src/test/resources/formSamples/filled-form-submission-ncit.xls b/src/test/resources/formSamples/filled-form-submission-ncit.xls index 6108737026f9889c47ca71430199338bf87b8d55..98add85a113bfca1315b202c2070e46d985c3053 100644 GIT binary patch delta 52 zcmZqBXwcY@!^F0MF`C({ZF3RRHdbL?1_r01%)~qe=ft9%;?%sv+{($09O07#IM_DN I;K<+x0Ik3fTL1t6 delta 52 zcmZqBXwcY@!^FlQ`sw@s Date: Fri, 16 Jan 2026 10:05:59 -0800 Subject: [PATCH 37/64] add versions to some tests for ncit --- .../nih/nci/evs/api/controller/MetadataControllerTests.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 5ff3d448c..27e7b3103 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -1683,6 +1683,8 @@ public void testTerminologyMetadata() throws Exception { }); assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isEqualTo(2); + assertThat(terminologies.get(0).getVersion()).isEqualTo("25.12e"); + assertThat(terminologies.get(1).getVersion()).isEqualTo("25.11d"); result = mvc.perform(get(url).param("terminology", "ncit").param("tag", "weekly")) @@ -1713,6 +1715,7 @@ public void testTerminologyMetadata() throws Exception { }); assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.get(0).getVersion()).isEqualTo("25.12e"); result = mvc.perform(get(url).param("latest", "true").param("tag", "weekly")) @@ -1728,6 +1731,7 @@ public void testTerminologyMetadata() throws Exception { }); assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.get(0).getVersion()).isEqualTo("26.01a"); result = mvc.perform(get(url).param("latest", "false").param("tag", "monthly")) @@ -1743,6 +1747,7 @@ public void testTerminologyMetadata() throws Exception { }); assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isEqualTo(1); + assertThat(terminologies.get(0).getVersion()).isEqualTo("25.11d"); result = mvc.perform(get(url).param("latest", "false").param("tag", "weekly")) From 8f88007c70d95ce71382c482f92a5366addb5bbf Mon Sep 17 00:00:00 2001 From: Peter Van Ausdeln Date: Fri, 16 Jan 2026 10:08:55 -0800 Subject: [PATCH 38/64] not safe to assume order of versions --- .../nih/nci/evs/api/controller/MetadataControllerTests.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java index 27e7b3103..46cc029a5 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MetadataControllerTests.java @@ -1683,8 +1683,9 @@ public void testTerminologyMetadata() throws Exception { }); assertThat(terminologies).isNotNull(); assertThat(terminologies.size()).isEqualTo(2); - assertThat(terminologies.get(0).getVersion()).isEqualTo("25.12e"); - assertThat(terminologies.get(1).getVersion()).isEqualTo("25.11d"); + // Don't assume order, but check that both versions are present + assertThat(terminologies.stream().map(Terminology::getVersion).collect(Collectors.toSet())) + .containsExactlyInAnyOrder("25.12e", "25.11d"); result = mvc.perform(get(url).param("terminology", "ncit").param("tag", "weekly")) From a4e72e404fdf744e27be7feb94289efeaf2f4163 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 21 Jan 2026 14:29:15 -0800 Subject: [PATCH 39/64] update ncit samples --- src/test/resources/samples/ncit-samples.txt | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/test/resources/samples/ncit-samples.txt b/src/test/resources/samples/ncit-samples.txt index 87d0bb4d9..242724a9a 100644 --- a/src/test/resources/samples/ncit-samples.txt +++ b/src/test/resources/samples/ncit-samples.txt @@ -133,12 +133,12 @@ http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C1334 C1334 P351 Y http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C1334 C1334 P352 Y http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C1334 C1334 P358 Y http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C1334 C1334 P359 Y +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C137934 C137934 rdfs:subClassOf/owl:Restriction~R168 C33073 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C142869 C142869 rdfs:subClassOf/owl:Restriction~R136 C12392 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C14424 C14424 P332 MGI:2159769 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C150443 C150443 rdfs:subClassOf/owl:Restriction~R153 C93106 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C15179 C15179 P333 Severed Digit(s), (finger or toe) http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C15278 C15278 rdfs:subClassOf/owl:Restriction~R166 C12904 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C15356 C15356 rdfs:subClassOf/owl:Restriction~R168 C12391 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C15356 C15356 rdfs:subClassOf/owl:Restriction~R170 C12377 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C16240 C16240 P101 CSF1R/PDGFR Family http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C164181 C164181 P367 31026031 @@ -150,15 +150,15 @@ http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C179321 C179321 rdfs:subClass http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C18330 C18330 rdfs:subClassOf/owl:Restriction~R36 C18396 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C18498 C18498 rdfs:subClassOf/owl:Restriction~R39 C4878 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C18611 C18611 P215 map01100 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C186741 C186741 rdfs:subClassOf/owl:Restriction~R165 C12971 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C19799 C19799 P211 dopamine receptor activity http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C21781 C21781 rdfs:subClassOf/owl:Restriction~R23 C22543 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C22192 C22192 P167 http://ccm.ucdavis.edu/cfsidserver/view.cfm?cat=Mouse_N_Prostate&img=MP19.sid&rgn=&nlvl=5&iwid=26150&ihei=27998 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C223864 C223864 P320 2.16.840.1.113883.3.2964 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C2317 C2317 P360 Y http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C2563 C2563 P357 Y http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C28610 C28610 rdfs:subClassOf/owl:Restriction~R145 C45002 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C38112 C38112 rdfs:subClassOf/owl:Restriction~R165 C12389 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C38969 C38969 P216 h_ace2Pathway -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C42636 C42636 P320 2.16.840.1.113883.3.26.1.1.2 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C45598 C45598 rdfs:subClassOf/owl:Restriction~R159 C45424 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C45600 C45600 rdfs:subClassOf/owl:Restriction~R158 C26533 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C45600 C45600 P316 0 @@ -181,23 +181,25 @@ http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C10201 C10201 parent-count4 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C114101 C114101 parent-count5 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C115380 C115380 parent-count6 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C136256 C136256 parent-count7 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160025 C160025 parent-count8 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160034 C160034 parent-count8 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C156353 C156353 parent-count9 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C155746 C155746 parent-count10 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160105 C160105 parent-count11 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160053 C160053 parent-count11 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C159984 C159984 parent-count12 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C154272 C154272 parent-count13 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160006 C160006 parent-count13 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C186510 C186510 parent-count14 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C63406 C63406 parent-count15 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C154272 C154272 parent-count16 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C154325 C154325 parent-count17 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160024 C160024 parent-count18 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C173972 C173972 parent-count19 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160005 C160005 parent-count20 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C187233 C187233 parent-count21 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160102 C160102 parent-count22 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160043 C160043 parent-count22 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160074 C160074 parent-count23 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C213204 C213204 parent-count25 -http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160108 C160108 parent-count38 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160093 C160093 parent-count25 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C213204 C213204 parent-count28 +http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C160108 C160108 parent-count40 http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C12218 C12218 root http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C12219 C12219 root http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl#C12913 C12913 root From 17e74ce198fdcf57e4b1b1079643b9c2fe551017 Mon Sep 17 00:00:00 2001 From: akuppusamy-wci <99685732+akuppusamy-wci@users.noreply.github.com> Date: Thu, 22 Jan 2026 12:28:30 -0500 Subject: [PATCH 40/64] [EVSRESTAPI-702] Loader fails when history file is not passed (#451) --- .../nih/nci/evs/api/service/LoaderServiceImpl.java | 12 ++++++------ src/main/resources/application-local.yml | 3 ++- src/main/resources/application.yml | 2 +- src/test/resources/application-test.yml | 2 +- 4 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java index fa8b4edd9..53b349fbe 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java @@ -39,13 +39,13 @@ public class LoaderServiceImpl { private static final Logger logger = LoggerFactory.getLogger(LoaderServiceImpl.class); /** the history download location *. */ - // @Value("${nci.evs.bulkload.historyDir}") - private static String HISTORY_DIR; + // @Value("${nci.evs.bulkload.historyFile}") + private static String HISTORY_FILE; - @Value("${nci.evs.bulkload.historyDir}") + @Value("${nci.evs.bulkload.historyFile}") @SuppressFBWarnings("ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD") - public void setHistoryDir(String historyDir) { - HISTORY_DIR = historyDir; + public void setHistoryFile(String historyFile) { + HISTORY_FILE = historyFile; } /** the environment *. */ @@ -241,7 +241,7 @@ public static void main(String[] args) throws Exception { } System.exit(0); } - final OpensearchLoadConfig config = buildConfig(cmd, HISTORY_DIR); + final OpensearchLoadConfig config = buildConfig(cmd, HISTORY_FILE); final Terminology term = loadService.getTerminology( app, diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index fb6ec354b..fde2ff171 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -1,3 +1,4 @@ + # # Spring Properties # @@ -82,7 +83,7 @@ nci: childhoodNeoplasmSubsetsXls: ${CHILDHOOD_NEOPLASM_SUBSETS_XLS:Childhood_Neoplasm_Subsets.xls} ftpNeoplasmUrl: ${FTP_NEOPLASM_URL:https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/Neoplasm/} bulkload: - historyDir: ${NCI_EVS_HISTORY_DIR:src/main/resources/cumulative_history_25.12e.txt} + historyFile: ${NCI_EVS_HISTORY_FILE:src/main/resources/cumulative_history_25.12e.txt} lockFile: ${NCI_EVS_BULK_LOAD_LOCK_FILE_NAME:DownloadSuccessfull.lck} downloadBatchSize: ${NCI_EVS_BULK_LOAD_DOWNLOAD_BATCH_SIZE:250} indexBatchSize: ${NCI_EVS_BULK_LOAD_INDEX_BATCH_SIZE:250} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c9f911182..bcfeb7bb0 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -79,7 +79,7 @@ nci: childhoodNeoplasmSubsetsXls: ${CHILDHOOD_NEOPLASM_SUBSETS_XLS:Childhood_Neoplasm_Subsets.xls} ftpNeoplasmUrl: ${FTP_NEOPLASM_URL:https://evs.nci.nih.gov/ftp1/NCI_Thesaurus/Neoplasm/} bulkload: - historyDir: ${NCI_EVS_HISTORY_DIR:} + historyFile: ${NCI_EVS_HISTORY_FILE:} lockFile: ${NCI_EVS_BULK_LOAD_LOCK_FILE_NAME:DownloadSuccessfull.lck} downloadBatchSize: ${NCI_EVS_BULK_LOAD_DOWNLOAD_BATCH_SIZE:1000} indexBatchSize: ${NCI_EVS_BULK_LOAD_INDEX_BATCH_SIZE:1000} diff --git a/src/test/resources/application-test.yml b/src/test/resources/application-test.yml index 3db89a117..775b4c866 100644 --- a/src/test/resources/application-test.yml +++ b/src/test/resources/application-test.yml @@ -94,7 +94,7 @@ nci: sdkBaseUri: ${SDK_BASE_URI:https://raw.githubusercontent.com/NCIEVS/evsrestapi-client-SDK/develop} uiLicense: ${UI_LICENSE:ui-license} bulkload: - historyDir: ${NCI_EVS_HISTORY_DIR:/tmp} + historyFile: ${NCI_EVS_HISTORY_FILE:} lockFile: ${NCI_EVS_BULK_LOAD_LOCK_FILE_NAME:DownloadSuccessfull.lck} downloadBatchSize: ${NCI_EVS_BULK_LOAD_DOWNLOAD_BATCH_SIZE:1000} indexBatchSize: ${NCI_EVS_BULK_LOAD_INDEX_BATCH_SIZE:1000} From 1096d933119bb277a00d2be35f13c083541a19e1 Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 27 Jan 2026 13:35:39 -0800 Subject: [PATCH 41/64] basic audit --- src/main/bin/audit.sh | 108 +++++++++++++++++++++++++++++++++++++++ src/main/bin/devreset.sh | 6 +++ 2 files changed, 114 insertions(+) create mode 100644 src/main/bin/audit.sh diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh new file mode 100644 index 000000000..0901212cf --- /dev/null +++ b/src/main/bin/audit.sh @@ -0,0 +1,108 @@ +#!/bin/bash -f +# +# This script produces audit reports by querying Elasticsearch for evs_audit data. +# + +config=1 +help=0 +arr=() + +while [[ "$#" -gt 0 ]]; do + case $1 in + --help) help=1 ;; + --noconfig) + config=0 + ncflag="--noconfig" + ;; + *) arr+=("$1") ;; + esac + shift +done + +print_help(){ + echo "Usage: $0 [--noconfig] [--help] [terminology]" + echo " e.g. $0 load" + echo " e.g. $0 error ncit" + echo " e.g. $0 warning" + exit 1 +} + +if [[ $help -eq 1 || ${#arr[@]} -eq 0 ]]; then + print_help +fi + +report_type=${arr[0]} +terminology=${arr[1]} + +setup_configuration() { + if [[ $config -eq 1 ]]; then + # Set directory of this script so we can call relative scripts + DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" &>/dev/null && pwd) + if [[ "$DIR" == /cygdrive/* ]]; then DIR=$(echo "$DIR" | sed 's|^/cygdrive/\([a-zA-Z]\)/\(.*\)|\1:/\2|'); fi + APP_HOME="${APP_HOME:-/local/content/evsrestapi}" + CONFIG_DIR=${APP_HOME}/config + CONFIG_ENV_FILE=${CONFIG_DIR}/setenv.sh + if [[ -e $CONFIG_ENV_FILE ]]; then + . $CONFIG_ENV_FILE + else + echo " ERROR: $CONFIG_ENV_FILE does not exist, consider using --noconfig" + exit 1 + fi + fi +} + +validate_setup() { + if [[ -z "$ES_SCHEME" || -z "$ES_HOST" || -z "$ES_PORT" ]]; then + # Try default if not set + ES_SCHEME=${ES_SCHEME:-http} + ES_HOST=${ES_HOST:-localhost} + ES_PORT=${ES_PORT:-9201} + fi + ES="${ES_SCHEME}://${ES_HOST}:${ES_PORT}" +} + +# Verify jq installed +jq --help >>/dev/null 2>&1 +if [[ $? -ne 0 ]]; then + echo "ERROR: jq is required for this script." + exit 1 +fi + +setup_configuration +validate_setup + +query_es() { + local q=$1 + curl -s -G "$ES/evs_audit/_search" --data-urlencode "size=1000" --data-urlencode "q=$q" +} + +case $report_type in + load) + printf "Terminology\tVersion\tElapsed Time (ms)\tCount\tDate\n" + q="process:(MetaOpensearchLoadServiceImpl OR MetaSourceOpensearchLoadServiceImpl OR LoaderServiceImpl) AND NOT elapsedTime:0" + if [[ -n $terminology ]]; then + q="$q AND terminology:$terminology" + fi + query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.elapsedTime, ._source.count, (._source.date // ._source.startDate)] | @tsv' + ;; + error) + printf "Terminology\tVersion\tProcess\tDetails\tDate\n" + q="logLevel:ERROR" + if [[ -n $terminology ]]; then + q="$q AND terminology:$terminology" + fi + query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' + ;; + warning) + printf "Terminology\tVersion\tProcess\tDetails\tDate\n" + q="logLevel:WARN" + if [[ -n $terminology ]]; then + q="$q AND terminology:$terminology" + fi + query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' + ;; + *) + echo "ERROR: Unknown report type: $report_type" + print_help + ;; +esac diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index 45339614c..23a5b6fda 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -433,6 +433,12 @@ load_mapping2 # Cleanup /bin/rm -f /tmp/x.$$.txt $dir/x.{sh,txt} +# Report audit data +echo " Audit report ...$(/bin/date)" +# send audit report to csv with date +./audit.sh load --noconfig > "devreset_terminology_load_audit_$(date +%Y%m%d_%H%M%S).csv" + + echo "" echo "--------------------------------------------------" echo "Finished ...`/bin/date`" From a05d75c215110cd10c430c48ff17605709c952b8 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 28 Jan 2026 15:59:05 -0800 Subject: [PATCH 42/64] all type report + output to csv/tsv --- .gitignore | 1 + src/main/bin/audit.sh | 62 ++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index b49ac2df0..44f7caa08 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ report.txt log .DS_Store src/main/bin/NCIT_HISTORY/ +src/main/bin/audit_reports/ report.html gradle.lockfile /.apt_generated/ diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh index 0901212cf..202437351 100644 --- a/src/main/bin/audit.sh +++ b/src/main/bin/audit.sh @@ -6,6 +6,8 @@ config=1 help=0 arr=() +output_fmt="tsv" +output_to_file=0 while [[ "$#" -gt 0 ]]; do case $1 in @@ -14,16 +16,26 @@ while [[ "$#" -gt 0 ]]; do config=0 ncflag="--noconfig" ;; + --tsv) + output_to_file=1 + output_fmt="tsv" + ;; + --csv) + output_to_file=1 + output_fmt="csv" + ;; *) arr+=("$1") ;; esac shift done print_help(){ - echo "Usage: $0 [--noconfig] [--help] [terminology]" + echo "Usage: $0 [--noconfig] [--help] [--tsv|--csv] [terminology]" echo " e.g. $0 load" + echo " e.g. $0 --csv load" echo " e.g. $0 error ncit" echo " e.g. $0 warning" + echo " e.g. $0 all" exit 1 } @@ -76,33 +88,69 @@ query_es() { curl -s -G "$ES/evs_audit/_search" --data-urlencode "size=1000" --data-urlencode "q=$q" } +# Output handling +if [[ $output_to_file -eq 1 ]]; then + mkdir -p audit_reports + timestamp=$(date +"%Y%m%d_%H%M%S") + output_file="audit_reports/${report_type}_${timestamp}.${output_fmt}" + exec > "$output_file" + # Note: We use tsv internally for jq then convert to csv if needed +fi + case $report_type in load) - printf "Terminology\tVersion\tElapsed Time (ms)\tCount\tDate\n" + header="Terminology\tVersion\tElapsed Time (ms)\tCount\tDate" q="process:(MetaOpensearchLoadServiceImpl OR MetaSourceOpensearchLoadServiceImpl OR LoaderServiceImpl) AND NOT elapsedTime:0" if [[ -n $terminology ]]; then q="$q AND terminology:$terminology" fi - query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.elapsedTime, ._source.count, (._source.date // ._source.startDate)] | @tsv' + data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.elapsedTime, ._source.count, (._source.date // ._source.startDate)] | @tsv') ;; error) - printf "Terminology\tVersion\tProcess\tDetails\tDate\n" + header="Terminology\tVersion\tProcess\tDetails\tDate" q="logLevel:ERROR" if [[ -n $terminology ]]; then q="$q AND terminology:$terminology" fi - query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' + data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv') ;; warning) - printf "Terminology\tVersion\tProcess\tDetails\tDate\n" + header="Terminology\tVersion\tProcess\tDetails\tDate" q="logLevel:WARN" if [[ -n $terminology ]]; then q="$q AND terminology:$terminology" fi - query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' + data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv') + ;; + all) + header="Type\tTerminology\tVersion\tProcess\tLogLevel\tDetails\tCount\tElapsed\tDate" + q="*:*" + if [[ -n $terminology ]]; then + q="$q AND terminology:$terminology" + fi + data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.type, ._source.terminology, ._source.version, ._source.process, ._source.logLevel, ._source.details, ._source.count, ._source.elapsedTime, (._source.date // ._source.startDate)] | @tsv') ;; *) echo "ERROR: Unknown report type: $report_type" print_help ;; esac + +# Final output with format conversion if needed +if [[ -n "$data" ]]; then + if [[ "$output_fmt" == "csv" ]]; then + echo -e "$header" | sed 's/\t/,/g' + echo -e "$data" | sed 's/\t/,/g' + else + echo -e "$header" + echo -e "$data" + fi +else + echo "No records found for report: $report_type" +fi + +if [[ $output_to_file -eq 1 ]]; then + # Close file and notify on stderr so it shows in console + exec >&2 + echo "Report generated: $output_file" +fi From 4f46ba67fef404344abf6d2e4b0b1a97ca83bdfb Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 3 Feb 2026 14:11:01 -0800 Subject: [PATCH 43/64] standardize UnitTestData folders/filenames --- src/main/bin/devreset.sh | 73 +++++++++++++++++++++++++++++++++------- 1 file changed, 61 insertions(+), 12 deletions(-) diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index 45339614c..d42061bcc 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -151,10 +151,24 @@ if [[ ! -e "$dir/OBIB/obib_2021-11.owl" ]]; then exit 1 fi +# Check CanMED +echo " check CanMED" +if [[ ! -e "$dir/CanMED/CANMED.202506.owl" ]]; then + echo "ERROR: unexpectedly missing CanMED/CANMED.202506.owl file" + exit 1 +fi + +# Check MEDRT +echo " check MEDRT" +if [[ ! -e "$dir/MEDRT/MEDRT.20250602.owl" ]]; then + echo "ERROR: unexpectedly missing MEDRT/MEDRT.20250602.owl file" + exit 1 +fi + # Check NDFRT echo " check NDFRT" -if [[ ! -e "$dir/NDFRT/NDFRT_Public_2018.02.05_Inferred.owl" ]]; then - echo "ERROR: unexpectedly missing NDFRT/NDFRT_Public_2018.02.05_Inferred.owl file" +if [[ ! -e "$dir/NDFRT/NDFRT.20180205.owl" ]]; then + echo "ERROR: unexpectedly missing NDFRT/NDFRT.20180205.owl file" exit 1 fi @@ -165,6 +179,41 @@ if [[ ! -e "$dir/CTCAE/ctcae6.owl" ]]; then exit 1 fi +# Check CTCAE5 +echo " check CTCAE5" +if [[ ! -e "$dir/CTCAE/ctcae5.owl" ]]; then + echo "ERROR: unexpectedly missing CTCAE/ctcae5.owl file" + exit 1 +fi + +# Check MGED +echo " check MGED" +if [[ ! -e "$dir/MGED/MGED.20070209.owl" ]]; then + echo "ERROR: unexpectedly missing MGED/MGED.20070209.owl file" + exit 1 +fi + +# Check NPO +echo " check NPO" +if [[ ! -e "$dir/NPO/NPO.20111208.owl" ]]; then + echo "ERROR: unexpectedly missing NPO/NPO.20111208.owl file" + exit 1 +fi + +# Check MA +echo " check MA" +if [[ ! -e "$dir/MA/MA.20160727.owl" ]]; then + echo "ERROR: unexpectedly missing MA/MA.20160727.owl file" + exit 1 +fi + +# Check Zebrafish +echo " check Zebrafish" +if [[ ! -e "$dir/Zebrafish/ZFA.20190802.owl" ]]; then + echo "ERROR: unexpectedly missing Zebrafish/ZFA.20190802.owl file" + exit 1 +fi + # check status check_status() { local retval=$1 @@ -351,18 +400,18 @@ load_data(){ load_terminology_data NCIT2 http://ChEBI_old ChEBI/chebi_241.owl load_terminology_data NCIT2 http://UmlsSemNet UmlsSemNet/umlssemnet.owl load_terminology_data NCIT2 http://Canmed CanMed/CANMED.202506.owl - load_terminology_data NCIT2 http://MEDRT MED-RT/MEDRT.2025-06-02.owl + load_terminology_data NCIT2 http://MEDRT MED-RT/MEDRT.20250602.owl load_terminology_data NCIT2 http://CTCAE CTCAE/ctcae5.owl load_terminology_data NCIT2 http://CTCAE6 CTCAE/ctcae6.owl - load_terminology_data NCIT2 http://DUO_monthly DUO/duo_Feb21.owl - load_terminology_data NCIT2 http://DUO_monthly DUO/iao_Dec20.owl - load_terminology_data NCIT2 http://OBI_monthly OBI/obi_2022_07.owl - load_terminology_data NCIT2 http://OBIB OBIB/obib_2021-11.owl - load_terminology_data NCIT2 http://NDFRT2 NDFRT/NDFRT_Public_2018.02.05_Inferred.owl - load_terminology_data NCIT2 http://MGED MGED/MGEDOntology.fix.owl - load_terminology_data NCIT2 http://NPO NPO/npo-2011-12-08_inferred.owl - load_terminology_data NCIT2 http://MA Mouse_Anatomy/ma_07_27_2016.owl - load_terminology_data NCIT2 http://Zebrafish Zebrafish/zfa_2019_08_02.owl + load_terminology_data NCIT2 http://DUO_monthly DUO/DUO.202102.owl + load_terminology_data NCIT2 http://DUO_monthly DUO/IAO.202012.owl + load_terminology_data NCIT2 http://OBI_monthly OBI/OBI.202207.owl + load_terminology_data NCIT2 http://OBIB OBIB/OBIB.202111.owl + load_terminology_data NCIT2 http://NDFRT2 NDFRT/NDFRT.20180205.owl + load_terminology_data NCIT2 http://MGED MGED/MGED.20070209.owl + load_terminology_data NCIT2 http://NPO NPO/NPO.20111208.owl + load_terminology_data NCIT2 http://MA Mouse_Anatomy/MA.20160727.owl + load_terminology_data NCIT2 http://Zebrafish Zebrafish/ZFA.20190802.owl } # Run reindex script but in a way to avoid loading mappings until terminologies are loaded From 7a0c7b4c9d11f008f2fe3a182e48d1d94cb09f1f Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 3 Feb 2026 17:32:52 -0800 Subject: [PATCH 44/64] forgot to change a couple of things --- src/main/bin/devreset.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index d42061bcc..50f3499c8 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -132,22 +132,22 @@ fi # Check DUO echo " check DUO" -if [[ ! -e "$dir/DUO/duo_Feb21.owl" ]]; then - echo "ERROR: unexpectedly missing DUO/duo_Feb21.owl file" +if [[ ! -e "$dir/DUO/DUO.202102.owl" ]]; then + echo "ERROR: unexpectedly missing DUO/DUO.202102.owl file" exit 1 fi # Check OBI echo " check OBI" -if [[ ! -e "$dir/OBI/obi_2022_07.owl" ]]; then - echo "ERROR: unexpectedly missing OBI/obi_2022_07.owl file" +if [[ ! -e "$dir/OBI/OBI.202207.owl" ]]; then + echo "ERROR: unexpectedly missing OBI/OBI.202207.owl file" exit 1 fi # Check OBIB echo " check OBIB" -if [[ ! -e "$dir/OBIB/obib_2021-11.owl" ]]; then - echo "ERROR: unexpectedly missing OBI/obib_2021-11.owl file" +if [[ ! -e "$dir/OBIB/OBIB.202111.owl" ]]; then + echo "ERROR: unexpectedly missing OBI/OBIB.202111.owl file" exit 1 fi From 47406394b75497130893d3e6d53b4a9e3efbedce Mon Sep 17 00:00:00 2001 From: peter-va Date: Tue, 3 Feb 2026 17:41:29 -0800 Subject: [PATCH 45/64] patch filepaths again --- src/main/bin/devreset.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/bin/devreset.sh b/src/main/bin/devreset.sh index 50f3499c8..066e86435 100755 --- a/src/main/bin/devreset.sh +++ b/src/main/bin/devreset.sh @@ -153,15 +153,15 @@ fi # Check CanMED echo " check CanMED" -if [[ ! -e "$dir/CanMED/CANMED.202506.owl" ]]; then - echo "ERROR: unexpectedly missing CanMED/CANMED.202506.owl file" +if [[ ! -e "$dir/CanMed/CANMED.202506.owl" ]]; then + echo "ERROR: unexpectedly missing CanMed/CANMED.202506.owl file" exit 1 fi # Check MEDRT echo " check MEDRT" -if [[ ! -e "$dir/MEDRT/MEDRT.20250602.owl" ]]; then - echo "ERROR: unexpectedly missing MEDRT/MEDRT.20250602.owl file" +if [[ ! -e "$dir/MED-RT/MEDRT.20250602.owl" ]]; then + echo "ERROR: unexpectedly missing MED-RT/MEDRT.20250602.owl file" exit 1 fi @@ -201,9 +201,9 @@ if [[ ! -e "$dir/NPO/NPO.20111208.owl" ]]; then fi # Check MA -echo " check MA" -if [[ ! -e "$dir/MA/MA.20160727.owl" ]]; then - echo "ERROR: unexpectedly missing MA/MA.20160727.owl file" +echo " check Mouse_Anatomy" +if [[ ! -e "$dir/Mouse_Anatomy/MA.20160727.owl" ]]; then + echo "ERROR: unexpectedly missing Mouse_Anatomy/MA.20160727.owl file" exit 1 fi From 21ba50c9dc1816ec9fa36ec3da6033eb84c339d5 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 9 Feb 2026 13:12:38 -0800 Subject: [PATCH 46/64] update output for readability --- src/main/bin/audit.sh | 57 ++++++++++++++++++++++++++++--------------- 1 file changed, 37 insertions(+), 20 deletions(-) diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh index 202437351..c3c0a3adf 100644 --- a/src/main/bin/audit.sh +++ b/src/main/bin/audit.sh @@ -24,16 +24,20 @@ while [[ "$#" -gt 0 ]]; do output_to_file=1 output_fmt="csv" ;; + --recent) + recent=1 + ;; *) arr+=("$1") ;; esac shift done print_help(){ - echo "Usage: $0 [--noconfig] [--help] [--tsv|--csv] [terminology]" + echo "Usage: $0 [--noconfig] [--help] [--tsv|--csv] [--recent] [terminology]" echo " e.g. $0 load" echo " e.g. $0 --csv load" echo " e.g. $0 error ncit" + echo " e.g. $0 --recent error" echo " e.g. $0 warning" echo " e.g. $0 all" exit 1 @@ -99,42 +103,43 @@ fi case $report_type in load) - header="Terminology\tVersion\tElapsed Time (ms)\tCount\tDate" - q="process:(MetaOpensearchLoadServiceImpl OR MetaSourceOpensearchLoadServiceImpl OR LoaderServiceImpl) AND NOT elapsedTime:0" - if [[ -n $terminology ]]; then - q="$q AND terminology:$terminology" - fi - data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.elapsedTime, ._source.count, (._source.date // ._source.startDate)] | @tsv') + header="Terminology\tVersion\tElapsed Time\tCount\tDate" + q="process:(MetaOpensearchLoadServiceImpl OR MetaSourceOpensearchLoadServiceImpl OR LoaderServiceImpl OR GraphOpensearchLoadServiceImpl) AND NOT elapsedTime:0" + filter='def f: . as $ms | if $ms < 1000 then ($ms|tostring)+"ms" else ($ms/1000|floor) as $s | ($s/3600|floor) as $h | (($s%3600)/60|floor) as $m | ($s%60) as $sec | (if $h>0 then ($h|tostring)+"h " else "" end) + (if $m>0 or $h>0 then ($m|tostring)+"m " else "" end) + ($sec|tostring)+"s" end; .hits.hits[] | [._source.terminology, ._source.version, (._source.elapsedTime | f), ._source.count, (._source.date // ._source.startDate)] | @tsv' ;; error) header="Terminology\tVersion\tProcess\tDetails\tDate" q="logLevel:ERROR" - if [[ -n $terminology ]]; then - q="$q AND terminology:$terminology" - fi - data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv') + filter='.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' ;; warning) header="Terminology\tVersion\tProcess\tDetails\tDate" q="logLevel:WARN" - if [[ -n $terminology ]]; then - q="$q AND terminology:$terminology" - fi - data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv') + filter='.hits.hits[] | [._source.terminology, ._source.version, ._source.process, ._source.details, ._source.date] | @tsv' ;; all) header="Type\tTerminology\tVersion\tProcess\tLogLevel\tDetails\tCount\tElapsed\tDate" q="*:*" - if [[ -n $terminology ]]; then - q="$q AND terminology:$terminology" - fi - data=$(query_es "$q" | jq -r '.hits.hits[] | [._source.type, ._source.terminology, ._source.version, ._source.process, ._source.logLevel, ._source.details, ._source.count, ._source.elapsedTime, (._source.date // ._source.startDate)] | @tsv') + filter='def f: . as $ms | if $ms < 1000 then ($ms|tostring)+"ms" else ($ms/1000|floor) as $s | ($s/3600|floor) as $h | (($s%3600)/60|floor) as $m | ($s%60) as $sec | (if $h>0 then ($h|tostring)+"h " else "" end) + (if $m>0 or $h>0 then ($m|tostring)+"m " else "" end) + ($sec|tostring)+"s" end; .hits.hits[] | [._source.type, ._source.terminology, ._source.version, ._source.process, ._source.logLevel, ._source.details, ._source.count, (._source.elapsedTime | f), (._source.date // ._source.startDate)] | @tsv' ;; *) echo "ERROR: Unknown report type: $report_type" print_help ;; esac +if [[ -n $terminology ]]; then + q="$q AND terminology:$terminology" +fi + + +# recent flag restricts only to audits that happened in the last 24 hours +if [[ $recent -eq 1 ]]; then + start_date=$(date -d '24 hours ago' +%Y-%m-%dT%H:%M:%SZ) + end_date=$(date +%Y-%m-%dT%H:%M:%SZ) + q="$q AND (date:[$start_date TO $end_date] OR startDate:[$start_date TO $end_date])" +fi + +data=$(query_es "$q" | jq -r "$filter") # Final output with format conversion if needed if [[ -n "$data" ]]; then @@ -146,7 +151,19 @@ if [[ -n "$data" ]]; then echo -e "$data" fi else - echo "No records found for report: $report_type" + if [[ -n $terminology ]]; then + if [[ $recent -eq 1 ]]; then + echo "No records found for report: $report_type for terminology: $terminology (last 24 hours)" + else + echo "No records found for report: $report_type for terminology: $terminology" + fi + else + if [[ $recent -eq 1 ]]; then + echo "No records found for report: $report_type (last 24 hours)" + else + echo "No records found for report: $report_type" + fi + fi fi if [[ $output_to_file -eq 1 ]]; then From 56bbf85b5968147ac53b1e67f95ebb684cdc0655 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 9 Feb 2026 13:55:29 -0800 Subject: [PATCH 47/64] compress no records warning logic --- src/main/bin/audit.sh | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh index c3c0a3adf..4d8143e49 100644 --- a/src/main/bin/audit.sh +++ b/src/main/bin/audit.sh @@ -151,19 +151,7 @@ if [[ -n "$data" ]]; then echo -e "$data" fi else - if [[ -n $terminology ]]; then - if [[ $recent -eq 1 ]]; then - echo "No records found for report: $report_type for terminology: $terminology (last 24 hours)" - else - echo "No records found for report: $report_type for terminology: $terminology" - fi - else - if [[ $recent -eq 1 ]]; then - echo "No records found for report: $report_type (last 24 hours)" - else - echo "No records found for report: $report_type" - fi - fi + echo "No records found for report: $report_type${terminology:+ for terminology: $terminology}${recent:+ (last 24 hours)}" fi if [[ $output_to_file -eq 1 ]]; then From 63cf1c7422c4a9e0ffdb2737a1fa396a69aea485 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 9 Feb 2026 17:35:53 -0800 Subject: [PATCH 48/64] exit with error message on failed ES call --- src/main/bin/audit.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh index 4d8143e49..c5cd944c8 100644 --- a/src/main/bin/audit.sh +++ b/src/main/bin/audit.sh @@ -89,9 +89,14 @@ validate_setup query_es() { local q=$1 - curl -s -G "$ES/evs_audit/_search" --data-urlencode "size=1000" --data-urlencode "q=$q" + # Use -f to fail on HTTP errors and -S to show error on stderr + if ! curl -s -S -f -G "$ES/evs_audit/_search" --data-urlencode "size=1000" --data-urlencode "q=$q"; then + echo "ERROR: Elasticsearch query failed." >&2 + exit 1 + fi } + # Output handling if [[ $output_to_file -eq 1 ]]; then mkdir -p audit_reports From 37ff955e4b49c92c7e93ef1b26623e65c82595cd Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 9 Feb 2026 20:32:54 -0800 Subject: [PATCH 49/64] extend options and make help command better --- src/main/bin/audit.sh | 52 +++++++++++++++++++++++++++++++------------ 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/src/main/bin/audit.sh b/src/main/bin/audit.sh index c5cd944c8..4d96aa83b 100644 --- a/src/main/bin/audit.sh +++ b/src/main/bin/audit.sh @@ -11,35 +11,57 @@ output_to_file=0 while [[ "$#" -gt 0 ]]; do case $1 in - --help) help=1 ;; - --noconfig) + -h | --help) help=1 ;; + -n | --noconfig) config=0 ncflag="--noconfig" ;; - --tsv) + -v | --tsv) output_to_file=1 output_fmt="tsv" ;; - --csv) + -c | --csv) output_to_file=1 output_fmt="csv" ;; - --recent) + -r | --recent) recent=1 ;; + -T | --terminology) + shift + terminology=$1 + ;; *) arr+=("$1") ;; esac shift done -print_help(){ - echo "Usage: $0 [--noconfig] [--help] [--tsv|--csv] [--recent] [terminology]" - echo " e.g. $0 load" - echo " e.g. $0 --csv load" - echo " e.g. $0 error ncit" - echo " e.g. $0 --recent error" - echo " e.g. $0 warning" - echo " e.g. $0 all" +print_help() { + echo "Audit Script - Query Elasticsearch for audit data" + echo "" + echo "Usage: $0 [options] [terminology]" + echo "" + echo "Report Types (Required):" + echo " load Terminology loading and indexing metrics" + echo " error Audit records with ERROR log level" + echo " warning Audit records with WARN log level" + echo " all All audit records" + echo "" + echo "Options:" + echo " -h, --help Show this help message" + echo " -r, --recent Limit results to the last 24 hours" + echo " -n, --noconfig Skip sourcing /local/content/evsrestapi/config/setenv.sh" + echo " -T, --terminology Filter by terminology (can also be 2nd positional argument)" + echo "" + echo "Output Control (Default is console):" + echo " -c, --csv Generate a CSV file in audit_reports/" + echo " -v, --tsv Generate a TSV file in audit_reports/" + echo "" + echo "Examples:" + echo " $0 load # Load report to console" + echo " $0 --csv load ncit # CSV report for NCIt" + echo " $0 -r -c all # Recent records for all types in CSV" + echo " $0 all -T medrt # Use explicit flag for terminology" exit 1 } @@ -48,7 +70,9 @@ if [[ $help -eq 1 || ${#arr[@]} -eq 0 ]]; then fi report_type=${arr[0]} -terminology=${arr[1]} +# Use positional terminology ONLY if not already set by -T flag +terminology=${terminology:-${arr[1]}} + setup_configuration() { if [[ $config -eq 1 ]]; then From f9e5be36c6d58a4e2481b3b1c4d98b41b81432fd Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 18 Feb 2026 14:41:03 -0800 Subject: [PATCH 50/64] partial word searches boost --- .../api/service/OpenSearchServiceImpl.java | 71 ++++++------ .../api/controller/MapsetControllerTests.java | 1 + .../api/controller/SearchControllerTests.java | 107 ++++++++++++++++++ 3 files changed, 145 insertions(+), 34 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index 168841731..a6f92f120 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -430,13 +430,10 @@ private BoolQueryBuilder getContainsQuery( // Partial word match queries - boost higher than phrase but lower than exact // Only apply for "contains" type queries, not for "phrase" queries - QueryStringQueryBuilder partialWordNameQuery = null; - QueryStringQueryBuilder partialWordSynonymQuery = null; + BoolQueryBuilder partialWordNameQuery = null; + BoolQueryBuilder partialWordSynonymQuery = null; NestedQueryBuilder nestedPartialWordSynonymQuery = null; - // This is a very targeted approach to a particular set of cases - // but does achieve support for searches like "rectal car" - // build partial word query if we have partial/short words if ("contains".equalsIgnoreCase(type)) { String[] tokens = normTerm.split("\\s+"); @@ -445,10 +442,7 @@ private BoolQueryBuilder getContainsQuery( for (int i = 0; i < tokens.length; i++) { String token = tokens[i]; - boolean isPartialWord = - (token.length() >= 2 && token.length() <= 4) - || (i == tokens.length - 1 && token.length() >= 2 && token.length() <= 5); - + boolean isPartialWord = token.length() >= 1 && token.length() <= 6; if (isPartialWord) { partialTokens[i] = token + "*"; hasPartialWord = true; @@ -459,19 +453,36 @@ private BoolQueryBuilder getContainsQuery( // Only create partial word queries if we actually have partial words if (hasPartialWord) { - partialWordNameQuery = - QueryBuilders.queryStringQuery(String.join(" AND ", partialTokens)) - .field("name") - .defaultOperator(Operator.AND) - .analyzeWildcard(true) - .boost(20f); - - partialWordSynonymQuery = - QueryBuilders.queryStringQuery(String.join(" AND ", partialTokens)) - .field("synonyms.name") - .defaultOperator(Operator.AND) - .analyzeWildcard(true) - .boost(19f); + // Build a manual BoolQuery with WildcardQuery clauses for reliability. + // This ensures that ALL tokens must match at least a part of the 'name' field. + BoolQueryBuilder nameBool = QueryBuilders.boolQuery(); + BoolQueryBuilder synonymBool = QueryBuilders.boolQuery(); + + // Regex for "Exact Token Count" match to prioritize terms with no extra words. + StringBuilder regex = new StringBuilder(); + + for (int i = 0; i < tokens.length; i++) { + String token = tokens[i]; + boolean isPartial = token.length() >= 1 && token.length() <= 6; + String pToken = isPartial ? token + "*" : token; + + nameBool.must(QueryBuilders.wildcardQuery("name", pToken)); + synonymBool.must(QueryBuilders.wildcardQuery("synonyms.name", pToken)); + + if (i > 0) { + regex.append(" "); + } + regex.append(token).append("[a-z0-9]*"); + } + + // Exact token count tie-breaker (e.g. ^rect[a-z0-9]* car[a-z0-9]*$) + // Lucene Regex is anchored at both ends by default. + nameBool.should(QueryBuilders.regexpQuery("normName", regex.toString()).boost(100.0f)); + synonymBool.should( + QueryBuilders.regexpQuery("synonyms.normName", regex.toString()).boost(100.0f)); + + partialWordNameQuery = nameBool.boost(100.0f); + partialWordSynonymQuery = synonymBool.boost(50.0f); nestedPartialWordSynonymQuery = QueryBuilders.nestedQuery("synonyms", partialWordSynonymQuery, ScoreMode.Max); } @@ -550,12 +561,8 @@ private BoolQueryBuilder getContainsQuery( synonymFixNormNameQuery.fuzziness(Fuzziness.ONE); synonymStemNameQuery.fuzziness(Fuzziness.ONE); definitionQuery.fuzziness(Fuzziness.ONE); - if (partialWordNameQuery != null) { - partialWordNameQuery.fuzziness(Fuzziness.ONE); - } - if (partialWordSynonymQuery != null) { - partialWordSynonymQuery.fuzziness(Fuzziness.ONE); - } + // Note: partialWordNameQuery/partialWordSynonymQuery use wildcard queries - no fuzziness + // needed } else { fixNameQuery.fuzziness(Fuzziness.ZERO); fixNormNameQuery.fuzziness(Fuzziness.ZERO); @@ -564,12 +571,8 @@ private BoolQueryBuilder getContainsQuery( synonymFixNormNameQuery.fuzziness(Fuzziness.ZERO); synonymStemNameQuery.fuzziness(Fuzziness.ZERO); definitionQuery.fuzziness(Fuzziness.ZERO); - if (partialWordNameQuery != null) { - partialWordNameQuery.fuzziness(Fuzziness.ZERO); - } - if (partialWordSynonymQuery != null) { - partialWordSynonymQuery.fuzziness(Fuzziness.ZERO); - } + // Note: partialWordNameQuery/partialWordSynonymQuery use wildcard queries - no fuzziness + // needed } // -- wildcard search is assumed to be a term search or phrase search diff --git a/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java index a78c5f38f..707ad941d 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/MapsetControllerTests.java @@ -10,6 +10,7 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.dnault.xmlpatch.internal.Log; import gov.nih.nci.evs.api.model.Concept; import gov.nih.nci.evs.api.model.Mapping; diff --git a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java index 6d31371e6..5a58f2f73 100644 --- a/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java +++ b/src/test/java/gov/nih/nci/evs/api/controller/SearchControllerTests.java @@ -4704,6 +4704,113 @@ public void testSearchMultiplePartialWordMatch() throws Exception { } } + /** + * Test search for partial word matching with extended cases: partial first word ("rect car"), + * full first word with partial second ("rectal car" ranked first), and partial second+third words + * ("single agen ther"). + */ + @Test + public void testSearchPartialWordMatchExtended() throws Exception { + + // Test Case 1: "recta car" - partial FIRST word, should rank "Rectal Carcinoma" first + { + String term = "recta car"; + log.info("Testing partial first word match for term - " + term); + + MvcResult result = + this.mvc + .perform( + get(baseUrl) + .param("terminology", "ncit") + .param("include", "summary") + .param("term", term) + .param("type", "contains")) + .andExpect(status().isOk()) + .andReturn(); + String content = result.getResponse().getContentAsString(); + assertThat(content).isNotNull(); + + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); + assertThat(list.getConcepts()).isNotNull(); + assertThat(list.getConcepts()).isNotEmpty(); + + log.info("Top 10 results for '" + term + "':"); + for (int i = 0; i < Math.min(10, list.getConcepts().size()); i++) { + Concept concept = list.getConcepts().get(i); + log.info(" " + (i + 1) + ". " + concept.getName() + " (" + concept.getCode() + ")"); + } + + assertThat(list.getConcepts().get(0).getName()) + .as("'Rectal Carcinoma' should be ranked first for term: " + term) + .isEqualTo("Rectal Carcinoma"); + } + // Test Case 2: "rectal car" - full first word, partial second word, should rank first + { + String term = "rectal car"; + log.info("Testing full+partial word match for term - " + term); + + MvcResult result = + this.mvc + .perform( + get(baseUrl) + .param("terminology", "ncit") + .param("include", "summary") + .param("term", term) + .param("type", "contains")) + .andExpect(status().isOk()) + .andReturn(); + String content = result.getResponse().getContentAsString(); + assertThat(content).isNotNull(); + + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); + assertThat(list.getConcepts()).isNotNull(); + assertThat(list.getConcepts()).isNotEmpty(); + + log.info("Top 5 results for '" + term + "':"); + for (int i = 0; i < Math.min(5, list.getConcepts().size()); i++) { + Concept concept = list.getConcepts().get(i); + log.info(" " + (i + 1) + ". " + concept.getName() + " (" + concept.getCode() + ")"); + } + + assertThat(list.getConcepts().get(0).getName()) + .as("'Rectal Carcinoma' should be ranked first (position 0) for term: " + term) + .isEqualTo("Rectal Carcinoma"); + } + + // Test Case 3: "single agen ther" - partial second AND third words + { + String term = "single agen ther"; + log.info("Testing partial second+third word match for term - " + term); + + MvcResult result = + this.mvc + .perform( + get(baseUrl) + .param("terminology", "ncit") + .param("include", "summary") + .param("term", term) + .param("type", "contains")) + .andExpect(status().isOk()) + .andReturn(); + String content = result.getResponse().getContentAsString(); + assertThat(content).isNotNull(); + + ConceptResultList list = ThreadLocalMapper.get().readValue(content, ConceptResultList.class); + assertThat(list.getConcepts()).isNotNull(); + assertThat(list.getConcepts()).isNotEmpty(); + + log.info("Top 5 results for '" + term + "':"); + for (int i = 0; i < Math.min(5, list.getConcepts().size()); i++) { + Concept concept = list.getConcepts().get(i); + log.info(" " + (i + 1) + ". " + concept.getName() + " (" + concept.getCode() + ")"); + } + + assertThat(list.getConcepts().get(0).getName()) + .as("'Single Agent Therapy' should be ranked first for term: " + term) + .isEqualTo("Single Agent Therapy"); + } + } + /** * Removes the time taken. * From b96ccff9201a93be37a1d3fb2059fc200c2f8574 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 18 Feb 2026 14:46:47 -0800 Subject: [PATCH 51/64] cleanup --- .../api/service/OpenSearchServiceImpl.java | 47 +++++++------------ 1 file changed, 16 insertions(+), 31 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index a6f92f120..b3a8ee820 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -436,47 +436,32 @@ private BoolQueryBuilder getContainsQuery( // build partial word query if we have partial/short words if ("contains".equalsIgnoreCase(type)) { - String[] tokens = normTerm.split("\\s+"); + final String[] tokens = normTerm.split("\\s+"); + final BoolQueryBuilder nameBool = QueryBuilders.boolQuery(); + final BoolQueryBuilder synonymBool = QueryBuilders.boolQuery(); + final StringBuilder regex = new StringBuilder(); boolean hasPartialWord = false; - String[] partialTokens = new String[tokens.length]; for (int i = 0; i < tokens.length; i++) { - String token = tokens[i]; - boolean isPartialWord = token.length() >= 1 && token.length() <= 6; - if (isPartialWord) { - partialTokens[i] = token + "*"; + final String token = tokens[i]; + final boolean isPartial = token.length() >= 1 && token.length() <= 6; + final String pToken = isPartial ? token + "*" : token; + if (isPartial) { hasPartialWord = true; - } else { - partialTokens[i] = token; } + + nameBool.must(QueryBuilders.wildcardQuery("name", pToken)); + synonymBool.must(QueryBuilders.wildcardQuery("synonyms.name", pToken)); + + if (i > 0) { + regex.append(" "); + } + regex.append(token).append("[a-z0-9]*"); } // Only create partial word queries if we actually have partial words if (hasPartialWord) { - // Build a manual BoolQuery with WildcardQuery clauses for reliability. - // This ensures that ALL tokens must match at least a part of the 'name' field. - BoolQueryBuilder nameBool = QueryBuilders.boolQuery(); - BoolQueryBuilder synonymBool = QueryBuilders.boolQuery(); - - // Regex for "Exact Token Count" match to prioritize terms with no extra words. - StringBuilder regex = new StringBuilder(); - - for (int i = 0; i < tokens.length; i++) { - String token = tokens[i]; - boolean isPartial = token.length() >= 1 && token.length() <= 6; - String pToken = isPartial ? token + "*" : token; - - nameBool.must(QueryBuilders.wildcardQuery("name", pToken)); - synonymBool.must(QueryBuilders.wildcardQuery("synonyms.name", pToken)); - - if (i > 0) { - regex.append(" "); - } - regex.append(token).append("[a-z0-9]*"); - } - // Exact token count tie-breaker (e.g. ^rect[a-z0-9]* car[a-z0-9]*$) - // Lucene Regex is anchored at both ends by default. nameBool.should(QueryBuilders.regexpQuery("normName", regex.toString()).boost(100.0f)); synonymBool.should( QueryBuilders.regexpQuery("synonyms.normName", regex.toString()).boost(100.0f)); From 618911566c51683c259087d18570fdecb93e8369 Mon Sep 17 00:00:00 2001 From: peter-va Date: Wed, 18 Feb 2026 17:07:46 -0800 Subject: [PATCH 52/64] regex tweaks --- .../gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index b3a8ee820..8148f9f8e 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -456,15 +456,15 @@ private BoolQueryBuilder getContainsQuery( if (i > 0) { regex.append(" "); } - regex.append(token).append("[a-z0-9]*"); + regex.append(token).append("[^ ]*"); } // Only create partial word queries if we actually have partial words if (hasPartialWord) { - // Exact token count tie-breaker (e.g. ^rect[a-z0-9]* car[a-z0-9]*$) + // Exact token count tie-breaker (e.g. ^rect[^ ]* car[^ ]*$) nameBool.should(QueryBuilders.regexpQuery("normName", regex.toString()).boost(100.0f)); synonymBool.should( - QueryBuilders.regexpQuery("synonyms.normName", regex.toString()).boost(100.0f)); + QueryBuilders.regexpQuery("synonyms.normName", regex.toString()).boost(50.0f)); partialWordNameQuery = nameBool.boost(100.0f); partialWordSynonymQuery = synonymBool.boost(50.0f); From 4ca70a1c1af525e1c64c2e8196a3a0fd84af84a4 Mon Sep 17 00:00:00 2001 From: peter-va Date: Thu, 19 Feb 2026 11:48:19 -0800 Subject: [PATCH 53/64] consolidate code --- .../api/service/OpenSearchServiceImpl.java | 56 ++++++++----------- 1 file changed, 24 insertions(+), 32 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index 8148f9f8e..b3d17745a 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -420,8 +420,7 @@ private BoolQueryBuilder getContainsQuery( // exactTerm).boost(50f); // Exact match queries - final MatchQueryBuilder normNameQuery = - QueryBuilders.matchQuery("normName", normTerm).boost(40f); + final MatchQueryBuilder normNameQuery = QueryBuilders.matchQuery("normName", normTerm).boost(40f); final NestedQueryBuilder nestedSynonymNormNameQuery = QueryBuilders.nestedQuery( "synonyms", @@ -431,55 +430,51 @@ private BoolQueryBuilder getContainsQuery( // Partial word match queries - boost higher than phrase but lower than exact // Only apply for "contains" type queries, not for "phrase" queries BoolQueryBuilder partialWordNameQuery = null; - BoolQueryBuilder partialWordSynonymQuery = null; NestedQueryBuilder nestedPartialWordSynonymQuery = null; // build partial word query if we have partial/short words if ("contains".equalsIgnoreCase(type)) { final String[] tokens = normTerm.split("\\s+"); - final BoolQueryBuilder nameBool = QueryBuilders.boolQuery(); - final BoolQueryBuilder synonymBool = QueryBuilders.boolQuery(); final StringBuilder regex = new StringBuilder(); boolean hasPartialWord = false; for (int i = 0; i < tokens.length; i++) { - final String token = tokens[i]; - final boolean isPartial = token.length() >= 1 && token.length() <= 6; - final String pToken = isPartial ? token + "*" : token; - if (isPartial) { + if (tokens[i].length() >= 1 && tokens[i].length() <= 6) { hasPartialWord = true; } - - nameBool.must(QueryBuilders.wildcardQuery("name", pToken)); - synonymBool.must(QueryBuilders.wildcardQuery("synonyms.name", pToken)); - if (i > 0) { regex.append(" "); } - regex.append(token).append("[^ ]*"); + regex.append(tokens[i]).append("[^ ]*"); } // Only create partial word queries if we actually have partial words if (hasPartialWord) { - // Exact token count tie-breaker (e.g. ^rect[^ ]* car[^ ]*$) - nameBool.should(QueryBuilders.regexpQuery("normName", regex.toString()).boost(100.0f)); - synonymBool.should( - QueryBuilders.regexpQuery("synonyms.normName", regex.toString()).boost(50.0f)); - - partialWordNameQuery = nameBool.boost(100.0f); - partialWordSynonymQuery = synonymBool.boost(50.0f); + // Name partial word match (must match all tokens, boost exact token count) + partialWordNameQuery = + QueryBuilders.boolQuery() + .must( + QueryBuilders.queryStringQuery(fixNormTerm) + .field("name") + .defaultOperator(Operator.AND)) + .should(QueryBuilders.regexpQuery("normName", regex.toString())) + .boost(35.0f); + + // Synonym partial word match (must match all tokens in SAME synonym) nestedPartialWordSynonymQuery = - QueryBuilders.nestedQuery("synonyms", partialWordSynonymQuery, ScoreMode.Max); + QueryBuilders.nestedQuery( + "synonyms", + QueryBuilders.boolQuery() + .must( + QueryBuilders.queryStringQuery(fixNormTerm) + .field("synonyms.name") + .defaultOperator(Operator.AND)) + .should(QueryBuilders.regexpQuery("synonyms.normName", regex.toString())), + ScoreMode.Max); + nestedPartialWordSynonymQuery.boost(34.0f); } } - // Boost exact matches - final NestedQueryBuilder nestedSynonymExactQuery = - QueryBuilders.nestedQuery( - "synonyms", - QueryBuilders.matchQuery("synonyms.normName", normTerm).boost(40f), - ScoreMode.Max); - // Boosting matches with words next to each other final QueryStringQueryBuilder phraseNormNameQuery = QueryBuilders.queryStringQuery("\"" + term + "\"").field("name").boost(30f); @@ -616,9 +611,6 @@ private BoolQueryBuilder getContainsQuery( if (!"phrase".equals(type.toLowerCase())) { termQuery - // Exact query - .should(nestedSynonymExactQuery) - // Text queries on "name" and "norm name" and "stem name" using fix names .should(fixNameQuery) .should(fixNormNameQuery) From c5ecce50e872b381a63e3e9fa105e560a02d2c61 Mon Sep 17 00:00:00 2001 From: peter-va Date: Thu, 19 Feb 2026 11:49:54 -0800 Subject: [PATCH 54/64] spotless --- .../gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index b3d17745a..51bf71740 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -420,7 +420,8 @@ private BoolQueryBuilder getContainsQuery( // exactTerm).boost(50f); // Exact match queries - final MatchQueryBuilder normNameQuery = QueryBuilders.matchQuery("normName", normTerm).boost(40f); + final MatchQueryBuilder normNameQuery = + QueryBuilders.matchQuery("normName", normTerm).boost(40f); final NestedQueryBuilder nestedSynonymNormNameQuery = QueryBuilders.nestedQuery( "synonyms", From d0f433596641127879c717d30501718f829345fc Mon Sep 17 00:00:00 2001 From: peter-va Date: Thu, 19 Feb 2026 15:36:15 -0800 Subject: [PATCH 55/64] comments --- .../gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index 51bf71740..70fafccd3 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -542,8 +542,7 @@ private BoolQueryBuilder getContainsQuery( synonymFixNormNameQuery.fuzziness(Fuzziness.ONE); synonymStemNameQuery.fuzziness(Fuzziness.ONE); definitionQuery.fuzziness(Fuzziness.ONE); - // Note: partialWordNameQuery/partialWordSynonymQuery use wildcard queries - no fuzziness - // needed + // partials don't use fuzziness anymore } else { fixNameQuery.fuzziness(Fuzziness.ZERO); fixNormNameQuery.fuzziness(Fuzziness.ZERO); @@ -552,8 +551,7 @@ private BoolQueryBuilder getContainsQuery( synonymFixNormNameQuery.fuzziness(Fuzziness.ZERO); synonymStemNameQuery.fuzziness(Fuzziness.ZERO); definitionQuery.fuzziness(Fuzziness.ZERO); - // Note: partialWordNameQuery/partialWordSynonymQuery use wildcard queries - no fuzziness - // needed + // partials don't use fuzziness anymore } // -- wildcard search is assumed to be a term search or phrase search From 8421aa2fda411a43e3c13fef62e759a79220e9a7 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 2 Mar 2026 15:38:49 -0800 Subject: [PATCH 56/64] version changes in fhir --- .../evs/api/fhir/R4/CodeSystemProviderR4.java | 7 ++ .../evs/api/fhir/R4/ConceptMapProviderR4.java | 3 + .../evs/api/fhir/R4/ValueSetProviderR4.java | 2 + .../evs/api/fhir/R5/CodeSystemProviderR5.java | 9 ++ .../evs/api/fhir/R5/ConceptMapProviderR5.java | 3 + .../evs/api/fhir/R5/ValueSetProviderR5.java | 3 + .../nci/evs/api/util/TerminologyUtils.java | 42 ++++++++ .../api/fhir/FhirVersioningStrategyTests.java | 102 ++++++++++++++++++ 8 files changed, 171 insertions(+) create mode 100644 src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java index 509d56995..f1b8eb904 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java @@ -36,7 +36,9 @@ import java.util.Collections; import java.util.Comparator; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.CodeSystem; @@ -946,9 +948,11 @@ private List findPossibleCodeSystems( } final List terms = termUtils.getIndexedTerminologies(osQueryService); + final Map map = new HashMap<>(); final List list = new ArrayList<>(); for (final Terminology terminology : terms) { + map.put(terminology.getTerminology(), terminology); final CodeSystem cs = FhirUtilityR4.toR4(terminology); // Skip non-matching if ((id != null && !id.getIdPart().equals(cs.getId())) @@ -963,6 +967,9 @@ private List findPossibleCodeSystems( list.add(cs); } + + TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); + return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java index f798df3a8..66cdcf719 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java @@ -554,6 +554,9 @@ private List findPossibleConceptMaps( list.add(cm); } + + TerminologyUtils.sortVersionsDescending(list, a -> a.getVersion()); + return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java index d58bd7c26..2c44dfbd1 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java @@ -1698,6 +1698,8 @@ private List findPossibleValueSets( list.add(vs); } + TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); + return list; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java index 5d4d430a0..6993169e2 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java @@ -31,7 +31,9 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Optional; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.CodeSystem; @@ -999,6 +1001,10 @@ private List findPossibleCodeSystems( } final List terms = termUtils.getIndexedTerminologies(osQueryService); + final Map map = new HashMap<>(); + for (final Terminology terminology : terms) { + map.put(terminology.getTerminology(), terminology); + } final List list = new ArrayList<>(); // Find the matching code systems for (final Terminology terminology : terms) { @@ -1015,6 +1021,9 @@ private List findPossibleCodeSystems( } list.add(cs); } + + TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); + return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java index d772f070f..137622b7c 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java @@ -633,6 +633,9 @@ private List findPossibleConceptMaps( list.add(cm); } + + TerminologyUtils.sortVersionsDescending(list, a -> a.getVersion()); + return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java index 218691967..1263961c3 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java @@ -1315,6 +1315,9 @@ public List findPossibleValueSets( } list.add(vs); } + + TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); + return list; } diff --git a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java index 04e86898d..4623911cb 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import org.apache.commons.text.StringSubstitutor; import org.apache.http.HttpEntity; @@ -477,4 +478,45 @@ public void checkLicenseHttp( public static void clearCache() { licenseCache.clear(); } + + /** + * Sorts the given list of objects by determining the latest terminology based on the map. + * + * @param the type parameter + * @param list the list + * @param map the map of terminology name to Terminology object + * @param keyExtractor the function to extract the terminology name from the object + */ + public static void sortLatest( + List list, Map map, Function keyExtractor) { + list.sort( + (a, b) -> { + Terminology termA = map.get(keyExtractor.apply(a)); + Terminology termB = map.get(keyExtractor.apply(b)); + if (termA != null && termB != null) { + return Boolean.compare(termB.getLatest(), termA.getLatest()); + } + return 0; + }); + } + + /** + * Sorts the given list of objects with a version string by version descending. + * + * @param the type parameter + * @param list the list + * @param versionExtractor the function to extract the version string from the object + */ + public static void sortVersionsDescending( + List list, Function versionExtractor) { + list.sort( + (a, b) -> { + String versionA = versionExtractor.apply(a); + String versionB = versionExtractor.apply(b); + if (versionA != null && versionB != null) { + return versionB.compareTo(versionA); + } + return 0; + }); + } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java new file mode 100644 index 000000000..3afd2a475 --- /dev/null +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java @@ -0,0 +1,102 @@ +package gov.nih.nci.evs.api.fhir; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import gov.nih.nci.evs.api.properties.TestProperties; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.test.web.server.LocalServerPort; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +@ExtendWith(SpringExtension.class) +@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +public class FhirVersioningStrategyTests { + + @LocalServerPort private int port; + + @Autowired private TestRestTemplate restTemplate; + + @SuppressWarnings("unused") + @Autowired + private TestProperties testProperties; + + private final String localHost = "http://localhost:"; + + private static IParser parserR4; + private static IParser parserR5; + + @BeforeAll + public static void setUpOnce() { + parserR4 = FhirContext.forR4().newJsonParser(); + parserR5 = FhirContext.forR5().newJsonParser(); + } + + @Test + public void testCodeSystemLookupNoVersionR4() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + String code = "C3224"; + String endpoint = localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r4.model.Parameters params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + assertNotNull(params.getParameter("version")); + } + + @Test + public void testValueSetExpandNoVersionR4() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; + String endpoint = localHost + port + "/fhir/r4/ValueSet/$expand?url=" + url; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r4.model.ValueSet vs = parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); + assertNotNull(vs.getVersion()); + } + + @Test + public void testConceptMapTranslateNoVersionR4() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; + String system = "http://purl.obolibrary.org/obo/go.owl"; + String code = "GO:0000021"; + String endpoint = localHost + port + "/fhir/r4/ConceptMap/$translate?url=" + url + "&system=" + system + "&code=" + code; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r4.model.Parameters params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + assertNotNull(params.getParameter("result")); + } + + @Test + public void testCodeSystemLookupNoVersionR5() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + String code = "C3224"; + String endpoint = localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r5.model.Parameters params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + assertNotNull(params.getParameter("version")); + } + + @Test + public void testValueSetExpandNoVersionR5() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; + String endpoint = localHost + port + "/fhir/r5/ValueSet/$expand?url=" + url; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r5.model.ValueSet vs = parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); + assertNotNull(vs.getVersion()); + } + + @Test + public void testConceptMapTranslateNoVersionR5() throws Exception { + String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; + String system = "http://purl.obolibrary.org/obo/go.owl"; + String code = "GO:0000021"; + String endpoint = localHost + port + "/fhir/r5/ConceptMap/$translate?url=" + url + "&system=" + system + "&sourceCode=" + code; + String content = this.restTemplate.getForObject(endpoint, String.class); + org.hl7.fhir.r5.model.Parameters params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + assertNotNull(params.getParameter("result")); + } +} From fbc02a661504de60431a75c171b97e3d2bee9168 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 2 Mar 2026 16:18:11 -0800 Subject: [PATCH 57/64] fix other tests --- .../fhir/FhirR4ValueSetReadSearchTests.java | 19 ++++++++++--------- .../fhir/FhirR5ValueSetReadSearchTests.java | 18 +++++++++--------- 2 files changed, 19 insertions(+), 18 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java index fe3a2bb71..47dd8a826 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4ValueSetReadSearchTests.java @@ -669,13 +669,14 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { data.getEntry().stream().map(BundleEntryComponent::getResource).toList(); final ValueSet firstValueSet = (ValueSet) valueSets.get(0); + final String firstValueSetName = firstValueSet.getName(); final String firstValueSetTitle = firstValueSet.getTitle(); // Test 2: Basic name search (without modifier) final String basicNameUrl = endpoint + "?name=" + URLEncoder.encode(firstValueSetName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(basicNameUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(basicNameUrl), String.class); final Bundle basicNameBundle = parser.parseResource(Bundle.class, content); assertNotNull(basicNameBundle.getEntry()); @@ -687,7 +688,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String upperCaseName = firstValueSetName.toUpperCase(); final String exactMatchUrl = endpoint + "?name:exact=" + URLEncoder.encode(upperCaseName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(exactMatchUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(exactMatchUrl), String.class); final Bundle exactMatchBundle = parser.parseResource(Bundle.class, content); assertNotNull(exactMatchBundle.getEntry()); @@ -699,7 +700,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String partialName = firstValueSetName.substring(1, firstValueSetName.length() - 1); String containsUrl = endpoint + "?name:contains=" + URLEncoder.encode(partialName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(containsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(containsUrl), String.class); Bundle containsBundle = parser.parseResource(Bundle.class, content); assertNotNull(containsBundle.getEntry()); @@ -714,7 +715,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String namePrefix = firstValueSetName.substring(0, 3); final String startsWithUrl = endpoint + "?name:startsWith=" + URLEncoder.encode(namePrefix, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(startsWithUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(startsWithUrl), String.class); final Bundle startsWithBundle = parser.parseResource(Bundle.class, content); assertNotNull(startsWithBundle.getEntry()); @@ -729,7 +730,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String nonExistentName = "NonExistentValueSet" + UUID.randomUUID(); final String negativeTestUrl = endpoint + "?name:exact=" + URLEncoder.encode(nonExistentName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(negativeTestUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(negativeTestUrl), String.class); final Bundle emptyBundle = parser.parseResource(Bundle.class, content); assertTrue(emptyBundle.getEntry() == null || emptyBundle.getEntry().isEmpty()); @@ -738,7 +739,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String upperCaseTitle = firstValueSetTitle.toUpperCase(); final String titleExactUrl = endpoint + "?title:exact=" + URLEncoder.encode(upperCaseTitle, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleExactUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleExactUrl), String.class); final Bundle titleExactBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleExactBundle.getEntry()); @@ -750,7 +751,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String titlePrefix = firstValueSetTitle.substring(0, 3); final String titleStartsWithUrl = endpoint + "?title:startsWith=" + URLEncoder.encode(titlePrefix, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleStartsWithUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleStartsWithUrl), String.class); final Bundle titleStartsWithBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleStartsWithBundle.getEntry()); @@ -765,7 +766,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String partialTitle = firstValueSetTitle.substring(1, firstValueSetTitle.length() - 1); final String titleContainsUrl = endpoint + "?title:contains=" + URLEncoder.encode(partialTitle, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleContainsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleContainsUrl), String.class); final Bundle titleContainsBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleContainsBundle.getEntry()); @@ -794,7 +795,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String cdiscName = "CDISC"; containsUrl = endpoint + "?name:contains=" + URLEncoder.encode(cdiscName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(containsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(containsUrl), String.class); containsBundle = parser.parseResource(Bundle.class, content); assertNotNull(containsBundle.getEntry()); diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java index fe120025c..adbfffb1b 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR5ValueSetReadSearchTests.java @@ -707,7 +707,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { // Test 2: Basic name search (without modifier) final String basicNameUrl = endpoint + "?name=" + URLEncoder.encode(firstValueSetName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(basicNameUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(basicNameUrl), String.class); final Bundle basicNameBundle = parser.parseResource(Bundle.class, content); assertNotNull(basicNameBundle.getEntry()); @@ -719,7 +719,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String upperCaseName = firstValueSetName.toUpperCase(); final String exactMatchUrl = endpoint + "?name:exact=" + URLEncoder.encode(upperCaseName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(exactMatchUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(exactMatchUrl), String.class); final Bundle exactMatchBundle = parser.parseResource(Bundle.class, content); assertNotNull(exactMatchBundle.getEntry()); @@ -731,7 +731,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String partialName = firstValueSetName.substring(1, firstValueSetName.length() - 1); String containsUrl = endpoint + "?name:contains=" + URLEncoder.encode(partialName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(containsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(containsUrl), String.class); Bundle containsBundle = parser.parseResource(Bundle.class, content); assertNotNull(containsBundle.getEntry()); @@ -746,7 +746,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String namePrefix = firstValueSetName.substring(0, 3); final String startsWithUrl = endpoint + "?name:startsWith=" + URLEncoder.encode(namePrefix, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(startsWithUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(startsWithUrl), String.class); final Bundle startsWithBundle = parser.parseResource(Bundle.class, content); assertNotNull(startsWithBundle.getEntry()); @@ -761,7 +761,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String nonExistentName = "NonExistentValueSet" + UUID.randomUUID(); final String negativeTestUrl = endpoint + "?name:exact=" + URLEncoder.encode(nonExistentName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(negativeTestUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(negativeTestUrl), String.class); final Bundle emptyBundle = parser.parseResource(Bundle.class, content); assertTrue(emptyBundle.getEntry() == null || emptyBundle.getEntry().isEmpty()); @@ -770,7 +770,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String upperCaseTitle = firstValueSetTitle.toUpperCase(); final String titleExactUrl = endpoint + "?title:exact=" + URLEncoder.encode(upperCaseTitle, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleExactUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleExactUrl), String.class); final Bundle titleExactBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleExactBundle.getEntry()); @@ -782,7 +782,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String titlePrefix = firstValueSetTitle.substring(0, 3); final String titleStartsWithUrl = endpoint + "?title:startsWith=" + URLEncoder.encode(titlePrefix, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleStartsWithUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleStartsWithUrl), String.class); final Bundle titleStartsWithBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleStartsWithBundle.getEntry()); @@ -797,7 +797,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String partialTitle = firstValueSetTitle.substring(1, firstValueSetTitle.length() - 1); final String titleContainsUrl = endpoint + "?title:contains=" + URLEncoder.encode(partialTitle, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(titleContainsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(titleContainsUrl), String.class); final Bundle titleContainsBundle = parser.parseResource(Bundle.class, content); assertNotNull(titleContainsBundle.getEntry()); @@ -826,7 +826,7 @@ public void testValueSetSearchVariantsWithParameters() throws Exception { final String cdiscName = "CDISC"; containsUrl = endpoint + "?name:contains=" + URLEncoder.encode(cdiscName, StandardCharsets.UTF_8); - content = this.restTemplate.getForObject(containsUrl, String.class); + content = this.restTemplate.getForObject(new java.net.URI(containsUrl), String.class); containsBundle = parser.parseResource(Bundle.class, content); assertNotNull(containsBundle.getEntry()); From 788ad97877f7e588a3568e84310cc7ca8dd2e665 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 2 Mar 2026 16:54:48 -0800 Subject: [PATCH 58/64] spotless --- .../api/fhir/FhirVersioningStrategyTests.java | 44 ++++++++++++++----- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java index 3afd2a475..3634eef43 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java @@ -44,9 +44,11 @@ public static void setUpOnce() { public void testCodeSystemLookupNoVersionR4() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; String code = "C3224"; - String endpoint = localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; + String endpoint = + localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r4.model.Parameters params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + org.hl7.fhir.r4.model.Parameters params = + parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); assertNotNull(params.getParameter("version")); } @@ -55,7 +57,8 @@ public void testValueSetExpandNoVersionR4() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; String endpoint = localHost + port + "/fhir/r4/ValueSet/$expand?url=" + url; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r4.model.ValueSet vs = parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); + org.hl7.fhir.r4.model.ValueSet vs = + parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); assertNotNull(vs.getVersion()); } @@ -64,9 +67,18 @@ public void testConceptMapTranslateNoVersionR4() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; String system = "http://purl.obolibrary.org/obo/go.owl"; String code = "GO:0000021"; - String endpoint = localHost + port + "/fhir/r4/ConceptMap/$translate?url=" + url + "&system=" + system + "&code=" + code; + String endpoint = + localHost + + port + + "/fhir/r4/ConceptMap/$translate?url=" + + url + + "&system=" + + system + + "&code=" + + code; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r4.model.Parameters params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + org.hl7.fhir.r4.model.Parameters params = + parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); assertNotNull(params.getParameter("result")); } @@ -74,9 +86,11 @@ public void testConceptMapTranslateNoVersionR4() throws Exception { public void testCodeSystemLookupNoVersionR5() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; String code = "C3224"; - String endpoint = localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; + String endpoint = + localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r5.model.Parameters params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + org.hl7.fhir.r5.model.Parameters params = + parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); assertNotNull(params.getParameter("version")); } @@ -85,7 +99,8 @@ public void testValueSetExpandNoVersionR5() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; String endpoint = localHost + port + "/fhir/r5/ValueSet/$expand?url=" + url; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r5.model.ValueSet vs = parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); + org.hl7.fhir.r5.model.ValueSet vs = + parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); assertNotNull(vs.getVersion()); } @@ -94,9 +109,18 @@ public void testConceptMapTranslateNoVersionR5() throws Exception { String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; String system = "http://purl.obolibrary.org/obo/go.owl"; String code = "GO:0000021"; - String endpoint = localHost + port + "/fhir/r5/ConceptMap/$translate?url=" + url + "&system=" + system + "&sourceCode=" + code; + String endpoint = + localHost + + port + + "/fhir/r5/ConceptMap/$translate?url=" + + url + + "&system=" + + system + + "&sourceCode=" + + code; String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r5.model.Parameters params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + org.hl7.fhir.r5.model.Parameters params = + parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); assertNotNull(params.getParameter("result")); } } From 31805800567560ebd1cf3f46419d8111cbf02866 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 2 Mar 2026 17:34:08 -0800 Subject: [PATCH 59/64] vulnterability fixes --- build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build.gradle b/build.gradle index 4d956d054..9a593a51f 100644 --- a/build.gradle +++ b/build.gradle @@ -96,6 +96,11 @@ dependencies { // For vulnerabilities - may not be needed with Spring Boot 3.4.10 // implementation "org.apache.tomcat.embed:tomcat-embed-core:10.1.44" + // For vulnerability GHSA-72hv-8253-57qq + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.6' + // For vulnerability CVE-2026-24400 + implementation 'org.assertj:assertj-core:3.27.7' + //implementation "org.springframework.data:spring-data-elasticsearch:4.2.12" implementation "org.opensearch.client:spring-data-opensearch-starter:1.7.1" From 6c5d5ea490a2dd9470e1769d3254ca2215cefe55 Mon Sep 17 00:00:00 2001 From: peter-va Date: Mon, 2 Mar 2026 17:37:15 -0800 Subject: [PATCH 60/64] forgot the actual fix --- build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.gradle b/build.gradle index 9a593a51f..d720d8232 100644 --- a/build.gradle +++ b/build.gradle @@ -97,7 +97,7 @@ dependencies { // implementation "org.apache.tomcat.embed:tomcat-embed-core:10.1.44" // For vulnerability GHSA-72hv-8253-57qq - implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.6' + implementation 'com.fasterxml.jackson.core:jackson-core:2.18.6' // For vulnerability CVE-2026-24400 implementation 'org.assertj:assertj-core:3.27.7' From 8320693496445a39208dd5eff9a367125b452d0f Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Mon, 30 Mar 2026 18:10:52 -0700 Subject: [PATCH 61/64] Refactored the solution to use comparators and also extend the tests and account for 'monthly' --- .../evs/api/fhir/R4/CodeSystemProviderR4.java | 81 ++++---- .../evs/api/fhir/R4/ConceptMapProviderR4.java | 3 +- .../evs/api/fhir/R4/ValueSetProviderR4.java | 10 +- .../evs/api/fhir/R5/CodeSystemProviderR5.java | 70 +++---- .../evs/api/fhir/R5/ConceptMapProviderR5.java | 3 +- .../evs/api/fhir/R5/OpenApiInterceptorR5.java | 92 +++++---- .../evs/api/fhir/R5/ValueSetProviderR5.java | 10 +- .../nci/evs/api/util/TerminologyUtils.java | 101 ++++----- .../FhirR4CodeSystemGeneralOperations.java | 10 +- .../api/fhir/FhirVersioningStrategyTests.java | 191 +++++++++++++++--- 10 files changed, 346 insertions(+), 225 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java index f1b8eb904..3f638399a 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java @@ -1,5 +1,29 @@ package gov.nih.nci.evs.api.fhir.R4; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.hl7.fhir.r4.model.OperationOutcome.IssueType; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.UriType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.History; @@ -31,30 +55,6 @@ import gov.nih.nci.evs.api.util.TerminologyUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.CodeSystem; -import org.hl7.fhir.r4.model.CodeType; -import org.hl7.fhir.r4.model.Coding; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Meta; -import org.hl7.fhir.r4.model.OperationOutcome; -import org.hl7.fhir.r4.model.OperationOutcome.IssueType; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.UriType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; /** FHIR R4 CodeSystem provider. */ @Component @@ -143,6 +143,7 @@ public Parameters lookupImplicit( } else if (coding != null) { codeToLookup = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); @@ -298,6 +299,7 @@ public Parameters lookupInstance( } else if (coding != null) { codeToLookup = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); // if system is supplied, ensure it matches the url returned on the codeSys found by id if ((systemToLookup != null) && !codeSys.getUrl().equals(systemToLookup.getValue())) { @@ -469,6 +471,7 @@ public Parameters validateCodeImplicit( } else if (coding != null) { codeToValidate = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); @@ -585,6 +588,7 @@ public Parameters validateCodeInstance( } else if (coding != null) { codeToValidate = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); // if url is supplied, ensure it matches the url returned on the codeSys found by id if ((systemToLookup != null) && !codeSys.getUrl().equals(systemToLookup.getValue())) { @@ -709,6 +713,7 @@ public Parameters subsumesImplicit( throw FhirUtilityR4.exception( "No codeB parameter provided in request", OperationOutcome.IssueType.EXCEPTION, 400); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); @@ -811,6 +816,7 @@ public Parameters subsumesInstance( throw FhirUtilityR4.exception( "No codeB parameter provided in request", OperationOutcome.IssueType.EXCEPTION, 400); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); @@ -882,11 +888,9 @@ public Bundle findCodeSystems( FhirUtilityR4.notSupportedSearchParams(request); FhirUtilityR4.mutuallyExclusive("url", url, "system", system); - final List terms = termUtils.getIndexedTerminologies(osQueryService); - final List list = new ArrayList<>(); - for (final Terminology terminology : terms) { - final CodeSystem cs = FhirUtilityR4.toR4(terminology); + for (final CodeSystem cs : findPossibleCodeSystems(null, null, null)) { + // Skip non-matching if ((id != null && !id.getValue().equals(cs.getId())) || (system != null && !system.getValue().equals(cs.getUrl()))) { @@ -913,7 +917,7 @@ public Bundle findCodeSystems( list.add(cs); } - // Apply sorting if requested + // Apply sorting if requested via API applySorting(list, sort); return FhirUtilityR4.makeBundle(request, list, count, offset); @@ -937,22 +941,19 @@ public Bundle findCodeSystems( * @throws Exception the exception */ private List findPossibleCodeSystems( - @OptionalParam(name = "_id") final IdType id, - @OptionalParam(name = "url") final UriType url, - @OptionalParam(name = "version") final StringType version) - throws Exception { + final IdType id, final UriType url, final StringType version) throws Exception { try { - // If no ID and no url are specified, no code systems match - if (id == null && url == null) { - return new ArrayList<>(0); - } + // If no ID and no url are specified, ALL code systems match + // if (id == null && url == null) { + // return new ArrayList<>(0); + // } + // Get all terminologies sorted on version final List terms = termUtils.getIndexedTerminologies(osQueryService); - final Map map = new HashMap<>(); + Collections.sort(terms, TerminologyUtils.SORT_LATEST_MONTHLY); final List list = new ArrayList<>(); for (final Terminology terminology : terms) { - map.put(terminology.getTerminology(), terminology); final CodeSystem cs = FhirUtilityR4.toR4(terminology); // Skip non-matching if ((id != null && !id.getIdPart().equals(cs.getId())) @@ -968,8 +969,6 @@ private List findPossibleCodeSystems( list.add(cs); } - TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); - return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java index 66cdcf719..c92ca7210 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ConceptMapProviderR4.java @@ -502,6 +502,7 @@ private List findPossibleConceptMaps( map.put(terminology.getTerminology(), terminology); } final List mapsets = osQueryService.getMapsets(new IncludeParam("properties")); + Collections.sort(mapsets, TerminologyUtils.REVERSE_SORT_VERSIONS); final List list = new ArrayList<>(); for (final Concept mapset : mapsets) { @@ -555,8 +556,6 @@ private List findPossibleConceptMaps( list.add(cm); } - TerminologyUtils.sortVersionsDescending(list, a -> a.getVersion()); - return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java index 2c44dfbd1..212b7d7ad 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/ValueSetProviderR4.java @@ -1638,10 +1638,7 @@ public ValueSet getValueSet(@IdParam final IdType id) throws Exception { * @throws Exception the exception */ private List findPossibleValueSets( - @OptionalParam(name = "_id") final IdType id, - @OptionalParam(name = "system") final UriType system, - @OptionalParam(name = "url") final UriType url, - @OptionalParam(name = "version") final StringType version) + final IdType id, final UriType system, final UriType url, final StringType version) throws Exception { // If no ID and no url are specified, no code systems match if (id == null && url == null) { @@ -1649,6 +1646,7 @@ private List findPossibleValueSets( } final List terms = termUtils.getIndexedTerminologies(osQueryService); + Collections.sort(terms, TerminologyUtils.SORT_LATEST_MONTHLY); final Map map = new HashMap<>(); final List list = new ArrayList(); @@ -1675,6 +1673,8 @@ private List findPossibleValueSets( list.add(vs); } + + // This currently only gets latest monthly subsets, not earlier versions final List subsets = getNcitSubsets(); final List subsetsAsConcepts = subsets.stream().flatMap(Concept::streamSelfAndChildren).toList(); @@ -1698,8 +1698,6 @@ private List findPossibleValueSets( list.add(vs); } - TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); - return list; } diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java index 6993169e2..ba8a820ce 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java @@ -1,5 +1,27 @@ package gov.nih.nci.evs.api.fhir.R5; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Optional; + +import org.hl7.fhir.r5.model.Bundle; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.Meta; +import org.hl7.fhir.r5.model.OperationOutcome; +import org.hl7.fhir.r5.model.OperationOutcome.IssueType; +import org.hl7.fhir.r5.model.Parameters; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.UriType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.History; @@ -28,28 +50,6 @@ import gov.nih.nci.evs.api.util.TerminologyUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Optional; -import org.hl7.fhir.r5.model.Bundle; -import org.hl7.fhir.r5.model.CodeSystem; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.Coding; -import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.Meta; -import org.hl7.fhir.r5.model.OperationOutcome; -import org.hl7.fhir.r5.model.OperationOutcome.IssueType; -import org.hl7.fhir.r5.model.Parameters; -import org.hl7.fhir.r5.model.StringType; -import org.hl7.fhir.r5.model.UriType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; /** FHIR R5 CodeSystem provider. */ @Component @@ -124,12 +124,10 @@ public Bundle findCodeSystems( FhirUtilityR5.mutuallyExclusive("url", url, "system", system); // Get the indexed terms - final List terms = termUtils.getIndexedTerminologies(osQueryService); final List list = new ArrayList<>(); // Find the matching code systems in the list of terms - for (final Terminology terminology : terms) { - final CodeSystem cs = FhirUtilityR5.toR5(terminology); + for (final CodeSystem cs : findPossibleCodeSystems(null, null, null)) { // Skip non-matching if ((id != null && !id.getValue().equals(cs.getIdPart())) @@ -248,6 +246,7 @@ public Parameters lookupImplicit( } else if (coding != null) { codeToLookup = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); final Terminology term = termUtils.getIndexedTerminology(codeSys.getTitle(), osQueryService, true); @@ -401,6 +400,7 @@ public Parameters lookupInstance( } else if (coding != null) { codeToLookup = coding.getCode(); } + // This should be the latest (+monthly) version final CodeSystem codeSys = cs.get(0); if ((systemToLookup != null) && !codeSys.getUrl().equals(systemToLookup.getValue())) { throw FhirUtilityR5.exception( @@ -991,20 +991,16 @@ public CodeSystem getCodeSystem(@IdParam final IdType id) throws Exception { * @throws Exception exception */ private List findPossibleCodeSystems( - @OperationParam(name = "_id") final IdType id, - @OperationParam(name = "url") final UriType url, - @OperationParam(name = "version") final StringType version) - throws Exception { + final IdType id, final UriType url, final StringType version) throws Exception { try { - if (id == null && url == null) { - return new ArrayList<>(0); - } + // If no ID and no url are specified, ALL code systems match + // if (id == null && url == null) { + // return new ArrayList<>(0); + // } final List terms = termUtils.getIndexedTerminologies(osQueryService); - final Map map = new HashMap<>(); - for (final Terminology terminology : terms) { - map.put(terminology.getTerminology(), terminology); - } + Collections.sort(terms, TerminologyUtils.SORT_LATEST_MONTHLY); + final List list = new ArrayList<>(); // Find the matching code systems for (final Terminology terminology : terms) { @@ -1022,8 +1018,6 @@ private List findPossibleCodeSystems( list.add(cs); } - TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); - return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java index 137622b7c..3047c6140 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ConceptMapProviderR5.java @@ -588,6 +588,7 @@ private List findPossibleConceptMaps( map.put(terminology.getTerminology(), terminology); } final List mapsets = osQueryService.getMapsets(new IncludeParam("properties")); + Collections.sort(mapsets, TerminologyUtils.REVERSE_SORT_VERSIONS); final List list = new ArrayList<>(); // Find the matching mapsets @@ -634,8 +635,6 @@ private List findPossibleConceptMaps( list.add(cm); } - TerminologyUtils.sortVersionsDescending(list, a -> a.getVersion()); - return list; } catch (final FHIRServerResponseException e) { throw e; diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java index f9d8ef5d5..d5896b2cf 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java @@ -4,50 +4,6 @@ import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.interceptor.api.Hook; -import ca.uhn.fhir.interceptor.api.Pointcut; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.server.IServerAddressStrategy; -import ca.uhn.fhir.rest.server.IServerConformanceProvider; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestfulServerUtils; -import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; -import ca.uhn.fhir.util.ClasspathUtil; -import ca.uhn.fhir.util.ExtensionConstants; -import ca.uhn.fhir.util.HapiExtensions; -import ca.uhn.fhir.util.UrlUtil; -import com.vladsch.flexmark.html.HtmlRenderer; -import com.vladsch.flexmark.parser.Parser; -import io.swagger.v3.core.util.Yaml; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.PathItem.HttpMethod; -import io.swagger.v3.oas.models.Paths; -import io.swagger.v3.oas.models.examples.Example; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.ObjectSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; -import io.swagger.v3.oas.models.parameters.RequestBody; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.oas.models.responses.ApiResponses; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import io.swagger.v3.oas.models.tags.Tag; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -65,6 +21,7 @@ import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Triple; @@ -115,6 +72,52 @@ import org.thymeleaf.web.servlet.IServletWebExchange; import org.thymeleaf.web.servlet.JakartaServletWebApplication; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; + +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.interceptor.api.Hook; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.server.IServerAddressStrategy; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.rest.server.RestfulServerUtils; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import ca.uhn.fhir.util.ClasspathUtil; +import ca.uhn.fhir.util.ExtensionConstants; +import ca.uhn.fhir.util.HapiExtensions; +import ca.uhn.fhir.util.UrlUtil; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.PathItem.HttpMethod; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.examples.Example; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.tags.Tag; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + /** * EVSRESTAPI FHIR R5 interceptor to fix header, inject header auth token. Borrowed from * OpenApiInterceptor and modified. @@ -932,6 +935,7 @@ private CapabilityStatement getCapabilityStatement( * @param theResourceType the resource type * @param theOperation the operation */ + @SuppressWarnings("null") private void addFhirOperation( final FhirContext theFhirContext, final OpenAPI theOpenApi, diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java index 1263961c3..4426573c7 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/ValueSetProviderR5.java @@ -1259,10 +1259,7 @@ public ValueSet getValueSet(@IdParam final IdType id) throws Exception { * @throws Exception the exception */ public List findPossibleValueSets( - @OptionalParam(name = "_id") final IdType id, - @OptionalParam(name = "system") final UriType system, - @OptionalParam(name = "url") final UriType url, - @OptionalParam(name = "version") final StringType version) + final IdType id, final UriType system, final UriType url, final StringType version) throws Exception { // If no ID and no url are specified, no code systems match if (id == null && url == null) { @@ -1270,6 +1267,8 @@ public List findPossibleValueSets( } final List terms = termUtils.getIndexedTerminologies(osQueryService); + Collections.sort(terms, TerminologyUtils.SORT_LATEST_MONTHLY); + final List list = new ArrayList(); final Map map = new HashMap<>(); for (final Terminology terminology : terms) { @@ -1294,6 +1293,7 @@ public List findPossibleValueSets( } list.add(vs); } + // This currently only gets latest monthly subsets, not earlier versions final List subsets = getNcitSubsets(); final Set subsetsAsConcepts = subsets.stream().flatMap(Concept::streamSelfAndChildren).collect(Collectors.toSet()); @@ -1316,8 +1316,6 @@ public List findPossibleValueSets( list.add(vs); } - TerminologyUtils.sortLatest(list, map, a -> a.getTitle()); - return list; } diff --git a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java index 4623911cb..d863ea218 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java @@ -1,16 +1,11 @@ package gov.nih.nci.evs.api.util; -import gov.nih.nci.evs.api.model.Terminology; -import gov.nih.nci.evs.api.properties.ApplicationProperties; -import gov.nih.nci.evs.api.properties.GraphProperties; -import gov.nih.nci.evs.api.service.OpensearchQueryService; -import gov.nih.nci.evs.api.service.SparqlQueryManagerService; -import gov.nih.nci.evs.api.support.es.IndexMetadata; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Collections; +import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -18,8 +13,8 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.function.Function; import java.util.stream.Collectors; + import org.apache.commons.text.StringSubstitutor; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; @@ -37,6 +32,14 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.server.ResponseStatusException; +import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.properties.GraphProperties; +import gov.nih.nci.evs.api.service.OpensearchQueryService; +import gov.nih.nci.evs.api.service.SparqlQueryManagerService; +import gov.nih.nci.evs.api.support.es.IndexMetadata; + /** Utilities for handling the "include" flag, and converting EVSConcept to Concept. */ @Component public final class TerminologyUtils { @@ -44,6 +47,42 @@ public final class TerminologyUtils { /** The Constant logger. */ private static final Logger logger = LoggerFactory.getLogger(TerminologyUtils.class); + /** The Constant SORT_LATEST. Latest sorts before not latest. */ + public static final Comparator SORT_LATEST = + new Comparator<>() { + @Override + public int compare(final Terminology t1, final Terminology t2) { + return Boolean.compare(t1.getLatest(), t2.getLatest()); + } + }; + + /** + * The Constant SORT_LATEST_MONTHLY. Monthly sorts before weekly. latest sorts before not latest. + * (lowest string value sorts first) + */ + public static final Comparator SORT_LATEST_MONTHLY = + new Comparator<>() { + @Override + public int compare(final Terminology t1, final Terminology t2) { + final String k1 = + (t1.getTags().containsKey("monthly") ? "0" : "1") + (t1.getLatest() ? "0" : "1"); + final String k2 = + (t2.getTags().containsKey("monthly") ? "0" : "1") + (t2.getLatest() ? "0" : "1"); + return k1.compareTo(k2); + } + }; + + /** The Constant SORT_VERSIONS. Reverse sort based on version (+terminology) alphabetically. */ + public static final Comparator REVERSE_SORT_VERSIONS = + new Comparator<>() { + @Override + public int compare(final Concept c1, final Concept c2) { + final String k1 = c1.getVersion() + c1.getTerminology(); + final String k2 = c1.getVersion() + c1.getTerminology(); + return k2.compareTo(k1); + } + }; + /** The graph db properties. */ @Autowired GraphProperties graphProperties; @@ -93,7 +132,8 @@ public List getIndexedTerminologies(OpensearchQueryService osQueryS * Returns the stale terminologies. * * @param dbs the dbs - * @param terminology the terminology + * @param sparqlQueryManagerService the sparql query manager service + * @param osQueryService the os query service * @return the stale terminologies * @throws Exception the exception */ @@ -144,10 +184,11 @@ public Terminology getTerminology( } /** - * Get the indexed terminology + * Get the indexed terminology. * * @param terminology search terminology * @param osQueryService opensearch query service + * @param requireFlag the require flag * @return the Terminology * @throws Exception the exception */ @@ -163,6 +204,7 @@ public Terminology getIndexedTerminology( * * @param terminology target terminology * @param terminologies list of terminologies to search through + * @param requireFlag the require flag * @return the Terminology */ private Terminology findTerminology( @@ -478,45 +520,4 @@ public void checkLicenseHttp( public static void clearCache() { licenseCache.clear(); } - - /** - * Sorts the given list of objects by determining the latest terminology based on the map. - * - * @param the type parameter - * @param list the list - * @param map the map of terminology name to Terminology object - * @param keyExtractor the function to extract the terminology name from the object - */ - public static void sortLatest( - List list, Map map, Function keyExtractor) { - list.sort( - (a, b) -> { - Terminology termA = map.get(keyExtractor.apply(a)); - Terminology termB = map.get(keyExtractor.apply(b)); - if (termA != null && termB != null) { - return Boolean.compare(termB.getLatest(), termA.getLatest()); - } - return 0; - }); - } - - /** - * Sorts the given list of objects with a version string by version descending. - * - * @param the type parameter - * @param list the list - * @param versionExtractor the function to extract the version string from the object - */ - public static void sortVersionsDescending( - List list, Function versionExtractor) { - list.sort( - (a, b) -> { - String versionA = versionExtractor.apply(a); - String versionB = versionExtractor.apply(b); - if (versionA != null && versionB != null) { - return versionB.compareTo(versionA); - } - return 0; - }); - } } diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java index b99bec527..7711dacee 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java @@ -2,10 +2,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.parser.IParser; -import com.fasterxml.jackson.databind.ObjectMapper; -import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -20,6 +16,12 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; +import com.fasterxml.jackson.databind.ObjectMapper; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; + /** * Unit FhirR4Tests. Tests the functionality of the FHIR R4 endpoint CodeSystem specifically the * general operations. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java index 3634eef43..edfacd2c5 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java @@ -1,13 +1,14 @@ package gov.nih.nci.evs.api.fhir; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.parser.IParser; -import gov.nih.nci.evs.api.properties.TestProperties; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -16,57 +17,124 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import gov.nih.nci.evs.api.properties.TestProperties; + +/** FHIR version strategy tests. */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) @AutoConfigureMockMvc public class FhirVersioningStrategyTests { + /** The Constant log. */ + private static final Logger log = LoggerFactory.getLogger(FhirVersioningStrategyTests.class); + + /** The port. */ @LocalServerPort private int port; + /** The rest template. */ @Autowired private TestRestTemplate restTemplate; + /** The test properties. */ @SuppressWarnings("unused") @Autowired private TestProperties testProperties; + /** The local host. */ private final String localHost = "http://localhost:"; + /** The parser R 4. */ private static IParser parserR4; + + /** The parser R 5. */ private static IParser parserR5; + /** Sets the up once. */ @BeforeAll public static void setUpOnce() { parserR4 = FhirContext.forR4().newJsonParser(); parserR5 = FhirContext.forR5().newJsonParser(); } + /** + * Test code system lookup no version R 4. + * + * @throws Exception the exception + */ @Test public void testCodeSystemLookupNoVersionR4() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - String code = "C3224"; - String endpoint = - localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; - String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r4.model.Parameters params = - parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + String url = null; + String code = null; + String endpoint = null; + String content = null; + org.hl7.fhir.r4.model.Parameters params = null; + + // NCI should be "latest monthly" not just "latest" + url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + code = "C3224"; + endpoint = localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; + content = this.restTemplate.getForObject(endpoint, String.class); + // log.info(" content = " + content); + params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); assertNotNull(params.getParameter("version")); + assertEquals("25.12e", params.getParameter("version").getValue().toString()); + + // MDR should be "latest" because monthly doesn't matter + url = "https://www.meddra.org"; + code = "10008906"; + endpoint = localHost + port + "/fhir/r4/CodeSystem/$lookup?system=" + url + "&code=" + code; + content = this.restTemplate.getForObject(endpoint, String.class); + // log.info(" content = " + content); + params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); + assertNotNull(params.getParameter("version")); + assertEquals("28_0", params.getParameter("version").getValue().toString()); } + /** + * Test value set expand no version R 4. + * + * @throws Exception the exception + */ @Test public void testValueSetExpandNoVersionR4() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; - String endpoint = localHost + port + "/fhir/r4/ValueSet/$expand?url=" + url; - String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r4.model.ValueSet vs = - parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); + + String url = null; + String endpoint = null; + String content = null; + org.hl7.fhir.r4.model.ValueSet vs = null; + + // We expect "latest monthly" for "ncit" + url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; + endpoint = localHost + port + "/fhir/r4/ValueSet/$expand?url=" + url; + content = this.restTemplate.getForObject(endpoint, String.class); + + // log.info(" content = " + content); + vs = parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); assertNotNull(vs.getVersion()); + assertEquals("25.12e", vs.getVersion()); + + // We expect "latest" for "mdr" + url = "https://www.meddra.org?fhir_vs"; + endpoint = localHost + port + "/fhir/r4/ValueSet/$expand?url=" + url; + content = this.restTemplate.getForObject(endpoint, String.class); + + // log.info(" content = " + content); + vs = parserR4.parseResource(org.hl7.fhir.r4.model.ValueSet.class, content); + assertNotNull(vs.getVersion()); + assertEquals("28_0", vs.getVersion()); } + /** + * Test concept map translate no version R 4. + * + * @throws Exception the exception + */ @Test public void testConceptMapTranslateNoVersionR4() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; + String url = "http://purl.obolibrary.org/obo/go.owl?fhir_cm=GO_to_NCIt_Mapping"; String system = "http://purl.obolibrary.org/obo/go.owl"; - String code = "GO:0000021"; + String code = "GO:0016887"; String endpoint = localHost + port @@ -77,38 +145,93 @@ public void testConceptMapTranslateNoVersionR4() throws Exception { + "&code=" + code; String content = this.restTemplate.getForObject(endpoint, String.class); + log.info(" content = " + content); org.hl7.fhir.r4.model.Parameters params = parserR4.parseResource(org.hl7.fhir.r4.model.Parameters.class, content); assertNotNull(params.getParameter("result")); + assertTrue( + ((org.hl7.fhir.r4.model.BooleanType) params.getParameter("result").getValue()) + .booleanValue()); } + /** + * Test code system lookup no version R 5. + * + * @throws Exception the exception + */ @Test public void testCodeSystemLookupNoVersionR5() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; - String code = "C3224"; - String endpoint = - localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; - String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r5.model.Parameters params = - parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + String url = null; + String code = null; + String endpoint = null; + String content = null; + org.hl7.fhir.r5.model.Parameters params = null; + + // NCI should be "latest monthly" not just "latest" + url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl"; + code = "C3224"; + endpoint = localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; + content = this.restTemplate.getForObject(endpoint, String.class); + log.info(" content = " + content); + params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); assertNotNull(params.getParameter("version")); + assertEquals("25.12e", params.getParameter("version").getValue().toString()); + + // MDR should be "latest" because monthly doesn't matter + url = "https://www.meddra.org"; + code = "10008906"; + endpoint = localHost + port + "/fhir/r5/CodeSystem/$lookup?system=" + url + "&code=" + code; + content = this.restTemplate.getForObject(endpoint, String.class); + log.info(" content = " + content); + params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); + assertNotNull(params.getParameter("version")); + assertEquals("28_0", params.getParameter("version").getValue().toString()); } + /** + * Test value set expand no version R 5. + * + * @throws Exception the exception + */ @Test public void testValueSetExpandNoVersionR5() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; - String endpoint = localHost + port + "/fhir/r5/ValueSet/$expand?url=" + url; - String content = this.restTemplate.getForObject(endpoint, String.class); - org.hl7.fhir.r5.model.ValueSet vs = - parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); + + String url = null; + String endpoint = null; + String content = null; + org.hl7.fhir.r5.model.ValueSet vs = null; + + // We expect "latest monthly" for "ncit" + url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_vs"; + endpoint = localHost + port + "/fhir/r5/ValueSet/$expand?url=" + url; + content = this.restTemplate.getForObject(endpoint, String.class); + + // log.info(" content = " + content); + vs = parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); assertNotNull(vs.getVersion()); + assertEquals("25.12e", vs.getVersion()); + + // We expect "latest" for "mdr" + url = "https://www.meddra.org?fhir_vs"; + endpoint = localHost + port + "/fhir/r5/ValueSet/$expand?url=" + url; + content = this.restTemplate.getForObject(endpoint, String.class); + + // log.info(" content = " + content); + vs = parserR5.parseResource(org.hl7.fhir.r5.model.ValueSet.class, content); + assertNotNull(vs.getVersion()); + assertEquals("28_0", vs.getVersion()); } + /** + * Test concept map translate no version R 5. + * + * @throws Exception the exception + */ @Test public void testConceptMapTranslateNoVersionR5() throws Exception { - String url = "http://ncicb.nci.nih.gov/xml/owl/EVS/Thesaurus.owl?fhir_cm=GO_to_NCIt_Mapping"; + String url = "http://purl.obolibrary.org/obo/go.owl?fhir_cm=GO_to_NCIt_Mapping"; String system = "http://purl.obolibrary.org/obo/go.owl"; - String code = "GO:0000021"; + String code = "GO:0016887"; String endpoint = localHost + port @@ -116,11 +239,15 @@ public void testConceptMapTranslateNoVersionR5() throws Exception { + url + "&system=" + system - + "&sourceCode=" + + "&code=" + code; String content = this.restTemplate.getForObject(endpoint, String.class); + log.info(" content = " + content); org.hl7.fhir.r5.model.Parameters params = parserR5.parseResource(org.hl7.fhir.r5.model.Parameters.class, content); assertNotNull(params.getParameter("result")); + assertTrue( + ((org.hl7.fhir.r5.model.BooleanType) params.getParameter("result").getValue()) + .booleanValue()); } } From 0b0a4ce2ccfecb887c8f59f368466e7b92d8cc0d Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Mon, 30 Mar 2026 18:12:06 -0700 Subject: [PATCH 62/64] Fix R5 parameter for sourceCode --- .../gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java index edfacd2c5..edf2766e7 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java @@ -239,7 +239,7 @@ public void testConceptMapTranslateNoVersionR5() throws Exception { + url + "&system=" + system - + "&code=" + + "&sourceCode=" + code; String content = this.restTemplate.getForObject(endpoint, String.class); log.info(" content = " + content); From 81cca843769c2e7ae950d20682de23a134f5827e Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Mon, 30 Mar 2026 18:14:35 -0700 Subject: [PATCH 63/64] spotless and merge develop in for trivy --- .../evs/api/fhir/R4/CodeSystemProviderR4.java | 46 +++++----- .../evs/api/fhir/R5/CodeSystemProviderR5.java | 42 ++++----- .../evs/api/fhir/R5/OpenApiInterceptorR5.java | 91 +++++++++---------- .../nci/evs/api/util/TerminologyUtils.java | 16 ++-- .../FhirR4CodeSystemGeneralOperations.java | 10 +- .../api/fhir/FhirVersioningStrategyTests.java | 7 +- 6 files changed, 100 insertions(+), 112 deletions(-) diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java index 3f638399a..4cd295c59 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R4/CodeSystemProviderR4.java @@ -1,29 +1,5 @@ package gov.nih.nci.evs.api.fhir.R4; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.List; -import java.util.Optional; - -import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.CodeSystem; -import org.hl7.fhir.r4.model.CodeType; -import org.hl7.fhir.r4.model.Coding; -import org.hl7.fhir.r4.model.IdType; -import org.hl7.fhir.r4.model.Meta; -import org.hl7.fhir.r4.model.OperationOutcome; -import org.hl7.fhir.r4.model.OperationOutcome.IssueType; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.UriType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.History; @@ -55,6 +31,28 @@ import gov.nih.nci.evs.api.util.TerminologyUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.CodeSystem; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Meta; +import org.hl7.fhir.r4.model.OperationOutcome; +import org.hl7.fhir.r4.model.OperationOutcome.IssueType; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.UriType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** FHIR R4 CodeSystem provider. */ @Component diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java index ba8a820ce..7681a155d 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/CodeSystemProviderR5.java @@ -1,27 +1,5 @@ package gov.nih.nci.evs.api.fhir.R5; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.List; -import java.util.Optional; - -import org.hl7.fhir.r5.model.Bundle; -import org.hl7.fhir.r5.model.CodeSystem; -import org.hl7.fhir.r5.model.CodeType; -import org.hl7.fhir.r5.model.Coding; -import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.Meta; -import org.hl7.fhir.r5.model.OperationOutcome; -import org.hl7.fhir.r5.model.OperationOutcome.IssueType; -import org.hl7.fhir.r5.model.Parameters; -import org.hl7.fhir.r5.model.StringType; -import org.hl7.fhir.r5.model.UriType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.History; @@ -50,6 +28,26 @@ import gov.nih.nci.evs.api.util.TerminologyUtils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.List; +import java.util.Optional; +import org.hl7.fhir.r5.model.Bundle; +import org.hl7.fhir.r5.model.CodeSystem; +import org.hl7.fhir.r5.model.CodeType; +import org.hl7.fhir.r5.model.Coding; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.Meta; +import org.hl7.fhir.r5.model.OperationOutcome; +import org.hl7.fhir.r5.model.OperationOutcome.IssueType; +import org.hl7.fhir.r5.model.Parameters; +import org.hl7.fhir.r5.model.StringType; +import org.hl7.fhir.r5.model.UriType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; /** FHIR R5 CodeSystem provider. */ @Component diff --git a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java index d5896b2cf..eb105c12a 100644 --- a/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java +++ b/src/main/java/gov/nih/nci/evs/api/fhir/R5/OpenApiInterceptorR5.java @@ -4,6 +4,50 @@ import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.interceptor.api.Hook; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.server.IServerAddressStrategy; +import ca.uhn.fhir.rest.server.IServerConformanceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.rest.server.RestfulServerUtils; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import ca.uhn.fhir.util.ClasspathUtil; +import ca.uhn.fhir.util.ExtensionConstants; +import ca.uhn.fhir.util.HapiExtensions; +import ca.uhn.fhir.util.UrlUtil; +import com.vladsch.flexmark.html.HtmlRenderer; +import com.vladsch.flexmark.parser.Parser; +import io.swagger.v3.core.util.Yaml; +import io.swagger.v3.oas.models.Components; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.PathItem; +import io.swagger.v3.oas.models.PathItem.HttpMethod; +import io.swagger.v3.oas.models.Paths; +import io.swagger.v3.oas.models.examples.Example; +import io.swagger.v3.oas.models.info.Contact; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.Content; +import io.swagger.v3.oas.models.media.MediaType; +import io.swagger.v3.oas.models.media.ObjectSchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.parameters.Parameter; +import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; +import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.oas.models.responses.ApiResponses; +import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.tags.Tag; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletOutputStream; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; @@ -21,7 +65,6 @@ import java.util.Set; import java.util.function.Supplier; import java.util.stream.Collectors; - import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Triple; @@ -72,52 +115,6 @@ import org.thymeleaf.web.servlet.IServletWebExchange; import org.thymeleaf.web.servlet.JakartaServletWebApplication; -import com.vladsch.flexmark.html.HtmlRenderer; -import com.vladsch.flexmark.parser.Parser; - -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.interceptor.api.Hook; -import ca.uhn.fhir.interceptor.api.Pointcut; -import ca.uhn.fhir.rest.api.Constants; -import ca.uhn.fhir.rest.server.IServerAddressStrategy; -import ca.uhn.fhir.rest.server.IServerConformanceProvider; -import ca.uhn.fhir.rest.server.RestfulServer; -import ca.uhn.fhir.rest.server.RestfulServerUtils; -import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; -import ca.uhn.fhir.util.ClasspathUtil; -import ca.uhn.fhir.util.ExtensionConstants; -import ca.uhn.fhir.util.HapiExtensions; -import ca.uhn.fhir.util.UrlUtil; -import io.swagger.v3.core.util.Yaml; -import io.swagger.v3.oas.models.Components; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.PathItem; -import io.swagger.v3.oas.models.PathItem.HttpMethod; -import io.swagger.v3.oas.models.Paths; -import io.swagger.v3.oas.models.examples.Example; -import io.swagger.v3.oas.models.info.Contact; -import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.ObjectSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.parameters.Parameter.StyleEnum; -import io.swagger.v3.oas.models.parameters.RequestBody; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.oas.models.responses.ApiResponses; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.servers.Server; -import io.swagger.v3.oas.models.tags.Tag; -import jakarta.servlet.ServletContext; -import jakarta.servlet.ServletOutputStream; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - /** * EVSRESTAPI FHIR R5 interceptor to fix header, inject header auth token. Borrowed from * OpenApiInterceptor and modified. diff --git a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java index d863ea218..3837636b7 100644 --- a/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java +++ b/src/main/java/gov/nih/nci/evs/api/util/TerminologyUtils.java @@ -1,5 +1,12 @@ package gov.nih.nci.evs.api.util; +import gov.nih.nci.evs.api.model.Concept; +import gov.nih.nci.evs.api.model.Terminology; +import gov.nih.nci.evs.api.properties.ApplicationProperties; +import gov.nih.nci.evs.api.properties.GraphProperties; +import gov.nih.nci.evs.api.service.OpensearchQueryService; +import gov.nih.nci.evs.api.service.SparqlQueryManagerService; +import gov.nih.nci.evs.api.support.es.IndexMetadata; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -14,7 +21,6 @@ import java.util.Map; import java.util.Set; import java.util.stream.Collectors; - import org.apache.commons.text.StringSubstitutor; import org.apache.http.HttpEntity; import org.apache.http.client.methods.CloseableHttpResponse; @@ -32,14 +38,6 @@ import org.springframework.util.CollectionUtils; import org.springframework.web.server.ResponseStatusException; -import gov.nih.nci.evs.api.model.Concept; -import gov.nih.nci.evs.api.model.Terminology; -import gov.nih.nci.evs.api.properties.ApplicationProperties; -import gov.nih.nci.evs.api.properties.GraphProperties; -import gov.nih.nci.evs.api.service.OpensearchQueryService; -import gov.nih.nci.evs.api.service.SparqlQueryManagerService; -import gov.nih.nci.evs.api.support.es.IndexMetadata; - /** Utilities for handling the "include" flag, and converting EVSConcept to Concept. */ @Component public final class TerminologyUtils { diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java index 7711dacee..b99bec527 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirR4CodeSystemGeneralOperations.java @@ -2,6 +2,10 @@ import static org.junit.jupiter.api.Assertions.assertEquals; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import com.fasterxml.jackson.databind.ObjectMapper; +import gov.nih.nci.evs.api.util.ThreadLocalMapper; import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.junit.jupiter.api.BeforeAll; @@ -16,12 +20,6 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import com.fasterxml.jackson.databind.ObjectMapper; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.parser.IParser; -import gov.nih.nci.evs.api.util.ThreadLocalMapper; - /** * Unit FhirR4Tests. Tests the functionality of the FHIR R4 endpoint CodeSystem specifically the * general operations. diff --git a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java index edf2766e7..56d92af41 100644 --- a/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java +++ b/src/test/java/gov/nih/nci/evs/api/fhir/FhirVersioningStrategyTests.java @@ -4,6 +4,9 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.parser.IParser; +import gov.nih.nci.evs.api.properties.TestProperties; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -17,10 +20,6 @@ import org.springframework.boot.test.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.parser.IParser; -import gov.nih.nci.evs.api.properties.TestProperties; - /** FHIR version strategy tests. */ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT) From 7b7763ecbd399455e29584fe389d3422bda20239 Mon Sep 17 00:00:00 2001 From: Brian Carlsen Date: Tue, 31 Mar 2026 18:16:09 -0700 Subject: [PATCH 64/64] Upgrade dependencies for vulnerabilities, fix breaking changes in FetchSourceFilter --- build.gradle | 39 ++++++++----------- .../evs/api/service/LoaderServiceImpl.java | 1 - .../api/service/OpenSearchServiceImpl.java | 3 +- .../service/OpensearchQueryServiceImpl.java | 25 ++++++++---- .../SparqlQueryManagerServiceImpl.java | 1 - 5 files changed, 36 insertions(+), 33 deletions(-) diff --git a/build.gradle b/build.gradle index 6c300b07f..d263caf57 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ buildscript { ext { - springBootVersion = '3.4.12' + springBootVersion = '3.5.13' // Remove this line to see what version is favored by springBootVersion // and the version brought in by spring-data-elasticsearch set('elasticsearch.version', '7.12.1') @@ -87,31 +87,23 @@ dependencies { implementation "org.springframework.boot:spring-boot-devtools" implementation "org.springframework.boot:spring-boot-starter-actuator" - // Explicit patch for spring-core to mitigate CVE-2025-41249 - implementation 'org.springframework:spring-core:6.2.11' implementation "org.springframework.boot:spring-boot-starter-cache" implementation "org.springframework.boot:spring-boot-properties-migrator" implementation "org.springframework:spring-aop" - // For vulnerabilities - may not be needed with Spring Boot 3.4.10 - // implementation "org.apache.tomcat.embed:tomcat-embed-core:10.1.44" - implementation "com.fasterxml.jackson.core:jackson-core:2.18.6" + // These override org.hl7.fhir.*:6.4.0 requested by hapi-fhir-validation:7.6.1 and hapi-fhir-converter:7.6.1. + // 6.4.0 contains a vulnerability; 6.9.4 is the version co-packaged with HAPI FHIR that fixes it. + // These overrides can only be removed by upgrading to HAPI FHIR 8.x (a major breaking-change migration). implementation "org.fhir:ucum:1.0.9" - // These are needed to override dependencies from hapi-fhir-base (until it is fixed) - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.convertors:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu2:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu2016may:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu3:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r4:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r4b:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r5:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.utilities:6.9.0" - implementation "ca.uhn.hapi.fhir:org.hl7.fhir.validation:6.9.0" - - // For vulnerability GHSA-72hv-8253-57qq - implementation 'com.fasterxml.jackson.core:jackson-core:2.18.6' - // For vulnerability CVE-2026-24400 - implementation 'org.assertj:assertj-core:3.27.7' + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.convertors:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu2:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu2016may:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.dstu3:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r4:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r4b:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.r5:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.utilities:6.9.4" + implementation "ca.uhn.hapi.fhir:org.hl7.fhir.validation:6.9.4" //implementation "org.springframework.data:spring-data-elasticsearch:4.2.12" implementation "org.opensearch.client:spring-data-opensearch-starter:1.7.1" @@ -123,14 +115,15 @@ dependencies { //Java Mail Sender dependency implementation "org.springframework.boot:spring-boot-starter-mail" - implementation "org.aspectj:aspectjweaver:1.9.2" + // aspectjweaver is now managed by Spring Boot BOM (1.9.25.1 in 3.5.x) + implementation "org.aspectj:aspectjweaver" implementation "org.apache.commons:commons-text:1.10.0" //implementation "org.apache.opennlp:opennlp-tools:2.2.0" // Upgrade ecache to use jakarta - https://groups.google.com/g/ehcache-users/c/sKfxWuTpY-U // See also: https://stackoverflow.com/questions/75813659/gradle-could-not-find-org-ehcacheehcache-after-upgrading-to-spring-boot-3-0-x // Note: ehcache 3.10.8 uses Jakarta by default, no classifier needed - implementation "org.ehcache:ehcache:3.10.8" + implementation "org.ehcache:ehcache:3.10.9" // JAXB dependencies required for ehcache with Java 9+ // ehcache 3.10.8 still uses javax.xml.bind internally for XML parsing diff --git a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java index 53b349fbe..e0e2b15ff 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/LoaderServiceImpl.java @@ -72,7 +72,6 @@ public static void setStaticServices( } @PostConstruct - @SuppressWarnings("static-access") public void init() { setStaticServices(this.operationsService, this.osQueryService, this.termUtils); } diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java index 70fafccd3..1f6415017 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpenSearchServiceImpl.java @@ -129,7 +129,8 @@ public ConceptResultList findConcepts( .withQuery(boolQuery) .withPageable(pageable) .withSourceFilter( - new FetchSourceFilter(include.getIncludedFields(), include.getExcludedFields())); + new FetchSourceFilter( + true, include.getIncludedFields(), include.getExcludedFields())); // avoid setting min score // .withMinScore(0.01f); diff --git a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java index 0c589d726..31c59011d 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/OpensearchQueryServiceImpl.java @@ -119,7 +119,8 @@ public List getConcepts( NativeSearchQuery query = new NativeSearchQueryBuilder() .withFilter(QueryBuilders.idsQuery().addIds(codes.toArray(new String[0]))) - .withSourceFilter(new FetchSourceFilter(ip.getIncludedFields(), ip.getExcludedFields())) + .withSourceFilter( + new FetchSourceFilter(true, ip.getIncludedFields(), ip.getExcludedFields())) .withPageable(new EVSPageable(0, codes.size(), 0)) .build(); @@ -257,7 +258,9 @@ public List getSuperclasses(String code, Terminology terminology) { @Override public Optional getLabel(String code, Terminology terminology) { Optional concept = getConcept(code, terminology, new IncludeParam("minimal")); - if (!concept.isPresent() || concept.get().getName() == null) return Optional.empty(); + if (!concept.isPresent() || concept.get().getName() == null) { + return Optional.empty(); + } return Optional.of(concept.get().getName()); } @@ -275,7 +278,9 @@ public Optional getLabel(String code, Terminology terminology) { public List getRootNodes(Terminology terminology, IncludeParam ip) throws JsonParseException, JsonMappingException, IOException { Optional hierarchy = getHierarchyRoots(terminology); - if (!hierarchy.isPresent()) return Collections.emptyList(); + if (!hierarchy.isPresent()) { + return Collections.emptyList(); + } List hierarchyRoots = hierarchy.get().getHierarchyRoots(); if (hierarchyRoots.size() < 1) { return new ArrayList(); @@ -302,7 +307,9 @@ public List getRootNodes(Terminology terminology, IncludeParam ip) public List getRootNodesHierarchy(Terminology terminology) throws JsonParseException, JsonMappingException, IOException { Optional hierarchy = getHierarchyRoots(terminology); - if (!hierarchy.isPresent()) return Collections.emptyList(); + if (!hierarchy.isPresent()) { + return Collections.emptyList(); + } List nodes = new ArrayList<>(); List hierarchyRoots = hierarchy.get().getHierarchyRoots(); List concepts = getConcepts(hierarchyRoots, terminology, new IncludeParam("minimal")); @@ -515,7 +522,9 @@ public List getIndexMetadata(boolean completedOnly) { public Optional getHierarchyRoots(Terminology terminology) throws JsonMappingException, JsonProcessingException { Optional esObject = getOpensearchObject("hierarchy", terminology); - if (!esObject.isPresent()) return Optional.empty(); + if (!esObject.isPresent()) { + return Optional.empty(); + } return Optional.of(esObject.get().getHierarchy()); } @@ -871,7 +880,8 @@ public List getMapsets(IncludeParam ip) throws Exception { NativeSearchQuery query = new NativeSearchQueryBuilder() - .withSourceFilter(new FetchSourceFilter(ip.getIncludedFields(), ip.getExcludedFields())) + .withSourceFilter( + new FetchSourceFilter(true, ip.getIncludedFields(), ip.getExcludedFields())) // assuming pageSize < 10000, trying to get all maps, 17 at the time of this comment .withPageable(PageRequest.of(0, 10000)) .build(); @@ -885,7 +895,8 @@ public List getMapset(String code, IncludeParam ip) throws Exception { NativeSearchQuery query = new NativeSearchQueryBuilder() .withFilter(QueryBuilders.termQuery("_id", code)) - .withSourceFilter(new FetchSourceFilter(ip.getIncludedFields(), ip.getExcludedFields())) + .withSourceFilter( + new FetchSourceFilter(true, ip.getIncludedFields(), ip.getExcludedFields())) .build(); return getResults(query, Concept.class, OpensearchOperationsService.MAPSET_INDEX); diff --git a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java index b81f291ba..d465c7442 100644 --- a/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java +++ b/src/main/java/gov/nih/nci/evs/api/service/SparqlQueryManagerServiceImpl.java @@ -2228,7 +2228,6 @@ public List getAllRoles(final Terminology terminology, final IncludePar .orElse(null); } if (concept.getCode().equals(concept.getName()) - && bindings != null && matchConcept != null && matchConcept.getPropertyLabel() != null) { concept.setName(matchConcept.getPropertyLabel().getValue());