From dc41d5ad61d42aeda2f42bfd56974cb23570d39b Mon Sep 17 00:00:00 2001 From: James Agnew Date: Sun, 21 Mar 2021 12:03:57 -0400 Subject: [PATCH] Add terminology mapping and display population interceptors (#2488) * Start work on code mapping interceptors * Work on generation * Add terminology mapping and display population interceptors * Add changelog * License header updates * Test fixes * Fix typo * Interceptor fixes * License header update * Test fixes * Mapping fixes * Version bump * License header updates * Add null tests * Add null guard * Intermittent fix --- hapi-deployable-pom/pom.xml | 2 +- hapi-fhir-android/pom.xml | 2 +- hapi-fhir-base/pom.xml | 2 +- .../context/support/IValidationSupport.java | 80 + .../support/TranslateConceptResult.java | 154 ++ .../support/TranslateConceptResults.java | 94 + .../java/ca/uhn/fhir/util/IModelVisitor2.java | 2 +- .../ca/uhn/fhir/i18n/hapi-messages.properties | 9 +- hapi-fhir-bom/pom.xml | 4 +- hapi-fhir-cli/hapi-fhir-cli-api/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-app/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml | 2 +- hapi-fhir-cli/pom.xml | 2 +- hapi-fhir-client-okhttp/pom.xml | 2 +- hapi-fhir-client/pom.xml | 2 +- hapi-fhir-converter/pom.xml | 2 +- hapi-fhir-dist/pom.xml | 2 +- hapi-fhir-docs/pom.xml | 8 +- .../uhn/hapi/fhir/docs/ServletExamples.java | 22 + ...g-and-display-population-interceptors.yaml | 5 + .../built_in_server_interceptors.md | 50 + hapi-fhir-jacoco/pom.xml | 2 +- hapi-fhir-jaxrsserver-base/pom.xml | 2 +- hapi-fhir-jaxrsserver-example/pom.xml | 2 +- hapi-fhir-jpaserver-api/pom.xml | 2 +- .../ca/uhn/fhir/jpa/api/config/DaoConfig.java | 3 + .../api/dao/IFhirResourceDaoConceptMap.java | 4 +- .../fhir/jpa/api/model/TranslationMatch.java | 74 - .../fhir/jpa/api/model/TranslationResult.java | 88 - hapi-fhir-jpaserver-base/pom.xml | 2 +- .../ca/uhn/fhir/jpa/config/BaseConfig.java | 16 + .../fhir/jpa/config/BaseConfigDstu3Plus.java | 7 +- .../dstu3/FhirResourceDaoConceptMapDstu3.java | 127 +- .../dao/r4/FhirResourceDaoConceptMapR4.java | 140 +- .../dao/r5/FhirResourceDaoConceptMapR5.java | 152 +- .../uhn/fhir/jpa/entity/TermConceptMap.java | 7 + ...aseJpaResourceProviderConceptMapDstu3.java | 7 +- .../BaseJpaResourceProviderConceptMapR4.java | 7 +- .../BaseJpaResourceProviderConceptMapR5.java | 7 +- .../fhir/jpa/term/BaseTermReadSvcImpl.java | 558 +----- .../jpa/term/TermConceptMappingSvcImpl.java | 698 ++++++++ .../uhn/fhir/jpa/term/TermReadSvcDstu3.java | 3 +- .../ca/uhn/fhir/jpa/term/TermReadSvcR4.java | 3 +- .../ca/uhn/fhir/jpa/term/TermReadSvcR5.java | 3 +- .../jpa/term/api/ITermConceptMappingSvc.java | 42 + .../uhn/fhir/jpa/term/api/ITermReadSvc.java | 8 - .../uhn/fhir/jpa/util/MemoryCacheService.java | 25 +- .../validation/JpaValidationSupportChain.java | 4 + .../fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java | 5 +- .../FhirResourceDaoDstu3ConceptMapTest.java | 102 +- .../ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java | 8 +- .../r4/FhirResourceDaoR4ConceptMapTest.java | 904 +++++----- .../ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java | 5 +- ...TerminologyTranslationInterceptorTest.java | 133 ++ .../ResourceProviderDstu3ConceptMapTest.java | 24 +- ...sentInterceptorResourceProviderR4Test.java | 17 +- .../r4/ResourceProviderR4ConceptMapTest.java | 60 +- .../r5/ResourceProviderR5ConceptMapTest.java | 4 +- .../term/TermConceptMappingSvcImplTest.java | 1587 +++++++++++++++++ .../jpa/term/TerminologySvcImplR4Test.java | 1587 ----------------- hapi-fhir-jpaserver-batch/pom.xml | 2 +- hapi-fhir-jpaserver-cql/pom.xml | 6 +- hapi-fhir-jpaserver-mdm/pom.xml | 6 +- hapi-fhir-jpaserver-migrate/pom.xml | 2 +- .../tasks/HapiFhirJpaMigrationTasks.java | 57 +- hapi-fhir-jpaserver-model/pom.xml | 2 +- hapi-fhir-jpaserver-searchparam/pom.xml | 2 +- hapi-fhir-jpaserver-subscription/pom.xml | 2 +- hapi-fhir-jpaserver-test-utilities/pom.xml | 2 +- hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 4 +- hapi-fhir-server-mdm/pom.xml | 2 +- hapi-fhir-server/pom.xml | 2 +- .../BaseResponseTerminologyInterceptor.java | 99 + .../server/interceptor/InterceptorOrders.java | 3 + ...rminologyDisplayPopulationInterceptor.java | 120 ++ ...onseTerminologyTranslationInterceptor.java | 191 ++ .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../hapi-fhir-spring-boot-samples/pom.xml | 2 +- .../hapi-fhir-spring-boot-starter/pom.xml | 2 +- hapi-fhir-spring-boot/pom.xml | 2 +- hapi-fhir-structures-dstu2.1/pom.xml | 2 +- hapi-fhir-structures-dstu2/pom.xml | 2 +- hapi-fhir-structures-dstu3/pom.xml | 2 +- hapi-fhir-structures-hl7org-dstu2/pom.xml | 2 +- hapi-fhir-structures-r4/pom.xml | 2 +- hapi-fhir-structures-r5/pom.xml | 2 +- hapi-fhir-test-utilities/pom.xml | 2 +- hapi-fhir-testpage-overlay/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-validation-resources-dstu2/pom.xml | 2 +- hapi-fhir-validation-resources-dstu3/pom.xml | 2 +- hapi-fhir-validation-resources-r4/pom.xml | 2 +- hapi-fhir-validation-resources-r5/pom.xml | 2 +- hapi-fhir-validation/pom.xml | 2 +- .../support/BaseValidationSupportWrapper.java | 8 +- .../support/CachingValidationSupport.java | 120 +- ...oryTerminologyServerValidationSupport.java | 2 +- .../support/ValidationSupportChain.java | 28 +- ...ologyDisplayPopulationInterceptorTest.java | 94 + hapi-tinder-plugin/pom.xml | 16 +- hapi-tinder-test/pom.xml | 2 +- pom.xml | 2 +- restful-server-example/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- 109 files changed, 4282 insertions(+), 3421 deletions(-) create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResult.java create mode 100644 hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResults.java create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2488-add-term-mapping-and-display-population-interceptors.yaml delete mode 100644 hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationMatch.java delete mode 100644 hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationResult.java create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImpl.java create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermConceptMappingSvc.java create mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/ResponseTerminologyTranslationInterceptorTest.java create mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImplTest.java create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseResponseTerminologyInterceptor.java create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java create mode 100644 hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.java create mode 100644 hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 4eb78edfb61..60a649855a2 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index e1488cd9480..17926225600 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 58faa6905de..be0a59f9c68 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java index 91a622301cd..8b08e8d8708 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java @@ -24,6 +24,8 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.ParametersUtil; import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseParameters; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -84,6 +86,7 @@ public interface IValidationSupport { * @param theValueSetToExpand The valueset that should be expanded * @return The expansion, or null */ + @Nullable default ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, @Nullable ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { return null; } @@ -93,6 +96,7 @@ public interface IValidationSupport { * validation support module. This method may return null if it doesn't * make sense for a given module. */ + @Nullable default List fetchAllConformanceResources() { return null; } @@ -100,6 +104,7 @@ public interface IValidationSupport { /** * Load and return all possible structure definitions */ + @Nullable default List fetchAllStructureDefinitions() { return null; } @@ -110,6 +115,7 @@ public interface IValidationSupport { * @param theSystem The code system * @return The valueset (must not be null, but can be an empty ValueSet) */ + @Nullable default IBaseResource fetchCodeSystem(String theSystem) { return null; } @@ -128,6 +134,7 @@ public interface IValidationSupport { * given URI can be found */ @SuppressWarnings("unchecked") + @Nullable default T fetchResource(@Nullable Class theClass, String theUri) { Validate.notBlank(theUri, "theUri must not be null or blank"); @@ -161,6 +168,7 @@ public interface IValidationSupport { return null; } + @Nullable default IBaseResource fetchStructureDefinition(String theUrl) { return null; } @@ -182,6 +190,7 @@ public interface IValidationSupport { /** * Fetch the given ValueSet by URL */ + @Nullable default IBaseResource fetchValueSet(String theValueSetUrl) { return null; } @@ -199,6 +208,7 @@ public interface IValidationSupport { * @param theDisplay The display name, if it should also be validated * @return Returns a validation result object */ + @Nullable default CodeValidationResult validateCode(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, String theValueSetUrl) { return null; } @@ -216,6 +226,7 @@ public interface IValidationSupport { * @param theValueSet The ValueSet to validate against. Must not be null, and must be a ValueSet resource. * @return Returns a validation result object, or null if this validation support module can not handle this kind of request */ + @Nullable default CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { return null; } @@ -228,6 +239,7 @@ public interface IValidationSupport { * @param theSystem The CodeSystem URL * @param theCode The code */ + @Nullable default LookupCodeResult lookupCode(ValidationSupportContext theValidationSupportContext, String theSystem, String theCode) { return null; } @@ -251,6 +263,7 @@ public interface IValidationSupport { * other method in the support chain, so that they can be passed through the entire chain. Implementations of this interface may always safely ignore this parameter. * @return Returns null if this module does not know how to handle this request */ + @Nullable default IBaseResource generateSnapshot(ValidationSupportContext theValidationSupportContext, IBaseResource theInput, String theUrl, String theWebUrl, String theProfileName) { return null; } @@ -268,6 +281,14 @@ public interface IValidationSupport { // nothing } + /** + * Attempt to translate the given concept from one code system to another + */ + @Nullable + default TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { + return null; + } + enum IssueSeverity { /** @@ -289,6 +310,7 @@ public interface IValidationSupport { } class ConceptDesignation { + private String myLanguage; private String myUseSystem; private String myUseCode; @@ -710,4 +732,62 @@ public interface IValidationSupport { } } + + class TranslateCodeRequest { + private final String mySourceSystemUrl; + private final String mySourceCode; + private final String myTargetSystemUrl; + private final int myHashCode; + + public TranslateCodeRequest(String theSourceSystemUrl, String theSourceCode, String theTargetSystemUrl) { + mySourceSystemUrl = theSourceSystemUrl; + mySourceCode = theSourceCode; + myTargetSystemUrl = theTargetSystemUrl; + + myHashCode = new HashCodeBuilder(17, 37) + .append(mySourceSystemUrl) + .append(mySourceCode) + .append(myTargetSystemUrl) + .toHashCode(); + } + + @Override + public boolean equals(Object theO) { + if (this == theO) { + return true; + } + + if (theO == null || getClass() != theO.getClass()) { + return false; + } + + TranslateCodeRequest that = (TranslateCodeRequest) theO; + + return new EqualsBuilder() + .append(mySourceSystemUrl, that.mySourceSystemUrl) + .append(mySourceCode, that.mySourceCode) + .append(myTargetSystemUrl, that.myTargetSystemUrl) + .isEquals(); + } + + @Override + public int hashCode() { + return myHashCode; + } + + public String getSourceSystemUrl() { + return mySourceSystemUrl; + } + + public String getSourceCode() { + return mySourceCode; + } + + public String getTargetSystemUrl() { + return myTargetSystemUrl; + } + } + + + } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResult.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResult.java new file mode 100644 index 00000000000..406e733deff --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResult.java @@ -0,0 +1,154 @@ +package ca.uhn.fhir.context.support; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.apache.commons.lang3.builder.ToStringBuilder; +import org.apache.commons.lang3.builder.ToStringStyle; + +public class TranslateConceptResult { + private String mySystem; + private String myCode; + private String myDisplay; + private String myEquivalence; + private String myConceptMapUrl; + private String myValueSet; + private String mySystemVersion; + + /** + * Constructor + */ + public TranslateConceptResult() { + super(); + } + + public String getSystem() { + return mySystem; + } + + public TranslateConceptResult setSystem(String theSystem) { + mySystem = theSystem; + return this; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("system", mySystem) + .append("code", myCode) + .append("display", myDisplay) + .append("equivalence", myEquivalence) + .append("conceptMapUrl", myConceptMapUrl) + .append("valueSet", myValueSet) + .append("systemVersion", mySystemVersion) + .toString(); + } + + public String getCode() { + return myCode; + } + + public TranslateConceptResult setCode(String theCode) { + myCode = theCode; + return this; + } + + public String getDisplay() { + return myDisplay; + } + + public TranslateConceptResult setDisplay(String theDisplay) { + myDisplay = theDisplay; + return this; + } + + public String getEquivalence() { + return myEquivalence; + } + + public TranslateConceptResult setEquivalence(String theEquivalence) { + myEquivalence = theEquivalence; + return this; + } + + public String getSystemVersion() { + return mySystemVersion; + } + + public void setSystemVersion(String theSystemVersion) { + mySystemVersion = theSystemVersion; + } + + public String getValueSet() { + return myValueSet; + } + + public TranslateConceptResult setValueSet(String theValueSet) { + myValueSet = theValueSet; + return this; + } + + public String getConceptMapUrl() { + return myConceptMapUrl; + } + + public TranslateConceptResult setConceptMapUrl(String theConceptMapUrl) { + myConceptMapUrl = theConceptMapUrl; + return this; + } + + @Override + public boolean equals(Object theO) { + if (this == theO) { + return true; + } + + if (theO == null || getClass() != theO.getClass()) { + return false; + } + + TranslateConceptResult that = (TranslateConceptResult) theO; + + EqualsBuilder b = new EqualsBuilder(); + b.append(mySystem, that.mySystem); + b.append(myCode, that.myCode); + b.append(myDisplay, that.myDisplay); + b.append(myEquivalence, that.myEquivalence); + b.append(myConceptMapUrl, that.myConceptMapUrl); + b.append(myValueSet, that.myValueSet); + b.append(mySystemVersion, that.mySystemVersion); + return b.isEquals(); + } + + @Override + public int hashCode() { + HashCodeBuilder b = new HashCodeBuilder(17, 37); + b.append(mySystem); + b.append(myCode); + b.append(myDisplay); + b.append(myEquivalence); + b.append(myConceptMapUrl); + b.append(myValueSet); + b.append(mySystemVersion); + return b.toHashCode(); + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResults.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResults.java new file mode 100644 index 00000000000..f3b264c2692 --- /dev/null +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/TranslateConceptResults.java @@ -0,0 +1,94 @@ +package ca.uhn.fhir.context.support; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import org.apache.commons.lang3.builder.EqualsBuilder; +import org.apache.commons.lang3.builder.HashCodeBuilder; + +import java.util.ArrayList; +import java.util.List; + +public class TranslateConceptResults { + private List myResults; + private String myMessage; + private boolean myResult; + + public TranslateConceptResults() { + super(); + myResults = new ArrayList<>(); + } + + public List getResults() { + return myResults; + } + + public void setResults(List theResults) { + myResults = theResults; + } + + public String getMessage() { + return myMessage; + } + + public void setMessage(String theMessage) { + myMessage = theMessage; + } + + public boolean getResult() { + return myResult; + } + + public void setResult(boolean theMatched) { + myResult = theMatched; + } + + public int size() { + return getResults().size(); + } + + public boolean isEmpty() { + return getResults().isEmpty(); + } + + @Override + public boolean equals(Object theO) { + if (this == theO) { + return true; + } + + if (theO == null || getClass() != theO.getClass()) { + return false; + } + + TranslateConceptResults that = (TranslateConceptResults) theO; + + EqualsBuilder b = new EqualsBuilder(); + b.append(myResults, that.myResults); + return b.isEquals(); + } + + @Override + public int hashCode() { + HashCodeBuilder b = new HashCodeBuilder(17, 37); + b.append(myResults); + return b.toHashCode(); + } +} diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java index 1971350b816..1719c5dcbc1 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/IModelVisitor2.java @@ -32,7 +32,7 @@ import java.util.List; * THIS API IS EXPERIMENTAL IN HAPI FHIR - USE WITH CAUTION AS THE PUBLISHED API MAY * CHANGE * - * @see FhirTerser#visit(IBaseResource, IModelVisitor2) + * @see FhirTerser#visit(IBase, IModelVisitor2) */ public interface IModelVisitor2 { diff --git a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties index 5a4fccb3a01..26c705f6f74 100644 --- a/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties +++ b/hapi-fhir-base/src/main/resources/ca/uhn/fhir/i18n/hapi-messages.properties @@ -131,12 +131,9 @@ ca.uhn.fhir.jpa.dao.LegacySearchBuilder.sourceParamDisabled=The _source paramete ca.uhn.fhir.jpa.dao.LegacySearchBuilder.invalidCodeMissingSystem=Invalid token specified for parameter {0} - No system specified: {1}|{2} ca.uhn.fhir.jpa.dao.LegacySearchBuilder.invalidCodeMissingCode=Invalid token specified for parameter {0} - No code specified: {1}|{2} -ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoConceptMapDstu3.matchesFound=Matches found! -ca.uhn.fhir.jpa.dao.dstu3.FhirResourceDaoConceptMapDstu3.noMatchesFound=No matches found! -ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoConceptMapR4.matchesFound=Matches found! -ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoConceptMapR4.noMatchesFound=No matches found! -ca.uhn.fhir.jpa.dao.r5.FhirResourceDaoConceptMapR5.matchesFound=Matches found! -ca.uhn.fhir.jpa.dao.r5.FhirResourceDaoConceptMapR5.noMatchesFound=No matches found! +ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.matchesFound=Matches found +ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl.noMatchesFound=No Matches found + ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoSearchParameterR4.invalidSearchParamExpression=The expression "{0}" can not be evaluated and may be invalid: {1} ca.uhn.fhir.jpa.dao.predicate.PredicateBuilderToken.textModifierDisabledForSearchParam=The :text modifier is disabled for this search parameter diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index c1fa6d2b00b..2ac3e2e3056 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -3,14 +3,14 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT pom HAPI FHIR BOM ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index a19ae9fa204..d7f36a7086e 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 0fabcc4bbe6..6b3b059e91e 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml index b5e6c9cf558..d6af098313f 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../hapi-deployable-pom diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index 986d1aaed66..d88b28f10fa 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 2898e3a46cf..1582b801d3b 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 867a847b37a..ceb44df269a 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 85b545298b5..dfe8cd9106c 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index 5467d2d3659..20e10729888 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index da0cb4aaad3..ad5ed2220ea 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -78,13 +78,13 @@ ca.uhn.hapi.fhir hapi-fhir-structures-dstu2 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT compile ca.uhn.hapi.fhir hapi-fhir-jpaserver-subscription - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT compile @@ -101,7 +101,7 @@ ca.uhn.hapi.fhir hapi-fhir-testpage-overlay - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT classes diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java index 66c968b827f..72f88194b42 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ServletExamples.java @@ -21,6 +21,7 @@ package ca.uhn.hapi.fhir.docs; */ import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.*; @@ -223,4 +224,25 @@ public class ServletExamples { } // END SNIPPET: corsInterceptor + + @WebServlet(urlPatterns = { "/fhir/*" }, displayName = "FHIR Server") + public class RestfulServerWithResponseTerminologyTranslationInterceptor extends RestfulServer { + + private IValidationSupport myValidationSupport; + + @Override + protected void initialize() throws ServletException { + // START SNIPPET: ResponseTerminologyTranslationInterceptor + + // Create an interceptor that will map from a proprietary CodeSystem to LOINC + ResponseTerminologyTranslationInterceptor interceptor = new ResponseTerminologyTranslationInterceptor(myValidationSupport); + interceptor.addMappingSpecification("http://examplelabs.org", "http://loinc.org"); + + // Register the interceptor + registerInterceptor(interceptor); + + // END SNIPPET: ResponseTerminologyTranslationInterceptor + } + } + } diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2488-add-term-mapping-and-display-population-interceptors.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2488-add-term-mapping-and-display-population-interceptors.yaml new file mode 100644 index 00000000000..4ef9b65db0f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/5_4_0/2488-add-term-mapping-and-display-population-interceptors.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 2488 +title: "Two new server interceptors have been added that can be used to map codes and populate code display names respectively + using the server terminology services." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md index f430e7367d5..78406b55b7e 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md @@ -193,6 +193,54 @@ If you wish to override the value of `Resource.meta.source` using the value supp * [CaptureResourceSourceFromHeaderInterceptor JavaDoc](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/CaptureResourceSourceFromHeaderInterceptor.html) * [CaptureResourceSourceFromHeaderInterceptor Source](https://github.com/hapifhir/hapi-fhir/blob/master/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/CaptureResourceSourceFromHeaderInterceptor.java) + +# Terminology: Map Response Terminology + +A common problem when implementing FHIR APIs is the challenge of how to return coded data using standard vocabularies when your source data is not modelled using these vocabularies. For example, suppose you want to implement support for an Implementation Guide that mandates the use of [LOINC](https://loinc.org) but your source data uses local/proprietary observation codes. + +One solution is to simply apply mappings and add them to the FHIR data you are storing in your repository as you are storing it. This solution, often called *Mapping on the Way In*, will work but it has potential pitfalls including: + +* All mappings must be known at the time the data is being stored. +* If mappings change because of mistakes or new information, updating existing data is difficult. + +A potentially better solution is to apply *Mapping on the Way Out*, meaning that your mappings are stored in a central spot and applied at runtime to data as it is leaving your system. HAPI FHIR supplies an interceptor called the ResponseTerminologyTranslationInterceptor that can help with this. + +* [ResponseTerminologyTranslationInterceptor JavaDoc](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.html) +* [ResponseTerminologyTranslationInterceptor Source](https://github.com/hapifhir/hapi-fhir/blob/master/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.java) + +This interceptor uses ConceptMap resources that are stored in your system, looking up mappings for CodeableConcept codings in your resources and adding them to the responses. + +The following code snippet shows a simple example of how to create and configure this interceptor. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServletExamples.java|ResponseTerminologyTranslationInterceptor}} +``` + +## Limitations + +The following limitations will hopefully be resolved in the future: + +This interceptor currently only works when registered against a RestfulServer backed by the HAPI FHIR JPA server. + +This interceptor only modifies responses to FHIR read/vread/search/history operations. Responses to these operations are not modified if they are found within a FHIR transaction operation. + + +# Terminology: Populate Code Display Names + +The HAPI FHIR ResponseTerminologyDisplayPopulationInterceptor interceptor looks for Coding elements within responses where the `Coding.system` and `Coding.code` values are populated but the `Coding.display` is not. The interceptor will attempt to resolve the correct display using the validation support module and will add it to the Coding display value if one is found. + +* [ResponseTerminologyDisplayPopulationInterceptor JavaDoc](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.html) +* [ResponseTerminologyDisplayPopulationInterceptor Source](https://github.com/hapifhir/hapi-fhir/blob/master/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java) + +This interceptor uses ConceptMap resources that are stored in your system, looking up mappings for CodeableConcept codings in your resources and adding them to the responses. + +## Limitations + +The following limitation will hopefully be resolved in the future: + +This interceptor only modifies responses to FHIR read/vread/search/history operations. Responses to these operations are not modified if they are found within a FHIR transaction operation. + + # Utility: ResponseSizeCapturingInterceptor The ResponseSizeCapturingInterceptor can be used to capture the number of characters written in each HTTP FHIR response. @@ -229,6 +277,8 @@ The UserRequestRetryVersionConflictsInterceptor allows clients to request that t The RepositoryValidatingInterceptor can be used to enforce validation rules on data stored in a HAPI FHIR JPA Repository. See [Repository Validating Interceptor](/docs/validation/repository_validating_interceptor.html) for more information. + + # Data Standardization ```StandardizingInterceptor``` handles data standardization (s13n) requirements. This interceptor applies standardization rules on all FHIR primitives as configured in the ```s13n.json``` file that should be made available on the classpath. This file contains FHIRPath definitions together with the standardizers that should be applied to that path. It comes with six per-build standardizers: NAME_FAMILY, NAME_GIVEN, EMAIL, TITLE, PHONE and TEXT. Custom standardizers can be developed by implementing ```ca.uhn.fhir.rest.server.interceptor.s13n.standardizers.IStandardizer``` interface. diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 9b73f1f0389..d67f8ed00bc 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index b65c45b07e0..59399a6cbd2 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-example/pom.xml b/hapi-fhir-jaxrsserver-example/pom.xml index 536eee06f6b..9fdf6430b82 100644 --- a/hapi-fhir-jaxrsserver-example/pom.xml +++ b/hapi-fhir-jaxrsserver-example/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-jpaserver-api/pom.xml b/hapi-fhir-jpaserver-api/pom.xml index e1534302319..617ad59f609 100644 --- a/hapi-fhir-jpaserver-api/pom.xml +++ b/hapi-fhir-jpaserver-api/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/config/DaoConfig.java b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/config/DaoConfig.java index 6b494fa7ed2..8c0f27d6a8b 100644 --- a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/config/DaoConfig.java +++ b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/config/DaoConfig.java @@ -14,6 +14,7 @@ import org.hl7.fhir.r4.model.Bundle; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -93,6 +94,7 @@ public class DaoConfig { /** * update setter javadoc if default changes */ + @Nonnull private Long myTranslationCachesExpireAfterWriteInMinutes = DEFAULT_TRANSLATION_CACHES_EXPIRE_AFTER_WRITE_IN_MINUTES; /** * update setter javadoc if default changes @@ -884,6 +886,7 @@ public class DaoConfig { * Specifies the duration in minutes for which values will be retained after being * written to the terminology translation cache. Defaults to 60. */ + @Nonnull public Long getTranslationCachesExpireAfterWriteInMinutes() { return myTranslationCachesExpireAfterWriteInMinutes; } diff --git a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/dao/IFhirResourceDaoConceptMap.java b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/dao/IFhirResourceDaoConceptMap.java index a01f5b86e8e..73d92fd35a7 100644 --- a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/dao/IFhirResourceDaoConceptMap.java +++ b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/dao/IFhirResourceDaoConceptMap.java @@ -21,10 +21,10 @@ package ca.uhn.fhir.jpa.api.dao; */ import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; public interface IFhirResourceDaoConceptMap extends IFhirResourceDao { - TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails); + TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails); } diff --git a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationMatch.java b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationMatch.java deleted file mode 100644 index c7968e131da..00000000000 --- a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationMatch.java +++ /dev/null @@ -1,74 +0,0 @@ -package ca.uhn.fhir.jpa.api.model; - -/* - * #%L - * HAPI FHIR JPA API - * %% - * Copyright (C) 2014 - 2021 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import org.hl7.fhir.r4.model.CodeType; -import org.hl7.fhir.r4.model.Coding; -import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; -import org.hl7.fhir.r4.model.UriType; - -public class TranslationMatch { - private Coding myConcept; - private CodeType myEquivalence; - private UriType mySource; - - public TranslationMatch() { - super(); - } - - public Coding getConcept() { - return myConcept; - } - - public void setConcept(Coding theConcept) { - myConcept = theConcept; - } - - public CodeType getEquivalence() { - return myEquivalence; - } - - public void setEquivalence(CodeType theEquivalence) { - myEquivalence = theEquivalence; - } - - public UriType getSource() { - return mySource; - } - - public void setSource(UriType theSource) { - mySource = theSource; - } - - public void toParameterParts(ParametersParameterComponent theParam) { - if (myEquivalence != null) { - theParam.addPart().setName("equivalence").setValue(myEquivalence); - } - - if (myConcept != null) { - theParam.addPart().setName("concept").setValue(myConcept); - } - - if (mySource != null) { - theParam.addPart().setName("source").setValue(mySource); - } - } -} diff --git a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationResult.java b/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationResult.java deleted file mode 100644 index d77468bd0d1..00000000000 --- a/hapi-fhir-jpaserver-api/src/main/java/ca/uhn/fhir/jpa/api/model/TranslationResult.java +++ /dev/null @@ -1,88 +0,0 @@ -package ca.uhn.fhir.jpa.api.model; - -/* - * #%L - * HAPI FHIR JPA API - * %% - * Copyright (C) 2014 - 2021 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ - -import org.hl7.fhir.r4.model.BooleanType; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.Parameters.ParametersParameterComponent; -import org.hl7.fhir.r4.model.StringType; - -import java.util.ArrayList; -import java.util.List; - -public class TranslationResult { - private List myMatches; - private StringType myMessage; - private BooleanType myResult; - - public TranslationResult() { - super(); - - myMatches = new ArrayList<>(); - } - - public List getMatches() { - return myMatches; - } - - public void setMatches(List theMatches) { - myMatches = theMatches; - } - - public boolean addMatch(TranslationMatch theMatch) { - return myMatches.add(theMatch); - } - - public StringType getMessage() { - return myMessage; - } - - public void setMessage(StringType theMessage) { - myMessage = theMessage; - } - - public BooleanType getResult() { - return myResult; - } - - public void setResult(BooleanType theMatched) { - myResult = theMatched; - } - - public Parameters toParameters() { - Parameters retVal = new Parameters(); - - if (myResult != null) { - retVal.addParameter().setName("result").setValue(myResult); - } - - if (myMessage != null) { - retVal.addParameter().setName("message").setValue(myMessage); - } - - for (TranslationMatch translationMatch : myMatches) { - ParametersParameterComponent matchParam = retVal.addParameter().setName("match"); - translationMatch.toParameterParts(matchParam); - } - - return retVal; - } -} diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 56fbea3a8b8..cbc53857d30 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java index 579ef42ee11..a0a29757444 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java @@ -1,6 +1,7 @@ package ca.uhn.fhir.jpa.config; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.i18n.HapiLocalizer; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorService; @@ -60,6 +61,7 @@ import ca.uhn.fhir.jpa.graphql.JpaStorageServices; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.interceptor.JpaConsentContextServices; import ca.uhn.fhir.jpa.interceptor.OverridePathBasedReferentialIntegrityForDeletesInterceptor; +import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationInterceptor; import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder; import ca.uhn.fhir.jpa.model.sched.ISchedulerService; import ca.uhn.fhir.jpa.packages.IHapiPackageCacheManager; @@ -119,6 +121,8 @@ import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.util.MemoryCacheService; import ca.uhn.fhir.jpa.validation.JpaResourceLoader; import ca.uhn.fhir.jpa.validation.ValidationSettings; @@ -251,6 +255,13 @@ public abstract class BaseConfig { return new CascadingDeleteInterceptor(theFhirContext, theDaoRegistry, theInterceptorBroadcaster); } + + @Lazy + @Bean + public ResponseTerminologyTranslationInterceptor responseTerminologyTranslationInterceptor(IValidationSupport theValidationSupport) { + return new ResponseTerminologyTranslationInterceptor(theValidationSupport); + } + /** * This method should be overridden to provide an actual completed * bean, but it provides a partially completed entity manager @@ -336,6 +347,11 @@ public abstract class BaseConfig { return new DatabaseSearchResultCacheSvcImpl(); } + @Bean + public ITermConceptMappingSvc termConceptMappingSvc() { + return new TermConceptMappingSvcImpl(); + } + @Bean public ThreadPoolTaskExecutor searchCoordinatorThreadFactory() { final ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfigDstu3Plus.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfigDstu3Plus.java index 22ddc045a33..796ba682cb9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfigDstu3Plus.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfigDstu3Plus.java @@ -82,7 +82,12 @@ public abstract class BaseConfigDstu3Plus extends BaseConfig { @Primary @Bean public IValidationSupport validationSupportChain() { - return new CachingValidationSupport(jpaValidationSupportChain()); + + // Short timeout for code translation because TermConceptMappingSvcImpl has its own caching + CachingValidationSupport.CacheTimeouts cacheTimeouts = CachingValidationSupport.CacheTimeouts.defaultValues() + .setTranslateCodeMillis(1000); + + return new CachingValidationSupport(jpaValidationSupportChain(), cacheTimeouts); } @Bean(name = "myInstanceValidator") diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoConceptMapDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoConceptMapDstu3.java index ebe9efd4570..4750d9bb0dc 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoConceptMapDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoConceptMapDstu3.java @@ -21,147 +21,38 @@ package ca.uhn.fhir.jpa.dao.dstu3; */ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; -import ca.uhn.fhir.jpa.api.model.TranslationMatch; import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; import ca.uhn.fhir.jpa.model.cross.IBasePersistedResource; import ca.uhn.fhir.jpa.model.entity.ResourceTable; -import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; -import ca.uhn.fhir.jpa.term.api.ITermReadSvc; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.api.server.storage.TransactionDetails; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import org.hl7.fhir.dstu3.model.ConceptMap; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseResource; -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.StringType; -import org.hl7.fhir.r4.model.UriType; import org.springframework.beans.factory.annotation.Autowired; import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Set; import static org.hl7.fhir.convertors.conv30_40.ConceptMap30_40.convertConceptMap; public class FhirResourceDaoConceptMapDstu3 extends BaseHapiFhirResourceDao implements IFhirResourceDaoConceptMap { @Autowired - private ITermReadSvc myHapiTerminologySvc; + private ITermConceptMappingSvc myTermConceptMappingSvc; @Override - public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { + public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { - return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest)); + return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); } - return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest)); + return myTermConceptMappingSvc.translate(theTranslationRequest); } - private TranslationResult buildTranslationResult(List theTargets) { - TranslationResult retVal = new TranslationResult(); - String msg; - if (theTargets.isEmpty()) { - - retVal.setResult(new BooleanType(false)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapDstu3.class, - "noMatchesFound"); - - retVal.setMessage(new StringType(msg)); - - } else { - - retVal.setResult(new BooleanType(true)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapDstu3.class, - "matchesFound"); - - retVal.setMessage(new StringType(msg)); - - TranslationMatch translationMatch; - Set targetsToReturn = new HashSet<>(); - for (TermConceptMapGroupElementTarget target : theTargets) { - if (targetsToReturn.add(target)) { - translationMatch = new TranslationMatch(); - - if (target.getEquivalence() != null) { - translationMatch.setEquivalence(new CodeType(target.getEquivalence().toCode())); - } - - translationMatch.setConcept( - new Coding() - .setCode(target.getCode()) - .setSystem(target.getSystem()) - .setVersion(target.getSystemVersion()) - .setDisplay(target.getDisplay()) - ); - - translationMatch.setSource(new UriType(target.getConceptMapUrl())); - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; - } - - private TranslationResult buildReverseTranslationResult(List theElements) { - TranslationResult retVal = new TranslationResult(); - - String msg; - if (theElements.isEmpty()) { - - retVal.setResult(new BooleanType(false)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapDstu3.class, - "noMatchesFound"); - - retVal.setMessage(new StringType(msg)); - - } else { - - retVal.setResult(new BooleanType(true)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapDstu3.class, - "matchesFound"); - - retVal.setMessage(new StringType(msg)); - - TranslationMatch translationMatch; - Set elementsToReturn = new HashSet<>(); - for (TermConceptMapGroupElement element : theElements) { - if (elementsToReturn.add(element)) { - translationMatch = new TranslationMatch(); - - translationMatch.setConcept( - new Coding() - .setCode(element.getCode()) - .setSystem(element.getSystem()) - .setVersion(element.getSystemVersion()) - .setDisplay(element.getDisplay()) - ); - - translationMatch.setSource(new UriType(element.getConceptMapUrl())); - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; - } @Override public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, IBasePersistedResource theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, @@ -173,12 +64,12 @@ public class FhirResourceDaoConceptMapDstu3 extends BaseHapiFhirResourceDao implements IFhirResourceDaoConceptMap { @Autowired - private ITermReadSvc myHapiTerminologySvc; + private ITermConceptMappingSvc myTermConceptMappingSvc; @Override - public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { + public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { - return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest)); + return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); } - return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest)); - } - - private TranslationResult buildTranslationResult(List theTargets) { - TranslationResult retVal = new TranslationResult(); - - String msg; - if (theTargets.isEmpty()) { - - retVal.setResult(new BooleanType(false)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR4.class, - "noMatchesFound"); - - retVal.setMessage(new StringType(msg)); - - } else { - - retVal.setResult(new BooleanType(true)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR4.class, - "matchesFound"); - - retVal.setMessage(new StringType(msg)); - - TranslationMatch translationMatch; - Set targetsToReturn = new HashSet<>(); - for (TermConceptMapGroupElementTarget target : theTargets) { - if (targetsToReturn.add(target)) { - translationMatch = new TranslationMatch(); - - if (target.getEquivalence() != null) { - translationMatch.setEquivalence(new CodeType(target.getEquivalence().toCode())); - } - - translationMatch.setConcept( - new Coding() - .setCode(target.getCode()) - .setSystem(target.getSystem()) - .setVersion(target.getSystemVersion()) - .setDisplay(target.getDisplay()) - ); - - translationMatch.setSource(new UriType(target.getConceptMapUrl())); - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; - } - - private TranslationResult buildReverseTranslationResult(List theElements) { - TranslationResult retVal = new TranslationResult(); - - String msg; - if (theElements.isEmpty()) { - - retVal.setResult(new BooleanType(false)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR4.class, - "noMatchesFound"); - - retVal.setMessage(new StringType(msg)); - - } else { - - retVal.setResult(new BooleanType(true)); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR4.class, - "matchesFound"); - - retVal.setMessage(new StringType(msg)); - - TranslationMatch translationMatch; - Set elementsToReturn = new HashSet<>(); - for (TermConceptMapGroupElement element : theElements) { - if (elementsToReturn.add(element)) { - translationMatch = new TranslationMatch(); - - translationMatch.setConcept( - new Coding() - .setCode(element.getCode()) - .setSystem(element.getSystem()) - .setVersion(element.getSystemVersion()) - .setDisplay(element.getDisplay()) - ); - - translationMatch.setSource(new UriType(element.getConceptMapUrl())); - - if (element.getConceptMapGroupElementTargets().size() == 1) { - - ConceptMapEquivalence eq = element.getConceptMapGroupElementTargets().get(0).getEquivalence(); - if (eq != null) { - translationMatch.setEquivalence(new CodeType(eq.toCode())); - } - } - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; + return myTermConceptMappingSvc.translate(theTranslationRequest); } @Override @@ -178,9 +56,9 @@ public class FhirResourceDaoConceptMapR4 extends BaseHapiFhirResourceDao implements IFhirResourceDaoConceptMap { @Autowired - private ITermReadSvc myHapiTerminologySvc; + private ITermConceptMappingSvc myTermConceptMappingSvc; @Override - public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { + public TranslateConceptResults translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) { if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) { - return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest)); + return myTermConceptMappingSvc.translateWithReverse(theTranslationRequest); } - return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest)); - } - - private TranslationResult buildTranslationResult(List theTargets) { - TranslationResult retVal = new TranslationResult(); - - String msg; - if (theTargets.isEmpty()) { - - retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(false))); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR5.class, - "noMatchesFound"); - - retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg))); - - } else { - - retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(true))); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR5.class, - "matchesFound"); - - retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg))); - - TranslationMatch translationMatch; - Set targetsToReturn = new HashSet<>(); - for (TermConceptMapGroupElementTarget target : theTargets) { - if (targetsToReturn.add(target)) { - translationMatch = new TranslationMatch(); - - if (target.getEquivalence() != null) { - translationMatch.setEquivalence(VersionConvertor_40_50.convertCode(new CodeType(target.getEquivalence().toCode()))); - } - - translationMatch.setConcept(VersionConvertor_40_50.convertCoding( - new Coding() - .setCode(target.getCode()) - .setSystem(target.getSystem()) - .setVersion(target.getSystemVersion()) - .setDisplay(target.getDisplay()) - )); - - translationMatch.setSource(VersionConvertor_40_50.convertUri(new UriType(target.getConceptMapUrl()))); - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; - } - - private TranslationResult buildReverseTranslationResult(List theElements) { - TranslationResult retVal = new TranslationResult(); - - String msg; - if (theElements.isEmpty()) { - - retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(false))); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR5.class, - "noMatchesFound"); - - retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg))); - - } else { - - retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(true))); - - msg = getContext().getLocalizer().getMessage( - FhirResourceDaoConceptMapR5.class, - "matchesFound"); - - retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg))); - - TranslationMatch translationMatch; - Set elementsToReturn = new HashSet<>(); - for (TermConceptMapGroupElement element : theElements) { - if (elementsToReturn.add(element)) { - translationMatch = new TranslationMatch(); - - translationMatch.setConcept(VersionConvertor_40_50.convertCoding( - new Coding() - .setCode(element.getCode()) - .setSystem(element.getSystem()) - .setVersion(element.getSystemVersion()) - .setDisplay(element.getDisplay()) - )); - - translationMatch.setSource(VersionConvertor_40_50.convertUri(new UriType(element.getConceptMapUrl()))); - - if (element.getConceptMapGroupElementTargets().size() == 1) { - - ConceptMapEquivalence eq = element.getConceptMapGroupElementTargets().get(0).getEquivalence(); - if (eq != null) { - translationMatch.setEquivalence(VersionConvertor_40_50.convertCode(new CodeType(eq.toCode()))); - } - } - - retVal.addMatch(translationMatch); - } - } - } - - return retVal; + return myTermConceptMappingSvc.translate(theTranslationRequest); } @Override @@ -178,12 +56,12 @@ public class FhirResourceDaoConceptMapR5 extends BaseHapiFhirResourceDao dao = (IFhirResourceDaoConceptMap) getDao(); - TranslationResult result = dao.translate(translationRequest, theRequestDetails); + TranslateConceptResults result = dao.translate(translationRequest, theRequestDetails); // Convert from R4 to DSTU3 - return convertParameters(result.toParameters()); + return convertParameters(TermConceptMappingSvcImpl.toParameters(result)); } catch (FHIRException fe) { throw new InternalErrorException(fe); } finally { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderConceptMapR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderConceptMapR4.java index 7014db1ffc9..2f77057b350 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderConceptMapR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r4/BaseJpaResourceProviderConceptMapR4.java @@ -22,8 +22,9 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; @@ -141,8 +142,8 @@ public class BaseJpaResourceProviderConceptMapR4 extends JpaResourceProviderR4 dao = (IFhirResourceDaoConceptMap) getDao(); - TranslationResult result = dao.translate(translationRequest, theRequestDetails); - return result.toParameters(); + TranslateConceptResults result = dao.translate(translationRequest, theRequestDetails); + return TermConceptMappingSvcImpl.toParameters(result); } finally { endRequest(theServletRequest); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderConceptMapR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderConceptMapR5.java index c0207567613..4e80fe87662 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderConceptMapR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/r5/BaseJpaResourceProviderConceptMapR5.java @@ -22,8 +22,9 @@ package ca.uhn.fhir.jpa.provider.r5; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoConceptMap; import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; @@ -142,8 +143,8 @@ public class BaseJpaResourceProviderConceptMapR5 extends JpaResourceProviderR5 dao = (IFhirResourceDaoConceptMap) getDao(); - TranslationResult result = dao.translate(translationRequest, theRequestDetails); - org.hl7.fhir.r4.model.Parameters parameters = result.toParameters(); + TranslateConceptResults result = dao.translate(translationRequest, theRequestDetails); + org.hl7.fhir.r4.model.Parameters parameters = TermConceptMappingSvcImpl.toParameters(result); return org.hl7.fhir.convertors.conv40_50.Parameters40_50.convertParameters(parameters); } finally { endRequest(theServletRequest); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java index 30526d363e0..077e4fc8804 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/BaseTermReadSvcImpl.java @@ -29,18 +29,12 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.IDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; -import ca.uhn.fhir.jpa.api.model.TranslationQuery; -import ca.uhn.fhir.jpa.api.model.TranslationRequest; import ca.uhn.fhir.jpa.config.HibernatePropertiesProvider; import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao; import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemVersionDao; import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; import ca.uhn.fhir.jpa.dao.data.ITermConceptDesignationDao; -import ca.uhn.fhir.jpa.dao.data.ITermConceptMapDao; -import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupDao; -import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupElementDao; -import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupElementTargetDao; import ca.uhn.fhir.jpa.dao.data.ITermConceptPropertyDao; import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao; import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao; @@ -51,10 +45,6 @@ import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermConcept; import ca.uhn.fhir.jpa.entity.TermConceptDesignation; -import ca.uhn.fhir.jpa.entity.TermConceptMap; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroup; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.entity.TermConceptProperty; @@ -72,12 +62,12 @@ import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.search.builder.SearchBuilder; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; import ca.uhn.fhir.jpa.term.ex.ExpansionTooCostlyException; import ca.uhn.fhir.jpa.util.LogicUtil; -import ca.uhn.fhir.jpa.util.ScrollableResultsIterator; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; @@ -102,8 +92,6 @@ import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.time.DateUtils; import org.apache.lucene.index.Term; import org.apache.lucene.search.RegexpQuery; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; import org.hibernate.search.backend.elasticsearch.ElasticsearchExtension; import org.hibernate.search.backend.lucene.LuceneExtension; import org.hibernate.search.engine.search.predicate.dsl.BooleanPredicateClausesStep; @@ -114,7 +102,6 @@ import org.hibernate.search.mapper.orm.Search; import org.hibernate.search.mapper.orm.session.SearchSession; import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService; import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; -import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBaseCoding; import org.hl7.fhir.instance.model.api.IBaseDatatype; @@ -126,11 +113,9 @@ import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Coding; -import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.DomainResource; import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Extension; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IntegerType; import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.ValueSet; @@ -139,7 +124,6 @@ import org.quartz.JobExecutionContext; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.ApplicationContext; import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Slice; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -170,7 +154,6 @@ import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -199,10 +182,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseTermReadSvcImpl.class); private static final ValueSetExpansionOptions DEFAULT_EXPANSION_OPTIONS = new ValueSetExpansionOptions(); private static final TermCodeSystemVersion NO_CURRENT_VERSION = new TermCodeSystemVersion().setId(-1L); - private static boolean ourLastResultsFromTranslationCache; // For testing. - private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing. private static Runnable myInvokeOnNextCallForUnitTest; - private final int myFetchSize = DEFAULT_FETCH_SIZE; private final Cache myCodeSystemCurrentVersionCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).build(); @Autowired protected DaoRegistry myDaoRegistry; @@ -211,14 +191,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { @Autowired protected ITermConceptDao myConceptDao; @Autowired - protected ITermConceptMapDao myConceptMapDao; - @Autowired - protected ITermConceptMapGroupDao myConceptMapGroupDao; - @Autowired - protected ITermConceptMapGroupElementDao myConceptMapGroupElementDao; - @Autowired - protected ITermConceptMapGroupElementTargetDao myConceptMapGroupElementTargetDao; - @Autowired protected ITermConceptPropertyDao myConceptPropertyDao; @Autowired protected ITermConceptDesignationDao myConceptDesignationDao; @@ -236,8 +208,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { private ITermCodeSystemVersionDao myCodeSystemVersionDao; @Autowired private DaoConfig myDaoConfig; - private Cache> myTranslationCache; - private Cache> myTranslationWithReverseCache; private TransactionTemplate myTxTemplate; @Autowired private PlatformTransactionManager myTransactionManager; @@ -257,6 +227,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { private ITermCodeSystemStorageSvc myConceptStorageSvc; @Autowired private ApplicationContext myApplicationContext; + @Autowired + private ITermConceptMappingSvc myTermConceptMappingSvc; + private volatile IValidationSupport myJpaValidationSupport; private volatile IValidationSupport myValidationSupport; @@ -351,44 +324,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { */ @VisibleForTesting public void clearCaches() { - myTranslationCache.invalidateAll(); - myTranslationWithReverseCache.invalidateAll(); myCodeSystemCurrentVersionCache.invalidateAll(); } - public void deleteConceptMap(ResourceTable theResourceTable) { - // Get existing entity so it can be deleted. - Optional optionalExistingTermConceptMapById = myConceptMapDao.findTermConceptMapByResourcePid(theResourceTable.getId()); - - if (optionalExistingTermConceptMapById.isPresent()) { - TermConceptMap existingTermConceptMap = optionalExistingTermConceptMapById.get(); - - ourLog.info("Deleting existing TermConceptMap[{}] and its children...", existingTermConceptMap.getId()); - for (TermConceptMapGroup group : existingTermConceptMap.getConceptMapGroups()) { - - for (TermConceptMapGroupElement element : group.getConceptMapGroupElements()) { - - for (TermConceptMapGroupElementTarget target : element.getConceptMapGroupElementTargets()) { - - myConceptMapGroupElementTargetDao.deleteTermConceptMapGroupElementTargetById(target.getId()); - } - - myConceptMapGroupElementDao.deleteTermConceptMapGroupElementById(element.getId()); - } - - myConceptMapGroupDao.deleteTermConceptMapGroupById(group.getId()); - } - - myConceptMapDao.deleteTermConceptMapById(existingTermConceptMap.getId()); - ourLog.info("Done deleting existing TermConceptMap[{}] and its children.", existingTermConceptMap.getId()); - } - } - - @Override - @Transactional - public void deleteConceptMapAndChildren(ResourceTable theResourceTable) { - deleteConceptMap(theResourceTable); - } public void deleteValueSetForResource(ResourceTable theResourceTable) { // Get existing entity so it can be deleted. @@ -533,13 +471,12 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { theAccumulator.addMessage(msg); if (isOracleDialect()) { expandConceptsOracle(theAccumulator, termValueSet, theFilter, theAdd); - } - else { + } else { expandConcepts(theAccumulator, termValueSet, theFilter, theAdd); } } - private boolean isOracleDialect(){ + private boolean isOracleDialect() { return myHibernatePropertiesProvider.getDialect() instanceof org.hibernate.dialect.Oracle12cDialect; } @@ -794,7 +731,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } // Allow to search by the end of the phrase. E.g. "working proficiency" will match "Limited working proficiency" - for (int start = 0; start <= tokens.size() - 1; ++ start) { + for (int start = 0; start <= tokens.size() - 1; ++start) { for (int end = start + 1; end <= tokens.size(); ++end) { String sublist = String.join(" ", tokens.subList(start, end)); if (startsWithIgnoreCase(sublist, theFilterDisplay)) @@ -1130,14 +1067,14 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { SearchQuery termConceptsQuery = searchSession.search(TermConcept.class) .where(f -> finishedQuery).toQuery(); - System.out.println("About to query:" + termConceptsQuery.queryString()); + System.out.println("About to query:" + termConceptsQuery.queryString()); List termConcepts = termConceptsQuery.fetchHits(theQueryIndex * maxResultsPerBatch, maxResultsPerBatch); int resultsInBatch = termConcepts.size(); int firstResult = theQueryIndex * maxResultsPerBatch;// TODO GGG HS we lose the ability to check the index of the first result, so just best-guessing it here. int delta = 0; - for (TermConcept concept: termConcepts) { + for (TermConcept concept : termConcepts) { count.incrementAndGet(); countForBatch.incrementAndGet(); if (theAdd && expansionStep != null) { @@ -1455,7 +1392,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } - private void addDisplayFilterInexact(SearchPredicateFactory f, BooleanPredicateClausesStep bool, ValueSet.ConceptSetFilterComponent nextFilter) { bool.must(f.phrase() .field("myDisplay").boost(4.0f) @@ -1489,7 +1425,7 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { addLoincFilterDescendantEqual(theSystem, f, b, theFilter); break; case IN: - addLoincFilterDescendantIn(theSystem, f,b , theFilter); + addLoincFilterDescendantIn(theSystem, f, b, theFilter); break; default: throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty()); @@ -1545,7 +1481,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } - private void logFilteringValueOnProperty(String theValue, String theProperty) { ourLog.debug(" * Filtering with value={} on property {}", theValue, theProperty); } @@ -1859,26 +1794,9 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { RuleBasedTransactionAttribute rules = new RuleBasedTransactionAttribute(); rules.getRollbackRules().add(new NoRollbackRuleAttribute(ExpansionTooCostlyException.class)); myTxTemplate = new TransactionTemplate(myTransactionManager, rules); - buildTranslationCaches(); scheduleJob(); } - private void buildTranslationCaches() { - Long timeout = myDaoConfig.getTranslationCachesExpireAfterWriteInMinutes(); - - myTranslationCache = - Caffeine.newBuilder() - .maximumSize(10000) - .expireAfterWrite(timeout, TimeUnit.MINUTES) - .build(); - - myTranslationWithReverseCache = - Caffeine.newBuilder() - .maximumSize(10000) - .expireAfterWrite(timeout, TimeUnit.MINUTES) - .build(); - } - public void scheduleJob() { // Register scheduled job to pre-expand ValueSets // In the future it would be great to make this a cluster-aware task somehow @@ -1888,163 +1806,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { mySchedulerService.scheduleClusteredJob(10 * DateUtils.MILLIS_PER_MINUTE, vsJobDefinition); } - @Override - @Transactional - public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) { - - ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); - if (isPlaceholder(theConceptMap)) { - ourLog.info("Not storing TermConceptMap for placeholder {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); - return; - } - - ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url"); - ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); - - TermConceptMap termConceptMap = new TermConceptMap(); - termConceptMap.setResource(theResourceTable); - termConceptMap.setUrl(theConceptMap.getUrl()); - termConceptMap.setVersion(theConceptMap.getVersion()); - - String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null; - String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null; - - /* - * If this is a mapping between "resources" instead of purely between - * "concepts" (this is a weird concept that is technically possible, at least as of - * FHIR R4), don't try to store the mappings. - * - * See here for a description of what that is: - * http://hl7.org/fhir/conceptmap.html#bnr - */ - if ("StructureDefinition".equals(new IdType(source).getResourceType()) || - "StructureDefinition".equals(new IdType(target).getResourceType())) { - return; - } - - if (source == null && theConceptMap.hasSourceCanonicalType()) { - source = theConceptMap.getSourceCanonicalType().getValueAsString(); - } - if (target == null && theConceptMap.hasTargetCanonicalType()) { - target = theConceptMap.getTargetCanonicalType().getValueAsString(); - } - - /* - * For now we always delete old versions. At some point, it would be nice to allow configuration to keep old versions. - */ - deleteConceptMap(theResourceTable); - - /* - * Do the upload. - */ - String conceptMapUrl = termConceptMap.getUrl(); - String conceptMapVersion = termConceptMap.getVersion(); - Optional optionalExistingTermConceptMapByUrl; - if (isBlank(conceptMapVersion)) { - optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrlAndNullVersion(conceptMapUrl); - } else { - optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrlAndVersion(conceptMapUrl, conceptMapVersion); - } - if (!optionalExistingTermConceptMapByUrl.isPresent()) { - try { - if (isNotBlank(source)) { - termConceptMap.setSource(source); - } - if (isNotBlank(target)) { - termConceptMap.setTarget(target); - } - } catch (FHIRException fe) { - throw new InternalErrorException(fe); - } - termConceptMap = myConceptMapDao.save(termConceptMap); - int codesSaved = 0; - - if (theConceptMap.hasGroup()) { - TermConceptMapGroup termConceptMapGroup; - for (ConceptMap.ConceptMapGroupComponent group : theConceptMap.getGroup()) { - - String groupSource = group.getSource(); - if (isBlank(groupSource)) { - groupSource = source; - } - if (isBlank(groupSource)) { - throw new UnprocessableEntityException("ConceptMap[url='" + theConceptMap.getUrl() + "'] contains at least one group without a value in ConceptMap.group.source"); - } - - String groupTarget = group.getTarget(); - if (isBlank(groupTarget)) { - groupTarget = target; - } - if (isBlank(groupTarget)) { - throw new UnprocessableEntityException("ConceptMap[url='" + theConceptMap.getUrl() + "'] contains at least one group without a value in ConceptMap.group.target"); - } - - termConceptMapGroup = new TermConceptMapGroup(); - termConceptMapGroup.setConceptMap(termConceptMap); - termConceptMapGroup.setSource(groupSource); - termConceptMapGroup.setSourceVersion(group.getSourceVersion()); - termConceptMapGroup.setTarget(groupTarget); - termConceptMapGroup.setTargetVersion(group.getTargetVersion()); - myConceptMapGroupDao.save(termConceptMapGroup); - - if (group.hasElement()) { - TermConceptMapGroupElement termConceptMapGroupElement; - for (ConceptMap.SourceElementComponent element : group.getElement()) { - if (isBlank(element.getCode())) { - continue; - } - termConceptMapGroupElement = new TermConceptMapGroupElement(); - termConceptMapGroupElement.setConceptMapGroup(termConceptMapGroup); - termConceptMapGroupElement.setCode(element.getCode()); - termConceptMapGroupElement.setDisplay(element.getDisplay()); - myConceptMapGroupElementDao.save(termConceptMapGroupElement); - - if (element.hasTarget()) { - TermConceptMapGroupElementTarget termConceptMapGroupElementTarget; - for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) { - if (isBlank(elementTarget.getCode())) { - continue; - } - termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget(); - termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement); - termConceptMapGroupElementTarget.setCode(elementTarget.getCode()); - termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay()); - termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence()); - myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget); - - if (++codesSaved % 250 == 0) { - ourLog.info("Have saved {} codes in ConceptMap", codesSaved); - myConceptMapGroupElementTargetDao.flush(); - } - } - } - } - } - } - } - } else { - TermConceptMap existingTermConceptMap = optionalExistingTermConceptMapByUrl.get(); - - if (isBlank(conceptMapVersion)) { - String msg = myContext.getLocalizer().getMessage( - BaseTermReadSvcImpl.class, - "cannotCreateDuplicateConceptMapUrl", - conceptMapUrl, - existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue()); - throw new UnprocessableEntityException(msg); - - } else { - String msg = myContext.getLocalizer().getMessage( - BaseTermReadSvcImpl.class, - "cannotCreateDuplicateConceptMapUrlAndVersion", - conceptMapUrl, conceptMapVersion, - existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue()); - throw new UnprocessableEntityException(msg); - } - } - - ourLog.info("Done storing TermConceptMap[{}] for {}", termConceptMap.getId(), theConceptMap.getIdElement().toVersionless().getValueAsString()); - } @Override public synchronized void preExpandDeferredValueSetsToTerminologyTables() { @@ -2244,15 +2005,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } } - private boolean isPlaceholder(DomainResource theResource) { - boolean retVal = false; - Extension extension = theResource.getExtensionByUrl(HapiExtensions.EXT_RESOURCE_PLACEHOLDER); - if (extension != null && extension.hasValue() && extension.getValue() instanceof BooleanType) { - retVal = ((BooleanType) extension.getValue()).booleanValue(); - } - return retVal; - } - @Override @Transactional public IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType theCodeA, IPrimitiveType theCodeB, @@ -2362,7 +2114,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } } - private ArrayList toVersionIndependentConcepts(String theSystem, Set codes) { ArrayList retVal = new ArrayList<>(codes.size()); for (TermConcept next : codes) { @@ -2371,254 +2122,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { return retVal; } - @Override - @Transactional(propagation = Propagation.REQUIRED) - public List translate(TranslationRequest theTranslationRequest) { - List retVal = new ArrayList<>(); - - CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery query = criteriaBuilder.createQuery(TermConceptMapGroupElementTarget.class); - Root root = query.from(TermConceptMapGroupElementTarget.class); - - Join elementJoin = root.join("myConceptMapGroupElement"); - Join groupJoin = elementJoin.join("myConceptMapGroup"); - Join conceptMapJoin = groupJoin.join("myConceptMap"); - - List translationQueries = theTranslationRequest.getTranslationQueries(); - List cachedTargets; - ArrayList predicates; - Coding coding; - - //-- get the latest ConceptMapVersion if theTranslationRequest has ConceptMap url but no ConceptMap version - String latestConceptMapVersion = null; - if (theTranslationRequest.hasUrl() && !theTranslationRequest.hasConceptMapVersion()) - latestConceptMapVersion = getLatestConceptMapVersion(theTranslationRequest); - - for (TranslationQuery translationQuery : translationQueries) { - cachedTargets = myTranslationCache.getIfPresent(translationQuery); - if (cachedTargets == null) { - final List targets = new ArrayList<>(); - - predicates = new ArrayList<>(); - - coding = translationQuery.getCoding(); - if (coding.hasCode()) { - predicates.add(criteriaBuilder.equal(elementJoin.get("myCode"), coding.getCode())); - } else { - throw new InvalidRequestException("A code must be provided for translation to occur."); - } - - if (coding.hasSystem()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), coding.getSystem())); - } - - if (coding.hasVersion()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("mySourceVersion"), coding.getVersion())); - } - - if (translationQuery.hasTargetSystem()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), translationQuery.getTargetSystem().getValueAsString())); - } - - if (translationQuery.hasUrl()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myUrl"), translationQuery.getUrl().getValueAsString())); - if (translationQuery.hasConceptMapVersion()) { - // both url and conceptMapVersion - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), translationQuery.getConceptMapVersion().getValueAsString())); - } else { - if (StringUtils.isNotBlank(latestConceptMapVersion)) { - // only url and use latestConceptMapVersion - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), latestConceptMapVersion)); - } else { - predicates.add(criteriaBuilder.isNull(conceptMapJoin.get("myVersion"))); - } - } - } - - if (translationQuery.hasSource()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getSource().getValueAsString())); - } - - if (translationQuery.hasTarget()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getTarget().getValueAsString())); - } - - if (translationQuery.hasResourceId()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId())); - } - - Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0])); - query.where(outerPredicate); - - // Use scrollable results. - final TypedQuery typedQuery = myEntityManager.createQuery(query.select(root)); - org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) typedQuery; - hibernateQuery.setFetchSize(myFetchSize); - ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); - try (ScrollableResultsIterator scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) { - - while (scrollableResultsIterator.hasNext()) { - targets.add(scrollableResultsIterator.next()); - } - - } - - ourLastResultsFromTranslationCache = false; // For testing. - myTranslationCache.get(translationQuery, k -> targets); - retVal.addAll(targets); - } else { - ourLastResultsFromTranslationCache = true; // For testing. - retVal.addAll(cachedTargets); - } - } - - return retVal; - } - - @Override - @Transactional(propagation = Propagation.REQUIRED) - public List translateWithReverse(TranslationRequest theTranslationRequest) { - List retVal = new ArrayList<>(); - - CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder(); - CriteriaQuery query = criteriaBuilder.createQuery(TermConceptMapGroupElement.class); - Root root = query.from(TermConceptMapGroupElement.class); - - Join targetJoin = root.join("myConceptMapGroupElementTargets"); - Join groupJoin = root.join("myConceptMapGroup"); - Join conceptMapJoin = groupJoin.join("myConceptMap"); - - List translationQueries = theTranslationRequest.getTranslationQueries(); - List cachedElements; - ArrayList predicates; - Coding coding; - - //-- get the latest ConceptMapVersion if theTranslationRequest has ConceptMap url but no ConceptMap version - String latestConceptMapVersion = null; - if (theTranslationRequest.hasUrl() && !theTranslationRequest.hasConceptMapVersion()) - latestConceptMapVersion = getLatestConceptMapVersion(theTranslationRequest); - - for (TranslationQuery translationQuery : translationQueries) { - cachedElements = myTranslationWithReverseCache.getIfPresent(translationQuery); - if (cachedElements == null) { - final List elements = new ArrayList<>(); - - predicates = new ArrayList<>(); - - coding = translationQuery.getCoding(); - String targetCode; - String targetCodeSystem = null; - if (coding.hasCode()) { - predicates.add(criteriaBuilder.equal(targetJoin.get("myCode"), coding.getCode())); - targetCode = coding.getCode(); - } else { - throw new InvalidRequestException("A code must be provided for translation to occur."); - } - - if (coding.hasSystem()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), coding.getSystem())); - targetCodeSystem = coding.getSystem(); - } - - if (coding.hasVersion()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("myTargetVersion"), coding.getVersion())); - } - - if (translationQuery.hasUrl()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myUrl"), translationQuery.getUrl().getValueAsString())); - if (translationQuery.hasConceptMapVersion()) { - // both url and conceptMapVersion - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), translationQuery.getConceptMapVersion().getValueAsString())); - } else { - if (StringUtils.isNotBlank(latestConceptMapVersion)) { - // only url and use latestConceptMapVersion - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), latestConceptMapVersion)); - } else { - predicates.add(criteriaBuilder.isNull(conceptMapJoin.get("myVersion"))); - } - } - } - - if (translationQuery.hasTargetSystem()) { - predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), translationQuery.getTargetSystem().getValueAsString())); - } - - if (translationQuery.hasSource()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getSource().getValueAsString())); - } - - if (translationQuery.hasTarget()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getTarget().getValueAsString())); - } - - if (translationQuery.hasResourceId()) { - predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId())); - } - - Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0])); - query.where(outerPredicate); - - // Use scrollable results. - final TypedQuery typedQuery = myEntityManager.createQuery(query.select(root)); - org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) typedQuery; - hibernateQuery.setFetchSize(myFetchSize); - ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); - try (ScrollableResultsIterator scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) { - - while (scrollableResultsIterator.hasNext()) { - TermConceptMapGroupElement nextElement = scrollableResultsIterator.next(); - // TODO: The invocation of the size() below does not seem to be necessary but for some reason, removing it causes tests in TerminologySvcImplR4Test to fail. - nextElement.getConceptMapGroupElementTargets().size(); - myEntityManager.detach(nextElement); - - if (isNotBlank(targetCode) && isNotBlank(targetCodeSystem)) { - for (Iterator iter = nextElement.getConceptMapGroupElementTargets().iterator(); iter.hasNext(); ) { - TermConceptMapGroupElementTarget next = iter.next(); - if (StringUtils.equals(targetCodeSystem, next.getSystem())) { - if (StringUtils.equals(targetCode, next.getCode())) { - continue; - } - } - - iter.remove(); - } - } - - elements.add(nextElement); - } - - } - - ourLastResultsFromTranslationWithReverseCache = false; // For testing. - myTranslationWithReverseCache.get(translationQuery, k -> elements); - retVal.addAll(elements); - } else { - ourLastResultsFromTranslationWithReverseCache = true; // For testing. - retVal.addAll(cachedElements); - } - } - - return retVal; - } - - void throwInvalidValueSet(String theValueSet) { - throw new ResourceNotFoundException("Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSet)); - } - - // Special case for the translate operation with url and without - // conceptMapVersion, find the latest conecptMapVersion - private String getLatestConceptMapVersion(TranslationRequest theTranslationRequest) { - - Pageable page = PageRequest.of(0, 1); - List theConceptMapList = myConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, - theTranslationRequest.getUrl().asStringValue()); - if (!theConceptMapList.isEmpty()) { - return theConceptMapList.get(0).getVersion(); - } - - return null; - } - @Override @Transactional public CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { @@ -2659,7 +2162,6 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { return createFailureCodeValidationResult(theCodeSystem, theCode); } - IValidationSupport.CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theValidationOptions, String theValueSetUrl, String theCodeSystem, String theCode, String theDisplay) { IBaseResource valueSet = theValidationSupportContext.getRootValidationSupport().fetchValueSet(theValueSetUrl); @@ -2962,6 +2464,15 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { } } + static boolean isPlaceholder(DomainResource theResource) { + boolean retVal = false; + Extension extension = theResource.getExtensionByUrl(HapiExtensions.EXT_RESOURCE_PLACEHOLDER); + if (extension != null && extension.hasValue() && extension.getValue() instanceof BooleanType) { + retVal = ((BooleanType) extension.getValue()).booleanValue(); + } + return retVal; + } + /** * This is only used for unit tests to test failure conditions */ @@ -3039,35 +2550,4 @@ public abstract class BaseTermReadSvcImpl implements ITermReadSvc { return termConcept; } - /** - * This method is present only for unit tests, do not call from client code - */ - @VisibleForTesting - public static void clearOurLastResultsFromTranslationCache() { - ourLastResultsFromTranslationCache = false; - } - - /** - * This method is present only for unit tests, do not call from client code - */ - @VisibleForTesting - public static void clearOurLastResultsFromTranslationWithReverseCache() { - ourLastResultsFromTranslationWithReverseCache = false; - } - - /** - * This method is present only for unit tests, do not call from client code - */ - @VisibleForTesting - static boolean isOurLastResultsFromTranslationCache() { - return ourLastResultsFromTranslationCache; - } - - /** - * This method is present only for unit tests, do not call from client code - */ - @VisibleForTesting - static boolean isOurLastResultsFromTranslationWithReverseCache() { - return ourLastResultsFromTranslationWithReverseCache; - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImpl.java new file mode 100644 index 00000000000..5817e396960 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImpl.java @@ -0,0 +1,698 @@ +package ca.uhn.fhir.jpa.term; + +/*- + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.TranslateConceptResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.jpa.api.model.TranslationQuery; +import ca.uhn.fhir.jpa.api.model.TranslationRequest; +import ca.uhn.fhir.jpa.dao.data.ITermConceptMapDao; +import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupDao; +import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupElementDao; +import ca.uhn.fhir.jpa.dao.data.ITermConceptMapGroupElementTargetDao; +import ca.uhn.fhir.jpa.entity.TermConceptMap; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroup; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; +import ca.uhn.fhir.jpa.model.entity.ResourceTable; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; +import ca.uhn.fhir.jpa.util.MemoryCacheService; +import ca.uhn.fhir.jpa.util.ScrollableResultsIterator; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.util.ValidateUtil; +import com.google.common.annotations.VisibleForTesting; +import org.apache.commons.lang3.StringUtils; +import org.hibernate.ScrollMode; +import org.hibernate.ScrollableResults; +import org.hl7.fhir.exceptions.FHIRException; +import org.hl7.fhir.r4.model.BooleanType; +import org.hl7.fhir.r4.model.CodeType; +import org.hl7.fhir.r4.model.CodeableConcept; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.ConceptMap; +import org.hl7.fhir.r4.model.IdType; +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.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import javax.persistence.EntityManager; +import javax.persistence.PersistenceContext; +import javax.persistence.PersistenceContextType; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Join; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; +import java.util.Set; + +import static ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl.isPlaceholder; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +public class TermConceptMappingSvcImpl implements ITermConceptMappingSvc { + + private static final Logger ourLog = LoggerFactory.getLogger(TermConceptMappingSvcImpl.class); + private static boolean ourLastResultsFromTranslationCache; // For testing. + private static boolean ourLastResultsFromTranslationWithReverseCache; // For testing. + private final int myFetchSize = BaseTermReadSvcImpl.DEFAULT_FETCH_SIZE; + @Autowired + protected ITermConceptMapDao myConceptMapDao; + @Autowired + protected ITermConceptMapGroupDao myConceptMapGroupDao; + @Autowired + protected ITermConceptMapGroupElementDao myConceptMapGroupElementDao; + @Autowired + protected ITermConceptMapGroupElementTargetDao myConceptMapGroupElementTargetDao; + @PersistenceContext(type = PersistenceContextType.TRANSACTION) + protected EntityManager myEntityManager; + @Autowired + private FhirContext myContext; + @Autowired + private MemoryCacheService myMemoryCacheService; + + @Override + @Transactional + public void deleteConceptMapAndChildren(ResourceTable theResourceTable) { + deleteConceptMap(theResourceTable); + } + + @Override + public FhirContext getFhirContext() { + return myContext; + } + + @Override + @Transactional + public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { + + CodeableConcept sourceCodeableConcept = new CodeableConcept(); + sourceCodeableConcept + .addCoding() + .setSystem(theRequest.getSourceSystemUrl()) + .setCode(theRequest.getSourceCode()); + + TranslationRequest request = new TranslationRequest(); + request.setCodeableConcept(sourceCodeableConcept); + request.setTargetSystem(new UriType(theRequest.getTargetSystemUrl())); + + return translate(request); + } + + @Override + @Transactional + public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) { + + ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied"); + if (isPlaceholder(theConceptMap)) { + ourLog.info("Not storing TermConceptMap for placeholder {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); + return; + } + + ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url"); + ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString()); + + TermConceptMap termConceptMap = new TermConceptMap(); + termConceptMap.setResource(theResourceTable); + termConceptMap.setUrl(theConceptMap.getUrl()); + termConceptMap.setVersion(theConceptMap.getVersion()); + + String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null; + String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null; + + /* + * If this is a mapping between "resources" instead of purely between + * "concepts" (this is a weird concept that is technically possible, at least as of + * FHIR R4), don't try to store the mappings. + * + * See here for a description of what that is: + * http://hl7.org/fhir/conceptmap.html#bnr + */ + if ("StructureDefinition".equals(new IdType(source).getResourceType()) || + "StructureDefinition".equals(new IdType(target).getResourceType())) { + return; + } + + if (source == null && theConceptMap.hasSourceCanonicalType()) { + source = theConceptMap.getSourceCanonicalType().getValueAsString(); + } + if (target == null && theConceptMap.hasTargetCanonicalType()) { + target = theConceptMap.getTargetCanonicalType().getValueAsString(); + } + + /* + * For now we always delete old versions. At some point, it would be nice to allow configuration to keep old versions. + */ + deleteConceptMap(theResourceTable); + + /* + * Do the upload. + */ + String conceptMapUrl = termConceptMap.getUrl(); + String conceptMapVersion = termConceptMap.getVersion(); + Optional optionalExistingTermConceptMapByUrl; + if (isBlank(conceptMapVersion)) { + optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrlAndNullVersion(conceptMapUrl); + } else { + optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrlAndVersion(conceptMapUrl, conceptMapVersion); + } + if (!optionalExistingTermConceptMapByUrl.isPresent()) { + try { + if (isNotBlank(source)) { + termConceptMap.setSource(source); + } + if (isNotBlank(target)) { + termConceptMap.setTarget(target); + } + } catch (FHIRException fe) { + throw new InternalErrorException(fe); + } + termConceptMap = myConceptMapDao.save(termConceptMap); + int codesSaved = 0; + + if (theConceptMap.hasGroup()) { + TermConceptMapGroup termConceptMapGroup; + for (ConceptMap.ConceptMapGroupComponent group : theConceptMap.getGroup()) { + + String groupSource = group.getSource(); + if (isBlank(groupSource)) { + groupSource = source; + } + if (isBlank(groupSource)) { + throw new UnprocessableEntityException("ConceptMap[url='" + theConceptMap.getUrl() + "'] contains at least one group without a value in ConceptMap.group.source"); + } + + String groupTarget = group.getTarget(); + if (isBlank(groupTarget)) { + groupTarget = target; + } + if (isBlank(groupTarget)) { + throw new UnprocessableEntityException("ConceptMap[url='" + theConceptMap.getUrl() + "'] contains at least one group without a value in ConceptMap.group.target"); + } + + termConceptMapGroup = new TermConceptMapGroup(); + termConceptMapGroup.setConceptMap(termConceptMap); + termConceptMapGroup.setSource(groupSource); + termConceptMapGroup.setSourceVersion(group.getSourceVersion()); + termConceptMapGroup.setTarget(groupTarget); + termConceptMapGroup.setTargetVersion(group.getTargetVersion()); + myConceptMapGroupDao.save(termConceptMapGroup); + + if (group.hasElement()) { + TermConceptMapGroupElement termConceptMapGroupElement; + for (ConceptMap.SourceElementComponent element : group.getElement()) { + if (isBlank(element.getCode())) { + continue; + } + termConceptMapGroupElement = new TermConceptMapGroupElement(); + termConceptMapGroupElement.setConceptMapGroup(termConceptMapGroup); + termConceptMapGroupElement.setCode(element.getCode()); + termConceptMapGroupElement.setDisplay(element.getDisplay()); + myConceptMapGroupElementDao.save(termConceptMapGroupElement); + + if (element.hasTarget()) { + TermConceptMapGroupElementTarget termConceptMapGroupElementTarget; + for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) { + if (isBlank(elementTarget.getCode())) { + continue; + } + termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget(); + termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement); + termConceptMapGroupElementTarget.setCode(elementTarget.getCode()); + termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay()); + termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence()); + myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget); + + if (++codesSaved % 250 == 0) { + ourLog.info("Have saved {} codes in ConceptMap", codesSaved); + myConceptMapGroupElementTargetDao.flush(); + } + } + } + } + } + } + } + } else { + TermConceptMap existingTermConceptMap = optionalExistingTermConceptMapByUrl.get(); + + if (isBlank(conceptMapVersion)) { + String msg = myContext.getLocalizer().getMessage( + BaseTermReadSvcImpl.class, + "cannotCreateDuplicateConceptMapUrl", + conceptMapUrl, + existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue()); + throw new UnprocessableEntityException(msg); + + } else { + String msg = myContext.getLocalizer().getMessage( + BaseTermReadSvcImpl.class, + "cannotCreateDuplicateConceptMapUrlAndVersion", + conceptMapUrl, conceptMapVersion, + existingTermConceptMap.getResource().getIdDt().toUnqualifiedVersionless().getValue()); + throw new UnprocessableEntityException(msg); + } + } + + ourLog.info("Done storing TermConceptMap[{}] for {}", termConceptMap.getId(), theConceptMap.getIdElement().toVersionless().getValueAsString()); + } + + @Override + @Transactional(propagation = Propagation.REQUIRED) + public TranslateConceptResults translate(TranslationRequest theTranslationRequest) { + TranslateConceptResults retVal = new TranslateConceptResults(); + + CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder(); + CriteriaQuery query = criteriaBuilder.createQuery(TermConceptMapGroupElementTarget.class); + Root root = query.from(TermConceptMapGroupElementTarget.class); + + Join elementJoin = root.join("myConceptMapGroupElement"); + Join groupJoin = elementJoin.join("myConceptMapGroup"); + Join conceptMapJoin = groupJoin.join("myConceptMap"); + + List translationQueries = theTranslationRequest.getTranslationQueries(); + List cachedTargets; + ArrayList predicates; + Coding coding; + + //-- get the latest ConceptMapVersion if theTranslationRequest has ConceptMap url but no ConceptMap version + String latestConceptMapVersion = null; + if (theTranslationRequest.hasUrl() && !theTranslationRequest.hasConceptMapVersion()) + latestConceptMapVersion = getLatestConceptMapVersion(theTranslationRequest); + + for (TranslationQuery translationQuery : translationQueries) { + cachedTargets = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.CONCEPT_TRANSLATION, translationQuery); + if (cachedTargets == null) { + final List targets = new ArrayList<>(); + + predicates = new ArrayList<>(); + + coding = translationQuery.getCoding(); + if (coding.hasCode()) { + predicates.add(criteriaBuilder.equal(elementJoin.get("myCode"), coding.getCode())); + } else { + throw new InvalidRequestException("A code must be provided for translation to occur."); + } + + if (coding.hasSystem()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), coding.getSystem())); + } + + if (coding.hasVersion()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("mySourceVersion"), coding.getVersion())); + } + + if (translationQuery.hasTargetSystem()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), translationQuery.getTargetSystem().getValueAsString())); + } + + if (translationQuery.hasUrl()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myUrl"), translationQuery.getUrl().getValueAsString())); + if (translationQuery.hasConceptMapVersion()) { + // both url and conceptMapVersion + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), translationQuery.getConceptMapVersion().getValueAsString())); + } else { + if (StringUtils.isNotBlank(latestConceptMapVersion)) { + // only url and use latestConceptMapVersion + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), latestConceptMapVersion)); + } else { + predicates.add(criteriaBuilder.isNull(conceptMapJoin.get("myVersion"))); + } + } + } + + if (translationQuery.hasSource()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getSource().getValueAsString())); + } + + if (translationQuery.hasTarget()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getTarget().getValueAsString())); + } + + if (translationQuery.hasResourceId()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId())); + } + + Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0])); + query.where(outerPredicate); + + // Use scrollable results. + final TypedQuery typedQuery = myEntityManager.createQuery(query.select(root)); + org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) typedQuery; + hibernateQuery.setFetchSize(myFetchSize); + ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); + try (ScrollableResultsIterator scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) { + + Set matches = new HashSet<>(); + while (scrollableResultsIterator.hasNext()) { + TermConceptMapGroupElementTarget next = scrollableResultsIterator.next(); + if (matches.add(next)) { + + TranslateConceptResult translationMatch = new TranslateConceptResult(); + if (next.getEquivalence() != null) { + translationMatch.setEquivalence(next.getEquivalence().toCode()); + } + + translationMatch.setCode(next.getCode()); + translationMatch.setSystem(next.getSystem()); + translationMatch.setSystemVersion(next.getSystemVersion()); + translationMatch.setDisplay(next.getDisplay()); + translationMatch.setValueSet(next.getValueSet()); + translationMatch.setSystemVersion(next.getSystemVersion()); + translationMatch.setConceptMapUrl(next.getConceptMapUrl()); + + targets.add(translationMatch); + } + } + + } + + ourLastResultsFromTranslationCache = false; // For testing. + myMemoryCacheService.put(MemoryCacheService.CacheEnum.CONCEPT_TRANSLATION, translationQuery, targets); + retVal.getResults().addAll(targets); + } else { + ourLastResultsFromTranslationCache = true; // For testing. + retVal.getResults().addAll(cachedTargets); + } + } + + buildTranslationResult(retVal); + return retVal; + } + + @Override + @Transactional(propagation = Propagation.REQUIRED) + public TranslateConceptResults translateWithReverse(TranslationRequest theTranslationRequest) { + TranslateConceptResults retVal = new TranslateConceptResults(); + + CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder(); + CriteriaQuery query = criteriaBuilder.createQuery(TermConceptMapGroupElement.class); + Root root = query.from(TermConceptMapGroupElement.class); + + Join targetJoin = root.join("myConceptMapGroupElementTargets"); + Join groupJoin = root.join("myConceptMapGroup"); + Join conceptMapJoin = groupJoin.join("myConceptMap"); + + List translationQueries = theTranslationRequest.getTranslationQueries(); + List cachedElements; + ArrayList predicates; + Coding coding; + + //-- get the latest ConceptMapVersion if theTranslationRequest has ConceptMap url but no ConceptMap version + String latestConceptMapVersion = null; + if (theTranslationRequest.hasUrl() && !theTranslationRequest.hasConceptMapVersion()) + latestConceptMapVersion = getLatestConceptMapVersion(theTranslationRequest); + + for (TranslationQuery translationQuery : translationQueries) { + cachedElements = myMemoryCacheService.getIfPresent(MemoryCacheService.CacheEnum.CONCEPT_TRANSLATION_REVERSE, translationQuery); + if (cachedElements == null) { + final List elements = new ArrayList<>(); + + predicates = new ArrayList<>(); + + coding = translationQuery.getCoding(); + String targetCode; + String targetCodeSystem = null; + if (coding.hasCode()) { + predicates.add(criteriaBuilder.equal(targetJoin.get("myCode"), coding.getCode())); + targetCode = coding.getCode(); + } else { + throw new InvalidRequestException("A code must be provided for translation to occur."); + } + + if (coding.hasSystem()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("myTarget"), coding.getSystem())); + targetCodeSystem = coding.getSystem(); + } + + if (coding.hasVersion()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("myTargetVersion"), coding.getVersion())); + } + + if (translationQuery.hasUrl()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myUrl"), translationQuery.getUrl().getValueAsString())); + if (translationQuery.hasConceptMapVersion()) { + // both url and conceptMapVersion + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), translationQuery.getConceptMapVersion().getValueAsString())); + } else { + if (StringUtils.isNotBlank(latestConceptMapVersion)) { + // only url and use latestConceptMapVersion + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myVersion"), latestConceptMapVersion)); + } else { + predicates.add(criteriaBuilder.isNull(conceptMapJoin.get("myVersion"))); + } + } + } + + if (translationQuery.hasTargetSystem()) { + predicates.add(criteriaBuilder.equal(groupJoin.get("mySource"), translationQuery.getTargetSystem().getValueAsString())); + } + + if (translationQuery.hasSource()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myTarget"), translationQuery.getSource().getValueAsString())); + } + + if (translationQuery.hasTarget()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("mySource"), translationQuery.getTarget().getValueAsString())); + } + + if (translationQuery.hasResourceId()) { + predicates.add(criteriaBuilder.equal(conceptMapJoin.get("myResourcePid"), translationQuery.getResourceId())); + } + + Predicate outerPredicate = criteriaBuilder.and(predicates.toArray(new Predicate[0])); + query.where(outerPredicate); + + // Use scrollable results. + final TypedQuery typedQuery = myEntityManager.createQuery(query.select(root)); + org.hibernate.query.Query hibernateQuery = (org.hibernate.query.Query) typedQuery; + hibernateQuery.setFetchSize(myFetchSize); + ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY); + try (ScrollableResultsIterator scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) { + + Set matches = new HashSet<>(); + while (scrollableResultsIterator.hasNext()) { + TermConceptMapGroupElement nextElement = scrollableResultsIterator.next(); + + // TODO: The invocation of the size() below does not seem to be necessary but for some reason, removing it causes tests in TerminologySvcImplR4Test to fail. + nextElement.getConceptMapGroupElementTargets().size(); + + myEntityManager.detach(nextElement); + + if (isNotBlank(targetCode)) { + for (TermConceptMapGroupElementTarget next : nextElement.getConceptMapGroupElementTargets()) { + if (matches.add(next)) { + if (isBlank(targetCodeSystem) || StringUtils.equals(targetCodeSystem, next.getSystem())) { + if (StringUtils.equals(targetCode, next.getCode())) { + TranslateConceptResult translationMatch = new TranslateConceptResult(); + translationMatch.setCode(nextElement.getCode()); + translationMatch.setSystem(nextElement.getSystem()); + translationMatch.setSystemVersion(nextElement.getSystemVersion()); + translationMatch.setDisplay(nextElement.getDisplay()); + translationMatch.setValueSet(nextElement.getValueSet()); + translationMatch.setSystemVersion(nextElement.getSystemVersion()); + translationMatch.setConceptMapUrl(nextElement.getConceptMapUrl()); + if (next.getEquivalence() != null) { + translationMatch.setEquivalence(next.getEquivalence().toCode()); + } + + if (alreadyContainsMapping(elements, translationMatch) || alreadyContainsMapping(retVal.getResults(), translationMatch)) { + continue; + } + + elements.add(translationMatch); + } + } + + } + } + } + } + + } + + ourLastResultsFromTranslationWithReverseCache = false; // For testing. + myMemoryCacheService.put(MemoryCacheService.CacheEnum.CONCEPT_TRANSLATION_REVERSE, translationQuery, elements); + retVal.getResults().addAll(elements); + } else { + ourLastResultsFromTranslationWithReverseCache = true; // For testing. + retVal.getResults().addAll(cachedElements); + } + } + + buildTranslationResult(retVal); + return retVal; + } + + private boolean alreadyContainsMapping(List elements, TranslateConceptResult translationMatch) { + for (TranslateConceptResult nextExistingElement : elements) { + if (nextExistingElement.getSystem().equals(translationMatch.getSystem())) { + if (nextExistingElement.getSystemVersion().equals(translationMatch.getSystemVersion())) { + if (nextExistingElement.getCode().equals(translationMatch.getCode())) { + return true; + } + } + } + } + return false; + } + + public void deleteConceptMap(ResourceTable theResourceTable) { + // Get existing entity so it can be deleted. + Optional optionalExistingTermConceptMapById = myConceptMapDao.findTermConceptMapByResourcePid(theResourceTable.getId()); + + if (optionalExistingTermConceptMapById.isPresent()) { + TermConceptMap existingTermConceptMap = optionalExistingTermConceptMapById.get(); + + ourLog.info("Deleting existing TermConceptMap[{}] and its children...", existingTermConceptMap.getId()); + for (TermConceptMapGroup group : existingTermConceptMap.getConceptMapGroups()) { + + for (TermConceptMapGroupElement element : group.getConceptMapGroupElements()) { + + for (TermConceptMapGroupElementTarget target : element.getConceptMapGroupElementTargets()) { + + myConceptMapGroupElementTargetDao.deleteTermConceptMapGroupElementTargetById(target.getId()); + } + + myConceptMapGroupElementDao.deleteTermConceptMapGroupElementById(element.getId()); + } + + myConceptMapGroupDao.deleteTermConceptMapGroupById(group.getId()); + } + + myConceptMapDao.deleteTermConceptMapById(existingTermConceptMap.getId()); + ourLog.info("Done deleting existing TermConceptMap[{}] and its children.", existingTermConceptMap.getId()); + } + } + + // Special case for the translate operation with url and without + // conceptMapVersion, find the latest conecptMapVersion + private String getLatestConceptMapVersion(TranslationRequest theTranslationRequest) { + + Pageable page = PageRequest.of(0, 1); + List theConceptMapList = myConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, + theTranslationRequest.getUrl().asStringValue()); + if (!theConceptMapList.isEmpty()) { + return theConceptMapList.get(0).getVersion(); + } + + return null; + } + + private void buildTranslationResult(TranslateConceptResults theTranslationResult) { + + String msg; + if (theTranslationResult.getResults().isEmpty()) { + theTranslationResult.setResult(false); + msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "noMatchesFound"); + theTranslationResult.setMessage(msg); + } else { + theTranslationResult.setResult(true); + msg = myContext.getLocalizer().getMessage(TermConceptMappingSvcImpl.class, "matchesFound"); + theTranslationResult.setMessage(msg); + } + + } + + + /** + * This method is present only for unit tests, do not call from client code + */ + @VisibleForTesting + public static void clearOurLastResultsFromTranslationCache() { + ourLastResultsFromTranslationCache = false; + } + + /** + * This method is present only for unit tests, do not call from client code + */ + @VisibleForTesting + public static void clearOurLastResultsFromTranslationWithReverseCache() { + ourLastResultsFromTranslationWithReverseCache = false; + } + + /** + * This method is present only for unit tests, do not call from client code + */ + @VisibleForTesting + static boolean isOurLastResultsFromTranslationCache() { + return ourLastResultsFromTranslationCache; + } + + /** + * This method is present only for unit tests, do not call from client code + */ + @VisibleForTesting + static boolean isOurLastResultsFromTranslationWithReverseCache() { + return ourLastResultsFromTranslationWithReverseCache; + } + + public static Parameters toParameters(TranslateConceptResults theTranslationResult) { + Parameters retVal = new Parameters(); + + retVal.addParameter().setName("result").setValue(new BooleanType(theTranslationResult.getResult())); + + if (theTranslationResult.getMessage() != null) { + retVal.addParameter().setName("message").setValue(new StringType(theTranslationResult.getMessage())); + } + + for (TranslateConceptResult translationMatch : theTranslationResult.getResults()) { + Parameters.ParametersParameterComponent matchParam = retVal.addParameter().setName("match"); + populateTranslateMatchParts(translationMatch, matchParam); + } + + return retVal; + } + + private static void populateTranslateMatchParts(TranslateConceptResult theTranslationMatch, Parameters.ParametersParameterComponent theParam) { + if (theTranslationMatch.getEquivalence() != null) { + theParam.addPart().setName("equivalence").setValue(new CodeType(theTranslationMatch.getEquivalence())); + } + + if (isNotBlank(theTranslationMatch.getSystem()) || isNotBlank(theTranslationMatch.getCode()) || isNotBlank(theTranslationMatch.getDisplay())) { + Coding value = new Coding(theTranslationMatch.getSystem(), theTranslationMatch.getCode(), theTranslationMatch.getDisplay()); + + if (isNotBlank(theTranslationMatch.getSystemVersion())) { + value.setVersion(theTranslationMatch.getSystemVersion()); + } + + theParam.addPart().setName("concept").setValue(value); + } + + if (isNotBlank(theTranslationMatch.getConceptMapUrl())) { + theParam.addPart().setName("source").setValue(new UriType(theTranslationMatch.getConceptMapUrl())); + } + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcDstu3.java index c56764edc28..5ed129c071e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcDstu3.java @@ -22,6 +22,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import static org.hl7.fhir.convertors.conv30_40.ValueSet30_40.convertValueSet; @@ -61,7 +62,7 @@ public class TermReadSvcDstu3 extends BaseTermReadSvcImpl implements IValidation @Override - public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { try { org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4; valueSetToExpandR4 = toCanonicalValueSet(theValueSetToExpand); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR4.java index f898803d580..576669c0ecc 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR4.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR4.java @@ -18,6 +18,7 @@ import org.hl7.fhir.r4.model.ValueSet; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; +import javax.annotation.Nonnull; import javax.transaction.Transactional; /* @@ -59,7 +60,7 @@ public class TermReadSvcR4 extends BaseTermReadSvcImpl implements ITermReadSvcR4 @Transactional(dontRollbackOn = {ExpansionTooCostlyException.class}) @Override - public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { ValueSet expanded = super.expandValueSet(theExpansionOptions, (ValueSet) theValueSetToExpand); return new IValidationSupport.ValueSetExpansionOutcome(expanded); } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR5.java index 4c74d2a71c0..5c2f7c08d86 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR5.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcR5.java @@ -24,6 +24,7 @@ import org.hl7.fhir.utilities.validation.ValidationOptions; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.PlatformTransactionManager; +import javax.annotation.Nonnull; import javax.annotation.Nullable; import javax.transaction.Transactional; @@ -56,7 +57,7 @@ public class TermReadSvcR5 extends BaseTermReadSvcImpl implements IValidationSup @Override @Transactional(dontRollbackOn = {ExpansionTooCostlyException.class}) - public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand; org.hl7.fhir.r4.model.ValueSet expandedR4 = super.expandValueSet(theExpansionOptions, org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(valueSetToExpand)); return new ValueSetExpansionOutcome(org.hl7.fhir.convertors.conv40_50.ValueSet40_50.convertValueSet(expandedR4)); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermConceptMappingSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermConceptMappingSvc.java new file mode 100644 index 00000000000..a1f0b14a729 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermConceptMappingSvc.java @@ -0,0 +1,42 @@ +package ca.uhn.fhir.jpa.term.api; + +/*- + * #%L + * HAPI FHIR JPA Server + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.jpa.api.model.TranslationRequest; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.jpa.model.entity.ResourceTable; +import org.hl7.fhir.r4.model.ConceptMap; + +public interface ITermConceptMappingSvc extends IValidationSupport { + + + TranslateConceptResults translate(TranslationRequest theTranslationRequest); + + TranslateConceptResults translateWithReverse(TranslationRequest theTranslationRequest); + + void deleteConceptMapAndChildren(ResourceTable theResourceTable); + + void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap); + + + +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermReadSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermReadSvc.java index 0ab828c3613..94e482fddba 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermReadSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/api/ITermReadSvc.java @@ -91,18 +91,10 @@ public interface ITermReadSvc extends IValidationSupport { CodeSystem fetchCanonicalCodeSystemFromCompleteContext(String theSystem); - void deleteConceptMapAndChildren(ResourceTable theResourceTable); - void deleteValueSetAndChildren(ResourceTable theResourceTable); - void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap); - void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet); - List translate(TranslationRequest theTranslationRequest); - - List translateWithReverse(TranslationRequest theTranslationRequest); - IFhirResourceDaoCodeSystem.SubsumesResult subsumes(IPrimitiveType theCodeA, IPrimitiveType theCodeB, IPrimitiveType theSystem, IBaseCoding theCodingA, IBaseCoding theCodingB); void preExpandDeferredValueSetsToTerminologyTables(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java index c78420df9e8..9681f125613 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/MemoryCacheService.java @@ -20,8 +20,10 @@ package ca.uhn.fhir.jpa.util; * #L% */ +import ca.uhn.fhir.jpa.api.config.DaoConfig; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import org.springframework.beans.factory.annotation.Autowired; import javax.annotation.PostConstruct; import java.util.EnumMap; @@ -39,6 +41,9 @@ import java.util.function.Function; */ public class MemoryCacheService { + @Autowired + private DaoConfig myDaoConfig; + private EnumMap> myCaches; @PostConstruct @@ -47,7 +52,23 @@ public class MemoryCacheService { myCaches = new EnumMap<>(CacheEnum.class); for (CacheEnum next : CacheEnum.values()) { - Cache nextCache = Caffeine.newBuilder().expireAfterWrite(1, TimeUnit.MINUTES).maximumSize(10000).build(); + + long timeoutSeconds; + switch (next) { + case CONCEPT_TRANSLATION: + case CONCEPT_TRANSLATION_REVERSE: + timeoutSeconds = myDaoConfig.getTranslationCachesExpireAfterWriteInMinutes() * 1000; + break; + case TAG_DEFINITION: + case PERSISTENT_ID: + case RESOURCE_LOOKUP: + case FORCED_ID: + default: + timeoutSeconds = 60; + break; + } + + Cache nextCache = Caffeine.newBuilder().expireAfterWrite(timeoutSeconds, TimeUnit.MINUTES).maximumSize(10000).build(); myCaches.put(next, nextCache); } @@ -85,6 +106,8 @@ public class MemoryCacheService { PERSISTENT_ID, RESOURCE_LOOKUP, FORCED_ID, + CONCEPT_TRANSLATION, + CONCEPT_TRANSLATION_REVERSE } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChain.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChain.java index e3d50ce141a..508bdf3b148 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChain.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaValidationSupportChain.java @@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.validation; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.jpa.packages.NpmJpaValidationSupport; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService; import org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport; @@ -49,6 +50,8 @@ public class JpaValidationSupportChain extends ValidationSupportChain { private ITermReadSvc myTerminologyService; @Autowired private NpmJpaValidationSupport myNpmJpaValidationSupport; + @Autowired + private ITermConceptMappingSvc myConceptMappingSvc; public JpaValidationSupportChain(FhirContext theFhirContext) { myFhirContext = theFhirContext; @@ -73,6 +76,7 @@ public class JpaValidationSupportChain extends ValidationSupportChain { addValidationSupport(new InMemoryTerminologyServerValidationSupport(myFhirContext)); addValidationSupport(myNpmJpaValidationSupport); addValidationSupport(new CommonCodeSystemsTerminologyService(myFhirContext)); + addValidationSupport(myConceptMappingSvc); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java index 3680f0247a5..9f86a56cde1 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java @@ -42,6 +42,7 @@ import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; @@ -363,8 +364,8 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest { public void afterClearTerminologyCaches() { BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc); baseHapiTerminologySvc.clearCaches(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); TermDeferredStorageSvcImpl deferredSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc); deferredSvc.clearDeferred(); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ConceptMapTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ConceptMapTest.java index 32cee6db0c2..7f390e8a904 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ConceptMapTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ConceptMapTest.java @@ -1,17 +1,12 @@ package ca.uhn.fhir.jpa.dao.dstu3; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.List; -import java.util.Optional; - +import ca.uhn.fhir.context.support.TranslateConceptResult; +import ca.uhn.fhir.jpa.api.model.TranslationRequest; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.jpa.entity.TermConceptMap; import org.hl7.fhir.dstu3.model.ConceptMap; import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus; import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.UriType; import org.junit.jupiter.api.BeforeEach; @@ -23,10 +18,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; -import ca.uhn.fhir.jpa.api.model.TranslationMatch; -import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; -import ca.uhn.fhir.jpa.entity.TermConceptMap; +import java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3ConceptMapTest.class); @@ -52,9 +50,9 @@ public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertFalse(translationResult.getResult().booleanValue()); + assertFalse(translationResult.getResult()); } }); @@ -76,32 +74,28 @@ public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); // } }); @@ -109,34 +103,34 @@ public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { @Test public void testConceptMapFindTermConceptMapByUrl() { - + Pageable page = PageRequest.of(0, 1); List theExpConceptMapList = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); assertEquals(1, theExpConceptMapList.size()); assertEquals(CM_URL, theExpConceptMapList.get(0).getUrl()); - + } @Test public void testConceptMapTwoConceptMapWithSameUrlDifferentVersion() { - + String theUrl = "http://loinc.org/property/analyte-suffix"; ConceptMap theConceptMap1 = new ConceptMap(); ConceptMap theConceptMap2 = new ConceptMap(); - + theConceptMap1.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name1").setVersion("v1"); theConceptMap2.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name2").setVersion("v2"); - + myConceptMapDao.create(theConceptMap1); myConceptMapDao.create(theConceptMap2); - + Optional theExpConceptMapV1 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v1"); Optional theExpConceptMapV2 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v2"); - + assertTrue(theExpConceptMapV1.isPresent()); assertEquals(theUrl, theExpConceptMapV1.get().getUrl()); assertEquals("v1", theExpConceptMapV1.get().getVersion()); - + assertTrue(theExpConceptMapV2.isPresent()); assertEquals(theUrl, theExpConceptMapV2.get().getUrl()); assertEquals("v2", theExpConceptMapV2.get().getVersion()); @@ -144,7 +138,7 @@ public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { // should return the latest one which is v2 Pageable page = PageRequest.of(0, 1); List theExpSecondOne = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, theUrl); - + assertEquals(1, theExpSecondOne.size()); assertEquals(theUrl, theExpSecondOne.get(0).getUrl()); assertEquals("v2", theExpSecondOne.get(0).getVersion()); @@ -152,29 +146,29 @@ public class FhirResourceDaoDstu3ConceptMapTest extends BaseJpaDstu3Test { @Test public void testConceptMapTwoConceptMapWithSameUrlOneWithoutVersion() { - + String theUrl = "http://loinc.org/property/analyte-suffix"; ConceptMap theConceptMap1 = new ConceptMap(); ConceptMap theConceptMap2 = new ConceptMap(); - + theConceptMap1.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name1").setVersion("v1"); theConceptMap2.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name2"); - + myConceptMapDao.create(theConceptMap1); myConceptMapDao.create(theConceptMap2); - + Optional theExpConceptMapV1 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v1"); - + assertTrue(theExpConceptMapV1.isPresent()); assertEquals(theUrl, theExpConceptMapV1.get().getUrl()); assertEquals("v1", theExpConceptMapV1.get().getVersion()); - + // should return the latest one which in this case is not versioned Pageable page = PageRequest.of(0, 1); List theExpSecondOne = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, theUrl); - + assertEquals(1, theExpSecondOne.size()); assertEquals(theUrl, theExpSecondOne.get(0).getUrl()); assertNull(theExpSecondOne.get(0).getVersion()); - } + } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java index 4d36ee8c648..50379f0f0fb 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseJpaR4Test.java @@ -74,9 +74,11 @@ import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc; import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl; import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.ValueSetExpansionR4Test; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; +import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermLoaderSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; @@ -197,6 +199,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil private static IValidationSupport ourJpaValidationSupportChainR4; private static IFhirResourceDaoValueSet ourValueSetDao; + @Autowired + protected ITermConceptMappingSvc myConceptMappingSvc; @Autowired protected IPartitionLookupSvc myPartitionConfigSvc; @Autowired @@ -510,8 +514,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil public void afterClearTerminologyCaches() { BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc); baseHapiTerminologySvc.clearCaches(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); TermDeferredStorageSvcImpl termDeferredStorageSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc); termDeferredStorageSvc.clearDeferred(); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConceptMapTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConceptMapTest.java index da8fab09060..9c2a5d6e8ee 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConceptMapTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConceptMapTest.java @@ -1,18 +1,13 @@ package ca.uhn.fhir.jpa.dao.r4; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.io.IOException; -import java.util.List; -import java.util.Optional; - +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.TranslateConceptResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.jpa.api.model.TranslationRequest; +import ca.uhn.fhir.jpa.entity.TermConceptMap; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CodeableConcept; -import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence; import org.hl7.fhir.r4.model.Enumerations.PublicationStatus; @@ -28,10 +23,18 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; -import ca.uhn.fhir.jpa.api.model.TranslationMatch; -import ca.uhn.fhir.jpa.api.model.TranslationRequest; -import ca.uhn.fhir.jpa.api.model.TranslationResult; -import ca.uhn.fhir.jpa.entity.TermConceptMap; +import javax.annotation.Nonnull; +import java.io.IOException; +import java.util.HashSet; +import java.util.List; +import java.util.Optional; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { private static final Logger ourLog = LoggerFactory.getLogger(FhirResourceDaoR4ConceptMapTest.class); @@ -50,16 +53,16 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() .setSystem(CS_URL) .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertFalse(translationResult.getResult().booleanValue()); + assertFalse(translationResult.getResult()); } }); @@ -73,7 +76,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { // TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() @@ -81,32 +84,29 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); + assertEquals(translationResult.size(), new HashSet<>(translationResult.getResults()).size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); // } }); @@ -120,7 +120,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { // TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() @@ -128,22 +128,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_2)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); // } }); @@ -157,7 +155,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { // TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() @@ -165,12 +163,12 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("BOGUS"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertFalse(translationResult.getResult().booleanValue()); - assertEquals("No matches found!", translationResult.getMessage().getValueAsString()); + assertFalse(translationResult.getResult()); + assertEquals("No Matches found", translationResult.getMessage()); - assertEquals(0, translationResult.getMatches().size()); + assertEquals(0, translationResult.getResults().size()); // } }); @@ -184,7 +182,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -193,42 +191,36 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.getCodeableConcept().addCoding() .setCode("12345"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(3, translationResult.getMatches().size()); + assertEquals(3, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(2); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(2); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -241,7 +233,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -254,22 +246,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_2)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -282,7 +272,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -295,32 +285,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setTargetSystem(new UriType(CS_URL_3)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -333,7 +319,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -344,42 +330,36 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setSystem(CS_URL) .setCode("12345"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(3, translationResult.getMatches().size()); + assertEquals(3, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(2); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(2); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -392,7 +372,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -405,22 +385,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345") .setVersion("Version 1"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -433,7 +411,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -446,32 +424,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345") .setVersion("Version 3"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -484,7 +458,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -495,42 +469,36 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setSource(new UriType(VS_URL)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(3, translationResult.getMatches().size()); + assertEquals(3, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(2); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(2); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -543,7 +511,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -554,42 +522,36 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("12345"); translationRequest.setTarget(new UriType(VS_URL_2)); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(3, translationResult.getMatches().size()); + assertEquals(3, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("34567", concept.getCode()); - assertEquals("Target Code 34567", concept.getDisplay()); - assertEquals(CS_URL_2, concept.getSystem()); - assertEquals("Version 2", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("34567", translationMatch.getCode()); + assertEquals("Target Code 34567", translationMatch.getDisplay()); + assertEquals(CS_URL_2, translationMatch.getSystem()); + assertEquals("Version 2", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("56789", concept.getCode()); - assertEquals("Target Code 56789", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("56789", translationMatch.getCode()); + assertEquals("Target Code 56789", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(2); - assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("67890", concept.getCode()); - assertEquals("Target Code 67890", concept.getDisplay()); - assertEquals(CS_URL_3, concept.getSystem()); - assertEquals("Version 4", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(2); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); + assertEquals("67890", translationMatch.getCode()); + assertEquals("Target Code 67890", translationMatch.getDisplay()); + assertEquals(CS_URL_3, translationMatch.getSystem()); + assertEquals("Version 4", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -602,7 +564,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -617,22 +579,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTargetSystem(new UriType(CS_URL_4)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -645,7 +605,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -660,22 +620,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTargetSystem(new UriType(CS_URL)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 3", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); - assertEquals("wider", translationMatch.getEquivalence().getCode()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 3", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); + assertEquals(ConceptMapEquivalence.WIDER.toCode(), translationMatch.getEquivalence()); } }); } @@ -688,7 +646,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { // TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() @@ -697,12 +655,12 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTargetSystem(new UriType(CS_URL)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertFalse(translationResult.getResult().booleanValue()); - assertEquals("No matches found!", translationResult.getMessage().getValueAsString()); + assertFalse(translationResult.getResult()); + assertEquals("No Matches found", translationResult.getMessage()); - assertEquals(0, translationResult.getMatches().size()); + assertEquals(0, translationResult.getResults().size()); // } }); @@ -716,7 +674,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -727,32 +685,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("34567"); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -765,7 +719,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -780,22 +734,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTargetSystem(new UriType(CS_URL)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -808,7 +760,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -823,22 +775,20 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTargetSystem(new UriType(CS_URL_4)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -851,7 +801,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -864,32 +814,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setCode("34567"); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -902,7 +848,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -917,32 +863,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { .setVersion("Version 2"); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -955,7 +897,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -968,32 +910,28 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setSource(new UriType(VS_URL_2)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } @@ -1006,7 +944,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { @Override - protected void doInTransactionWithoutResult(TransactionStatus theStatus) { + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { /* * Provided: * source code @@ -1019,39 +957,35 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTarget(new UriType(VS_URL)); translationRequest.setReverse(true); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(2, translationResult.getMatches().size()); + assertEquals(2, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("12345", concept.getCode()); - assertEquals("Source Code 12345", concept.getDisplay()); - assertEquals(CS_URL, concept.getSystem()); - assertEquals("Version 1", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("12345", translationMatch.getCode()); + assertEquals("Source Code 12345", translationMatch.getDisplay()); + assertEquals(CS_URL, translationMatch.getSystem()); + assertEquals("Version 1", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); - translationMatch = translationResult.getMatches().get(1); - assertEquals("narrower", translationMatch.getEquivalence().getCode()); - concept = translationMatch.getConcept(); - assertEquals("78901", concept.getCode()); - assertEquals("Source Code 78901", concept.getDisplay()); - assertEquals(CS_URL_4, concept.getSystem()); - assertEquals("Version 5", concept.getVersion()); - assertFalse(concept.getUserSelected()); - assertEquals(CM_URL, translationMatch.getSource().getValueAsString()); + translationMatch = translationResult.getResults().get(1); + assertEquals(ConceptMapEquivalence.NARROWER.toCode(), translationMatch.getEquivalence()); + assertEquals("78901", translationMatch.getCode()); + assertEquals("Source Code 78901", translationMatch.getDisplay()); + assertEquals(CS_URL_4, translationMatch.getSystem()); + assertEquals("Version 5", translationMatch.getSystemVersion()); + assertEquals(CM_URL, translationMatch.getConceptMapUrl()); } }); } /** * Some US core ConceptMaps use this style, e.g: - * + *

* http://hl7.org/fhir/us/core/ConceptMap/ndc-cvx */ @Test @@ -1064,7 +998,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { cm.addGroup().addElement().setCode("source1").addTarget().setCode("target1").setEquivalence(ConceptMapEquivalence.EQUAL); myConceptMapDao.create(cm); - runInTransaction(()->{ + runInTransaction(() -> { TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() .setSystem("http://source") @@ -1072,29 +1006,37 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTarget(new UriType("http://target")); ourLog.info("*** About to translate"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); ourLog.info("*** Done translating"); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); + + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("target1", translationMatch.getCode()); + assertNull(translationMatch.getDisplay()); + assertEquals("http://target", translationMatch.getSystem()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("target1", concept.getCode()); - assertEquals(null, concept.getDisplay()); - assertEquals("http://target", concept.getSystem()); }); - + List translationResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest("http://source", "source1", "http://target")).getResults(); + assertThat(translationResults.toString(), translationResults, hasItem( + new TranslateConceptResult() + .setSystem("http://target") + .setCode("target1") + .setEquivalence("equal") + .setConceptMapUrl("http://foo") + .setValueSet("http://target")) + ); + assertEquals(translationResults.size(), new HashSet<>(translationResults).size()); } - /** * Handle ConceptMaps where targets are missing, such as this one: - * + *

* https://www.hl7.org/fhir/conceptmap-example-specimen-type.html */ @Test @@ -1109,7 +1051,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { cm.addGroup().addElement().setCode("source3").addTarget().setComment("No target code"); // no target code myConceptMapDao.create(cm); - runInTransaction(()->{ + runInTransaction(() -> { TranslationRequest translationRequest = new TranslationRequest(); translationRequest.getCodeableConcept().addCoding() .setSystem("http://source") @@ -1117,27 +1059,25 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { translationRequest.setTarget(new UriType("http://target")); ourLog.info("*** About to translate"); - TranslationResult translationResult = myConceptMapDao.translate(translationRequest, null); + TranslateConceptResults translationResult = myConceptMapDao.translate(translationRequest, null); ourLog.info("*** Done translating"); - assertTrue(translationResult.getResult().booleanValue()); - assertEquals("Matches found!", translationResult.getMessage().getValueAsString()); + assertTrue(translationResult.getResult()); + assertEquals("Matches found", translationResult.getMessage()); - assertEquals(1, translationResult.getMatches().size()); + assertEquals(1, translationResult.getResults().size()); - TranslationMatch translationMatch = translationResult.getMatches().get(0); - assertEquals("equal", translationMatch.getEquivalence().getCode()); - Coding concept = translationMatch.getConcept(); - assertEquals("target1", concept.getCode()); - assertEquals(null, concept.getDisplay()); - assertEquals("http://target", concept.getSystem()); + TranslateConceptResult translationMatch = translationResult.getResults().get(0); + assertEquals(ConceptMapEquivalence.EQUAL.toCode(), translationMatch.getEquivalence()); + assertEquals("target1", translationMatch.getCode()); + assertNull(translationMatch.getDisplay()); + assertEquals("http://target", translationMatch.getSystem()); }); } - @Test public void testUploadAndApplyR4DemoConceptMap() throws IOException { upload("/r4/ConceptMap-icd-sct.xml"); @@ -1149,41 +1089,41 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { TranslationRequest request = new TranslationRequest(); request.setCodeableConcept(sourceCode); request.setTargetSystem(new UriType("http://hl7.org/fhir/sid/icd-10-us")); - TranslationResult outcome = myConceptMapDao.translate(request, mySrd); + TranslateConceptResults outcome = myConceptMapDao.translate(request, mySrd); - assertEquals("S52.209A", outcome.getMatches().get(0).getConcept().getCode()); + assertEquals("S52.209A", outcome.getResults().get(0).getCode()); } @Test public void testConceptMapFindTermConceptMapByUrl() { - + Pageable page = PageRequest.of(0, 1); List theExpConceptMapList = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); assertEquals(1, theExpConceptMapList.size()); assertEquals(CM_URL, theExpConceptMapList.get(0).getUrl()); - + } @Test public void testConceptMapTwoConceptMapWithSameUrlDifferentVersion() { - + String theUrl = "http://loinc.org/property/analyte-suffix"; ConceptMap theConceptMap1 = new ConceptMap(); ConceptMap theConceptMap2 = new ConceptMap(); - + theConceptMap1.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name1").setVersion("v1"); theConceptMap2.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name2").setVersion("v2"); - + myConceptMapDao.create(theConceptMap1); myConceptMapDao.create(theConceptMap2); - + Optional theExpConceptMapV1 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v1"); Optional theExpConceptMapV2 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v2"); - + assertTrue(theExpConceptMapV1.isPresent()); assertEquals(theUrl, theExpConceptMapV1.get().getUrl()); assertEquals("v1", theExpConceptMapV1.get().getVersion()); - + assertTrue(theExpConceptMapV2.isPresent()); assertEquals(theUrl, theExpConceptMapV2.get().getUrl()); assertEquals("v2", theExpConceptMapV2.get().getVersion()); @@ -1191,7 +1131,7 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { // should return the latest one which is v2 Pageable page = PageRequest.of(0, 1); List theExpSecondOne = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, theUrl); - + assertEquals(1, theExpSecondOne.size()); assertEquals(theUrl, theExpSecondOne.get(0).getUrl()); assertEquals("v2", theExpSecondOne.get(0).getVersion()); @@ -1199,27 +1139,27 @@ public class FhirResourceDaoR4ConceptMapTest extends BaseJpaR4Test { @Test public void testConceptMapTwoConceptMapWithSameUrlOneWithoutVersion() { - + String theUrl = "http://loinc.org/property/analyte-suffix"; ConceptMap theConceptMap1 = new ConceptMap(); ConceptMap theConceptMap2 = new ConceptMap(); - + theConceptMap1.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name1").setVersion("v1"); theConceptMap2.setUrl(theUrl).setStatus(PublicationStatus.ACTIVE).setName("name2"); - + myConceptMapDao.create(theConceptMap1); myConceptMapDao.create(theConceptMap2); - + Optional theExpConceptMapV1 = myTermConceptMapDao.findTermConceptMapByUrlAndVersion(theUrl, "v1"); - + assertTrue(theExpConceptMapV1.isPresent()); assertEquals(theUrl, theExpConceptMapV1.get().getUrl()); assertEquals("v1", theExpConceptMapV1.get().getVersion()); - + // should return the latest one which is v2 Pageable page = PageRequest.of(0, 1); List theExpSecondOne = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, theUrl); - + assertEquals(1, theExpSecondOne.size()); assertEquals(theUrl, theExpSecondOne.get(0).getUrl()); assertNull(theExpSecondOne.get(0).getVersion()); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java index 517c4915c11..9f1a8677c14 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r5/BaseJpaR5Test.java @@ -59,6 +59,7 @@ import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc; import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl; import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry; import ca.uhn.fhir.jpa.term.BaseTermReadSvcImpl; +import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.ValueSetExpansionR4Test; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; @@ -437,8 +438,8 @@ public abstract class BaseJpaR5Test extends BaseJpaTest { public void afterClearTerminologyCaches() { BaseTermReadSvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc); baseHapiTerminologySvc.clearCaches(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationCache(); - BaseTermReadSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationCache(); + TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); TermDeferredStorageSvcImpl deferredStorageSvc = AopTestUtils.getTargetObject(myTermDeferredStorageSvc); deferredStorageSvc.clearDeferred(); } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/ResponseTerminologyTranslationInterceptorTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/ResponseTerminologyTranslationInterceptorTest.java new file mode 100644 index 00000000000..b6b6926b40a --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/ResponseTerminologyTranslationInterceptorTest.java @@ -0,0 +1,133 @@ +package ca.uhn.fhir.jpa.interceptor; + +import ca.uhn.fhir.interceptor.api.IInterceptorService; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test; +import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationInterceptor; +import org.hamcrest.Matchers; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.Coding; +import org.hl7.fhir.r4.model.Observation; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; + +import javax.annotation.Nonnull; +import java.util.List; +import java.util.stream.Collectors; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class ResponseTerminologyTranslationInterceptorTest extends BaseResourceProviderR4Test { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResponseTerminologyTranslationInterceptorTest.class); + + @Autowired + private DaoRegistry myDaoRegistry; + @Autowired + private IInterceptorService myInterceptorBroadcaster; + @Autowired + private ResponseTerminologyTranslationInterceptor myResponseTerminologyTranslationInterceptor; + + @BeforeEach + public void beforeEach() { + myConceptMapDao.create(createConceptMap()); + ourRestServer.registerInterceptor(myResponseTerminologyTranslationInterceptor); + } + + @AfterEach + public void afterEach() { + myResponseTerminologyTranslationInterceptor.clearMappingSpecifications(); + ourRestServer.unregisterInterceptor(myResponseTerminologyTranslationInterceptor); + } + + @Test + public void testMapConcept_MappingFound() { + myResponseTerminologyTranslationInterceptor.addMappingSpecification(CS_URL, CS_URL_2); + + Observation observation = new Observation(); + observation.setStatus(Observation.ObservationStatus.AMENDED); + observation .getCode() + .addCoding(new Coding(CS_URL, "12345", null)); + IIdType id = myObservationDao.create(observation).getId(); + + // Read it back + observation = myClient.read().resource(Observation.class).withId(id).execute(); + + assertThat(toCodeStrings(observation).toString(), toCodeStrings(observation), Matchers.contains( + "[system=http://example.com/my_code_system, code=12345, display=null]", + "[system=http://example.com/my_code_system2, code=34567, display=Target Code 34567]" + )); + } + + @Test + public void testMapConcept_MultipleMappingsFound() { + myResponseTerminologyTranslationInterceptor.addMappingSpecification(CS_URL, CS_URL_3); + + Observation observation = new Observation(); + observation.setStatus(Observation.ObservationStatus.AMENDED); + observation .getCode() + .addCoding(new Coding(CS_URL, "12345", null)); + IIdType id = myObservationDao.create(observation).getId(); + + // Read it back + observation = myClient.read().resource(Observation.class).withId(id).execute(); + + assertThat(toCodeStrings(observation).toString(), toCodeStrings(observation), Matchers.contains( + "[system=http://example.com/my_code_system, code=12345, display=null]", + "[system=http://example.com/my_code_system3, code=56789, display=Target Code 56789]", + "[system=http://example.com/my_code_system3, code=67890, display=Target Code 67890]" + )); + } + + /** + * Don't map if we already have a code in the desired target + */ + @Test + public void testMapConcept_MappingNotNeeded() { + myResponseTerminologyTranslationInterceptor.addMappingSpecification(CS_URL, CS_URL_2); + + Observation observation = new Observation(); + observation.setStatus(Observation.ObservationStatus.AMENDED); + observation .getCode() + .addCoding(new Coding(CS_URL, "12345", null)) + .addCoding(new Coding(CS_URL_2, "9999", "Display 9999")); + IIdType id = myObservationDao.create(observation).getId(); + + // Read it back + observation = myClient.read().resource(Observation.class).withId(id).execute(); + + assertThat(toCodeStrings(observation).toString(), toCodeStrings(observation), Matchers.contains( + "[system=http://example.com/my_code_system, code=12345, display=null]", + "[system=http://example.com/my_code_system2, code=9999, display=Display 9999]" + )); + } + + @Test + public void testMapConcept_NoMappingExists() { + myResponseTerminologyTranslationInterceptor.addMappingSpecification(CS_URL, CS_URL_2); + + Observation observation = new Observation(); + observation.setStatus(Observation.ObservationStatus.AMENDED); + observation .getCode() + .addCoding(new Coding(CS_URL, "FOO", null)); + IIdType id = myObservationDao.create(observation).getId(); + + // Read it back + observation = myClient.read().resource(Observation.class).withId(id).execute(); + + assertThat(toCodeStrings(observation).toString(), toCodeStrings(observation), Matchers.contains( + "[system=http://example.com/my_code_system, code=FOO, display=null]" + )); + } + + @Nonnull + private List toCodeStrings(Observation observation) { + return observation.getCode().getCoding().stream().map(t -> "[system=" + t.getSystem() + ", code=" + t.getCode() + ", display=" + t.getDisplay() + "]").collect(Collectors.toList()); + } + + +} diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ConceptMapTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ConceptMapTest.java index 9d196fde0c0..0f1cd25e2c5 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ConceptMapTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3ConceptMapTest.java @@ -95,7 +95,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -156,7 +156,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -205,7 +205,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -255,7 +255,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -304,7 +304,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -352,7 +352,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -400,7 +400,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -446,7 +446,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertFalse(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("No matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("No Matches found", ((StringType) param.getValue()).getValueAsString()); } @@ -480,7 +480,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -525,7 +525,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -570,7 +570,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -615,7 +615,7 @@ public class ResourceProviderDstu3ConceptMapTest extends BaseResourceProviderDst assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java index 916bb3ffc70..d0144436f0e 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java @@ -567,11 +567,6 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid assertEquals(1, response.getEntry().size()); assertNull(response.getTotalElement().getValue()); - // Load next page - response = myClient.loadPage().next(response).execute(); - assertEquals(1, response.getEntry().size()); - assertNull(response.getTotalElement().getValue()); - StopWatch sw = new StopWatch(); while(true) { SearchStatusEnum status = runInTransaction(() -> { @@ -586,6 +581,11 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid } } + // Load next page + response = myClient.loadPage().next(response).execute(); + assertEquals(1, response.getEntry().size()); + assertNull(response.getTotalElement().getValue()); + runInTransaction(() -> { Search search = mySearchEntityDao.findByUuidAndFetchIncludes(searchId).orElseThrow(() -> new IllegalStateException()); assertEquals(3, search.getNumFound()); @@ -594,7 +594,12 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid }); // The paging should have ended now - but the last redacted female result is an empty existing page which should never have been there. - assertNull(BundleUtil.getLinkUrlOfType(myFhirCtx, response, "next")); + String next = BundleUtil.getLinkUrlOfType(myFhirCtx, response, "next"); + if (next != null) { + response = myClient.loadPage().next(response).execute(); + fail(myFhirCtx.newJsonParser().encodeResourceToString(response)); + } + } /** diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ConceptMapTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ConceptMapTest.java index 9236a043090..77f2315c5de 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ConceptMapTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4ConceptMapTest.java @@ -94,7 +94,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -152,7 +152,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -197,7 +197,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertFalse(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("No matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("No Matches found", ((StringType) param.getValue()).getValueAsString()); assertFalse(hasParameterByName(respParams, "match")); } @@ -230,7 +230,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(3, getNumberOfParametersByName(respParams, "match")); @@ -308,7 +308,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -361,7 +361,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(4, getNumberOfParametersByName(respParams, "match")); @@ -452,7 +452,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(3, getNumberOfParametersByName(respParams, "match")); @@ -531,7 +531,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -582,7 +582,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -647,7 +647,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -698,7 +698,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -761,7 +761,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(3, getNumberOfParametersByName(respParams, "match")); @@ -838,7 +838,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(3, getNumberOfParametersByName(respParams, "match")); @@ -949,7 +949,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -993,7 +993,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(3, getNumberOfParametersByName(respParams, "match")); @@ -1074,7 +1074,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -1120,7 +1120,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertFalse(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("No matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("No Matches found", ((StringType) param.getValue()).getValueAsString()); assertFalse(hasParameterByName(respParams, "match")); } @@ -1155,7 +1155,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1221,7 +1221,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1291,7 +1291,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(4, getNumberOfParametersByName(respParams, "match")); @@ -1324,9 +1324,9 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertEquals(CM_URL, ((UriType) part.getValue()).getValueAsString()); param = getParametersByName(respParams, "match").get(2); - assertEquals(2, param.getPart().size()); + assertEquals(3, param.getPart().size()); part = getPartByName(param, "equivalence"); - assertFalse(part.hasValue()); + assertEquals("wider", ((CodeType)part.getValue()).getCode()); part = getPartByName(param, "concept"); coding = (Coding) part.getValue(); assertEquals("23456", coding.getCode()); @@ -1384,7 +1384,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1451,7 +1451,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1518,7 +1518,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -1571,7 +1571,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); @@ -1622,7 +1622,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1687,7 +1687,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); @@ -1783,7 +1783,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -1828,7 +1828,7 @@ public class ResourceProviderR4ConceptMapTest extends BaseResourceProviderR4Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(2, getNumberOfParametersByName(respParams, "match")); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ConceptMapTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ConceptMapTest.java index a2cb18581f0..7acdbc38b35 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ConceptMapTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5ConceptMapTest.java @@ -88,7 +88,7 @@ public class ResourceProviderR5ConceptMapTest extends BaseResourceProviderR5Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); @@ -170,7 +170,7 @@ public class ResourceProviderR5ConceptMapTest extends BaseResourceProviderR5Test assertTrue(((BooleanType) param.getValue()).booleanValue()); param = getParameterByName(respParams, "message"); - assertEquals("Matches found!", ((StringType) param.getValue()).getValueAsString()); + assertEquals("Matches found", ((StringType) param.getValue()).getValueAsString()); assertEquals(1, getNumberOfParametersByName(respParams, "match")); param = getParametersByName(respParams, "match").get(0); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImplTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImplTest.java new file mode 100644 index 00000000000..ecfe133f24e --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TermConceptMappingSvcImplTest.java @@ -0,0 +1,1587 @@ +package ca.uhn.fhir.jpa.term; + +import ca.uhn.fhir.context.support.TranslateConceptResult; +import ca.uhn.fhir.jpa.api.model.TranslationRequest; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.jpa.entity.TermConceptMap; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroup; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; +import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.CanonicalType; +import org.hl7.fhir.r4.model.ConceptMap; +import org.hl7.fhir.r4.model.Enumerations; +import org.hl7.fhir.r4.model.UriType; +import org.hl7.fhir.r4.model.codesystems.HttpVerb; +import org.junit.jupiter.api.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.transaction.TransactionStatus; +import org.springframework.transaction.support.TransactionCallbackWithoutResult; +import org.springframework.transaction.support.TransactionTemplate; + +import javax.annotation.Nonnull; +import java.util.List; + +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.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +public class TermConceptMappingSvcImplTest extends BaseTermR4Test { + private static final Logger ourLog = LoggerFactory.getLogger(TermConceptMappingSvcImplTest.class); + + private IIdType myConceptMapId; + + @Test + public void testCreateConceptMapWithVirtualSourceSystem() { + ConceptMap conceptMap = createConceptMap(); + conceptMap.getGroup().forEach(t -> t.setSource(null)); + conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); + + persistConceptMap(conceptMap, HttpVerb.POST); + + } + + @Test + public void testCreateConceptMapWithVirtualSourceSystemWithClientAssignedId() { + ConceptMap conceptMap = createConceptMap(); + conceptMap.getGroup().forEach(t -> t.setSource(null)); + conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); + conceptMap.setId("ConceptMap/cm"); + + persistConceptMap(conceptMap, HttpVerb.PUT); + + } + + @Test + public void testByCodeSystemsAndSourceCodeOneToMany() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345"); + translationRequest.setTargetSystem(new UriType(CS_URL_3)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testByCodeSystemsAndSourceCodeOneToOne() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345"); + translationRequest.setTargetSystem(new UriType(CS_URL_2)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("ConceptMap.group.element.target:\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testByCodeSystemsAndSourceCodeUnmapped() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("BOGUS"); + translationRequest.setTargetSystem(new UriType(CS_URL_3)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertTrue(targets.isEmpty()); + } + }); + } + + @Test + public void testConceptMapWithNoSourceAndTargetValueSet() { + + ConceptMap conceptMap = new ConceptMap(); + conceptMap.setUrl(CM_URL); + conceptMap.setSource(null); + conceptMap.setTarget(null); + ConceptMap.ConceptMapGroupComponent group = conceptMap.addGroup() + .setSource(CS_URL) + .setTarget(CS_URL_2); + group.addElement() + .setCode("12345") + .addTarget() + .setCode("34567"); + group.addElement() + .setCode("888") + .addTarget() + .setCode("999"); + + myConceptMapDao.create(conceptMap); + + TranslationRequest translationRequest = new TranslationRequest() + .addCode(CS_URL, "12345") + .setTargetSystem(new UriType(CS_URL_2)); + + TranslateConceptResults resp = myConceptMappingSvc.translate(translationRequest); + assertEquals(1, resp.size()); + assertEquals("34567", resp.getResults().get(0).getCode()); + } + + @Test + public void testUsingPredicatesWithCodeOnly() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("12345"); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(2); + + ourLog.info("target(2):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceAndTargetSystem2() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * target code system #2 + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345"); + translationRequest.setTargetSystem(new UriType(CS_URL_2)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target:\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceAndTargetSystem3() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * target code system #3 + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345"); + translationRequest.setTargetSystem(new UriType(CS_URL_3)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceSystem() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345"); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(2); + + ourLog.info("target(2):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceSystemAndVersion1() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * source code system version #1 + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345") + .setVersion("Version 1"); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target:\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(1, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceSystemAndVersion3() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * source code system version #3 + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL) + .setCode("12345") + .setVersion("Version 3"); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(2, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithSourceValueSet() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source value set + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("12345"); + translationRequest.setSource(new UriType(VS_URL)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(2); + + ourLog.info("target(2):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testUsingPredicatesWithTargetValueSet() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * target value set + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("12345"); + translationRequest.setTarget(new UriType(VS_URL_2)); + + List targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + + TranslateConceptResult target = targets.get(0); + + ourLog.info("target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(1); + + ourLog.info("target(1):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = targets.get(2); + + ourLog.info("target(2):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER.toCode(), target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // Test caching. + targets = myConceptMappingSvc.translate(translationRequest).getResults(); + assertNotNull(targets); + assertEquals(3, targets.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationCache()); + } + }); + } + + @Test + public void testWithReverse() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * target code system + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_2) + .setCode("34567"); + translationRequest.setTargetSystem(new UriType(CS_URL_4)); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseByCodeSystemsAndSourceCodeUnmapped() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_3) + .setCode("BOGUS"); + translationRequest.setTargetSystem(new UriType(CS_URL)); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertTrue(elements.isEmpty()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithCodeOnly() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("34567"); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + element = elements.getResults().get(1); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithSourceAndTargetSystem1() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * target code system #1 + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_2) + .setCode("34567"); + translationRequest.setTargetSystem(new UriType(CS_URL)); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithSourceAndTargetSystem4() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * target code system #4 + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_2) + .setCode("34567"); + translationRequest.setTargetSystem(new UriType(CS_URL_4)); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(1, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithSourceSystem() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_2) + .setCode("34567"); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + element = elements.getResults().get(1); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithSourceSystemAndVersion() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source code system + * source code system version + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setSystem(CS_URL_2) + .setCode("34567") + .setVersion("Version 2"); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + element = elements.getResults().get(1); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithSourceValueSet() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * source value set + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("34567"); + translationRequest.setSource(new UriType(VS_URL_2)); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + element = elements.getResults().get(1); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testWithReverseUsingPredicatesWithTargetValueSet() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + /* + * Provided: + * source code + * target value set + * reverse = true + */ + TranslationRequest translationRequest = new TranslationRequest(); + translationRequest.getCodeableConcept().addCoding() + .setCode("34567"); + translationRequest.setTarget(new UriType(VS_URL)); + translationRequest.setReverse(true); + + TranslateConceptResults elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertFalse(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + + TranslateConceptResult element = elements.getResults().get(0); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + element = elements.getResults().get(1); + + ourLog.info("element:\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + // Test caching. + elements = myConceptMappingSvc.translateWithReverse(translationRequest); + assertNotNull(elements); + assertEquals(2, elements.size()); + assertTrue(TermConceptMappingSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); + } + }); + } + + @Test + public void testDuplicateConceptMapUrls() { + createAndPersistConceptMap(); + + try { + createAndPersistConceptMap(); + fail(); + } catch (UnprocessableEntityException e) { + assertEquals("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart(), e.getMessage()); + } + + } + + @Test + public void testDuplicateConceptMapUrlsAndVersions() { + createAndPersistConceptMap("v1"); + + try { + createAndPersistConceptMap("v1"); + fail(); + } catch (UnprocessableEntityException e) { + assertEquals("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\" and ConceptMap.version \"v1\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart(), e.getMessage()); + } + + } + + + @Test + public void testStoreTermConceptMapAndChildren() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + Pageable page = PageRequest.of(0, 1); + List optionalConceptMap = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); + assertEquals(1, optionalConceptMap.size()); + + TermConceptMap conceptMap = optionalConceptMap.get(0); + + ourLog.info("ConceptMap:\n" + conceptMap.toString()); + + assertEquals(VS_URL, conceptMap.getSource()); + assertEquals(VS_URL_2, conceptMap.getTarget()); + assertEquals(CM_URL, conceptMap.getUrl()); + assertEquals(3, conceptMap.getConceptMapGroups().size()); + + TermConceptMapGroup group = conceptMap.getConceptMapGroups().get(0); + + ourLog.info("ConceptMap.group(0):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 1", group.getSourceVersion()); + assertEquals(VS_URL, group.getSourceValueSet()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(VS_URL_2, group.getTargetValueSet()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(2, group.getConceptMapGroupElements().size()); + + TermConceptMapGroupElement element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(0).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + TermConceptMapGroupElementTarget target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(0).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + element = group.getConceptMapGroupElements().get(1); + + ourLog.info("ConceptMap.group(0).element(1):\n" + element.toString()); + + assertEquals("23456", element.getCode()); + assertEquals("Source Code 23456", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + ourLog.info("ConceptMap.group(0).element(1).target(0):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // We had deliberately added a duplicate, and here it is... + target = element.getConceptMapGroupElementTargets().get(1); + ourLog.info("ConceptMap.group(0).element(1).target(1):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(1); + + ourLog.info("ConceptMap.group(1):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 3", group.getSourceVersion()); + assertEquals(CS_URL_3, group.getTarget()); + assertEquals("Version 4", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(1).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 3", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(1).element(0).target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = element.getConceptMapGroupElementTargets().get(1); + + ourLog.info("ConceptMap.group(1).element(0).target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(2); + + ourLog.info("ConceptMap.group(2):\n" + group.toString()); + + assertEquals(CS_URL_4, group.getSource()); + assertEquals("Version 5", group.getSourceVersion()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(2).element(0):\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(2).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.NARROWER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + } + }); + } + + @Test + public void testStoreTermConceptMapAndChildrenWithClientAssignedId() { + createAndPersistConceptMap(); + ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); + + ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); + + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + Pageable page = PageRequest.of(0, 1); + List optionalConceptMap = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); + assertEquals(1, optionalConceptMap.size()); + + TermConceptMap conceptMap = optionalConceptMap.get(0); + + ourLog.info("ConceptMap:\n" + conceptMap.toString()); + + assertEquals(VS_URL, conceptMap.getSource()); + assertEquals(VS_URL_2, conceptMap.getTarget()); + assertEquals(CM_URL, conceptMap.getUrl()); + assertEquals(3, conceptMap.getConceptMapGroups().size()); + + TermConceptMapGroup group = conceptMap.getConceptMapGroups().get(0); + + ourLog.info("ConceptMap.group(0):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 1", group.getSourceVersion()); + assertEquals(VS_URL, group.getSourceValueSet()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(VS_URL_2, group.getTargetValueSet()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(2, group.getConceptMapGroupElements().size()); + + TermConceptMapGroupElement element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(0).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + TermConceptMapGroupElementTarget target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(0).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + element = group.getConceptMapGroupElements().get(1); + + ourLog.info("ConceptMap.group(0).element(1):\n" + element.toString()); + + assertEquals("23456", element.getCode()); + assertEquals("Source Code 23456", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 1", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + ourLog.info("ConceptMap.group(0).element(1).target(0):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + // We had deliberately added a duplicate, and here it is... + target = element.getConceptMapGroupElementTargets().get(1); + ourLog.info("ConceptMap.group(0).element(1).target(1):\n" + target.toString()); + assertEquals("45678", target.getCode()); + assertEquals("Target Code 45678", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(1); + + ourLog.info("ConceptMap.group(1):\n" + group.toString()); + + assertEquals(CS_URL, group.getSource()); + assertEquals("Version 3", group.getSourceVersion()); + assertEquals(CS_URL_3, group.getTarget()); + assertEquals("Version 4", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(1).element(0):\n" + element.toString()); + + assertEquals("12345", element.getCode()); + assertEquals("Source Code 12345", element.getDisplay()); + assertEquals(CS_URL, element.getSystem()); + assertEquals("Version 3", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(2, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(1).element(0).target(0):\n" + target.toString()); + + assertEquals("56789", target.getCode()); + assertEquals("Target Code 56789", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + target = element.getConceptMapGroupElementTargets().get(1); + + ourLog.info("ConceptMap.group(1).element(0).target(1):\n" + target.toString()); + + assertEquals("67890", target.getCode()); + assertEquals("Target Code 67890", target.getDisplay()); + assertEquals(CS_URL_3, target.getSystem()); + assertEquals("Version 4", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + + group = conceptMap.getConceptMapGroups().get(2); + + ourLog.info("ConceptMap.group(2):\n" + group.toString()); + + assertEquals(CS_URL_4, group.getSource()); + assertEquals("Version 5", group.getSourceVersion()); + assertEquals(CS_URL_2, group.getTarget()); + assertEquals("Version 2", group.getTargetVersion()); + assertEquals(CM_URL, group.getConceptMapUrl()); + assertEquals(1, group.getConceptMapGroupElements().size()); + + element = group.getConceptMapGroupElements().get(0); + + ourLog.info("ConceptMap.group(2).element(0):\n" + element.toString()); + + assertEquals("78901", element.getCode()); + assertEquals("Source Code 78901", element.getDisplay()); + assertEquals(CS_URL_4, element.getSystem()); + assertEquals("Version 5", element.getSystemVersion()); + assertEquals(VS_URL, element.getValueSet()); + assertEquals(CM_URL, element.getConceptMapUrl()); + assertEquals(1, element.getConceptMapGroupElementTargets().size()); + + target = element.getConceptMapGroupElementTargets().get(0); + + ourLog.info("ConceptMap.group(2).element(0).target(0):\n" + target.toString()); + + assertEquals("34567", target.getCode()); + assertEquals("Target Code 34567", target.getDisplay()); + assertEquals(CS_URL_2, target.getSystem()); + assertEquals("Version 2", target.getSystemVersion()); + assertEquals(Enumerations.ConceptMapEquivalence.NARROWER, target.getEquivalence()); + assertEquals(VS_URL_2, target.getValueSet()); + assertEquals(CM_URL, target.getConceptMapUrl()); + } + }); + } + + + private void createAndPersistConceptMap() { + ConceptMap conceptMap = createConceptMap(); + conceptMap.setId("ConceptMap/cm"); + persistConceptMap(conceptMap, HttpVerb.POST); + } + + private void createAndPersistConceptMap(String version) { + ConceptMap conceptMap = createConceptMap(); + conceptMap.setId("ConceptMap/cm"); + conceptMap.setVersion(version); + persistConceptMap(conceptMap, HttpVerb.POST); + } + + @SuppressWarnings("EnumSwitchStatementWhichMissesCases") + private void persistConceptMap(ConceptMap theConceptMap, HttpVerb theVerb) { + switch (theVerb) { + case POST: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + case PUT: + new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { + @Override + protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { + myConceptMapId = myConceptMapDao.update(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); + } + }); + break; + default: + throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); + } + } + +} diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java index 507b397ed7a..40aae7b0c75 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/TerminologySvcImplR4Test.java @@ -3,32 +3,21 @@ package ca.uhn.fhir.jpa.term; import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.ValidationSupportContext; -import ca.uhn.fhir.jpa.api.model.TranslationRequest; import ca.uhn.fhir.jpa.entity.TermCodeSystem; import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion; import ca.uhn.fhir.jpa.entity.TermConcept; -import ca.uhn.fhir.jpa.entity.TermConceptMap; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroup; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement; -import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget; import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.ConceptMap; -import org.hl7.fhir.r4.model.Enumerations; -import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence; -import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.ValueSet; import org.hl7.fhir.r4.model.codesystems.HttpVerb; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; @@ -44,7 +33,6 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; 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.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -53,44 +41,6 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test { private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplR4Test.class); ConceptValidationOptions optsNoGuess = new ConceptValidationOptions(); ConceptValidationOptions optsGuess = new ConceptValidationOptions().setInferSystem(true); - private IIdType myConceptMapId; - - private void createAndPersistConceptMap() { - ConceptMap conceptMap = createConceptMap(); - conceptMap.setId("ConceptMap/cm"); - persistConceptMap(conceptMap, HttpVerb.POST); - } - - private void createAndPersistConceptMap(String version) { - ConceptMap conceptMap = createConceptMap(); - conceptMap.setId("ConceptMap/cm"); - conceptMap.setVersion(version); - persistConceptMap(conceptMap, HttpVerb.POST); - } - - @SuppressWarnings("EnumSwitchStatementWhichMissesCases") - private void persistConceptMap(ConceptMap theConceptMap, HttpVerb theVerb) { - switch (theVerb) { - case POST: - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); - } - }); - break; - case PUT: - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - myConceptMapId = myConceptMapDao.update(theConceptMap, mySrd).getId().toUnqualifiedVersionless(); - } - }); - break; - default: - throw new IllegalArgumentException("HTTP verb is not supported: " + theVerb); - } - } @Test public void testCreateConceptMapWithMissingSourceSystem() { @@ -114,26 +64,6 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test { } - @Test - public void testCreateConceptMapWithVirtualSourceSystem() { - ConceptMap conceptMap = createConceptMap(); - conceptMap.getGroup().forEach(t -> t.setSource(null)); - conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); - - persistConceptMap(conceptMap, HttpVerb.POST); - - } - - @Test - public void testCreateConceptMapWithVirtualSourceSystemWithClientAssignedId() { - ConceptMap conceptMap = createConceptMap(); - conceptMap.getGroup().forEach(t -> t.setSource(null)); - conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd")); - conceptMap.setId("ConceptMap/cm"); - - persistConceptMap(conceptMap, HttpVerb.PUT); - - } @Test public void testCreateConceptMapWithMissingTargetSystems() { @@ -269,32 +199,7 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test { } } - @Test - public void testDuplicateConceptMapUrls() { - createAndPersistConceptMap(); - try { - createAndPersistConceptMap(); - fail(); - } catch (UnprocessableEntityException e) { - assertEquals("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart(), e.getMessage()); - } - - } - - @Test - public void testDuplicateConceptMapUrlsAndVersions() { - createAndPersistConceptMap("v1"); - - try { - createAndPersistConceptMap("v1"); - fail(); - } catch (UnprocessableEntityException e) { - assertEquals("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\" and ConceptMap.version \"v1\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart(), e.getMessage()); - } - - } - @Test public void testDuplicateValueSetUrls() throws Exception { myDaoConfig.setPreExpandValueSets(true); @@ -311,1498 +216,6 @@ public class TerminologySvcImplR4Test extends BaseTermR4Test { } - @Test - public void testStoreTermConceptMapAndChildren() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - Pageable page = PageRequest.of(0, 1); - List optionalConceptMap = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); - assertEquals(1, optionalConceptMap.size()); - - TermConceptMap conceptMap = optionalConceptMap.get(0); - - ourLog.info("ConceptMap:\n" + conceptMap.toString()); - - assertEquals(VS_URL, conceptMap.getSource()); - assertEquals(VS_URL_2, conceptMap.getTarget()); - assertEquals(CM_URL, conceptMap.getUrl()); - assertEquals(3, conceptMap.getConceptMapGroups().size()); - - TermConceptMapGroup group = conceptMap.getConceptMapGroups().get(0); - - ourLog.info("ConceptMap.group(0):\n" + group.toString()); - - assertEquals(CS_URL, group.getSource()); - assertEquals("Version 1", group.getSourceVersion()); - assertEquals(VS_URL, group.getSourceValueSet()); - assertEquals(CS_URL_2, group.getTarget()); - assertEquals("Version 2", group.getTargetVersion()); - assertEquals(VS_URL_2, group.getTargetValueSet()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(2, group.getConceptMapGroupElements().size()); - - TermConceptMapGroupElement element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(0).element(0):\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(1, element.getConceptMapGroupElementTargets().size()); - - TermConceptMapGroupElementTarget target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(0).element(0).target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - element = group.getConceptMapGroupElements().get(1); - - ourLog.info("ConceptMap.group(0).element(1):\n" + element.toString()); - - assertEquals("23456", element.getCode()); - assertEquals("Source Code 23456", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - assertEquals(2, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - ourLog.info("ConceptMap.group(0).element(1).target(0):\n" + target.toString()); - assertEquals("45678", target.getCode()); - assertEquals("Target Code 45678", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // We had deliberately added a duplicate, and here it is... - target = element.getConceptMapGroupElementTargets().get(1); - ourLog.info("ConceptMap.group(0).element(1).target(1):\n" + target.toString()); - assertEquals("45678", target.getCode()); - assertEquals("Target Code 45678", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - group = conceptMap.getConceptMapGroups().get(1); - - ourLog.info("ConceptMap.group(1):\n" + group.toString()); - - assertEquals(CS_URL, group.getSource()); - assertEquals("Version 3", group.getSourceVersion()); - assertEquals(CS_URL_3, group.getTarget()); - assertEquals("Version 4", group.getTargetVersion()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(1, group.getConceptMapGroupElements().size()); - - element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(1).element(0):\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 3", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(2, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(1).element(0).target(0):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = element.getConceptMapGroupElementTargets().get(1); - - ourLog.info("ConceptMap.group(1).element(0).target(1):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - group = conceptMap.getConceptMapGroups().get(2); - - ourLog.info("ConceptMap.group(2):\n" + group.toString()); - - assertEquals(CS_URL_4, group.getSource()); - assertEquals("Version 5", group.getSourceVersion()); - assertEquals(CS_URL_2, group.getTarget()); - assertEquals("Version 2", group.getTargetVersion()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(1, group.getConceptMapGroupElements().size()); - - element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(2).element(0):\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(1, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(2).element(0).target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.NARROWER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - } - }); - } - - @Test - public void testStoreTermConceptMapAndChildrenWithClientAssignedId() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - Pageable page = PageRequest.of(0, 1); - List optionalConceptMap = myTermConceptMapDao.getTermConceptMapEntitiesByUrlOrderByMostRecentUpdate(page, CM_URL); - assertEquals(1, optionalConceptMap.size()); - - TermConceptMap conceptMap = optionalConceptMap.get(0); - - ourLog.info("ConceptMap:\n" + conceptMap.toString()); - - assertEquals(VS_URL, conceptMap.getSource()); - assertEquals(VS_URL_2, conceptMap.getTarget()); - assertEquals(CM_URL, conceptMap.getUrl()); - assertEquals(3, conceptMap.getConceptMapGroups().size()); - - TermConceptMapGroup group = conceptMap.getConceptMapGroups().get(0); - - ourLog.info("ConceptMap.group(0):\n" + group.toString()); - - assertEquals(CS_URL, group.getSource()); - assertEquals("Version 1", group.getSourceVersion()); - assertEquals(VS_URL, group.getSourceValueSet()); - assertEquals(CS_URL_2, group.getTarget()); - assertEquals("Version 2", group.getTargetVersion()); - assertEquals(VS_URL_2, group.getTargetValueSet()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(2, group.getConceptMapGroupElements().size()); - - TermConceptMapGroupElement element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(0).element(0):\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(1, element.getConceptMapGroupElementTargets().size()); - - TermConceptMapGroupElementTarget target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(0).element(0).target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - element = group.getConceptMapGroupElements().get(1); - - ourLog.info("ConceptMap.group(0).element(1):\n" + element.toString()); - - assertEquals("23456", element.getCode()); - assertEquals("Source Code 23456", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - assertEquals(2, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - ourLog.info("ConceptMap.group(0).element(1).target(0):\n" + target.toString()); - assertEquals("45678", target.getCode()); - assertEquals("Target Code 45678", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // We had deliberately added a duplicate, and here it is... - target = element.getConceptMapGroupElementTargets().get(1); - ourLog.info("ConceptMap.group(0).element(1).target(1):\n" + target.toString()); - assertEquals("45678", target.getCode()); - assertEquals("Target Code 45678", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - group = conceptMap.getConceptMapGroups().get(1); - - ourLog.info("ConceptMap.group(1):\n" + group.toString()); - - assertEquals(CS_URL, group.getSource()); - assertEquals("Version 3", group.getSourceVersion()); - assertEquals(CS_URL_3, group.getTarget()); - assertEquals("Version 4", group.getTargetVersion()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(1, group.getConceptMapGroupElements().size()); - - element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(1).element(0):\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 3", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(2, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(1).element(0).target(0):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = element.getConceptMapGroupElementTargets().get(1); - - ourLog.info("ConceptMap.group(1).element(0).target(1):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - group = conceptMap.getConceptMapGroups().get(2); - - ourLog.info("ConceptMap.group(2):\n" + group.toString()); - - assertEquals(CS_URL_4, group.getSource()); - assertEquals("Version 5", group.getSourceVersion()); - assertEquals(CS_URL_2, group.getTarget()); - assertEquals("Version 2", group.getTargetVersion()); - assertEquals(CM_URL, group.getConceptMapUrl()); - assertEquals(1, group.getConceptMapGroupElements().size()); - - element = group.getConceptMapGroupElements().get(0); - - ourLog.info("ConceptMap.group(2).element(0):\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - assertEquals(1, element.getConceptMapGroupElementTargets().size()); - - target = element.getConceptMapGroupElementTargets().get(0); - - ourLog.info("ConceptMap.group(2).element(0).target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(Enumerations.ConceptMapEquivalence.NARROWER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - } - }); - } - - @Test - public void testTranslateByCodeSystemsAndSourceCodeOneToMany() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345"); - translationRequest.setTargetSystem(new UriType(CS_URL_3)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateByCodeSystemsAndSourceCodeOneToOne() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345"); - translationRequest.setTargetSystem(new UriType(CS_URL_2)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("ConceptMap.group.element.target:\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - TermConceptMapGroupElement element = target.getConceptMapGroupElement(); - - ourLog.info("ConceptMap.group.element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - TermConceptMapGroup group = element.getConceptMapGroup(); - - ourLog.info("ConceptMap.group:\n" + group.toString()); - - assertEquals(CS_URL, group.getSource()); - assertEquals("Version 1", group.getSourceVersion()); - assertEquals(VS_URL, group.getSourceValueSet()); - assertEquals(CS_URL_2, group.getTarget()); - assertEquals("Version 2", group.getTargetVersion()); - assertEquals(VS_URL_2, group.getTargetValueSet()); - assertEquals(CM_URL, group.getConceptMapUrl()); - - TermConceptMap conceptMap = group.getConceptMap(); - - ourLog.info("ConceptMap:\n" + conceptMap.toString()); - - assertNotNull(conceptMap); - assertEquals(VS_URL, conceptMap.getSource()); - assertEquals(VS_URL_2, conceptMap.getTarget()); - assertEquals(CM_URL, conceptMap.getUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateByCodeSystemsAndSourceCodeUnmapped() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("BOGUS"); - translationRequest.setTargetSystem(new UriType(CS_URL_3)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertTrue(targets.isEmpty()); - } - }); - } - - @Test - public void testTranslateConceptMapWithNoSourceAndTargetValueSet() { - - ConceptMap conceptMap = new ConceptMap(); - conceptMap.setUrl(CM_URL); - conceptMap.setSource(null); - conceptMap.setTarget(null); - ConceptMap.ConceptMapGroupComponent group = conceptMap.addGroup() - .setSource(CS_URL) - .setTarget(CS_URL_2); - group.addElement() - .setCode("12345") - .addTarget() - .setCode("34567"); - group.addElement() - .setCode("888") - .addTarget() - .setCode("999"); - - myConceptMapDao.create(conceptMap); - - TranslationRequest translationRequest = new TranslationRequest() - .addCode(CS_URL, "12345") - .setTargetSystem(new UriType(CS_URL_2)); - - List resp = myTermSvc.translate(translationRequest); - assertEquals(1, resp.size()); - assertEquals("34567", resp.get(0).getCode()); - } - - @Test - public void testTranslateUsingPredicatesWithCodeOnly() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("12345"); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(2); - - ourLog.info("target(2):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceAndTargetSystem2() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * target code system #2 - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345"); - translationRequest.setTargetSystem(new UriType(CS_URL_2)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target:\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceAndTargetSystem3() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * target code system #3 - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345"); - translationRequest.setTargetSystem(new UriType(CS_URL_3)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceSystem() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345"); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(2); - - ourLog.info("target(2):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceSystemAndVersion1() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * source code system version #1 - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345") - .setVersion("Version 1"); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target:\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(1, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceSystemAndVersion3() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * source code system version #3 - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL) - .setCode("12345") - .setVersion("Version 3"); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(2, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithSourceValueSet() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source value set - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("12345"); - translationRequest.setSource(new UriType(VS_URL)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(2); - - ourLog.info("target(2):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateUsingPredicatesWithTargetValueSet() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * target value set - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("12345"); - translationRequest.setTarget(new UriType(VS_URL_2)); - - List targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - - TermConceptMapGroupElementTarget target = targets.get(0); - - ourLog.info("target(0):\n" + target.toString()); - - assertEquals("34567", target.getCode()); - assertEquals("Target Code 34567", target.getDisplay()); - assertEquals(CS_URL_2, target.getSystem()); - assertEquals("Version 2", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(1); - - ourLog.info("target(1):\n" + target.toString()); - - assertEquals("56789", target.getCode()); - assertEquals("Target Code 56789", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.EQUAL, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - target = targets.get(2); - - ourLog.info("target(2):\n" + target.toString()); - - assertEquals("67890", target.getCode()); - assertEquals("Target Code 67890", target.getDisplay()); - assertEquals(CS_URL_3, target.getSystem()); - assertEquals("Version 4", target.getSystemVersion()); - assertEquals(ConceptMapEquivalence.WIDER, target.getEquivalence()); - assertEquals(VS_URL_2, target.getValueSet()); - assertEquals(CM_URL, target.getConceptMapUrl()); - - // Test caching. - targets = myTermSvc.translate(translationRequest); - assertNotNull(targets); - assertEquals(3, targets.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationCache()); - } - }); - } - - @Test - public void testTranslateWithReverse() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * target code system - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_2) - .setCode("34567"); - translationRequest.setTargetSystem(new UriType(CS_URL_4)); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseByCodeSystemsAndSourceCodeUnmapped() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_3) - .setCode("BOGUS"); - translationRequest.setTargetSystem(new UriType(CS_URL)); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertTrue(elements.isEmpty()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithCodeOnly() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("34567"); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - element = elements.get(1); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem1() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * target code system #1 - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_2) - .setCode("34567"); - translationRequest.setTargetSystem(new UriType(CS_URL)); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem4() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * target code system #4 - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_2) - .setCode("34567"); - translationRequest.setTargetSystem(new UriType(CS_URL_4)); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(1, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithSourceSystem() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_2) - .setCode("34567"); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - element = elements.get(1); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithSourceSystemAndVersion() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source code system - * source code system version - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setSystem(CS_URL_2) - .setCode("34567") - .setVersion("Version 2"); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - element = elements.get(1); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithSourceValueSet() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * source value set - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("34567"); - translationRequest.setSource(new UriType(VS_URL_2)); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - element = elements.get(1); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } - - @Test - public void testTranslateWithReverseUsingPredicatesWithTargetValueSet() { - createAndPersistConceptMap(); - ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId); - - ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap)); - - new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() { - @Override - protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) { - /* - * Provided: - * source code - * target value set - * reverse = true - */ - TranslationRequest translationRequest = new TranslationRequest(); - translationRequest.getCodeableConcept().addCoding() - .setCode("34567"); - translationRequest.setTarget(new UriType(VS_URL)); - translationRequest.setReverse(true); - - List elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertFalse(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - - TermConceptMapGroupElement element = elements.get(0); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("12345", element.getCode()); - assertEquals("Source Code 12345", element.getDisplay()); - assertEquals(CS_URL, element.getSystem()); - assertEquals("Version 1", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - element = elements.get(1); - - ourLog.info("element:\n" + element.toString()); - - assertEquals("78901", element.getCode()); - assertEquals("Source Code 78901", element.getDisplay()); - assertEquals(CS_URL_4, element.getSystem()); - assertEquals("Version 5", element.getSystemVersion()); - assertEquals(VS_URL, element.getValueSet()); - assertEquals(CM_URL, element.getConceptMapUrl()); - - // Test caching. - elements = myTermSvc.translateWithReverse(translationRequest); - assertNotNull(elements); - assertEquals(2, elements.size()); - assertTrue(BaseTermReadSvcImpl.isOurLastResultsFromTranslationWithReverseCache()); - } - }); - } @Test public void testValidateCode() { diff --git a/hapi-fhir-jpaserver-batch/pom.xml b/hapi-fhir-jpaserver-batch/pom.xml index c461ab9bbf1..95d1bee3105 100644 --- a/hapi-fhir-jpaserver-batch/pom.xml +++ b/hapi-fhir-jpaserver-batch/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml index 1bf1bb9a827..c7ec753f71c 100644 --- a/hapi-fhir-jpaserver-cql/pom.xml +++ b/hapi-fhir-jpaserver-cql/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -144,13 +144,13 @@ ca.uhn.hapi.fhir hapi-fhir-test-utilities - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT test ca.uhn.hapi.fhir hapi-fhir-jpaserver-test-utilities - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT test diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index 568806407a2..f6362d545f7 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -55,13 +55,13 @@ ca.uhn.hapi.fhir hapi-fhir-test-utilities - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT test ca.uhn.hapi.fhir hapi-fhir-jpaserver-test-utilities - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT test diff --git a/hapi-fhir-jpaserver-migrate/pom.xml b/hapi-fhir-jpaserver-migrate/pom.xml index 5e61a7c54e0..2d44f20af89 100644 --- a/hapi-fhir-jpaserver-migrate/pom.xml +++ b/hapi-fhir-jpaserver-migrate/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index a53a5a1f6da..de5042f9a43 100644 --- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -71,53 +71,54 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { init501(); // 20200514 - 20200515 init510(); // 20200516 - 20201028 init520(); // 20201029 - - init530(); + init530(); init540(); // 20210218 - } private void init540() { - + Builder version = forVersion(VersionEnum.V5_4_0); - + //-- add index on HFJ_SPIDX_DATE - version.onTable("HFJ_SPIDX_DATE").addIndex("20210309.1", "IDX_SP_DATE_HASH_HIGH") - .unique(false).withColumns("HASH_IDENTITY", "SP_VALUE_HIGH"); - + version.onTable("HFJ_SPIDX_DATE").addIndex("20210309.1", "IDX_SP_DATE_HASH_HIGH") + .unique(false).withColumns("HASH_IDENTITY", "SP_VALUE_HIGH"); + //-- add index on HFJ_FORCED_ID - version.onTable("HFJ_FORCED_ID").addIndex("20210309.2", "IDX_FORCEID_FID") - .unique(false).withColumns("FORCED_ID"); + version.onTable("HFJ_FORCED_ID").addIndex("20210309.2", "IDX_FORCEID_FID") + .unique(false).withColumns("FORCED_ID"); + } - + private void init530() { Builder version = forVersion(VersionEnum.V5_3_0); - + //-- TRM version .onTable("TRM_VALUESET_CONCEPT") .dropIndex("20210104.1", "IDX_VS_CONCEPT_CS_CODE"); - - version - .onTable("TRM_VALUESET_CONCEPT") - .addIndex("20210104.2", "IDX_VS_CONCEPT_CSCD").unique(true).withColumns("VALUESET_PID", "SYSTEM_URL", "CODEVAL"); - + + version + .onTable("TRM_VALUESET_CONCEPT") + .addIndex("20210104.2", "IDX_VS_CONCEPT_CSCD").unique(true).withColumns("VALUESET_PID", "SYSTEM_URL", "CODEVAL"); + //-- Add new Table, HFJ_SPIDX_QUANTITY_NRML version.addIdGenerator("20210109.1", "SEQ_SPIDX_QUANTITY_NRML"); Builder.BuilderAddTableByColumns pkg = version.addTableByColumns("20210109.2", "HFJ_SPIDX_QUANTITY_NRML", "SP_ID"); - pkg.addColumn("RES_ID").nonNullable().type(ColumnTypeEnum.LONG); - pkg.addColumn("RES_TYPE").nonNullable().type(ColumnTypeEnum.STRING, 100); - pkg.addColumn("SP_UPDATED").nullable().type(ColumnTypeEnum.DATE_TIMESTAMP); - pkg.addColumn("SP_MISSING").nonNullable().type(ColumnTypeEnum.BOOLEAN); + pkg.addColumn("RES_ID").nonNullable().type(ColumnTypeEnum.LONG); + pkg.addColumn("RES_TYPE").nonNullable().type(ColumnTypeEnum.STRING, 100); + pkg.addColumn("SP_UPDATED").nullable().type(ColumnTypeEnum.DATE_TIMESTAMP); + pkg.addColumn("SP_MISSING").nonNullable().type(ColumnTypeEnum.BOOLEAN); pkg.addColumn("SP_NAME").nonNullable().type(ColumnTypeEnum.STRING, 100); - pkg.addColumn("SP_ID").nonNullable().type(ColumnTypeEnum.LONG); + pkg.addColumn("SP_ID").nonNullable().type(ColumnTypeEnum.LONG); pkg.addColumn("SP_SYSTEM").nullable().type(ColumnTypeEnum.STRING, 200); pkg.addColumn("SP_UNITS").nullable().type(ColumnTypeEnum.STRING, 200); pkg.addColumn("HASH_IDENTITY_AND_UNITS").nullable().type(ColumnTypeEnum.LONG); pkg.addColumn("HASH_IDENTITY_SYS_UNITS").nullable().type(ColumnTypeEnum.LONG); pkg.addColumn("HASH_IDENTITY").nullable().type(ColumnTypeEnum.LONG); pkg.addColumn("SP_VALUE").nullable().type(ColumnTypeEnum.FLOAT); - pkg.addIndex("20210109.3", "IDX_SP_QNTY_NRML_HASH").unique(false).withColumns("HASH_IDENTITY","SP_VALUE"); - pkg.addIndex("20210109.4", "IDX_SP_QNTY_NRML_HASH_UN").unique(false).withColumns("HASH_IDENTITY_AND_UNITS","SP_VALUE"); - pkg.addIndex("20210109.5", "IDX_SP_QNTY_NRML_HASH_SYSUN").unique(false).withColumns("HASH_IDENTITY_SYS_UNITS","SP_VALUE"); + pkg.addIndex("20210109.3", "IDX_SP_QNTY_NRML_HASH").unique(false).withColumns("HASH_IDENTITY", "SP_VALUE"); + pkg.addIndex("20210109.4", "IDX_SP_QNTY_NRML_HASH_UN").unique(false).withColumns("HASH_IDENTITY_AND_UNITS", "SP_VALUE"); + pkg.addIndex("20210109.5", "IDX_SP_QNTY_NRML_HASH_SYSUN").unique(false).withColumns("HASH_IDENTITY_SYS_UNITS", "SP_VALUE"); pkg.addIndex("20210109.6", "IDX_SP_QNTY_NRML_UPDATED").unique(false).withColumns("SP_UPDATED"); pkg.addIndex("20210109.7", "IDX_SP_QNTY_NRML_RESID").unique(false).withColumns("RES_ID"); @@ -154,7 +155,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .toColumn("GOLDEN_RESOURCE_PID") .references("HFJ_RESOURCE", "RES_ID"); } - + protected void init510() { Builder version = forVersion(VersionEnum.V5_1_0); @@ -224,7 +225,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { init510_20200725(); //EMPI Target Type - empiLink.addColumn("20200727.1","TARGET_TYPE").nullable().type(ColumnTypeEnum.STRING, 40); + empiLink.addColumn("20200727.1", "TARGET_TYPE").nullable().type(ColumnTypeEnum.STRING, 40); //ConceptMap add version for search Builder.BuilderWithTableName trmConceptMap = version.onTable("TRM_CONCEPT_MAP"); @@ -1022,8 +1023,8 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { spidxUri .addTask(new CalculateHashesTask(VersionEnum.V3_5_0, "20180903.44") .setColumnName("HASH_IDENTITY") - .addCalculator("HASH_IDENTITY", t -> BaseResourceIndexedSearchParam.calculateHashIdentity(new PartitionSettings(), (RequestPartitionId)null, t.getResourceType(), t.getString("SP_NAME"))) - .addCalculator("HASH_URI", t -> ResourceIndexedSearchParamUri.calculateHashUri(new PartitionSettings(), (RequestPartitionId)null, t.getResourceType(), t.getString("SP_NAME"), t.getString("SP_URI"))) + .addCalculator("HASH_IDENTITY", t -> BaseResourceIndexedSearchParam.calculateHashIdentity(new PartitionSettings(), (RequestPartitionId) null, t.getResourceType(), t.getString("SP_NAME"))) + .addCalculator("HASH_URI", t -> ResourceIndexedSearchParamUri.calculateHashUri(new PartitionSettings(), (RequestPartitionId) null, t.getResourceType(), t.getString("SP_NAME"), t.getString("SP_URI"))) ); } @@ -1056,7 +1057,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { Boolean present = columnToBoolean(t.get("SP_PRESENT")); String resType = (String) t.get("RES_TYPE"); String paramName = (String) t.get("PARAM_NAME"); - Long hash = SearchParamPresent.calculateHashPresence(new PartitionSettings(), (RequestPartitionId)null, resType, paramName, present); + Long hash = SearchParamPresent.calculateHashPresence(new PartitionSettings(), (RequestPartitionId) null, resType, paramName, present); consolidateSearchParamPresenceIndexesTask.executeSql("HFJ_RES_PARAM_PRESENT", "update HFJ_RES_PARAM_PRESENT set HASH_PRESENCE = ? where PID = ?", hash, pid); }); version.addTask(consolidateSearchParamPresenceIndexesTask); diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 2866ec6e866..68a9fc35de9 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index d9f61c0b2ae..724615d932a 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 16fd9cb909a..41834647cbb 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index 5b0ac9b0a5f..de592655080 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index b9cb7f1f31f..944d39c11e5 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml @@ -169,7 +169,7 @@ ca.uhn.hapi.fhir hapi-fhir-converter - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 9dea7e84e8d..2817fc5ccd2 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index 0e0893ae8d5..2407e313e9b 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseResponseTerminologyInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseResponseTerminologyInterceptor.java new file mode 100644 index 00000000000..fdb50da4597 --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/BaseResponseTerminologyInterceptor.java @@ -0,0 +1,99 @@ +package ca.uhn.fhir.rest.server.interceptor; + +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.util.BundleUtil; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import javax.annotation.Nonnull; +import java.util.Collections; +import java.util.List; + +public class BaseResponseTerminologyInterceptor { + protected final IValidationSupport myValidationSupport; + protected final FhirContext myContext; + + /** + * Constructor + * + * @param theValidationSupport The validation support module + */ + public BaseResponseTerminologyInterceptor(@Nonnull IValidationSupport theValidationSupport) { + myValidationSupport = theValidationSupport; + Validate.notNull(theValidationSupport, "The validation support must not be null"); + + myContext = theValidationSupport.getFhirContext(); + Validate.notNull(myContext, "The validation support must not return a null context"); + } + + + @Nonnull + protected List toListForProcessing(RequestDetails theRequestDetails, IBaseResource theResource) { + + switch (theRequestDetails.getRestOperationType()) { + // Don't apply to these operations + case ADD_TAGS: + case DELETE_TAGS: + case GET_TAGS: + case GET_PAGE: + case GRAPHQL_REQUEST: + case EXTENDED_OPERATION_SERVER: + case EXTENDED_OPERATION_TYPE: + case EXTENDED_OPERATION_INSTANCE: + case CREATE: + case DELETE: + case TRANSACTION: + case UPDATE: + case VALIDATE: + case METADATA: + case META_ADD: + case META: + case META_DELETE: + case PATCH: + default: + return Collections.emptyList(); + + // Do apply to these operations + case HISTORY_INSTANCE: + case HISTORY_SYSTEM: + case HISTORY_TYPE: + case SEARCH_SYSTEM: + case SEARCH_TYPE: + case READ: + case VREAD: + break; + } + + List resources; + if (theResource instanceof IBaseBundle) { + resources = BundleUtil.toListOfResources(myContext, (IBaseBundle) theResource); + } else { + resources = Collections.singletonList(theResource); + } + return resources; + } + +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/InterceptorOrders.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/InterceptorOrders.java index 9c49270bd87..cf1895e1f4a 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/InterceptorOrders.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/InterceptorOrders.java @@ -26,6 +26,9 @@ public class InterceptorOrders { public static final int RESPONSE_HIGHLIGHTER_INTERCEPTOR = 10000; public static final int RESPONSE_SIZE_CAPTURING_INTERCEPTOR_COMPLETED = -1; + public static final int RESPONSE_TERMINOLOGY_TRANSLATION_INTERCEPTOR = 100; + public static final int RESPONSE_TERMINOLOGY_DISPLAY_POPULATION_INTERCEPTOR = 110; + /** * Non instantiable */ diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java new file mode 100644 index 00000000000..bcc22a8cb82 --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptor.java @@ -0,0 +1,120 @@ +package ca.uhn.fhir.rest.server.interceptor; + +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; +import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.ValidationSupportContext; +import ca.uhn.fhir.interceptor.api.Hook; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.util.FhirTerser; +import ca.uhn.fhir.util.IModelVisitor; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import java.util.List; +import java.util.Objects; + +import static ca.uhn.fhir.rest.server.interceptor.InterceptorOrders.RESPONSE_TERMINOLOGY_DISPLAY_POPULATION_INTERCEPTOR; +import static org.apache.commons.lang3.StringUtils.isBlank; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * This interceptor looks for coded data ( + * + * @since 5.4.0 + */ +public class ResponseTerminologyDisplayPopulationInterceptor extends BaseResponseTerminologyInterceptor { + + private final BaseRuntimeChildDefinition myCodingSystemChild; + private final BaseRuntimeChildDefinition myCodingCodeChild; + private final Class myCodingType; + private final BaseRuntimeElementCompositeDefinition myCodingDefinitition; + private final BaseRuntimeChildDefinition myCodingDisplayChild; + private final RuntimePrimitiveDatatypeDefinition myStringDefinition; + + /** + * Constructor + * + * @param theValidationSupport The validation support module + */ + public ResponseTerminologyDisplayPopulationInterceptor(IValidationSupport theValidationSupport) { + super(theValidationSupport); + + myCodingDefinitition = (BaseRuntimeElementCompositeDefinition) Objects.requireNonNull(myContext.getElementDefinition("Coding")); + myCodingType = myCodingDefinitition.getImplementingClass(); + myCodingSystemChild = myCodingDefinitition.getChildByName("system"); + myCodingCodeChild = myCodingDefinitition.getChildByName("code"); + myCodingDisplayChild = myCodingDefinitition.getChildByName("display"); + + myStringDefinition = (RuntimePrimitiveDatatypeDefinition) myContext.getElementDefinition("string"); + } + + @Hook(value = Pointcut.SERVER_OUTGOING_RESPONSE, order = RESPONSE_TERMINOLOGY_DISPLAY_POPULATION_INTERCEPTOR) + public void handleResource(RequestDetails theRequestDetails, IBaseResource theResource) { + List resources = toListForProcessing(theRequestDetails, theResource); + + FhirTerser terser = myContext.newTerser(); + for (IBaseResource nextResource : resources) { + terser.visit(nextResource, new MappingVisitor()); + } + + } + + private class MappingVisitor implements IModelVisitor { + + @Override + public void acceptElement(IBaseResource theResource, IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (myCodingType.isAssignableFrom(theElement.getClass())) { + String system = myCodingSystemChild.getAccessor().getFirstValueOrNull(theElement).map(t -> (IPrimitiveType) t).map(t -> t.getValueAsString()).orElse(null); + String code = myCodingCodeChild.getAccessor().getFirstValueOrNull(theElement).map(t -> (IPrimitiveType) t).map(t -> t.getValueAsString()).orElse(null); + if (isBlank(system) || isBlank(code)) { + return; + } + + String display = myCodingDisplayChild.getAccessor().getFirstValueOrNull(theElement).map(t -> (IPrimitiveType) t).map(t -> t.getValueAsString()).orElse(null); + if (isNotBlank(display)) { + return; + } + + ValidationSupportContext validationSupportContext = new ValidationSupportContext(myValidationSupport); + if (myValidationSupport.isCodeSystemSupported(validationSupportContext, system)) { + + IValidationSupport.LookupCodeResult lookupCodeResult = myValidationSupport.lookupCode(validationSupportContext, system, code); + if (lookupCodeResult.isFound()) { + String newDisplay = lookupCodeResult.getCodeDisplay(); + IPrimitiveType newString = myStringDefinition.newInstance(newDisplay); + myCodingDisplayChild.getMutator().addValue(theElement, newString); + } + + } + } + + } + + } + +} diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.java new file mode 100644 index 00000000000..cdf0926cd61 --- /dev/null +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyTranslationInterceptor.java @@ -0,0 +1,191 @@ +package ca.uhn.fhir.rest.server.interceptor; + +/*- + * #%L + * HAPI FHIR - Server Framework + * %% + * Copyright (C) 2014 - 2021 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.context.BaseRuntimeChildDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; +import ca.uhn.fhir.context.BaseRuntimeElementDefinition; +import ca.uhn.fhir.context.RuntimePrimitiveDatatypeDefinition; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.TranslateConceptResult; +import ca.uhn.fhir.context.support.TranslateConceptResults; +import ca.uhn.fhir.interceptor.api.Hook; +import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.util.FhirTerser; +import ca.uhn.fhir.util.IModelVisitor; +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.Multimap; +import org.apache.commons.lang3.Validate; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import static ca.uhn.fhir.rest.server.interceptor.InterceptorOrders.RESPONSE_TERMINOLOGY_TRANSLATION_INTERCEPTOR; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + +/** + * This interceptor leverages ConceptMap resources stored in the repository to automatically map + * terminology from one CodeSystem to another at runtime, in resources that are being + * returned by the server. + *

+ * Mappings are applied only if they are explicitly configured in the interceptor via + * the {@link #addMappingSpecification(String, String)} method. + *

+ * + * @since 5.4.0 + */ +public class ResponseTerminologyTranslationInterceptor extends BaseResponseTerminologyInterceptor { + + private final BaseRuntimeChildDefinition myCodingSystemChild; + private final BaseRuntimeChildDefinition myCodingCodeChild; + private final BaseRuntimeElementDefinition> myUriDefinition; + private final BaseRuntimeElementDefinition> myCodeDefinition; + private final Class myCodeableConceptType; + private final Class myCodingType; + private final BaseRuntimeChildDefinition myCodeableConceptCodingChild; + private final BaseRuntimeElementCompositeDefinition myCodingDefinitition; + private final RuntimePrimitiveDatatypeDefinition myStringDefinition; + private final BaseRuntimeChildDefinition myCodingDisplayChild; + private Map myMappingSpecifications = new HashMap<>(); + + /** + * Constructor + * + * @param theValidationSupport The validation support module + */ + public ResponseTerminologyTranslationInterceptor(IValidationSupport theValidationSupport) { + super(theValidationSupport); + + BaseRuntimeElementCompositeDefinition codeableConceptDef = (BaseRuntimeElementCompositeDefinition) Objects.requireNonNull(myContext.getElementDefinition("CodeableConcept")); + myCodeableConceptType = codeableConceptDef.getImplementingClass(); + myCodeableConceptCodingChild = codeableConceptDef.getChildByName("coding"); + + myCodingDefinitition = (BaseRuntimeElementCompositeDefinition) Objects.requireNonNull(myContext.getElementDefinition("Coding")); + myCodingType = myCodingDefinitition.getImplementingClass(); + myCodingSystemChild = myCodingDefinitition.getChildByName("system"); + myCodingCodeChild = myCodingDefinitition.getChildByName("code"); + myCodingDisplayChild = myCodingDefinitition.getChildByName("display"); + + myUriDefinition = (RuntimePrimitiveDatatypeDefinition) myContext.getElementDefinition("uri"); + myCodeDefinition = (RuntimePrimitiveDatatypeDefinition) myContext.getElementDefinition("code"); + myStringDefinition = (RuntimePrimitiveDatatypeDefinition) myContext.getElementDefinition("string"); + } + + /** + * Adds a mapping specification using only a source and target CodeSystem URL. Any mappings specified using + * this URL + * + * @param theSourceCodeSystemUrl The source CodeSystem URL + * @param theTargetCodeSystemUrl The target CodeSystem URL + */ + public void addMappingSpecification(String theSourceCodeSystemUrl, String theTargetCodeSystemUrl) { + Validate.notBlank(theSourceCodeSystemUrl, "theSourceCodeSystemUrl must not be null or blank"); + Validate.notBlank(theTargetCodeSystemUrl, "theTargetCodeSystemUrl must not be null or blank"); + + myMappingSpecifications.put(theSourceCodeSystemUrl, theTargetCodeSystemUrl); + } + + /** + * Clear all mapping specifications + */ + public void clearMappingSpecifications() { + myMappingSpecifications.clear(); + } + + + @Hook(value = Pointcut.SERVER_OUTGOING_RESPONSE, order = RESPONSE_TERMINOLOGY_TRANSLATION_INTERCEPTOR) + public void handleResource(RequestDetails theRequestDetails, IBaseResource theResource) { + List resources = toListForProcessing(theRequestDetails, theResource); + + FhirTerser terser = myContext.newTerser(); + for (IBaseResource nextResource : resources) { + terser.visit(nextResource, new MappingVisitor()); + } + + } + + + private class MappingVisitor implements IModelVisitor { + + @Override + public void acceptElement(IBaseResource theResource, IBase theElement, List thePathToElement, BaseRuntimeChildDefinition theChildDefinition, BaseRuntimeElementDefinition theDefinition) { + if (myCodeableConceptType.isAssignableFrom(theElement.getClass())) { + + // Find all existing Codings + Multimap foundSystemsToCodes = ArrayListMultimap.create(); + List nextCodeableConceptCodings = myCodeableConceptCodingChild.getAccessor().getValues(theElement); + for (IBase nextCodeableConceptCoding : nextCodeableConceptCodings) { + String system = myCodingSystemChild.getAccessor().getFirstValueOrNull(nextCodeableConceptCoding).map(t -> (IPrimitiveType) t).map(t -> t.getValueAsString()).orElse(null); + String code = myCodingCodeChild.getAccessor().getFirstValueOrNull(nextCodeableConceptCoding).map(t -> (IPrimitiveType) t).map(t -> t.getValueAsString()).orElse(null); + if (isNotBlank(system) && isNotBlank(code) && !foundSystemsToCodes.containsKey(system)) { + foundSystemsToCodes.put(system, code); + } + } + + // Look for mappings + for (String nextSourceSystem : foundSystemsToCodes.keySet()) { + String wantTargetSystem = myMappingSpecifications.get(nextSourceSystem); + if (wantTargetSystem != null) { + if (!foundSystemsToCodes.containsKey(wantTargetSystem)) { + + for (String code : foundSystemsToCodes.get(nextSourceSystem)) { + TranslateConceptResults translateConceptResults = myValidationSupport.translateConcept(new IValidationSupport.TranslateCodeRequest(nextSourceSystem, code, wantTargetSystem)); + if (translateConceptResults != null) { + List mappings = translateConceptResults.getResults(); + for (TranslateConceptResult nextMapping : mappings) { + + IBase newCoding = createCodingFromMappingTarget(nextMapping); + + // Add coding to existing CodeableConcept + myCodeableConceptCodingChild.getMutator().addValue(theElement, newCoding); + + } + } + } + } + } + } + + } + + } + + private IBase createCodingFromMappingTarget(TranslateConceptResult nextMapping) { + IBase newCoding = myCodingDefinitition.newInstance(); + IPrimitiveType newSystem = myUriDefinition.newInstance(nextMapping.getSystem()); + myCodingSystemChild.getMutator().addValue(newCoding, newSystem); + IPrimitiveType newCode = myCodeDefinition.newInstance(nextMapping.getCode()); + myCodingCodeChild.getMutator().addValue(newCoding, newCode); + if (isNotBlank(nextMapping.getDisplay())) { + IPrimitiveType newDisplay = myStringDefinition.newInstance(nextMapping.getDisplay()); + myCodingDisplayChild.getMutator().addValue(newCoding, newDisplay); + } + return newCoding; + } + + } +} diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 801015702e3..c92df1fa279 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 2a544a47fe5..95cd4751b8b 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index d2bb1653411..e6066b3326a 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT hapi-fhir-spring-boot-sample-client-okhttp diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index c43b89ca9fb..fb7ddb09c3a 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT hapi-fhir-spring-boot-sample-server-jersey diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index d49c9df752c..d6ebc5a399b 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT hapi-fhir-spring-boot-samples diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index ee1ef7400ce..a93a5fdf968 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index dd416146a40..b90b5a0d590 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 5ccb224816b..2990c9922c1 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 657730dcab6..a3e48873406 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index 02c218e82d2..9a03f490acc 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index 33be95ed04d..f94b37ea096 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 674daa483de..3a46d64b894 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index d04b1a5fe44..911d81a7d0b 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 9ce3bc3bc62..5d92d6d774a 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index b418de07bfb..55407e74af8 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 95f312078d3..a7c89b00189 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 27ac1bc796b..4d10b5868a7 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index 325e4736caf..caa4236810b 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index 5185712e048..90bc4b01919 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 98885fe44c0..23233a961e1 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index e2ef2cb4ad1..a04398bb661 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/BaseValidationSupportWrapper.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/BaseValidationSupportWrapper.java index cc04a447d10..3bec90fd887 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/BaseValidationSupportWrapper.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/BaseValidationSupportWrapper.java @@ -3,6 +3,7 @@ package org.hl7.fhir.common.hapi.validation.support; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import org.apache.commons.lang3.Validate; @@ -69,7 +70,7 @@ public class BaseValidationSupportWrapper extends BaseValidationSupport { } @Override - public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public IValidationSupport.ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { return myWrap.expandValueSet(theValidationSupportContext, theExpansionOptions, theValueSetToExpand); } @@ -99,5 +100,8 @@ public class BaseValidationSupportWrapper extends BaseValidationSupport { return myWrap.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet); } - + @Override + public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { + return myWrap.translateConcept(theRequest); + } } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java index b6515f00d64..43fbfff5c6c 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java @@ -3,9 +3,11 @@ package org.hl7.fhir.common.hapi.validation.support; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.ValidationSupportContext; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import org.apache.commons.lang3.time.DateUtils; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.slf4j.Logger; @@ -28,24 +30,44 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple private static final Logger ourLog = LoggerFactory.getLogger(CachingValidationSupport.class); private final Cache myCache; private final Cache myValidateCodeCache; + private final Cache myTranslateCodeCache; private final Cache myLookupCodeCache; - + /** + * Constuctor with default timeouts + * + * @param theWrap The validation support module to wrap + */ public CachingValidationSupport(IValidationSupport theWrap) { + this(theWrap, CacheTimeouts.defaultValues()); + } + + /** + * Constructor with configurable timeouts + * + * @param theWrap The validation support module to wrap + * @param theCacheTimeouts The timeouts to use + */ + public CachingValidationSupport(IValidationSupport theWrap, CacheTimeouts theCacheTimeouts) { super(theWrap.getFhirContext(), theWrap); myValidateCodeCache = Caffeine .newBuilder() - .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterWrite(theCacheTimeouts.getValidateCodeMillis(), TimeUnit.MILLISECONDS) .maximumSize(5000) .build(); myLookupCodeCache = Caffeine .newBuilder() - .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterWrite(theCacheTimeouts.getLookupCodeMillis(), TimeUnit.MILLISECONDS) + .maximumSize(5000) + .build(); + myTranslateCodeCache = Caffeine + .newBuilder() + .expireAfterWrite(theCacheTimeouts.getTranslateCodeMillis(), TimeUnit.MILLISECONDS) .maximumSize(5000) .build(); myCache = Caffeine .newBuilder() - .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterWrite(theCacheTimeouts.getMiscMillis(), TimeUnit.MILLISECONDS) .maximumSize(5000) .build(); } @@ -88,12 +110,30 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple return loadFromCache(myLookupCodeCache, key, t -> super.lookupCode(theValidationSupportContext, theSystem, theCode)); } + @Override + public IValidationSupport.CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theValidationOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { + + BaseRuntimeChildDefinition urlChild = myCtx.getResourceDefinition(theValueSet).getChildByName("url"); + Optional valueSetUrl = urlChild.getAccessor().getValues(theValueSet).stream().map(t -> ((IPrimitiveType) t).getValueAsString()).filter(t -> isNotBlank(t)).findFirst(); + if (valueSetUrl.isPresent()) { + String key = "validateCodeInValueSet " + theValidationOptions.toString() + " " + defaultString(theCodeSystem, "(null)") + " " + defaultString(theCode, "(null)") + " " + defaultString(theDisplay, "(null)") + " " + valueSetUrl.get(); + return loadFromCache(myValidateCodeCache, key, t -> super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet)); + } + + return super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet); + } + + @Override + public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { + return loadFromCache(myTranslateCodeCache, theRequest, k -> super.translateConcept(theRequest)); + } + @SuppressWarnings("OptionalAssignedToNull") @Nullable - private T loadFromCache(Cache theCache, String theKey, Function theLoader) { + private T loadFromCache(Cache theCache, S theKey, Function theLoader) { ourLog.trace("Fetching from cache: {}", theKey); - Function> loaderWrapper = key -> Optional.ofNullable(theLoader.apply(theKey)); + Function> loaderWrapper = key -> Optional.ofNullable(theLoader.apply(theKey)); Optional result = (Optional) theCache.get(theKey, loaderWrapper); assert result != null; @@ -101,23 +141,65 @@ public class CachingValidationSupport extends BaseValidationSupportWrapper imple } - @Override - public IValidationSupport.CodeValidationResult validateCodeInValueSet(ValidationSupportContext theValidationSupportContext, ConceptValidationOptions theValidationOptions, String theCodeSystem, String theCode, String theDisplay, @Nonnull IBaseResource theValueSet) { - - BaseRuntimeChildDefinition urlChild = myCtx.getResourceDefinition(theValueSet).getChildByName("url"); - Optional valueSetUrl = urlChild.getAccessor().getValues(theValueSet).stream().map(t -> ((IPrimitiveType) t).getValueAsString()).filter(t->isNotBlank(t)).findFirst(); - if (valueSetUrl.isPresent()) { - String key = "validateCodeInValueSet " + theValidationOptions.toString() + " " + defaultString(theCodeSystem, "(null)") + " " + defaultString(theCode, "(null)") + " " + defaultString(theDisplay, "(null)") + " " + valueSetUrl.get(); - return loadFromCache(myValidateCodeCache, key, t-> super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet)); - } - - return super.validateCodeInValueSet(theValidationSupportContext, theValidationOptions, theCodeSystem, theCode, theDisplay, theValueSet); - } - @Override public void invalidateCaches() { myLookupCodeCache.invalidateAll(); myCache.invalidateAll(); myValidateCodeCache.invalidateAll(); } + + /** + * @since 5.4.0 + */ + public static class CacheTimeouts { + + private long myTranslateCodeMillis; + private long myLookupCodeMillis; + private long myValidateCodeMillis; + private long myMiscMillis; + + public long getTranslateCodeMillis() { + return myTranslateCodeMillis; + } + + public CacheTimeouts setTranslateCodeMillis(long theTranslateCodeMillis) { + myTranslateCodeMillis = theTranslateCodeMillis; + return this; + } + + public long getLookupCodeMillis() { + return myLookupCodeMillis; + } + + public CacheTimeouts setLookupCodeMillis(long theLookupCodeMillis) { + myLookupCodeMillis = theLookupCodeMillis; + return this; + } + + public long getValidateCodeMillis() { + return myValidateCodeMillis; + } + + public CacheTimeouts setValidateCodeMillis(long theValidateCodeMillis) { + myValidateCodeMillis = theValidateCodeMillis; + return this; + } + + public long getMiscMillis() { + return myMiscMillis; + } + + public CacheTimeouts setMiscMillis(long theMiscMillis) { + myMiscMillis = theMiscMillis; + return this; + } + + public static CacheTimeouts defaultValues() { + return new CacheTimeouts() + .setLookupCodeMillis(10 * DateUtils.MILLIS_PER_MINUTE) + .setTranslateCodeMillis(10 * DateUtils.MILLIS_PER_MINUTE) + .setValidateCodeMillis(10 * DateUtils.MILLIS_PER_MINUTE) + .setMiscMillis(10 * DateUtils.MILLIS_PER_MINUTE); + } + } } diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/InMemoryTerminologyServerValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/InMemoryTerminologyServerValidationSupport.java index f9d134ffe39..28d2407fb33 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/InMemoryTerminologyServerValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/InMemoryTerminologyServerValidationSupport.java @@ -57,7 +57,7 @@ public class InMemoryTerminologyServerValidationSupport implements IValidationSu } @Override - public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { org.hl7.fhir.r5.model.ValueSet expansionR5 = expandValueSetToCanonical(theValidationSupportContext, theValueSetToExpand, null, null); if (expansionR5 == null) { diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java index 841038fd4b7..10ce6294421 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java @@ -5,6 +5,7 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.TranslateConceptResults; import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import org.apache.commons.lang3.Validate; @@ -42,6 +43,31 @@ public class ValidationSupportChain implements IValidationSupport { } } + @Override + public TranslateConceptResults translateConcept(TranslateCodeRequest theRequest) { + TranslateConceptResults retVal = null; + for (IValidationSupport next : myChain) { + TranslateConceptResults translations = next.translateConcept(theRequest); + if (translations != null) { + if (retVal == null) { + retVal = new TranslateConceptResults(); + } + + if (retVal.getMessage() == null) { + retVal.setMessage(translations.getMessage()); + } + + if (translations.getResult() && !retVal.getResult()) { + retVal.setResult(translations.getResult()); + retVal.setMessage(translations.getMessage()); + } + + retVal.getResults().addAll(translations.getResults()); + } + } + return retVal; + } + @Override public void invalidateCaches() { for (IValidationSupport next : myChain) { @@ -131,7 +157,7 @@ public class ValidationSupportChain implements IValidationSupport { } @Override - public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, IBaseResource theValueSetToExpand) { + public ValueSetExpansionOutcome expandValueSet(ValidationSupportContext theValidationSupportContext, ValueSetExpansionOptions theExpansionOptions, @Nonnull IBaseResource theValueSetToExpand) { for (IValidationSupport next : myChain) { // TODO: test if code system is supported? ValueSetExpansionOutcome expanded = next.expandValueSet(theValidationSupportContext, theExpansionOptions, theValueSetToExpand); diff --git a/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java new file mode 100644 index 00000000000..1a07ac3875e --- /dev/null +++ b/hapi-fhir-validation/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseTerminologyDisplayPopulationInterceptorTest.java @@ -0,0 +1,94 @@ +package ca.uhn.fhir.rest.server.interceptor; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.test.utilities.server.HashMapResourceProviderExtension; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.RegisterExtension; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ResponseTerminologyDisplayPopulationInterceptorTest { + + private final FhirContext myCtx = FhirContext.forCached(FhirVersionEnum.R4); + @Order(0) + @RegisterExtension + protected RestfulServerExtension myServerExtension = new RestfulServerExtension(myCtx); + @Order(1) + @RegisterExtension + protected HashMapResourceProviderExtension myProviderPatientExtension = new HashMapResourceProviderExtension<>(myServerExtension, Patient.class); + private IGenericClient myClient; + + @BeforeEach + public void beforeEach() { + myClient = myServerExtension.getFhirClient(); + } + + @AfterEach + public void afterEach() { + myServerExtension.getRestfulServer().getInterceptorService().unregisterAllInterceptors(); + } + + @Test + public void testPopulateCoding_Read() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); + IIdType id = myClient.create().resource(p).execute().getId(); + + p = myClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertEquals("Annulled", p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + + @Test + public void testPopulateCoding_Search() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A"); + IIdType id = myClient.create().resource(p).execute().getId(); + + Bundle bundle = myClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute(); + assertEquals(1, bundle.getEntry().size()); + p = (Patient) bundle.getEntry().get(0).getResource(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertEquals("Annulled", p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + + @Test + public void testDontPopulateCodingIfAlreadyPopulated() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("A").setDisplay("FOO"); + IIdType id = myClient.create().resource(p).execute().getId(); + + p = myClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertEquals("FOO", p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + + @Test + public void testDontPopulateCodingIfNoneFound() { + myServerExtension.getRestfulServer().registerInterceptor(new ResponseTerminologyDisplayPopulationInterceptor(myCtx.getValidationSupport())); + + Patient p = new Patient(); + p.getMaritalStatus().addCoding().setSystem("http://terminology.hl7.org/CodeSystem/v3-MaritalStatus").setCode("ZZZZZZ"); + IIdType id = myClient.create().resource(p).execute().getId(); + + p = myClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(1, p.getMaritalStatus().getCoding().size()); + assertEquals(null, p.getMaritalStatus().getCoding().get(0).getDisplay()); + } + +} diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index d1b246dc1b4..5f3f25b6514 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml @@ -58,37 +58,37 @@ ca.uhn.hapi.fhir hapi-fhir-structures-dstu3 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-hl7org-dstu2 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-r4 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-structures-r5 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-dstu2 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-dstu3 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-validation-resources-r4 - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT org.apache.velocity diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index fa9fc869023..87cdd749b64 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index c1c6c82099e..37e6ec00032 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. https://hapifhir.io diff --git a/restful-server-example/pom.xml b/restful-server-example/pom.xml index f88c2bac86b..0b83454925b 100644 --- a/restful-server-example/pom.xml +++ b/restful-server-example/pom.xml @@ -8,7 +8,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../pom.xml diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index 7020e739997..a9bfd82091e 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index 4da73724308..1bbe808dd62 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 5436174b35d..4a1c0978be1 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 5.4.0-PRE1-SNAPSHOT + 5.4.0-PRE2-SNAPSHOT ../../pom.xml