historyEntities =
myResourceHistoryTableDao.findForResourceIdAndReturnEntitiesAndFetchProvenance(
- PageRequest.of(page, pageSize), entity.getId(), historyEntity.getVersion());
+ pageRequest, entity.getId(), historyEntity.getVersion());
+
for (ResourceHistoryTable next : historyEntities) {
reindexOptimizeStorageHistoryEntity(entity, next);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
index fde57c39836f..d21dff545d32 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
@@ -205,7 +205,7 @@ public void preFetchResources(
*
* However, for realistic average workloads, this should reduce the number of round trips.
*/
- if (idChunk.size() >= 2) {
+ if (!idChunk.isEmpty()) {
List entityChunk = prefetchResourceTableHistoryAndProvenance(idChunk);
if (thePreFetchIndexes) {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java
index e9611614e45b..2b6462072957 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkRepository.java
@@ -150,6 +150,6 @@ List fetchAllChunkIdsForStepWithStatus(
@Param("status") WorkChunkStatusEnum theStatus);
@Query(
- "SELECT new ca.uhn.fhir.batch2.model.BatchWorkChunkStatusDTO(e.myTargetStepId, e.myStatus, min(e.myStartTime), max(e.myEndTime), avg(e.myEndTime - e.myStartTime), count(*)) FROM Batch2WorkChunkEntity e WHERE e.myInstanceId=:instanceId GROUP BY e.myTargetStepId, e.myStatus")
+ "SELECT new ca.uhn.fhir.batch2.model.BatchWorkChunkStatusDTO(e.myTargetStepId, e.myStatus, min(e.myStartTime), max(e.myEndTime), avg(cast((e.myEndTime - e.myStartTime) as long)), count(*)) FROM Batch2WorkChunkEntity e WHERE e.myInstanceId=:instanceId GROUP BY e.myTargetStepId, e.myStatus")
List fetchWorkChunkStatusForInstance(@Param("instanceId") String theInstanceId);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
index 477999b3d3eb..f169fba81d84 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/SearchCoordinatorSvcImpl.java
@@ -605,12 +605,12 @@ private PersistedJpaBundleProvider findCachedQuery(
.add(SearchParameterMap.class, theParams)
.add(RequestDetails.class, theRequestDetails)
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
- Object outcome = CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
+ boolean canUseCache = CompositeInterceptorBroadcaster.doCallHooks(
myInterceptorBroadcaster,
theRequestDetails,
Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH,
params);
- if (Boolean.FALSE.equals(outcome)) {
+ if (!canUseCache) {
return null;
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java
index 5eadee42cb1f..e7d688624d22 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/search/builder/QueryStack.java
@@ -210,7 +210,7 @@ public void addSortOnCoordsNear(String theParamName, boolean theAscending, Searc
CoordsPredicateBuilder coordsBuilder = (CoordsPredicateBuilder) builder;
List> params = theParams.get(theParamName);
- if (params.size() > 0 && params.get(0).size() > 0) {
+ if (!params.isEmpty() && !params.get(0).isEmpty()) {
IQueryParameterType param = params.get(0).get(0);
ParsedLocationParam location = ParsedLocationParam.from(theParams, param);
double latitudeValue = location.getLatitudeValue();
@@ -2134,6 +2134,10 @@ private boolean populateTokens(
if (nextParam.getModifier() == TokenParamModifier.NOT) {
paramInverted = true;
}
+ } else if (nextOrParam instanceof ReferenceParam) {
+ ReferenceParam nextParam = (ReferenceParam) nextOrParam;
+ code = nextParam.getValue();
+ system = null;
} else {
UriParam nextParam = (UriParam) nextOrParam;
code = nextParam.getValue();
@@ -2160,8 +2164,10 @@ private boolean checkHaveTags(List extends IQueryParameterType> theParams, Str
}
}
- UriParam nextParam = (UriParam) nextParamUncasted;
- if (isNotBlank(nextParam.getValue())) {
+ if (nextParamUncasted instanceof ReferenceParam
+ && isNotBlank(((ReferenceParam) nextParamUncasted).getValue())) {
+ return true;
+ } else if (nextParamUncasted instanceof UriParam && isNotBlank(((UriParam) nextParamUncasted).getValue())) {
return true;
}
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java
index 8cd06745910c..972255d93762 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermReadSvcImpl.java
@@ -1056,7 +1056,8 @@ private void expandValueSetHandleIncludeOrExclude(
if (theExpansionOptions != null
&& !theExpansionOptions.isFailOnMissingCodeSystem()
// Code system is unknown, therefore NOT_FOUND
- && e.getCodeValidationIssue().getCoding() == CodeValidationIssueCoding.NOT_FOUND) {
+ && e.getCodeValidationIssue()
+ .hasIssueDetailCode(CodeValidationIssueCoding.NOT_FOUND.getCode())) {
return;
}
throw new InternalErrorException(Msg.code(888) + e);
@@ -2203,7 +2204,7 @@ private CodeValidationResult createFailureCodeValidationResult(
.setSeverity(IssueSeverity.ERROR)
.setCodeSystemVersion(theCodeSystemVersion)
.setMessage(theMessage)
- .addCodeValidationIssue(new CodeValidationIssue(
+ .addIssue(new CodeValidationIssue(
theMessage,
IssueSeverity.ERROR,
CodeValidationIssueCode.CODE_INVALID,
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/helper/BaseMdmHelper.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/helper/BaseMdmHelper.java
index 33a288ee811a..ee0e08ef7eae 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/helper/BaseMdmHelper.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/helper/BaseMdmHelper.java
@@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.mdm.helper;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.api.Pointcut;
@@ -23,6 +24,7 @@
import java.util.function.Supplier;
import static org.awaitility.Awaitility.await;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
/**
@@ -78,6 +80,7 @@ public void beforeEach(ExtensionContext context) throws Exception {
//they are coming from an external HTTP Request.
MockitoAnnotations.initMocks(this);
when(myMockSrd.getInterceptorBroadcaster()).thenReturn(myMockInterceptorBroadcaster);
+ when(myMockInterceptorBroadcaster.callHooks(any(Pointcut.class), any(HookParams.class))).thenReturn(true);
when(myMockSrd.getServletRequest()).thenReturn(myMockServletRequest);
when(myMockSrd.getServer()).thenReturn(myMockRestfulServer);
when(myMockSrd.getRequestId()).thenReturn("MOCK_REQUEST");
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java
index d7f85325a7f6..ab890c96853e 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java
@@ -881,6 +881,11 @@ public void testPrestorageInterceptor_whenModifyingJobInstance_modifiedJobInstan
public void testFetchInstanceAndWorkChunkStatus() {
// Setup
+ Date date1 = new Date();
+ Date date2 = new Date();
+
+
+
List chunkIds = new ArrayList<>();
JobInstance instance = createInstance();
String instanceId = mySvc.storeNewInstance(instance);
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/imprt/svc/BulkDataImportR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/imprt/svc/BulkDataImportR4Test.java
index dec666c0c157..7c3a6e67c46e 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/imprt/svc/BulkDataImportR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/imprt/svc/BulkDataImportR4Test.java
@@ -17,6 +17,7 @@
import ca.uhn.fhir.jpa.bulk.imprt.model.ActivateJobResult;
import ca.uhn.fhir.jpa.bulk.imprt.model.BulkImportJobFileJson;
import ca.uhn.fhir.jpa.bulk.imprt.model.BulkImportJobJson;
+import ca.uhn.fhir.jpa.bulk.imprt.model.BulkImportJobStatusEnum;
import ca.uhn.fhir.jpa.bulk.imprt.model.JobFileRowProcessingModeEnum;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelConsumerSettings;
@@ -166,6 +167,8 @@ public void testFlow_TransactionRows() {
ActivateJobResult activateJobOutcome = mySvc.activateNextReadyJob();
assertTrue(activateJobOutcome.isActivated);
+ // validate that job changed status from READY to RUNNING
+ assertEquals(BulkImportJobStatusEnum.RUNNING, mySvc.getJobStatus(jobId).getStatus());
JobInstance instance = myBatch2JobHelper.awaitJobCompletion(activateJobOutcome.jobId, 60);
assertNotNull(instance);
@@ -196,6 +199,8 @@ public void testFlow_WithTenantNamesInInput() {
ActivateJobResult activateJobOutcome = mySvc.activateNextReadyJob();
assertTrue(activateJobOutcome.isActivated);
+ // validate that job changed status from READY to RUNNING
+ assertEquals(BulkImportJobStatusEnum.RUNNING, mySvc.getJobStatus(jobId).getStatus());
JobInstance instance = myBatch2JobHelper.awaitJobCompletion(activateJobOutcome.jobId);
assertNotNull(instance);
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseComboParamsR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseComboParamsR4Test.java
index f73670fbddc8..2eb8a60aa2e8 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseComboParamsR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/BaseComboParamsR4Test.java
@@ -62,6 +62,9 @@ public void before() throws Exception {
myMessages.add("REUSING CACHED SEARCH");
return null;
});
+
+ // allow searches to use cached results
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH), ArgumentMatchers.any(HookParams.class))).thenReturn(true);
}
@AfterEach
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ContainedTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ContainedTest.java
index 636ffd02b401..6b10598174b5 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ContainedTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ContainedTest.java
@@ -1,6 +1,7 @@
package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.i18n.Msg;
+import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@@ -23,6 +24,8 @@
import org.hl7.fhir.r4.model.ServiceRequest;
import org.hl7.fhir.r4.model.ServiceRequest.ServiceRequestIntent;
import org.hl7.fhir.r4.model.ServiceRequest.ServiceRequestStatus;
+import org.hl7.fhir.r4.model.Specimen;
+import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java
index c09eed9cb620..c8b4bdbe41bb 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4CreateTest.java
@@ -28,6 +28,7 @@
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.BundleBuilder;
import ca.uhn.fhir.util.ClasspathUtil;
import org.apache.commons.lang3.StringUtils;
@@ -81,6 +82,7 @@
import java.util.concurrent.Future;
import java.util.stream.Collectors;
+import static ca.uhn.fhir.test.utilities.UuidUtils.HASH_UUID_PATTERN;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -738,7 +740,8 @@ public void testTagsInContainedResourcesPreserved() {
String encoded = myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info("Input: {}", encoded);
- assertThat(encoded).contains("#1");
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
@@ -746,10 +749,12 @@ public void testTagsInContainedResourcesPreserved() {
encoded = myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info("Output: {}", encoded);
- assertThat(encoded).contains("#1");
+ String organizationUuidParsed = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuidParsed);
+ assertEquals(organizationUuid, organizationUuidParsed);
Organization org = (Organization) p.getManagingOrganization().getResource();
- assertEquals("#1", org.getId());
+ assertEquals("#" + organizationUuid, org.getId());
assertThat(org.getMeta().getTag()).hasSize(1);
}
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
index 635e847d5dcb..aa5fd85af49f 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QueryCountTest.java
@@ -2722,7 +2722,7 @@ public void testTransactionWithCreateClientAssignedIdAndReference() {
ourLog.debug(myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
- assertEquals(3, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
+ assertEquals(2, myCaptureQueriesListener.countSelectQueriesForCurrentThread());
myCaptureQueriesListener.logInsertQueriesForCurrentThread();
assertEquals(2, myCaptureQueriesListener.countInsertQueriesForCurrentThread());
myCaptureQueriesListener.logUpdateQueriesForCurrentThread();
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java
index 4ad723edfa30..f835c300c199 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4VersionedReferenceTest.java
@@ -428,7 +428,7 @@ public void testInsertVersionedReferenceAtPath_InTransaction_TargetUpdate() {
IdType observationId = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
// Make sure we're not introducing any extra DB operations
- assertThat(myCaptureQueriesListener.logSelectQueries()).hasSize(3);
+ assertThat(myCaptureQueriesListener.logSelectQueries()).hasSize(2);
// Read back and verify that reference is now versioned
observation = myObservationDao.read(observationId);
@@ -463,7 +463,7 @@ public void testInsertVersionedReferenceAtPath_InTransaction_TargetUpdateConditi
IdType observationId = new IdType(outcome.getEntry().get(1).getResponse().getLocation());
// Make sure we're not introducing any extra DB operations
- assertThat(myCaptureQueriesListener.logSelectQueries()).hasSize(4);
+ assertThat(myCaptureQueriesListener.logSelectQueries()).hasSize(3);
// Read back and verify that reference is now versioned
observation = myObservationDao.read(observationId);
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java
index 88a8def13c86..f36a093e147c 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4Test.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao.r4;
+import static ca.uhn.fhir.test.utilities.UuidUtils.HASH_UUID_PATTERN;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -3219,8 +3220,8 @@ public void testTransactionWithContainedResource() {
String id = outcome.getEntry().get(0).getResponse().getLocation();
patient = myPatientDao.read(new IdType(id));
- assertEquals("#1", patient.getManagingOrganization().getReference());
- assertEquals("#1", patient.getContained().get(0).getId());
+ assertThat(patient.getManagingOrganization().getReference()).containsPattern(HASH_UUID_PATTERN);
+ assertEquals(patient.getManagingOrganization().getReference(), patient.getContained().get(0).getId());
}
@Nonnull
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index 1ddb1cca9d32..8f3e849719f1 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -263,6 +263,8 @@ public void before() throws Exception {
myStorageSettings.setSearchPreFetchThresholds(new JpaStorageSettings().getSearchPreFetchThresholds());
}
+
+
@Test
public void testParameterWithNoValueThrowsError_InvalidChainOnCustomSearch() throws IOException {
SearchParameter searchParameter = new SearchParameter();
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ReindexTaskTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ReindexTaskTest.java
index c04a40f1ac7f..290dfcdf9b4b 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ReindexTaskTest.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ReindexTaskTest.java
@@ -180,6 +180,59 @@ public void testOptimizeStorage_AllVersions() {
}
+ @Test
+ public void testOptimizeStorage_AllVersions_SingleResourceWithMultipleVersion() {
+
+ // this difference of this test from testOptimizeStorage_AllVersions is that this one has only 1 resource
+ // (with multiple versions) in the db. There was a bug where if only one resource were being re-indexed, the
+ // resource wasn't processed for optimize storage.
+
+ // Setup
+ IIdType patientId = createPatient(withActiveTrue());
+ for (int i = 0; i < 10; i++) {
+ Patient p = new Patient();
+ p.setId(patientId.toUnqualifiedVersionless());
+ p.setActive(true);
+ p.addIdentifier().setValue(String.valueOf(i));
+ myPatientDao.update(p, mySrd);
+ }
+
+ // Move resource text to compressed storage, which we don't write to anymore but legacy
+ // data may exist that was previously stored there, so we're simulating that.
+ List allHistoryEntities = runInTransaction(() -> myResourceHistoryTableDao.findAll());
+ allHistoryEntities.forEach(t->relocateResourceTextToCompressedColumn(t.getResourceId(), t.getVersion()));
+
+ runInTransaction(()->{
+ assertEquals(11, myResourceHistoryTableDao.count());
+ for (ResourceHistoryTable history : myResourceHistoryTableDao.findAll()) {
+ assertNull(history.getResourceTextVc());
+ assertNotNull(history.getResource());
+ }
+ });
+
+ // execute
+ JobInstanceStartRequest startRequest = new JobInstanceStartRequest();
+ startRequest.setJobDefinitionId(JOB_REINDEX);
+ startRequest.setParameters(
+ new ReindexJobParameters()
+ .setOptimizeStorage(ReindexParameters.OptimizeStorageModeEnum.ALL_VERSIONS)
+ .setReindexSearchParameters(ReindexParameters.ReindexSearchParametersEnum.NONE)
+ );
+ Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(mySrd, startRequest);
+ myBatch2JobHelper.awaitJobCompletion(startResponse);
+
+ // validate
+ runInTransaction(()->{
+ assertEquals(11, myResourceHistoryTableDao.count());
+ for (ResourceHistoryTable history : myResourceHistoryTableDao.findAll()) {
+ assertNotNull(history.getResourceTextVc());
+ assertNull(history.getResource());
+ }
+ });
+ Patient patient = myPatientDao.read(patientId, mySrd);
+ assertTrue(patient.getActive());
+ }
+
@Test
public void testOptimizeStorage_AllVersions_CopyProvenanceEntityData() {
// Setup
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ValidateCodeOperationWithRemoteTerminologyR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateCodeWithRemoteTerminologyR4Test.java
similarity index 59%
rename from hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ValidateCodeOperationWithRemoteTerminologyR4Test.java
rename to hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateCodeWithRemoteTerminologyR4Test.java
index 4da204217f05..3787c611eb75 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ValidateCodeOperationWithRemoteTerminologyR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateCodeWithRemoteTerminologyR4Test.java
@@ -1,29 +1,21 @@
-package ca.uhn.fhir.jpa.provider.r4;
+package ca.uhn.fhir.jpa.validation;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.JpaConfig;
import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
-import ca.uhn.fhir.rest.annotation.IdParam;
-import ca.uhn.fhir.rest.annotation.Operation;
-import ca.uhn.fhir.rest.annotation.OperationParam;
-import ca.uhn.fhir.rest.annotation.RequiredParam;
-import ca.uhn.fhir.rest.annotation.Search;
-import ca.uhn.fhir.rest.param.UriParam;
-import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
-import jakarta.servlet.http.HttpServletRequest;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersR4;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
-import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.Coding;
-import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Parameters;
-import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.UriType;
import org.hl7.fhir.r4.model.ValueSet;
import org.junit.jupiter.api.AfterEach;
@@ -33,9 +25,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
-import java.util.ArrayList;
-import java.util.List;
-
+import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_VALIDATE_CODE;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -43,15 +33,15 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
-/*
+/**
* This set of integration tests that instantiates and injects an instance of
* {@link org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport}
* into the ValidationSupportChain, which tests the logic of dynamically selecting the correct Remote Terminology
- * implementation. It also exercises the code found in
- * {@link org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport#invokeRemoteValidateCode}
+ * implementation. It also exercises the validateCode output translation code found in
+ * {@link org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport}
*/
-public class ValidateCodeOperationWithRemoteTerminologyR4Test extends BaseResourceProviderR4Test {
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateCodeOperationWithRemoteTerminologyR4Test.class);
+public class ValidateCodeWithRemoteTerminologyR4Test extends BaseResourceProviderR4Test {
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidateCodeWithRemoteTerminologyR4Test.class);
private static final String DISPLAY = "DISPLAY";
private static final String DISPLAY_BODY_MASS_INDEX = "Body mass index (BMI) [Ratio]";
private static final String CODE_BODY_MASS_INDEX = "39156-5";
@@ -64,8 +54,8 @@ public class ValidateCodeOperationWithRemoteTerminologyR4Test extends BaseResour
protected static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
private RemoteTerminologyServiceValidationSupport mySvc;
- private MyCodeSystemProvider myCodeSystemProvider;
- private MyValueSetProvider myValueSetProvider;
+ private IValidationProviders.MyValidationProvider myCodeSystemProvider;
+ private IValidationProviders.MyValidationProvider myValueSetProvider;
@Autowired
@Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT_CHAIN)
@@ -76,8 +66,8 @@ public void before() throws Exception {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
myValidationSupportChain.addValidationSupport(0, mySvc);
- myCodeSystemProvider = new MyCodeSystemProvider();
- myValueSetProvider = new MyValueSetProvider();
+ myCodeSystemProvider = new IValidationProvidersR4.MyCodeSystemProviderR4();
+ myValueSetProvider = new IValidationProvidersR4.MyValueSetProviderR4();
ourRestfulServerExtension.registerProvider(myCodeSystemProvider);
ourRestfulServerExtension.registerProvider(myValueSetProvider);
}
@@ -103,11 +93,11 @@ public void validateCodeOperationOnCodeSystem_byCodingAndUrlWhereSystemIsDiffere
@Test
public void validateCodeOperationOnCodeSystem_byCodingAndUrl_usingBuiltInCodeSystems() {
- myCodeSystemProvider.myReturnCodeSystems = new ArrayList<>();
- myCodeSystemProvider.myReturnCodeSystems.add((CodeSystem) new CodeSystem().setId("CodeSystem/v2-0247"));
- myCodeSystemProvider.myReturnParams = new Parameters();
- myCodeSystemProvider.myReturnParams.addParameter("result", true);
- myCodeSystemProvider.myReturnParams.addParameter("display", DISPLAY);
+ final String code = "P";
+ final String system = CODE_SYSTEM_V2_0247_URI;;
+
+ Parameters params = new Parameters().addParameter("result", true).addParameter("display", DISPLAY);
+ setupCodeSystemValidateCode(system, code, params);
logAllConcepts();
@@ -115,8 +105,8 @@ public void validateCodeOperationOnCodeSystem_byCodingAndUrl_usingBuiltInCodeSys
.operation()
.onType(CodeSystem.class)
.named(JpaConstants.OPERATION_VALIDATE_CODE)
- .withParameter(Parameters.class, "coding", new Coding().setSystem(CODE_SYSTEM_V2_0247_URI).setCode("P"))
- .andParameter("url", new UriType(CODE_SYSTEM_V2_0247_URI))
+ .withParameter(Parameters.class, "coding", new Coding().setSystem(system).setCode(code))
+ .andParameter("url", new UriType(system))
.execute();
String resp = myFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
@@ -128,7 +118,7 @@ public void validateCodeOperationOnCodeSystem_byCodingAndUrl_usingBuiltInCodeSys
@Test
public void validateCodeOperationOnCodeSystem_byCodingAndUrlWhereCodeSystemIsUnknown_returnsFalse() {
- myCodeSystemProvider.myReturnCodeSystems = new ArrayList<>();
+ myCodeSystemProvider.setShouldThrowExceptionForResourceNotFound(false);
Parameters respParam = myClient
.operation()
@@ -166,21 +156,21 @@ public void validateCodeOperationOnValueSet_byCodingAndUrlWhereSystemIsDifferent
@Test
public void validateCodeOperationOnValueSet_byUrlAndSystem_usingBuiltInCodeSystems() {
- myCodeSystemProvider.myReturnCodeSystems = new ArrayList<>();
- myCodeSystemProvider.myReturnCodeSystems.add((CodeSystem) new CodeSystem().setId("CodeSystem/list-example-use-codes"));
- myValueSetProvider.myReturnValueSets = new ArrayList<>();
- myValueSetProvider.myReturnValueSets.add((ValueSet) new ValueSet().setId("ValueSet/list-example-codes"));
- myValueSetProvider.myReturnParams = new Parameters();
- myValueSetProvider.myReturnParams.addParameter("result", true);
- myValueSetProvider.myReturnParams.addParameter("display", DISPLAY);
+ final String code = "alerts";
+ final String system = "http://terminology.hl7.org/CodeSystem/list-example-use-codes";
+ final String valueSetUrl = "http://hl7.org/fhir/ValueSet/list-example-codes";
+
+ Parameters params = new Parameters().addParameter("result", true).addParameter("display", DISPLAY);
+ setupValueSetValidateCode(valueSetUrl, system, code, params);
+ setupCodeSystemValidateCode(system, code, params);
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named(JpaConstants.OPERATION_VALIDATE_CODE)
- .withParameter(Parameters.class, "code", new CodeType("alerts"))
- .andParameter("system", new UriType("http://terminology.hl7.org/CodeSystem/list-example-use-codes"))
- .andParameter("url", new UriType("http://hl7.org/fhir/ValueSet/list-example-codes"))
+ .withParameter(Parameters.class, "code", new CodeType(code))
+ .andParameter("system", new UriType(system))
+ .andParameter("url", new UriType(valueSetUrl))
.useHttpGet()
.execute();
@@ -193,21 +183,20 @@ public void validateCodeOperationOnValueSet_byUrlAndSystem_usingBuiltInCodeSyste
@Test
public void validateCodeOperationOnValueSet_byUrlSystemAndCode() {
- myCodeSystemProvider.myReturnCodeSystems = new ArrayList<>();
- myCodeSystemProvider.myReturnCodeSystems.add((CodeSystem) new CodeSystem().setId("CodeSystem/list-example-use-codes"));
- myValueSetProvider.myReturnValueSets = new ArrayList<>();
- myValueSetProvider.myReturnValueSets.add((ValueSet) new ValueSet().setId("ValueSet/list-example-codes"));
- myValueSetProvider.myReturnParams = new Parameters();
- myValueSetProvider.myReturnParams.addParameter("result", true);
- myValueSetProvider.myReturnParams.addParameter("display", DISPLAY_BODY_MASS_INDEX);
+ final String code = CODE_BODY_MASS_INDEX;
+ final String system = "http://terminology.hl7.org/CodeSystem/list-example-use-codes";
+ final String valueSetUrl = "http://hl7.org/fhir/ValueSet/list-example-codes";
+
+ Parameters params = new Parameters().addParameter("result", true).addParameter("display", DISPLAY_BODY_MASS_INDEX);
+ setupValueSetValidateCode(valueSetUrl, system, code, params);
Parameters respParam = myClient
.operation()
.onType(ValueSet.class)
.named(JpaConstants.OPERATION_VALIDATE_CODE)
- .withParameter(Parameters.class, "code", new CodeType(CODE_BODY_MASS_INDEX))
- .andParameter("url", new UriType("https://loinc.org"))
- .andParameter("system", new UriType("http://loinc.org"))
+ .withParameter(Parameters.class, "code", new CodeType(code))
+ .andParameter("url", new UriType(valueSetUrl))
+ .andParameter("system", new UriType(system))
.execute();
String resp = myFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(respParam);
@@ -219,7 +208,7 @@ public void validateCodeOperationOnValueSet_byUrlSystemAndCode() {
@Test
public void validateCodeOperationOnValueSet_byCodingAndUrlWhereValueSetIsUnknown_returnsFalse() {
- myValueSetProvider.myReturnValueSets = new ArrayList<>();
+ myValueSetProvider.setShouldThrowExceptionForResourceNotFound(false);
Parameters respParam = myClient
.operation()
@@ -238,70 +227,18 @@ public void validateCodeOperationOnValueSet_byCodingAndUrlWhereValueSetIsUnknown
" - Unknown or unusable ValueSet[" + UNKNOWN_VALUE_SYSTEM_URI + "]");
}
- @SuppressWarnings("unused")
- private static class MyCodeSystemProvider implements IResourceProvider {
- private List myReturnCodeSystems;
- private Parameters myReturnParams;
-
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
- @OperationParam(name = "result", type = BooleanType.class, min = 1),
- @OperationParam(name = "message", type = StringType.class),
- @OperationParam(name = "display", type = StringType.class)
- })
- public Parameters validateCode(
- HttpServletRequest theServletRequest,
- @IdParam(optional = true) IdType theId,
- @OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl,
- @OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
- @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay
- ) {
- return myReturnParams;
- }
-
- @Search
- public List find(@RequiredParam(name = "url") UriParam theUrlParam) {
- assert myReturnCodeSystems != null;
- return myReturnCodeSystems;
- }
+ private void setupValueSetValidateCode(String theUrl, String theSystem, String theCode, IBaseParameters theResponseParams) {
+ ValueSet valueSet = myValueSetProvider.addTerminologyResource(theUrl);
+ myValueSetProvider.addTerminologyResource(theSystem);
+ myValueSetProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, valueSet.getUrl(), theCode, theResponseParams);
- @Override
- public Class extends IBaseResource> getResourceType() {
- return CodeSystem.class;
- }
+ // we currently do this because VersionSpecificWorkerContextWrapper has logic to infer the system when missing
+ // based on the ValueSet by calling ValidationSupportUtils#extractCodeSystemForCode.
+ valueSet.getCompose().addInclude().setSystem(theSystem);
}
- @SuppressWarnings("unused")
- private static class MyValueSetProvider implements IResourceProvider {
- private Parameters myReturnParams;
- private List myReturnValueSets;
-
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
- @OperationParam(name = "result", type = BooleanType.class, min = 1),
- @OperationParam(name = "message", type = StringType.class),
- @OperationParam(name = "display", type = StringType.class)
- })
- public Parameters validateCode(
- HttpServletRequest theServletRequest,
- @IdParam(optional = true) IdType theId,
- @OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
- @OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
- @OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
- @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
- @OperationParam(name = "valueSet") ValueSet theValueSet
- ) {
- return myReturnParams;
- }
-
- @Search
- public List find(@RequiredParam(name = "url") UriParam theUrlParam) {
- assert myReturnValueSets != null;
- return myReturnValueSets;
- }
-
- @Override
- public Class extends IBaseResource> getResourceType() {
- return ValueSet.class;
- }
-
+ private void setupCodeSystemValidateCode(String theUrl, String theCode, IBaseParameters theResponseParams) {
+ CodeSystem codeSystem = myCodeSystemProvider.addTerminologyResource(theUrl);
+ myCodeSystemProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, codeSystem.getUrl(), theCode, theResponseParams);
}
}
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateWithRemoteTerminologyTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateWithRemoteTerminologyTest.java
new file mode 100644
index 000000000000..79a656db39c7
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/validation/ValidateWithRemoteTerminologyTest.java
@@ -0,0 +1,261 @@
+package ca.uhn.fhir.jpa.validation;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.config.JpaConfig;
+import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
+import ca.uhn.fhir.rest.api.MethodOutcome;
+import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersR4;
+import ca.uhn.fhir.util.ClasspathUtil;
+import org.apache.commons.lang3.StringUtils;
+import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
+import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.CodeSystem;
+import org.hl7.fhir.r4.model.Encounter;
+import org.hl7.fhir.r4.model.Observation;
+import org.hl7.fhir.r4.model.OperationOutcome;
+import org.hl7.fhir.r4.model.Procedure;
+import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.StructureDefinition;
+import org.hl7.fhir.r4.model.ValueSet;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.RegisterExtension;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+
+import java.util.List;
+
+import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_VALIDATE_CODE;
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Tests resource validation with Remote Terminology bindings.
+ * To create a new test, you need to do 3 things:
+ * (1) the resource profile, if any custom one is needed should be stored in the FHIR repository
+ * (2) all the CodeSystem and ValueSet terminology resources need to be added to the corresponding resource provider.
+ * At the moment only placeholder CodeSystem/ValueSet resources are returned with id and url populated. For the moment
+ * there was no need to load the full resource, but that can be done if there is logic run which requires it.
+ * This is a minimal setup.
+ * (3) the Remote Terminology operation responses that are needed for the test need to be added to the corresponding
+ * resource provider. The intention is to record and use the responses of an actual terminology server
+ * e.g. OntoServer.
+ * This is done as a result of the fact that unit test cannot always catch bugs which are introduced as a result of
+ * changes in the OntoServer or FHIR Validator library, or both.
+ * @see #setupValueSetValidateCode
+ * @see #setupCodeSystemValidateCode
+ * The responses are in Parameters resource format where issues is an OperationOutcome resource.
+ */
+public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Test {
+ private static final FhirContext ourCtx = FhirContext.forR4Cached();
+
+ @RegisterExtension
+ protected static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
+ private RemoteTerminologyServiceValidationSupport mySvc;
+ @Autowired
+ @Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT_CHAIN)
+ private ValidationSupportChain myValidationSupportChain;
+ private IValidationProviders.MyValidationProvider myCodeSystemProvider;
+ private IValidationProviders.MyValidationProvider myValueSetProvider;
+
+ @BeforeEach
+ public void before() {
+ String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
+ mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
+ myValidationSupportChain.addValidationSupport(0, mySvc);
+ myCodeSystemProvider = new IValidationProvidersR4.MyCodeSystemProviderR4();
+ myValueSetProvider = new IValidationProvidersR4.MyValueSetProviderR4();
+ ourRestfulServerExtension.registerProvider(myCodeSystemProvider);
+ ourRestfulServerExtension.registerProvider(myValueSetProvider);
+ }
+
+ @AfterEach
+ public void after() {
+ myValidationSupportChain.removeValidationSupport(mySvc);
+ ourRestfulServerExtension.getRestfulServer().getInterceptorService().unregisterAllInterceptors();
+ ourRestfulServerExtension.unregisterProvider(myCodeSystemProvider);
+ ourRestfulServerExtension.unregisterProvider(myValueSetProvider);
+ }
+
+ @Test
+ public void validate_withProfileWithValidCodesFromAllBindingTypes_returnsNoErrors() {
+ // setup
+ final StructureDefinition profileEncounter = ClasspathUtil.loadResource(ourCtx, StructureDefinition.class, "validation/encounter/profile-encounter-custom.json");
+ myClient.update().resource(profileEncounter).execute();
+
+ final String statusCode = "planned";
+ final String classCode = "IMP";
+ final String identifierTypeCode = "VN";
+
+ final String statusSystem = "http://hl7.org/fhir/encounter-status"; // implied system
+ final String classSystem = "http://terminology.hl7.org/CodeSystem/v3-ActCode";
+ final String identifierTypeSystem = "http://terminology.hl7.org/CodeSystem/v2-0203";
+
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/encounter-status", "http://hl7.org/fhir/encounter-status", statusCode, "validation/encounter/validateCode-ValueSet-encounter-status.json");
+ setupValueSetValidateCode("http://terminology.hl7.org/ValueSet/v3-ActEncounterCode", "http://terminology.hl7.org/CodeSystem/v3-ActCode", classCode, "validation/encounter/validateCode-ValueSet-v3-ActEncounterCode.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/identifier-type", "http://hl7.org/fhir/identifier-type", identifierTypeCode, "validation/encounter/validateCode-ValueSet-identifier-type.json");
+
+ setupCodeSystemValidateCode(statusSystem, statusCode, "validation/encounter/validateCode-CodeSystem-encounter-status.json");
+ setupCodeSystemValidateCode(classSystem, classCode, "validation/encounter/validateCode-CodeSystem-v3-ActCode.json");
+ setupCodeSystemValidateCode(identifierTypeSystem, identifierTypeCode, "validation/encounter/validateCode-CodeSystem-v2-0203.json");
+
+ Encounter encounter = new Encounter();
+ encounter.getMeta().addProfile("http://example.ca/fhir/StructureDefinition/profile-encounter");
+
+ // required binding
+ encounter.setStatus(Encounter.EncounterStatus.fromCode(statusCode));
+
+ // preferred binding
+ encounter.getClass_()
+ .setSystem(classSystem)
+ .setCode(classCode)
+ .setDisplay("inpatient encounter");
+
+ // extensible binding
+ encounter.addIdentifier()
+ .getType().addCoding()
+ .setSystem(identifierTypeSystem)
+ .setCode(identifierTypeCode)
+ .setDisplay("Visit number");
+
+ // execute
+ List errors = getValidationErrors(encounter);
+
+ // verify
+ assertThat(errors).isEmpty();
+ }
+
+ @Test
+ public void validate_withInvalidCode_returnsErrors() {
+ // setup
+ final String statusCode = "final";
+ final String code = "10xx";
+
+ final String statusSystem = "http://hl7.org/fhir/observation-status";
+ final String loincSystem = "http://loinc.org";
+ final String system = "http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM";
+
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/observation-status", statusSystem, statusCode, "validation/observation/validateCode-ValueSet-observation-status.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/observation-codes", loincSystem, statusCode, "validation/observation/validateCode-ValueSet-codes.json");
+
+ setupCodeSystemValidateCode(statusSystem, statusCode, "validation/observation/validateCode-CodeSystem-observation-status.json");
+ setupCodeSystemValidateCode(system, code, "validation/observation/validateCode-CodeSystem-ICD9CM.json");
+
+ Observation obs = new Observation();
+ obs.setStatus(Observation.ObservationStatus.fromCode(statusCode));
+ obs.getCode().addCoding().setCode(code).setSystem(system);
+
+ // execute
+ List errors = getValidationErrors(obs);
+ assertThat(errors).hasSize(1);
+
+ // verify
+ assertThat(errors.get(0))
+ .contains("Unknown code '10xx' in the CodeSystem 'http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM");
+ }
+
+ @Test
+ public void validate_withProfileWithInvalidCode_returnsErrors() {
+ // setup
+ String profile = "http://example.ca/fhir/StructureDefinition/profile-procedure";
+ StructureDefinition profileProcedure = ClasspathUtil.loadResource(myFhirContext, StructureDefinition.class, "validation/procedure/profile-procedure.json");
+ myClient.update().resource(profileProcedure).execute();
+
+ final String statusCode = "completed";
+ final String procedureCode1 = "417005";
+ final String procedureCode2 = "xx417005";
+
+ final String statusSystem = "http://hl7.org/fhir/event-status";
+ final String snomedSystem = "http://snomed.info/sct";
+
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode1, "validation/procedure/validateCode-ValueSet-procedure-code-valid.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode2, "validation/procedure/validateCode-ValueSet-procedure-code-invalid.json");
+
+ setupCodeSystemValidateCode(statusSystem, statusCode, "validation/procedure/validateCode-CodeSystem-event-status.json");
+ setupCodeSystemValidateCode(snomedSystem, procedureCode1, "validation/procedure/validateCode-CodeSystem-snomed-valid.json");
+ setupCodeSystemValidateCode(snomedSystem, procedureCode2, "validation/procedure/validateCode-CodeSystem-snomed-invalid.json");
+
+ Procedure procedure = new Procedure();
+ procedure.setSubject(new Reference("Patient/P1"));
+ procedure.setStatus(Procedure.ProcedureStatus.fromCode(statusCode));
+ procedure.getCode().addCoding().setSystem(snomedSystem).setCode(procedureCode1);
+ procedure.getCode().addCoding().setSystem(snomedSystem).setCode(procedureCode2);
+ procedure.getMeta().addProfile(profile);
+
+ // execute
+ List errors = getValidationErrors(procedure);
+ // TODO: there is currently some duplication in the errors returned. This needs to be investigated and fixed.
+ // assertThat(errors).hasSize(1);
+
+ // verify
+ // note that we're not selecting an explicit versions (using latest) so the message verification does not include it.
+ assertThat(StringUtils.join("", errors))
+ .contains("Unknown code 'xx417005' in the CodeSystem 'http://snomed.info/sct'")
+ .doesNotContain("The provided code 'http://snomed.info/sct#xx417005' was not found in the value set 'http://hl7.org/fhir/ValueSet/procedure-code")
+ .doesNotContain("http://snomed.info/sct#417005");
+ }
+
+ @Test
+ public void validate_withProfileWithSlicingWithValidCode_returnsNoErrors() {
+ // setup
+ String profile = "http://example.ca/fhir/StructureDefinition/profile-procedure-with-slicing";
+ StructureDefinition profileProcedure = ClasspathUtil.loadResource(myFhirContext, StructureDefinition.class, "validation/procedure/profile-procedure-slicing.json");
+ myClient.update().resource(profileProcedure).execute();
+
+ final String statusCode = "completed";
+ final String procedureCode = "no-procedure-info";
+
+ final String statusSystem = "http://hl7.org/fhir/event-status";
+ final String snomedSystem = "http://snomed.info/sct";
+ final String absentUnknownSystem = "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips";
+
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode, "validation/procedure/validateCode-ValueSet-procedure-code-invalid-slice.json");
+ setupValueSetValidateCode("http://hl7.org/fhir/uv/ips/ValueSet/absent-or-unknown-procedures-uv-ips", absentUnknownSystem, procedureCode, "validation/procedure/validateCode-ValueSet-absent-or-unknown-procedure.json");
+
+ setupCodeSystemValidateCode(statusSystem, statusCode, "validation/procedure/validateCode-CodeSystem-event-status.json");
+ setupCodeSystemValidateCode(absentUnknownSystem, procedureCode, "validation/procedure/validateCode-CodeSystem-absent-or-unknown.json");
+
+ Procedure procedure = new Procedure();
+ procedure.setSubject(new Reference("Patient/P1"));
+ procedure.setStatus(Procedure.ProcedureStatus.fromCode(statusCode));
+ procedure.getCode().addCoding().setSystem(absentUnknownSystem).setCode(procedureCode);
+ procedure.getMeta().addProfile(profile);
+
+ // execute
+ List errors = getValidationErrors(procedure);
+ assertThat(errors).hasSize(0);
+ }
+
+ private void setupValueSetValidateCode(String theUrl, String theSystem, String theCode, String theTerminologyResponseFile) {
+ ValueSet valueSet = myValueSetProvider.addTerminologyResource(theUrl);
+ myCodeSystemProvider.addTerminologyResource(theSystem);
+ myValueSetProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, valueSet.getUrl(), theCode, ourCtx, theTerminologyResponseFile);
+
+ // we currently do this because VersionSpecificWorkerContextWrapper has logic to infer the system when missing
+ // based on the ValueSet by calling ValidationSupportUtils#extractCodeSystemForCode.
+ valueSet.getCompose().addInclude().setSystem(theSystem);
+
+ // you will notice each of these calls require also a call to setupCodeSystemValidateCode
+ // that is necessary because VersionSpecificWorkerContextWrapper#validateCodeInValueSet
+ // which also attempts a validateCode against the CodeSystem after the validateCode against the ValueSet
+ }
+
+ private void setupCodeSystemValidateCode(String theUrl, String theCode, String theTerminologyResponseFile) {
+ CodeSystem codeSystem = myCodeSystemProvider.addTerminologyResource(theUrl);
+ myCodeSystemProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, codeSystem.getUrl(), theCode, ourCtx, theTerminologyResponseFile);
+ }
+
+ private List getValidationErrors(IBaseResource theResource) {
+ MethodOutcome resultProcedure = myClient.validate().resource(theResource).execute();
+ OperationOutcome operationOutcome = (OperationOutcome) resultProcedure.getOperationOutcome();
+ return operationOutcome.getIssue().stream()
+ .filter(issue -> issue.getSeverity() == OperationOutcome.IssueSeverity.ERROR)
+ .map(OperationOutcome.OperationOutcomeIssueComponent::getDiagnostics)
+ .toList();
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/profile-encounter-custom.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/profile-encounter-custom.json
new file mode 100644
index 000000000000..a553a61a1c20
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/profile-encounter-custom.json
@@ -0,0 +1,49 @@
+{
+ "resourceType": "StructureDefinition",
+ "id": "profile-encounter",
+ "url": "http://example.ca/fhir/StructureDefinition/profile-encounter",
+ "version": "0.11.0",
+ "name": "EncounterProfile",
+ "title": "Encounter Profile",
+ "status": "active",
+ "date": "2022-10-15T12:00:00+00:00",
+ "publisher": "Example Organization",
+ "fhirVersion": "4.0.1",
+ "kind": "resource",
+ "abstract": false,
+ "type": "Encounter",
+ "baseDefinition": "http://hl7.org/fhir/StructureDefinition/Encounter",
+ "derivation": "constraint",
+ "differential": {
+ "element": [
+ {
+ "id": "Encounter.identifier.type.coding",
+ "path": "Encounter.identifier.type.coding",
+ "min": 1,
+ "max": "1",
+ "mustSupport": true
+ },
+ {
+ "id": "Encounter.identifier.type.coding.system",
+ "path": "Encounter.identifier.type.coding.system",
+ "min": 1,
+ "fixedUri": "http://terminology.hl7.org/CodeSystem/v2-0203",
+ "mustSupport": true
+ },
+ {
+ "id": "Encounter.identifier.type.coding.code",
+ "path": "Encounter.identifier.type.coding.code",
+ "min": 1,
+ "fixedCode": "VN",
+ "mustSupport": true
+ },
+ {
+ "id": "Encounter.identifier.type.coding.display",
+ "path": "Encounter.identifier.type.coding.display",
+ "min": 1,
+ "fixedString": "Visit number",
+ "mustSupport": true
+ }
+ ]
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-encounter-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-encounter-status.json
new file mode 100644
index 000000000000..2399dc870ec8
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-encounter-status.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "planned"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/encounter-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Planned"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use CodeSystem http://hl7.org/fhir/encounter-status|5.0.0-ballot"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to draft CodeSystem http://hl7.org/fhir/encounter-status|5.0.0-ballot"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v2-0203.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v2-0203.json
new file mode 100644
index 000000000000..10747c14ee38
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v2-0203.json
@@ -0,0 +1,25 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "VN"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://terminology.hl7.org/CodeSystem/v2-0203"
+ },
+ {
+ "name": "version",
+ "valueString": "3.0.0"
+ },
+ {
+ "name": "display",
+ "valueString": "Visit number"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v3-ActCode.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v3-ActCode.json
new file mode 100644
index 000000000000..b692847e0fbb
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-CodeSystem-v3-ActCode.json
@@ -0,0 +1,46 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "IMP"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
+ },
+ {
+ "name": "version",
+ "valueString": "2018-08-12"
+ },
+ {
+ "name": "display",
+ "valueString": "inpatient encounter"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to draft CodeSystem http://terminology.hl7.org/CodeSystem/v3-ActCode|2018-08-12"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-encounter-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-encounter-status.json
new file mode 100644
index 000000000000..2399dc870ec8
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-encounter-status.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "planned"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/encounter-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Planned"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use CodeSystem http://hl7.org/fhir/encounter-status|5.0.0-ballot"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to draft CodeSystem http://hl7.org/fhir/encounter-status|5.0.0-ballot"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-identifier-type.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-identifier-type.json
new file mode 100644
index 000000000000..b0767dc2f188
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-identifier-type.json
@@ -0,0 +1,52 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "VN"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://terminology.hl7.org/CodeSystem/v2-0203"
+ },
+ {
+ "name": "version",
+ "valueString": "3.0.0"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "not-in-vs"
+ }
+ ],
+ "text": "The provided code 'http://terminology.hl7.org/CodeSystem/v2-0203#VN' was not found in the value set 'http://hl7.org/fhir/ValueSet/identifier-type|5.0.0-ballot'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "The provided code 'http://terminology.hl7.org/CodeSystem/v2-0203#VN' was not found in the value set 'http://hl7.org/fhir/ValueSet/identifier-type|5.0.0-ballot'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-v3-ActEncounterCode.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-v3-ActEncounterCode.json
new file mode 100644
index 000000000000..083dbffae43d
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/encounter/validateCode-ValueSet-v3-ActEncounterCode.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "IMP"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://terminology.hl7.org/CodeSystem/v3-ActCode"
+ },
+ {
+ "name": "version",
+ "valueString": "2018-08-12"
+ },
+ {
+ "name": "display",
+ "valueString": "inpatient encounter"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use ValueSet http://terminology.hl7.org/ValueSet/v3-ActEncounterCode|2014-03-26"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to draft CodeSystem http://terminology.hl7.org/CodeSystem/v3-ActCode|2018-08-12"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-ICD9CM.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-ICD9CM.json
new file mode 100644
index 000000000000..831ac6660fa6
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-ICD9CM.json
@@ -0,0 +1,48 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "10xx"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "invalid-code"
+ }
+ ],
+ "text": "Unknown code '10xx' in the CodeSystem 'http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM' version '0.1.0'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "Unknown code '10xx' in the CodeSystem 'http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM' version '0.1.0'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-observation-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-observation-status.json
new file mode 100644
index 000000000000..7914321876c3
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-CodeSystem-observation-status.json
@@ -0,0 +1,25 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "final"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/observation-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Final"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-codes.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-codes.json
new file mode 100644
index 000000000000..4571362033f0
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-codes.json
@@ -0,0 +1,48 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "10xx"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "not-in-vs"
+ }
+ ],
+ "text": "The provided code 'http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM#10xx' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-codes|5.0.0-ballot'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "The provided code 'http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM#10xx' was not found in the value set 'http://hl7.org/fhir/ValueSet/observation-codes|5.0.0-ballot'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-observation-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-observation-status.json
new file mode 100644
index 000000000000..7914321876c3
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/observation/validateCode-ValueSet-observation-status.json
@@ -0,0 +1,25 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "final"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/observation-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Final"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure-slicing.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure-slicing.json
new file mode 100644
index 000000000000..8bc05c70cf00
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure-slicing.json
@@ -0,0 +1,79 @@
+{
+ "resourceType": "StructureDefinition",
+ "id": "profile-procedure-with-slicing",
+ "url": "http://example.ca/fhir/StructureDefinition/profile-procedure-with-slicing",
+ "version": "0.11.0",
+ "name": "ProcedureProfile",
+ "title": "Procedure Profile",
+ "status": "active",
+ "date": "2022-10-15T12:00:00+00:00",
+ "publisher": "Example Organization",
+ "fhirVersion": "4.0.1",
+ "kind": "resource",
+ "abstract": false,
+ "type": "Procedure",
+ "baseDefinition": "http://hl7.org/fhir/StructureDefinition/Procedure",
+ "derivation": "constraint",
+ "differential": {
+ "element": [
+ {
+ "id": "Procedure.code.coding",
+ "path": "Procedure.code.coding",
+ "slicing": {
+ "discriminator": [
+ {
+ "type": "pattern",
+ "path": "$this"
+ }
+ ],
+ "description": "Discriminated by the bound value set",
+ "rules": "open"
+ },
+ "mustSupport": true,
+ "binding": {
+ "strength": "preferred",
+ "valueSet": "http://hl7.org/fhir/ValueSet/procedure-code"
+ }
+ },
+ {
+ "id": "Procedure.code.coding.display.extension:translation",
+ "path": "Procedure.code.coding.display.extension",
+ "sliceName": "translation"
+ },
+ {
+ "id": "Procedure.code.coding.display.extension:translation.extension",
+ "path": "Procedure.code.coding.display.extension.extension",
+ "min": 2
+ },
+ {
+ "id": "Procedure.code.coding:absentOrUnknownProcedure",
+ "path": "Procedure.code.coding",
+ "sliceName": "absentOrUnknownProcedure",
+ "short": "Optional slice for representing a code for absent problem or for unknown procedure",
+ "definition": "Code representing the statement \"absent problem\" or the statement \"procedures unknown\"",
+ "mustSupport": true,
+ "binding": {
+ "extension": [
+ {
+ "url": "http://hl7.org/fhir/StructureDefinition/elementdefinition-bindingName",
+ "valueString": "absentOrUnknownProcedure"
+ }
+ ],
+ "strength": "required",
+ "description": "A code to identify absent or unknown procedures",
+ "valueSet": "http://hl7.org/fhir/uv/ips/ValueSet/absent-or-unknown-procedures-uv-ips"
+ }
+ },
+ {
+ "id": "Procedure.code.coding:absentOrUnknownProcedure.display.extension:translation",
+ "path": "Procedure.code.coding.display.extension",
+ "sliceName": "translation"
+ },
+ {
+ "id": "Procedure.code.coding:absentOrUnknownProcedure.display.extension:translation.extension",
+ "path": "Procedure.code.coding.display.extension.extension",
+ "min": 2
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure.json
new file mode 100644
index 000000000000..5315694dece4
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/profile-procedure.json
@@ -0,0 +1,50 @@
+{
+ "resourceType": "StructureDefinition",
+ "id": "profile-procedure",
+ "url": "http://example.ca/fhir/StructureDefinition/profile-procedure",
+ "version": "0.11.0",
+ "name": "ProcedureProfile",
+ "title": "Procedure Profile",
+ "status": "active",
+ "date": "2022-10-15T12:00:00+00:00",
+ "publisher": "Example Organization",
+ "fhirVersion": "4.0.1",
+ "kind": "resource",
+ "abstract": false,
+ "type": "Procedure",
+ "baseDefinition": "http://hl7.org/fhir/StructureDefinition/Procedure",
+ "derivation": "constraint",
+ "differential": {
+ "element": [
+ {
+ "id": "Procedure.code.coding",
+ "path": "Procedure.code.coding",
+ "slicing": {
+ "discriminator": [
+ {
+ "type": "pattern",
+ "path": "$this"
+ }
+ ],
+ "description": "Discriminated by the bound value set",
+ "rules": "open"
+ },
+ "mustSupport": true,
+ "binding": {
+ "strength": "preferred",
+ "valueSet": "http://hl7.org/fhir/ValueSet/procedure-code"
+ }
+ },
+ {
+ "id": "Procedure.code.coding.display.extension:translation",
+ "path": "Procedure.code.coding.display.extension",
+ "sliceName": "translation"
+ },
+ {
+ "id": "Procedure.code.coding.display.extension:translation.extension",
+ "path": "Procedure.code.coding.display.extension.extension",
+ "min": 2
+ }
+ ]
+ }
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-absent-or-unknown.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-absent-or-unknown.json
new file mode 100644
index 000000000000..4d7b20f0881d
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-absent-or-unknown.json
@@ -0,0 +1,46 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "no-procedure-info"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips"
+ },
+ {
+ "name": "version",
+ "valueString": "1.1.0"
+ },
+ {
+ "name": "display",
+ "valueString": "No information about past history of procedures"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use CodeSystem http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips|1.1.0"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-event-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-event-status.json
new file mode 100644
index 000000000000..620624a991e9
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-event-status.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "completed"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/event-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Completed"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use CodeSystem http://hl7.org/fhir/event-status|5.0.0-ballot"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to experimental CodeSystem http://hl7.org/fhir/event-status|5.0.0-ballot"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-invalid.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-invalid.json
new file mode 100644
index 000000000000..f6a86048d6e8
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-invalid.json
@@ -0,0 +1,48 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "xx417005"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://snomed.info/sct"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "invalid-code"
+ }
+ ],
+ "text": "Unknown code 'xx417005' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/32506021000036107/version/20241031'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "Unknown code 'xx417005' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/32506021000036107/version/20241031'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-valid.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-valid.json
new file mode 100644
index 000000000000..a602bfda9f00
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-CodeSystem-snomed-valid.json
@@ -0,0 +1,25 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "417005"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://snomed.info/sct"
+ },
+ {
+ "name": "version",
+ "valueString": "http://snomed.info/sct/32506021000036107/version/20241031"
+ },
+ {
+ "name": "display",
+ "valueString": "Hospital re-admission"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-absent-or-unknown-procedure.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-absent-or-unknown-procedure.json
new file mode 100644
index 000000000000..aaee02a00233
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-absent-or-unknown-procedure.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "no-procedure-info"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips"
+ },
+ {
+ "name": "version",
+ "valueString": "1.1.0"
+ },
+ {
+ "name": "display",
+ "valueString": "No information about past history of procedures"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use CodeSystem http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips|1.1.0"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to trial-use ValueSet http://hl7.org/fhir/uv/ips/ValueSet/absent-or-unknown-procedures-uv-ips|1.1.0"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-event-status.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-event-status.json
new file mode 100644
index 000000000000..aaad08b83e8e
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-event-status.json
@@ -0,0 +1,25 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "final"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/procedure-status"
+ },
+ {
+ "name": "version",
+ "valueString": "5.0.0-ballot"
+ },
+ {
+ "name": "display",
+ "valueString": "Final"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid-slice.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid-slice.json
new file mode 100644
index 000000000000..4dcb4791944e
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid-slice.json
@@ -0,0 +1,48 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "no-procedure-info"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "not-in-vs"
+ }
+ ],
+ "text": "The provided code 'http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips#no-procedure-info' was not found in the value set 'http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "The provided code 'http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips#no-procedure-info' was not found in the value set 'http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid.json
new file mode 100644
index 000000000000..fac3785fe2d2
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-invalid.json
@@ -0,0 +1,67 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": false
+ },
+ {
+ "name": "code",
+ "valueCode": "xx417005"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://snomed.info/sct"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "not-in-vs"
+ }
+ ],
+ "text": "The provided code 'http://snomed.info/sct#xx417005' was not found in the value set 'http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ },
+ {
+ "severity": "error",
+ "code": "code-invalid",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "invalid-code"
+ }
+ ],
+ "text": "Unknown code 'xx417005' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/32506021000036107/version/20241031'"
+ },
+ "location": [
+ "code"
+ ],
+ "expression": [
+ "code"
+ ]
+ }
+ ]
+ }
+ },
+ {
+ "name": "message",
+ "valueString": "Unknown code 'xx417005' in the CodeSystem 'http://snomed.info/sct' version 'http://snomed.info/sct/32506021000036107/version/20241031'; The provided code 'http://snomed.info/sct#xx417005' was not found in the value set 'http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot'"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-valid.json b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-valid.json
new file mode 100644
index 000000000000..4554379edadf
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-r4/src/test/resources/validation/procedure/validateCode-ValueSet-procedure-code-valid.json
@@ -0,0 +1,59 @@
+{
+ "resourceType": "Parameters",
+ "parameter": [
+ {
+ "name": "result",
+ "valueBoolean": true
+ },
+ {
+ "name": "code",
+ "valueCode": "417005"
+ },
+ {
+ "name": "system",
+ "valueUri": "http://snomed.info/sct"
+ },
+ {
+ "name": "version",
+ "valueString": "http://snomed.info/sct/32506021000036107/version/20241031"
+ },
+ {
+ "name": "display",
+ "valueString": "Hospital re-admission"
+ },
+ {
+ "name": "issues",
+ "resource": {
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to draft ValueSet http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot"
+ }
+ },
+ {
+ "severity": "information",
+ "code": "business-rule",
+ "details": {
+ "coding": [
+ {
+ "system": "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
+ "code": "status-check"
+ }
+ ],
+ "text": "Reference to experimental ValueSet http://hl7.org/fhir/ValueSet/procedure-code|5.0.0-ballot"
+ }
+ }
+ ]
+ }
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/H2_EMBEDDED.sql b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/H2_EMBEDDED.sql
index fd2eb6c3c988..095d79d0fb33 100644
--- a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/H2_EMBEDDED.sql
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/H2_EMBEDDED.sql
@@ -51,3 +51,33 @@ INSERT INTO TRM_CONCEPT_DESIG (
54,
150
);
+
+INSERT INTO HFJ_RES_LINK (
+ PID,
+ PARTITION_DATE,
+ PARTITION_ID,
+ SRC_PATH,
+ SRC_RESOURCE_ID,
+ SOURCE_RESOURCE_TYPE,
+ TARGET_RESOURCE_ID,
+ TARGET_RESOURCE_TYPE,
+ TARGET_RESOURCE_URL,
+ TARGET_RESOURCE_VERSION,
+ SP_UPDATED,
+ TARGET_RES_PARTITION_ID,
+ TARGET_RES_PARTITION_DATE
+) VALUES (
+ 702,
+ '2024-11-05',
+ 1,
+ 'Observation.subject.where(resolve() is Patient)',
+ 1656,
+ 'Observation',
+ 1906,
+ 'Patient',
+ 'http://localhost:8000/Patient/123',
+ 1,
+ '2024-11-01 18:01:12.921',
+ 1,
+ '2024-11-05'
+);
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/MSSQL_2012.sql b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/MSSQL_2012.sql
index fd2eb6c3c988..82df69243933 100644
--- a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/MSSQL_2012.sql
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/MSSQL_2012.sql
@@ -51,3 +51,33 @@ INSERT INTO TRM_CONCEPT_DESIG (
54,
150
);
+
+INSERT INTO HFJ_RES_LINK (
+ PID,
+ PARTITION_DATE,
+ PARTITION_ID,
+ SRC_PATH,
+ SRC_RESOURCE_ID,
+ SOURCE_RESOURCE_TYPE,
+ TARGET_RESOURCE_ID,
+ TARGET_RESOURCE_TYPE,
+ TARGET_RESOURCE_URL,
+ TARGET_RESOURCE_VERSION,
+ SP_UPDATED,
+ TARGET_RES_PARTITION_ID,
+ TARGET_RES_PARTITION_DATE
+) VALUES (
+ 702,
+ '2024-11-05',
+ 1,
+ 'Observation.subject.where(resolve() is Patient)',
+ 1653,
+ 'Observation',
+ 1906,
+ 'Patient',
+ 'http://localhost:8000/Patient/123',
+ 1,
+ '2024-11-01 18:01:12.921',
+ 1,
+ '2024-11-05'
+);
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/ORACLE_12C.sql b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/ORACLE_12C.sql
index 442d66619194..ecb31b3d5878 100644
--- a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/ORACLE_12C.sql
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/ORACLE_12C.sql
@@ -51,3 +51,33 @@ INSERT INTO TRM_CONCEPT_DESIG (
54,
150
);
+
+INSERT INTO HFJ_RES_LINK (
+ PID,
+ PARTITION_DATE,
+ PARTITION_ID,
+ SRC_PATH,
+ SRC_RESOURCE_ID,
+ SOURCE_RESOURCE_TYPE,
+ TARGET_RESOURCE_ID,
+ TARGET_RESOURCE_TYPE,
+ TARGET_RESOURCE_URL,
+ TARGET_RESOURCE_VERSION,
+ SP_UPDATED,
+ TARGET_RES_PARTITION_ID,
+ TARGET_RES_PARTITION_DATE
+) VALUES (
+ 702,
+ SYSDATE,
+ 1,
+ 'Observation.subject.where(resolve() is Patient)',
+ 1653,
+ 'Observation',
+ 1906,
+ 'Patient',
+ 'http://localhost:8000/Patient/123',
+ 1,
+ SYSDATE,
+ 1,
+ SYSDATE
+);
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/POSTGRES_9_4.sql b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/POSTGRES_9_4.sql
index fd2eb6c3c988..82df69243933 100644
--- a/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/POSTGRES_9_4.sql
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/resources/migration/releases/V7_4_0/data/POSTGRES_9_4.sql
@@ -51,3 +51,33 @@ INSERT INTO TRM_CONCEPT_DESIG (
54,
150
);
+
+INSERT INTO HFJ_RES_LINK (
+ PID,
+ PARTITION_DATE,
+ PARTITION_ID,
+ SRC_PATH,
+ SRC_RESOURCE_ID,
+ SOURCE_RESOURCE_TYPE,
+ TARGET_RESOURCE_ID,
+ TARGET_RESOURCE_TYPE,
+ TARGET_RESOURCE_URL,
+ TARGET_RESOURCE_VERSION,
+ SP_UPDATED,
+ TARGET_RES_PARTITION_ID,
+ TARGET_RES_PARTITION_DATE
+) VALUES (
+ 702,
+ '2024-11-05',
+ 1,
+ 'Observation.subject.where(resolve() is Patient)',
+ 1653,
+ 'Observation',
+ 1906,
+ 'Patient',
+ 'http://localhost:8000/Patient/123',
+ 1,
+ '2024-11-01 18:01:12.921',
+ 1,
+ '2024-11-05'
+);
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcaster.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcaster.java
index 39d75793f28d..6670ab15a4c1 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcaster.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcaster.java
@@ -81,7 +81,7 @@ public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
}
if (theRequestDetails != null && theRequestDetails.getInterceptorBroadcaster() != null && retVal) {
IInterceptorBroadcaster interceptorBroadcaster = theRequestDetails.getInterceptorBroadcaster();
- interceptorBroadcaster.callHooks(thePointcut, theParams);
+ retVal = interceptorBroadcaster.callHooks(thePointcut, theParams);
}
return retVal;
}
diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcasterTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcasterTest.java
new file mode 100644
index 000000000000..2a670d158113
--- /dev/null
+++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/util/CompositeInterceptorBroadcasterTest.java
@@ -0,0 +1,161 @@
+package ca.uhn.fhir.rest.server.util;
+
+import ca.uhn.fhir.interceptor.api.HookParams;
+import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
+import ca.uhn.fhir.interceptor.api.Pointcut;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(MockitoExtension.class)
+class CompositeInterceptorBroadcasterTest {
+
+ @Mock
+ private IInterceptorBroadcaster myModuleBroadcasterMock;
+ @Mock
+ private IInterceptorBroadcaster myReqDetailsBroadcasterMock;
+ @Mock
+ private Pointcut myPointcutMock;
+ @Mock
+ private HookParams myHookParamsMock;
+ @Mock
+ private RequestDetails myRequestDetailsMock;
+
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_RequestDetailsBroadcasterReturnsTrue_ThenReturnsTrue() {
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+ when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
+ myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isTrue();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_RequestDetailsBroadcasterReturnsFalse_ThenReturnsFalse() {
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+ when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
+ myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isFalse();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsFalse_ThenSkipsBroadcasterInRequestDetails_And_ReturnsFalse() {
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
+ myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isFalse();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ verify(myReqDetailsBroadcasterMock, never()).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_NullRequestDetailsBroadcaster_ThenReturnsTrue() {
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(null);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock, myPointcutMock,
+ myHookParamsMock);
+
+ assertThat(retVal).isTrue();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsFalse_And_NullRequestDetailsBroadcaster_ThenReturnsFalse() {
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(null);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock, myPointcutMock,
+ myHookParamsMock);
+
+ assertThat(retVal).isFalse();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_NullRequestDetails_ThenReturnsTrue() {
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, null, myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isTrue();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenModuleBroadcasterReturnsFalse_And_NullRequestDetails_ThenReturnsFalse() {
+
+ when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, null, myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isFalse();
+
+ verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+ @Test
+ void doCallHooks_WhenNullModuleBroadcaster_And_NullRequestDetails_ThenReturnsTrue() {
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, null, myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isTrue();
+ }
+
+ @Test
+ void doCallHooks_WhenNullModuleBroadcaster_And_RequestDetailsBroadcasterReturnsTrue_ThenReturnsTrue() {
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
+ when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, myRequestDetailsMock, myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isTrue();
+ verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+
+
+ @Test
+ void doCallHooks_WhenNullModuleBroadcaster_And_RequestDetailsBroadcasterReturnsFalse_ThenReturnsFalse() {
+ when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
+ when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
+
+ boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, myRequestDetailsMock, myPointcutMock, myHookParamsMock);
+
+ assertThat(retVal).isFalse();
+ verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
+ }
+}
diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java
index 88269f41756e..c3489d3f6312 100644
--- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java
+++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java
@@ -397,7 +397,7 @@ public class BuilderAddIndexUnique {
private final String myVersion;
private final boolean myUnique;
private String[] myIncludeColumns;
- private boolean myOnline;
+ private boolean myOnline = true;
public BuilderAddIndexUnique(String theVersion, boolean theUnique) {
myVersion = theVersion;
diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/v1/ReindexV1Config.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/v1/ReindexV1Config.java
index fe8f736aef52..4dd956389370 100644
--- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/v1/ReindexV1Config.java
+++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/v1/ReindexV1Config.java
@@ -92,7 +92,7 @@ public JobDefinition reindexJobDefinitionV1() {
"Load IDs of resources to reindex",
ResourceIdListWorkChunkJson.class,
myReindexLoadIdsStep)
- .addLastStep("reindex-start", "Start the resource reindex", reindexStepV1())
+ .addLastStep("reindex", "Start the resource reindex", reindexStepV1())
.build();
}
diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/BatchWorkChunkStatusDTO.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/BatchWorkChunkStatusDTO.java
index 4f00448aa764..6c1918f28eea 100644
--- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/BatchWorkChunkStatusDTO.java
+++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/BatchWorkChunkStatusDTO.java
@@ -26,6 +26,7 @@ public class BatchWorkChunkStatusDTO {
public final WorkChunkStatusEnum status;
public final Date start;
public final Date stop;
+
public final Double avg;
public final Long totalChunks;
diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/dstu3/EvaluateOperationConfig.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/dstu3/EvaluateOperationConfig.java
index 22867e527edd..6598ab08d9ca 100644
--- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/dstu3/EvaluateOperationConfig.java
+++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/dstu3/EvaluateOperationConfig.java
@@ -21,15 +21,20 @@
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
+import ca.uhn.fhir.cr.config.CrProcessorConfig;
import ca.uhn.fhir.cr.config.ProviderLoader;
import ca.uhn.fhir.cr.config.ProviderSelector;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
import java.util.Arrays;
import java.util.Map;
+@Configuration
+@Import(CrProcessorConfig.class)
public class EvaluateOperationConfig {
@Bean
ca.uhn.fhir.cr.dstu3.library.LibraryEvaluateProvider dstu3LibraryEvaluateProvider() {
diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/EvaluateOperationConfig.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/EvaluateOperationConfig.java
index c0d0ae48faca..8cf8ecf76533 100644
--- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/EvaluateOperationConfig.java
+++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/config/r4/EvaluateOperationConfig.java
@@ -21,15 +21,20 @@
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
+import ca.uhn.fhir.cr.config.CrProcessorConfig;
import ca.uhn.fhir.cr.config.ProviderLoader;
import ca.uhn.fhir.cr.config.ProviderSelector;
import ca.uhn.fhir.rest.server.RestfulServer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Import;
import java.util.Arrays;
import java.util.Map;
+@Configuration
+@Import(CrProcessorConfig.class)
public class EvaluateOperationConfig {
@Bean
ca.uhn.fhir.cr.r4.library.LibraryEvaluateProvider r4LibraryEvaluateProvider() {
diff --git a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/HapiFhirRepositoryR4Test.java b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/HapiFhirRepositoryR4Test.java
index 76996239ee5a..144822283712 100644
--- a/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/HapiFhirRepositoryR4Test.java
+++ b/hapi-fhir-storage-cr/src/test/java/ca/uhn/fhir/cr/r4/HapiFhirRepositoryR4Test.java
@@ -25,6 +25,7 @@
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -54,6 +55,25 @@ void repositoryTests(){
assertTrue(crudTest(repository));
}
+ @Test
+ void _profileCanBeReferenceParam() {
+ // as per https://www.hl7.org/fhir/r4/search.html#all _profile is a reference param
+ var repository = new HapiFhirRepository(myDaoRegistry, setupRequestDetails(), myRestfulServer);
+ var profileToFind = "http://www.a-test-profile.com";
+ var encounterWithProfile = new Encounter();
+ encounterWithProfile.getMeta().addProfile(profileToFind);
+ repository.create(encounterWithProfile);
+ repository.create(new Encounter());
+ Map> map = new HashMap<>();
+ map.put("_profile", Collections.singletonList(new ReferenceParam(profileToFind)));
+ assertDoesNotThrow(() -> {
+ var returnBundle = repository.search(Bundle.class, Encounter.class, map);
+ assertTrue(returnBundle.hasEntry());
+ assertEquals(1,returnBundle.getEntry().size());
+ assertEquals(profileToFind, returnBundle.getEntryFirstRep().getResource().getMeta().getProfile().get(0).getValue());
+ });
+ }
+
Boolean crudTest(HapiFhirRepository theRepository) {
diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2_1Test.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2_1Test.java
index e03d8d6c187f..18c74d8617b8 100644
--- a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2_1Test.java
+++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2_1Test.java
@@ -11,6 +11,7 @@
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.parser.PatientWithExtendedContactDstu3.CustomContactComponent;
import ca.uhn.fhir.parser.XmlParserDstu2_1Test.TestPatientFor327;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets;
@@ -407,6 +408,8 @@ public void testEncodeContainedResource() {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
@@ -415,14 +418,14 @@ public void testEncodeContainedResource() {
"\"contained\": [",
"{",
"\"resourceType\": \"Condition\",",
- "\"id\": \"1\"",
+ "\"id\": \"" + conditionUuid + "\"",
"}",
"],",
"\"extension\": [",
"{",
"\"url\": \"test\",",
"\"valueReference\": {",
- "\"reference\": \"#1\"",
+ "\"reference\": \"#" + conditionUuid + "\"",
"}",
"}",
"],",
@@ -632,19 +635,21 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
"\"resourceType\": \"Patient\"",
"\"contained\": [",
"\"resourceType\": \"Condition\"",
- "\"id\": \"1\"",
+ "\"id\": \"" + conditionUuid + "\"",
"\"bodySite\": [",
"\"text\": \"BODY SITE\"",
"\"extension\": [",
"\"url\": \"testCondition\",",
"\"valueReference\": {",
- "\"reference\": \"#1\"",
+ "\"reference\": \"#" + conditionUuid + "\"",
"\"birthDate\": \"2016-04-14\"",
"}"
);
diff --git a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2_1Test.java b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2_1Test.java
index 7b3fbd7a4598..4c6fea901d86 100644
--- a/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2_1Test.java
+++ b/hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2_1Test.java
@@ -13,6 +13,7 @@
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension;
import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets;
@@ -378,8 +379,11 @@ public void testEncodeAndParseContained() {
String encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
+
assertThat(encoded).contains("");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// Create a bundle with just the patient resource
Bundle b = new Bundle();
@@ -388,35 +392,35 @@ public void testEncodeAndParseContained() {
// Encode the bundle
encoded = xmlParser.encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
- assertThat(encoded).contains("");
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
+ assertThat(encoded).contains("");
assertThat(encoded).containsSubsequence(Arrays.asList("", ""));
assertThat(encoded).doesNotContainPattern("(?s).*.*");
// Re-parse the bundle
patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
- assertEquals("#1", patient.getManagingOrganization().getReference());
+ assertEquals("#" + organizationUuid, patient.getManagingOrganization().getReference());
assertNotNull(patient.getManagingOrganization().getResource());
org = (Organization) patient.getManagingOrganization().getResource();
- assertEquals("#1", org.getIdElement().getValue());
+ assertEquals("#" + organizationUuid, org.getIdElement().getValue());
assertEquals("Contained Test Organization", org.getName());
// And re-encode a second time
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared
patient.getContained().clear();
patient.getManagingOrganization().setReference(null);
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared and a manually set local ID
patient.getContained().clear();
@@ -447,6 +451,8 @@ public void testEncodeAndParseContainedCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
//@formatter:off
assertThat(output).containsSubsequence(
@@ -456,7 +462,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -465,7 +471,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"");
//@formatter:on
@@ -477,7 +483,7 @@ public void testEncodeAndParseContainedCustomTypes() {
dr = (CustomDiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
- assertEquals("#1", dr.getResult().get(0).getReference());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference());
obs = (CustomObservation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
@@ -500,19 +506,21 @@ public void testEncodeAndParseContainedNonCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
//@formatter:off
assertThat(output).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
"",
"",
- "",
+ "",
"",
"");
//@formatter:on
@@ -524,7 +532,7 @@ public void testEncodeAndParseContainedNonCustomTypes() {
dr = (DiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
- assertEquals("#1", dr.getResult().get(0).getReference());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference());
obs = (Observation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
@@ -832,18 +840,20 @@ public void testEncodeContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -911,10 +921,12 @@ public void testEncodeContainedResourcesAutomatic() {
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String encoded = p.encodeResourceToString(medicationPrescript);
ourLog.info(encoded);
+ String medicationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(medicationUuid);
//@formatter:on
- assertThat(encoded).containsSubsequence("", "", "", "", "", "",
- "", "", "
", "
", "", "", "", "",
+ assertThat(encoded).containsSubsequence("", "", "", "", "", "",
+ "", "", "
", "
", "", "", "", "",
"", "", "");
//@formatter:off
}
@@ -1185,13 +1197,15 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -1199,7 +1213,7 @@ public void testEncodeExtensionWithContainedResource() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomTypeDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomTypeDstu2Test.java
index 5862838b5b10..e3f230440f1b 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomTypeDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/CustomTypeDstu2Test.java
@@ -16,6 +16,7 @@
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.CustomResource364Dstu2.CustomResource364CustomDate;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ElementUtil;
import ca.uhn.fhir.util.TestUtil;
import org.junit.jupiter.api.AfterAll;
@@ -54,20 +55,23 @@ public void testConstrainedFieldContainedResource() {
String string = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(mo);
ourLog.info(string);
-
+
+ String medicationUuid = UuidUtils.findFirstUUID(string);
+ assertNotNull(medicationUuid);
+
//@formatter:on
assertThat(string).containsSubsequence(
"",
" ",
- " ",
- " ",
+ " ",
+ " ",
" ",
" ",
"
",
" ",
" ",
" ",
- " ",
+ " ",
" ",
"");
//@formatter:on
@@ -76,7 +80,7 @@ public void testConstrainedFieldContainedResource() {
medication = (Medication) mo.getMedication().getResource();
assertNotNull(medication);
- assertEquals("#1", medication.getId().getValue());
+ assertEquals("#" + medicationUuid, medication.getId().getValue());
assertEquals("MED TEXT", medication.getCode().getText());
}
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
index 85fa64620f51..ef7737273957 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2Test.java
@@ -50,6 +50,7 @@
import ca.uhn.fhir.parser.testprofile.CommunicationProfile;
import ca.uhn.fhir.parser.testprofile.PatientProfile;
import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.TestUtil;
import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.Logger;
@@ -1705,14 +1706,16 @@ public void testParseContained() {
String enc = parser.encodeResourceToString(o);
ourLog.info(enc);
+ String patientUuid = UuidUtils.findFirstUUID(enc);
+ assertNotNull(patientUuid);
//@formatter:off
assertThat(enc).containsSubsequence(
"\"resourceType\": \"Observation\"",
"\"contained\": [",
"\"resourceType\": \"Patient\",",
- "\"id\": \"1\"",
- "\"reference\": \"#1\""
+ "\"id\": \"" + patientUuid + "\"",
+ "\"reference\": \"#" + patientUuid + "\""
);
//@formatter:on
diff --git a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java
index 9d48d2fc8301..b5586fd64455 100644
--- a/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java
+++ b/hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2Test.java
@@ -62,6 +62,7 @@
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets;
@@ -512,8 +513,10 @@ public void testEncodeAndParseContained() {
String encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
assertThat(encoded).contains("");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// Create a bundle with just the patient resource
ca.uhn.fhir.model.dstu2.resource.Bundle b = new ca.uhn.fhir.model.dstu2.resource.Bundle();
@@ -522,35 +525,37 @@ public void testEncodeAndParseContained() {
// Encode the bundle
encoded = xmlParser.encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
- assertThat(encoded).contains("");
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
+ assertThat(encoded).contains("");
assertThat(encoded).containsSubsequence(Arrays.asList("", ""));
assertThat(encoded).doesNotContainPattern("(?s).*.*");
// Re-parse the bundle
patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
- assertEquals("#1", patient.getManagingOrganization().getReference().getValue());
+ assertEquals("#" + organizationUuid, patient.getManagingOrganization().getReference().getValue());
assertNotNull(patient.getManagingOrganization().getResource());
org = (Organization) patient.getManagingOrganization().getResource();
- assertEquals("#1", org.getId().getValue());
+ assertEquals("#" + organizationUuid, org.getId().getValue());
assertEquals("Contained Test Organization", org.getName());
// And re-encode a second time
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared
patient.getContained().getContainedResources().clear();
patient.getManagingOrganization().setReference((String) null);
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared and a manually set local ID
patient.getContained().getContainedResources().clear();
@@ -581,6 +586,8 @@ public void testEncodeAndParseContainedCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
//@formatter:off
assertThat(output).containsSubsequence(
@@ -590,7 +597,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -599,7 +606,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"");
//@formatter:on
@@ -611,7 +618,7 @@ public void testEncodeAndParseContainedCustomTypes() {
dr = (CustomDiagnosticReportDstu2) parser.parseResource(output);
assertEquals(DiagnosticReportStatusEnum.FINAL, dr.getStatusElement().getValueAsEnum());
- assertEquals("#1", dr.getResult().get(0).getReference().getValueAsString());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference().getValueAsString());
obs = (CustomObservationDstu2) dr.getResult().get(0).getResource();
assertEquals(ObservationStatusEnum.FINAL, obs.getStatusElement().getValueAsEnum());
@@ -665,19 +672,21 @@ public void testEncodeAndParseContainedNonCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
//@formatter:off
assertThat(output).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
"",
"",
- "",
+ "",
"",
"");
//@formatter:on
@@ -689,7 +698,7 @@ public void testEncodeAndParseContainedNonCustomTypes() {
dr = (DiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatusEnum.FINAL, dr.getStatusElement().getValueAsEnum());
- assertEquals("#1", dr.getResult().get(0).getReference().getValueAsString());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference().getValueAsString());
obs = (Observation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatusEnum.FINAL, obs.getStatusElement().getValueAsEnum());
@@ -1305,10 +1314,12 @@ public void testEncodeContainedResourcesAutomatic() {
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String encoded = p.encodeResourceToString(medicationPrescript);
ourLog.info(encoded);
+ String medicationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(medicationUuid);
//@formatter:on
- assertThat(encoded).containsSubsequence("", "", "", "", "", "",
- "", "", "
", "
", "", "", "", "",
+ assertThat(encoded).containsSubsequence("", "", "", "", "", "",
+ "", "", "
", "
", "", "", "", "",
"", "", "");
//@formatter:off
}
@@ -1561,13 +1572,15 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -1575,7 +1588,7 @@ public void testEncodeExtensionWithContainedResource() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -2535,15 +2548,17 @@ public void testParseContained() {
String enc = parser.encodeResourceToString(o);
ourLog.info(enc);
+ String patientUuid = UuidUtils.findFirstUUID(enc);
+ assertNotNull(patientUuid);
//@formatter:off
assertThat(enc).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
- ""
+ ""
);
//@formatter:on
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
index 268a5bbcc7b2..a0de44b0fde5 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
@@ -13,6 +13,7 @@
import ca.uhn.fhir.parser.XmlParserDstu3Test.TestPatientFor327;
import ca.uhn.fhir.parser.json.BaseJsonLikeValue.ScalarType;
import ca.uhn.fhir.parser.json.BaseJsonLikeValue.ValueType;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.validation.FhirValidator;
@@ -648,6 +649,8 @@ public void testEncodeContainedResource() {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).contains(
@@ -656,14 +659,14 @@ public void testEncodeContainedResource() {
"\"contained\": [",
"{",
"\"resourceType\": \"Condition\",",
- "\"id\": \"1\"",
+ "\"id\": \"" + conditionUuid + "\"",
"}",
"],",
"\"extension\": [",
"{",
"\"url\": \"test\",",
"\"valueReference\": {",
- "\"reference\": \"#1\"",
+ "\"reference\": \"#" + conditionUuid + "\"",
"}",
"}",
"],",
@@ -920,19 +923,21 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).contains(
"\"resourceType\": \"Patient\"",
"\"contained\": [",
"\"resourceType\": \"Condition\"",
- "\"id\": \"1\"",
+ "\"id\": \"" + conditionUuid + "\"",
"\"bodySite\": [",
"\"text\": \"BODY SITE\"",
"\"extension\": [",
"\"url\": \"testCondition\",",
"\"valueReference\": {",
- "\"reference\": \"#1\"",
+ "\"reference\": \"#" + conditionUuid + "\"",
"\"birthDate\": \"2016-04-14\"",
"}"
);
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
index 58e1477e361c..2388fa72413d 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
@@ -13,6 +13,7 @@
import ca.uhn.fhir.parser.FooMessageHeaderWithExplicitField.FooMessageSourceComponent;
import ca.uhn.fhir.parser.IParserErrorHandler.IParseLocation;
import ca.uhn.fhir.parser.PatientWithCustomCompositeExtension.FooParentExtension;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets;
@@ -560,8 +561,11 @@ public void testEncodeAndParseContained() {
String encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
+
assertThat(encoded).contains("");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// Create a bundle with just the patient resource
Bundle b = new Bundle();
@@ -570,35 +574,35 @@ public void testEncodeAndParseContained() {
// Encode the bundle
encoded = xmlParser.encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).contains(Arrays.asList("", "", ""));
- assertThat(encoded).contains("");
+ assertThat(encoded).contains(Arrays.asList("", "", ""));
+ assertThat(encoded).contains("");
assertThat(encoded).contains(Arrays.asList("", ""));
assertThat(encoded).doesNotContainPattern("(?s).*.*");
// Re-parse the bundle
patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
- assertEquals("#1", patient.getManagingOrganization().getReference());
+ assertEquals("#" + organizationUuid, patient.getManagingOrganization().getReference());
assertNotNull(patient.getManagingOrganization().getResource());
org = (Organization) patient.getManagingOrganization().getResource();
- assertEquals("#1", org.getIdElement().getValue());
+ assertEquals("#" + organizationUuid, org.getIdElement().getValue());
assertEquals("Contained Test Organization", org.getName());
// And re-encode a second time
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).contains(Arrays.asList("", "", "", ""));
+ assertThat(encoded).contains(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared
patient.getContained().clear();
patient.getManagingOrganization().setReference(null);
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).contains(Arrays.asList("", "", "", ""));
+ assertThat(encoded).contains(Arrays.asList("", "", "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared and a manually set local ID
patient.getContained().clear();
@@ -629,6 +633,8 @@ public void testEncodeAndParseContainedCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
assertThat(output).contains(
"",
@@ -637,7 +643,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -646,7 +652,7 @@ public void testEncodeAndParseContainedCustomTypes() {
"",
"",
"",
- "",
+ "",
"",
"");
@@ -657,7 +663,7 @@ public void testEncodeAndParseContainedCustomTypes() {
dr = (CustomDiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
- assertEquals("#1", dr.getResult().get(0).getReference());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference());
obs = (CustomObservation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
@@ -680,18 +686,20 @@ public void testEncodeAndParseContainedNonCustomTypes() {
String output = parser.encodeResourceToString(dr);
ourLog.info(output);
+ String observationUuid = UuidUtils.findFirstUUID(output);
+ assertNotNull(observationUuid);
assertThat(output).contains(
"",
"",
"",
- "",
+ "",
"",
"",
"",
"",
"",
- "",
+ "",
"",
"");
@@ -702,7 +710,7 @@ public void testEncodeAndParseContainedNonCustomTypes() {
dr = (DiagnosticReport) parser.parseResource(output);
assertEquals(DiagnosticReportStatus.FINAL, dr.getStatus());
- assertEquals("#1", dr.getResult().get(0).getReference());
+ assertEquals("#" + observationUuid, dr.getResult().get(0).getReference());
obs = (Observation) dr.getResult().get(0).getResource();
assertEquals(ObservationStatus.FINAL, obs.getStatus());
@@ -1282,17 +1290,19 @@ public void testEncodeContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
assertThat(encoded).contains(
"",
"",
"",
- "",
+ "",
"",
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -1359,10 +1369,12 @@ public void testEncodeContainedResourcesAutomatic() {
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String encoded = p.encodeResourceToString(medicationPrescript);
ourLog.info(encoded);
+ String medicationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(medicationUuid);
assertThat(encoded).contains
- ("", "", "", "", "", "",
- "", "", "
", "
", "", "", "", "",
+ ("", "", "", "", "", "",
+ "", "", "
", "
", "", "", "", "",
"", "", "");
}
@@ -1726,12 +1738,14 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
assertThat(encoded).contains(
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -1739,7 +1753,7 @@ public void testEncodeExtensionWithContainedResource() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserHl7OrgDstu2Test.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserHl7OrgDstu2Test.java
index 6889414f15bf..6a5ead67c1cf 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserHl7OrgDstu2Test.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/JsonParserHl7OrgDstu2Test.java
@@ -4,6 +4,7 @@
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import ca.uhn.fhir.util.ClasspathUtil;
import ca.uhn.fhir.util.TestUtil;
import net.sf.json.JSON;
@@ -58,6 +59,7 @@
import java.util.Arrays;
import java.util.List;
+import static ca.uhn.fhir.test.utilities.UuidUtils.UUID_PATTERN;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -408,7 +410,10 @@ public void testEncodeContained() {
String encoded = jsonParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"1\"", "\"identifier\"", "\"reference\": \"#1\""));
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
+
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"" + organizationUuid + "\"", "\"identifier\"", "\"reference\": \"#" + organizationUuid + "\""));
// Create a bundle with just the patient resource
Bundle b = new Bundle();
@@ -417,21 +422,21 @@ public void testEncodeContained() {
// Encode the bundle
encoded = jsonParser.encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"1\"", "\"identifier\"", "\"reference\": \"#1\""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"" + organizationUuid + "\"", "\"identifier\"", "\"reference\": \"#" + organizationUuid + "\""));
// Re-parse the bundle
patient = (Patient) jsonParser.parseResource(jsonParser.encodeResourceToString(patient));
- assertEquals("#1", patient.getManagingOrganization().getReference());
+ assertEquals("#" + organizationUuid, patient.getManagingOrganization().getReference());
assertNotNull(patient.getManagingOrganization().getResource());
org = (Organization) patient.getManagingOrganization().getResource();
- assertEquals("#1", org.getIdElement().getValue());
+ assertEquals("#" + organizationUuid, org.getIdElement().getValue());
assertEquals("Contained Test Organization", org.getName());
// And re-encode a second time
encoded = jsonParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"1\"", "\"identifier\"", "\"reference\": \"#1\""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"" + organizationUuid + "\"", "\"identifier\"", "\"reference\": \"#" + organizationUuid + "\""));
assertThat(encoded).doesNotContainPattern("(?s)\"contained\":.*\\[.*\"contained\":");
// And re-encode once more, with the references cleared
@@ -439,7 +444,7 @@ public void testEncodeContained() {
patient.getManagingOrganization().setReference(null);
encoded = jsonParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"1\"", "\"identifier\"", "\"reference\": \"#1\""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\": [", "\"id\": \"" + organizationUuid + "\"", "\"identifier\"", "\"reference\": \"#" + organizationUuid + "\""));
assertThat(encoded).doesNotContainPattern("(?s).*\"contained\":.*\\[.*\"contained\":");
// And re-encode once more, with the references cleared and a manually set local ID
@@ -472,13 +477,16 @@ public void testEncodeContained__() {
// Encode the buntdle
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\"", "resourceType\": \"Organization", "id\": \"1\""));
- assertThat(encoded).contains("reference\": \"#1\"");
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
+
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\"", "resourceType\": \"Organization", "id\": \"" + organizationUuid + "\""));
+ assertThat(encoded).contains("reference\": \"#" + organizationUuid + "\"");
encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\"", "resourceType\": \"Organization", "id\": \"1\""));
- assertThat(encoded).contains("reference\": \"#1\"");
+ assertThat(encoded).containsSubsequence(Arrays.asList("\"contained\"", "resourceType\": \"Organization", "id\": \"" + organizationUuid + "\""));
+ assertThat(encoded).contains("reference\": \"#" + organizationUuid + "\"");
}
@Test
@@ -696,7 +704,7 @@ public void testEncodeIds() {
String enc = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(list);
ourLog.info(enc);
- assertThat(enc).contains("\"id\": \"1\"");
+ assertThat(enc).containsPattern("\"id\": \"" + UUID_PATTERN);
List_ parsed = ourCtx.newJsonParser().parseResource(List_.class,enc);
assertEquals(Patient.class, parsed.getEntry().get(0).getItem().getResource().getClass());
diff --git a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java
index 4356a997a060..d9582e02ba23 100644
--- a/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java
+++ b/hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/parser/XmlParserHl7OrgDstu2Test.java
@@ -9,6 +9,7 @@
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredAddressExtension;
import ca.uhn.fhir.parser.JsonParserHl7OrgDstu2Test.MyPatientWithOneDeclaredExtension;
import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.test.utilities.UuidUtils;
import net.sf.json.JSON;
import net.sf.json.JSONSerializer;
import org.apache.commons.io.IOUtils;
@@ -216,8 +217,11 @@ public void testEncodeAndParseContained() {
String encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
+ String organizationUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(organizationUuid);
+
assertThat(encoded).contains("");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// Create a bundle with just the patient resource
Bundle b = new Bundle();
@@ -226,37 +230,37 @@ public void testEncodeAndParseContained() {
// Encode the bundle
encoded = xmlParser.encodeResourceToString(b);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
- assertThat(encoded).contains("");
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "", ""));
+ assertThat(encoded).contains("");
assertThat(encoded).containsSubsequence(Arrays.asList("", ""));
assertThat(encoded).doesNotContainPattern("(?s).*.*");
// Re-parse the bundle
patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient));
- assertEquals("#1", patient.getManagingOrganization().getReferenceElement().getValue());
+ assertEquals("#" + organizationUuid, patient.getManagingOrganization().getReferenceElement().getValue());
assertNotNull(patient.getManagingOrganization().getResource());
org = (Organization) patient.getManagingOrganization().getResource();
- assertEquals("#1", org.getIdElement().getValue());
+ assertEquals("#" + organizationUuid, org.getIdElement().getValue());
assertEquals("Contained Test Organization", org.getName());
// And re-encode a second time
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "",
- "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "",
+ "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared
patient.getContained().clear();
patient.getManagingOrganization().setReference(null);
encoded = xmlParser.encodeResourceToString(patient);
ourLog.info(encoded);
- assertThat(encoded).containsSubsequence(Arrays.asList("", "",
- "", ""));
+ assertThat(encoded).containsSubsequence(Arrays.asList("", "",
+ "", ""));
assertThat(encoded).doesNotContainPattern("(?s).*");
- assertThat(encoded).contains("");
+ assertThat(encoded).contains("");
// And re-encode once more, with the references cleared and a manually set
// local ID
@@ -969,13 +973,15 @@ public void testEncodeExtensionWithContainedResource() {
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
+ String conditionUuid = UuidUtils.findFirstUUID(encoded);
+ assertNotNull(conditionUuid);
//@formatter:off
assertThat(encoded).containsSubsequence(
"",
"",
"",
- "",
+ "",
"",
"",
"",
@@ -983,7 +989,7 @@ public void testEncodeExtensionWithContainedResource() {
"",
"",
"",
- "",
+ "",
"",
"",
"",
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
index 251004846491..b80251d29108 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
@@ -7,6 +7,7 @@
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.test.BaseTest;
+import ca.uhn.fhir.util.BundleBuilder;
import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.TestUtil;
import com.google.common.collect.Sets;
@@ -23,10 +24,12 @@
import org.hl7.fhir.r4.model.DateTimeType;
import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.Device;
+import org.hl7.fhir.r4.model.DiagnosticReport;
import org.hl7.fhir.r4.model.DocumentReference;
import org.hl7.fhir.r4.model.Encounter;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.HumanName;
+import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.Medication;
import org.hl7.fhir.r4.model.MedicationDispense;
@@ -43,6 +46,7 @@
import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.QuestionnaireResponse;
import org.hl7.fhir.r4.model.Reference;
+import org.hl7.fhir.r4.model.Specimen;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.Type;
import org.hl7.fhir.r4.model.codesystems.DataAbsentReason;
@@ -55,7 +59,10 @@
import org.slf4j.LoggerFactory;
import jakarta.annotation.Nonnull;
+import org.testcontainers.shaded.com.trilead.ssh2.packets.PacketDisconnect;
+
import java.io.IOException;
+import java.sql.Ref;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
@@ -261,6 +268,36 @@ public void testDuplicateContainedResourcesNotOutputtedTwice() {
idx = encoded.indexOf("\"Medication\"", idx + 1);
assertEquals(-1, idx);
+ }
+
+ @Test
+ public void testDuplicateContainedResourcesAcrossABundleAreReplicated() {
+ Bundle b = new Bundle();
+ Specimen specimen = new Specimen();
+ Practitioner practitioner = new Practitioner();
+ DiagnosticReport report = new DiagnosticReport();
+ report.addSpecimen(new Reference(specimen));
+ b.addEntry().setResource(report).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("/DiagnosticReport");
+
+ Observation obs = new Observation();
+ obs.addPerformer(new Reference(practitioner));
+ obs.setSpecimen(new Reference(specimen));
+
+ b.addEntry().setResource(obs).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("/Observation");
+
+ String encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(b);
+ //Then: Diag should contain one local contained specimen
+ assertThat(encoded).contains("[{\"resource\":{\"resourceType\":\"DiagnosticReport\",\"contained\":[{\"resourceType\":\"Specimen\",\"id\":\""+ specimen.getId().replaceFirst("#", "") +"\"}]");
+ //Then: Obs should contain one local contained specimen, and one local contained pract
+ assertThat(encoded).contains("\"resource\":{\"resourceType\":\"Observation\",\"contained\":[{\"resourceType\":\"Specimen\",\"id\":\""+ specimen.getId().replaceFirst("#", "") +"\"},{\"resourceType\":\"Practitioner\",\"id\":\"" + practitioner.getId().replaceAll("#","") + "\"}]");
+ assertThat(encoded).contains("\"performer\":[{\"reference\":\""+practitioner.getId()+"\"}],\"specimen\":{\"reference\":\""+specimen.getId()+"\"}");
+
+ //Also, reverting the operation should work too!
+ Bundle bundle = ourCtx.newJsonParser().parseResource(Bundle.class, encoded);
+ IBaseResource resource1 = ((DiagnosticReport) bundle.getEntry().get(0).getResource()).getSpecimenFirstRep().getResource();
+ IBaseResource resource = ((Observation) bundle.getEntry().get(1).getResource()).getSpecimen().getResource();
+ assertThat(resource1.getIdElement().getIdPart()).isEqualTo(resource.getIdElement().getIdPart());
+ assertThat(resource1).isNotSameAs(resource);
}
@@ -279,8 +316,9 @@ public void testContainedResourcesNotAutoContainedWhenConfiguredNotToDoSo() {
ourCtx.getParserOptions().setAutoContainReferenceTargetsWithNoId(true);
encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(md);
- assertEquals("{\"resourceType\":\"MedicationDispense\",\"contained\":[{\"resourceType\":\"Medication\",\"id\":\"1\",\"code\":{\"text\":\"MED\"}}],\"identifier\":[{\"value\":\"DISPENSE\"}],\"medicationReference\":{\"reference\":\"#1\"}}", encoded);
-
+ String guidWithHash = med.getId();
+ String withoutHash = guidWithHash.replace("#", "");
+ assertThat(encoded).contains("{\"resourceType\":\"MedicationDispense\",\"contained\":[{\"resourceType\":\"Medication\",\"id\":\"" + withoutHash + "\",\"code\":{\"text\":\"MED\"}}],\"identifier\":[{\"value\":\"DISPENSE\"}],\"medicationReference\":{\"reference\":\"" + guidWithHash +"\"}}"); //Note we dont check exact ID since its a GUID
}
@Test
@@ -571,7 +609,7 @@ public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocal
obs = ourCtx.newJsonParser().parseResource(Observation.class, encoded);
assertEquals("#1", obs.getContained().get(0).getId());
- assertEquals("#2", obs.getContained().get(1).getId());
+ assertEquals(enc.getId(), obs.getContained().get(1).getId());
pt = (Patient) obs.getSubject().getResource();
assertEquals("FAM", pt.getNameFirstRep().getFamily());
@@ -600,7 +638,7 @@ public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocal
obs = ourCtx.newJsonParser().parseResource(Observation.class, encoded);
assertEquals("#1", obs.getContained().get(0).getId());
- assertEquals("#2", obs.getContained().get(1).getId());
+ assertEquals(pt.getId(), obs.getContained().get(1).getId());
pt = (Patient) obs.getSubject().getResource();
assertEquals("FAM", pt.getNameFirstRep().getFamily());
@@ -620,13 +658,14 @@ public void testEncodeResourceWithMixedManualAndAutomaticContainedResourcesLocal
ourLog.info(encoded);
mr = ourCtx.newJsonParser().parseResource(MedicationRequest.class, encoded);
- mr.setMedication(new Reference(new Medication().setStatus(Medication.MedicationStatus.ACTIVE)));
+ Medication med = new Medication().setStatus(Medication.MedicationStatus.ACTIVE);
+ mr.setMedication(new Reference(med));
encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(mr);
ourLog.info(encoded);
mr = ourCtx.newJsonParser().parseResource(MedicationRequest.class, encoded);
- assertEquals("#1", mr.getContained().get(0).getId());
- assertEquals("#2", mr.getContained().get(1).getId());
+ assertEquals(pract.getId(), mr.getContained().get(0).getId());
+ assertEquals(med.getId(), mr.getContained().get(1).getId());
}
diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/FhirTerserR4Test.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/FhirTerserR4Test.java
index 87a33805db63..0f2e122fd6f9 100644
--- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/FhirTerserR4Test.java
+++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/FhirTerserR4Test.java
@@ -6,7 +6,10 @@
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.parser.DataFormatException;
+import ca.uhn.fhir.parser.IParser;
+import ca.uhn.fhir.parser.JsonParser;
import com.google.common.collect.Lists;
+import org.apache.jena.base.Sys;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseReference;
@@ -47,6 +50,8 @@
import org.mockito.ArgumentCaptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.testcontainers.shaded.com.fasterxml.jackson.core.JsonProcessingException;
+import org.testcontainers.shaded.com.fasterxml.jackson.databind.ObjectMapper;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
@@ -62,6 +67,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
+import static ca.uhn.fhir.test.utilities.UuidUtils.HASH_UUID_PATTERN;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -188,12 +194,12 @@ public void testContainResourcesWithModify() {
FhirTerser.ContainedResources contained = myCtx.newTerser().containResources(mr, FhirTerser.OptionsEnum.MODIFY_RESOURCE, FhirTerser.OptionsEnum.STORE_AND_REUSE_RESULTS);
- assertEquals("#1", mr.getContained().get(0).getId());
- assertEquals("#2", mr.getContained().get(1).getId());
+ assertThat(mr.getContained().get(0).getId()).containsPattern(HASH_UUID_PATTERN);
+ assertThat(mr.getContained().get(1).getId()).containsPattern(HASH_UUID_PATTERN);
assertEquals(ResourceType.Medication, mr.getContained().get(0).getResourceType());
assertEquals(ResourceType.Practitioner, mr.getContained().get(1).getResourceType());
- assertEquals("#1", mr.getMedicationReference().getReference());
- assertEquals("#2", mr.getRequester().getReference());
+ assertEquals(mr.getContained().get(0).getId(), mr.getMedicationReference().getReference());
+ assertEquals(mr.getContained().get(1).getId(), mr.getRequester().getReference());
FhirTerser.ContainedResources secondPass = myCtx.newTerser().containResources(mr, FhirTerser.OptionsEnum.MODIFY_RESOURCE, FhirTerser.OptionsEnum.STORE_AND_REUSE_RESULTS);
assertThat(secondPass).isSameAs(contained);
@@ -212,12 +218,12 @@ public void testContainedResourcesWithModify_DoubleLink() {
myCtx.newTerser().containResources(medAdmin, FhirTerser.OptionsEnum.MODIFY_RESOURCE, FhirTerser.OptionsEnum.STORE_AND_REUSE_RESULTS);
- assertEquals("#1", medAdmin.getContained().get(0).getId());
- assertEquals("#2", medAdmin.getContained().get(1).getId());
+ assertThat(medAdmin.getContained().get(0).getId()).containsPattern(HASH_UUID_PATTERN);
+ assertThat(medAdmin.getContained().get(1).getId()).containsPattern(HASH_UUID_PATTERN);
assertEquals(ResourceType.Medication, medAdmin.getContained().get(0).getResourceType());
assertEquals(ResourceType.Substance, medAdmin.getContained().get(1).getResourceType());
- assertEquals("#1", medAdmin.getMedicationReference().getReference());
- assertEquals("#2", ((Medication) (medAdmin.getContained().get(0))).getIngredientFirstRep().getItemReference().getReference());
+ assertEquals(medAdmin.getContained().get(0).getId(), medAdmin.getMedicationReference().getReference());
+ assertEquals(medAdmin.getContained().get(1).getId(), ((Medication) (medAdmin.getContained().get(0))).getIngredientFirstRep().getItemReference().getReference());
}
@@ -1545,23 +1551,29 @@ private List toStrings(List theStrings) {
@Test
void copyingAndParsingCreatesDuplicateContainedResources() {
- var input = new Library();
+ var library = new Library();
var params = new Parameters();
var id = "#expansion-parameters-ecr";
params.setId(id);
params.addParameter("system-version", new StringType("test2"));
var paramsExt = new Extension();
+
paramsExt.setUrl("test").setValue(new Reference(id));
- input.addContained(params);
- input.addExtension(paramsExt);
+ library.addContained(params);
+ library.addExtension(paramsExt);
+
final var parser = FhirContext.forR4Cached().newJsonParser();
- var stringified = parser.encodeResourceToString(input);
+ var stringified = parser.encodeResourceToString(library);
+
+
var parsed = parser.parseResource(stringified);
var copy = ((Library) parsed).copy();
+
assertEquals(1, copy.getContained().size());
- var stringifiedCopy = parser.encodeResourceToString(copy);
- var parsedCopy = parser.parseResource(stringifiedCopy);
- assertEquals(1, ((Library) parsedCopy).getContained().size());
+
+ String stringifiedCopy = FhirContext.forR4Cached().newJsonParser().encodeResourceToString(copy);
+ Library parsedCopy = (Library) parser.parseResource(stringifiedCopy);
+ assertEquals(1, parsedCopy.getContained().size());
}
/**
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/UuidUtils.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/UuidUtils.java
new file mode 100644
index 000000000000..7cd9e85f2138
--- /dev/null
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/UuidUtils.java
@@ -0,0 +1,47 @@
+/*-
+ * #%L
+ * HAPI FHIR Test Utilities
+ * %%
+ * Copyright (C) 2014 - 2024 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%
+ */
+package ca.uhn.fhir.test.utilities;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class UuidUtils {
+
+ private UuidUtils() {
+ }
+
+ public static final String UUID_PATTERN = "[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}";
+ public static final String HASH_UUID_PATTERN = "#" + UUID_PATTERN;
+ private static final Pattern COMPILED_UUID_PATTERN = Pattern.compile(UUID_PATTERN);
+
+ /**
+ * Extracts first UUID from String.
+ * Returns null if no UUID present in the String.
+ */
+ public static String findFirstUUID(String input) {
+ Matcher matcher = COMPILED_UUID_PATTERN.matcher(input);
+
+ if (matcher.find()) {
+ return matcher.group();
+ }
+ return null;
+ }
+
+}
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProviders.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProviders.java
new file mode 100644
index 000000000000..d9933708e477
--- /dev/null
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProviders.java
@@ -0,0 +1,123 @@
+/*-
+ * #%L
+ * HAPI FHIR Test Utilities
+ * %%
+ * Copyright (C) 2014 - 2024 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%
+ */
+package ca.uhn.fhir.test.utilities.validation;
+
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.context.support.IValidationSupport;
+import ca.uhn.fhir.rest.annotation.RequiredParam;
+import ca.uhn.fhir.rest.annotation.Search;
+import ca.uhn.fhir.rest.param.UriParam;
+import ca.uhn.fhir.rest.server.IResourceProvider;
+import ca.uhn.fhir.util.ClasspathUtil;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
+import org.hl7.fhir.instance.model.api.IDomainResource;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public interface IValidationProviders {
+ String CODE_SYSTEM = "http://code.system/url";
+ String CODE_SYSTEM_VERSION = "1.0.0";
+ String CODE_SYSTEM_NAME = "Test Code System";
+ String CODE = "CODE";
+ String VALUE_SET_URL = "http://value.set/url";
+ String DISPLAY = "Explanation for code TestCode.";
+ String LANGUAGE = "en";
+ String ERROR_MESSAGE = "This is an error message";
+
+ interface IMyValidationProvider extends IResourceProvider {
+ void addException(String theOperation, String theUrl, String theCode, Exception theException);
+ void addTerminologyResponse(String theOperation, String theUrl, String theCode, P theReturnParams);
+ IBaseParameters addTerminologyResponse(String theOperation, String theUrl, String theCode, FhirContext theFhirContext, String theTerminologyResponseFile);
+ }
+
+ abstract class MyValidationProvider implements IMyValidationProvider {
+ private final Map myExceptionMap = new HashMap<>();
+ private boolean myShouldThrowExceptionForResourceNotFound = true;
+ private final Map myTerminologyResponseMap = new HashMap<>();
+ private final Map myTerminologyResourceMap = new HashMap<>();
+
+ static String getInputKey(String theOperation, String theUrl, String theCode) {
+ return theOperation + "-" + theUrl + "#" + theCode;
+ }
+
+ public void setShouldThrowExceptionForResourceNotFound(boolean theShouldThrowExceptionForResourceNotFound) {
+ myShouldThrowExceptionForResourceNotFound = theShouldThrowExceptionForResourceNotFound;
+ }
+
+ public void addException(String theOperation, String theUrl, String theCode, Exception theException) {
+ String inputKey = getInputKey(theOperation, theUrl, theCode);
+ myExceptionMap.put(inputKey, theException);
+ }
+
+ abstract Class extends IBaseParameters> getParameterType();
+
+ @Override
+ public void addTerminologyResponse(String theOperation, String theUrl, String theCode, P theReturnParams) {
+ myTerminologyResponseMap.put(getInputKey(theOperation, theUrl, theCode), theReturnParams);
+ }
+
+ public IBaseParameters addTerminologyResponse(String theOperation, String theUrl, String theCode, FhirContext theFhirContext, String theTerminologyResponseFile) {
+ IBaseParameters responseParams = ClasspathUtil.loadResource(theFhirContext, getParameterType(), theTerminologyResponseFile);
+ addTerminologyResponse(theOperation, theUrl, theCode, responseParams);
+ return responseParams;
+ }
+
+ protected void addTerminologyResource(String theUrl, T theResource) {
+ myTerminologyResourceMap.put(theUrl, theResource);
+ }
+
+ public abstract T addTerminologyResource(String theUrl);
+
+ protected IBaseParameters getTerminologyResponse(String theOperation, String theUrl, String theCode) throws Exception {
+ String inputKey = getInputKey(theOperation, theUrl, theCode);
+ if (myExceptionMap.containsKey(inputKey)) {
+ throw myExceptionMap.get(inputKey);
+ }
+ IBaseParameters params = myTerminologyResponseMap.get(inputKey);
+ if (params == null) {
+ throw new IllegalStateException("Test setup incomplete. Missing return params for " + inputKey);
+ }
+ return params;
+ }
+
+ protected T getTerminologyResource(UriParam theUrlParam) {
+ if (theUrlParam.isEmpty()) {
+ throw new IllegalStateException("CodeSystem url should not be null.");
+ }
+ String urlValue = theUrlParam.getValue();
+ if (!myTerminologyResourceMap.containsKey(urlValue) && myShouldThrowExceptionForResourceNotFound) {
+ throw new IllegalStateException("Test setup incomplete. CodeSystem not found " + urlValue);
+ }
+ return myTerminologyResourceMap.get(urlValue);
+ }
+
+ @Search
+ public List find(@RequiredParam(name = "url") UriParam theUrlParam) {
+ T resource = getTerminologyResource(theUrlParam);
+ return resource != null ? List.of(resource) : List.of();
+ }
+ }
+
+ interface IMyLookupCodeProvider extends IResourceProvider {
+ void setLookupCodeResult(IValidationSupport.LookupCodeResult theLookupCodeResult);
+ }
+}
diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersDstu3.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersDstu3.java
new file mode 100644
index 000000000000..11c5244df414
--- /dev/null
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersDstu3.java
@@ -0,0 +1,137 @@
+/*-
+ * #%L
+ * HAPI FHIR Test Utilities
+ * %%
+ * Copyright (C) 2014 - 2024 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%
+ */
+package ca.uhn.fhir.test.utilities.validation;
+
+import ca.uhn.fhir.rest.annotation.IdParam;
+import ca.uhn.fhir.rest.annotation.Operation;
+import ca.uhn.fhir.rest.annotation.OperationParam;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
+import jakarta.servlet.http.HttpServletRequest;
+import org.hl7.fhir.dstu3.model.BooleanType;
+import org.hl7.fhir.dstu3.model.CodeSystem;
+import org.hl7.fhir.dstu3.model.CodeType;
+import org.hl7.fhir.dstu3.model.Coding;
+import org.hl7.fhir.dstu3.model.IdType;
+import org.hl7.fhir.dstu3.model.Parameters;
+import org.hl7.fhir.dstu3.model.StringType;
+import org.hl7.fhir.dstu3.model.UriType;
+import org.hl7.fhir.dstu3.model.ValueSet;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+
+import java.util.List;
+
+public interface IValidationProvidersDstu3 {
+ @SuppressWarnings("unused")
+ class MyCodeSystemProviderDstu3 extends IValidationProviders.MyValidationProvider {
+ @Operation(name = "$validate-code", idempotent = true, returnParameters = {
+ @OperationParam(name = "result", type = BooleanType.class, min = 1),
+ @OperationParam(name = "message", type = StringType.class),
+ @OperationParam(name = "display", type = StringType.class)
+ })
+ public IBaseParameters validateCode(
+ HttpServletRequest theServletRequest,
+ @IdParam(optional = true) IdType theId,
+ @OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl,
+ @OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
+ @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay
+ ) throws Exception {
+ String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$validate-code", url, code);
+ }
+
+ @Operation(name = "$lookup", idempotent = true, returnParameters= {
+ @OperationParam(name = "name", type = StringType.class, min = 1),
+ @OperationParam(name = "version", type = StringType.class),
+ @OperationParam(name = "display", type = StringType.class, min = 1),
+ @OperationParam(name = "abstract", type = BooleanType.class, min = 1),
+ @OperationParam(name = "property", type = StringType.class, min = 0, max = OperationParam.MAX_UNLIMITED)
+ })
+ public IBaseParameters lookup(
+ HttpServletRequest theServletRequest,
+ @OperationParam(name = "code", max = 1) CodeType theCode,
+ @OperationParam(name = "system",max = 1) UriType theSystem,
+ @OperationParam(name = "coding", max = 1) Coding theCoding,
+ @OperationParam(name = "version", max = 1) StringType theVersion,
+ @OperationParam(name = "displayLanguage", max = 1) CodeType theDisplayLanguage,
+ @OperationParam(name = "property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames,
+ RequestDetails theRequestDetails
+ ) throws Exception {
+ String url = theSystem != null ? theSystem.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$lookup", url, code);
+ }
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return CodeSystem.class;
+ }
+ @Override
+ Class getParameterType() {
+ return Parameters.class;
+ }
+ @Override
+ public CodeSystem addTerminologyResource(String theUrl) {
+ CodeSystem codeSystem = new CodeSystem();
+ codeSystem.setId(theUrl.substring(0, theUrl.lastIndexOf("/")));
+ codeSystem.setUrl(theUrl);
+ addTerminologyResource(theUrl, codeSystem);
+ return codeSystem;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ class MyValueSetProviderDstu3 extends IValidationProviders.MyValidationProvider {
+ @Operation(name = "$validate-code", idempotent = true, returnParameters = {
+ @OperationParam(name = "result", type = BooleanType.class, min = 1),
+ @OperationParam(name = "message", type = StringType.class),
+ @OperationParam(name = "display", type = StringType.class)
+ })
+ public IBaseParameters validateCode(
+ HttpServletRequest theServletRequest,
+ @IdParam(optional = true) IdType theId,
+ @OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
+ @OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
+ @OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
+ @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
+ @OperationParam(name = "valueSet") ValueSet theValueSet
+ ) throws Exception {
+ String url = theValueSetUrl != null ? theValueSetUrl.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$validate-code", url, code);
+ }
+ @Override
+ public Class extends IBaseResource> getResourceType() {
+ return ValueSet.class;
+ }
+ @Override
+ Class getParameterType() {
+ return Parameters.class;
+ }
+ @Override
+ public ValueSet addTerminologyResource(String theUrl) {
+ ValueSet valueSet = new ValueSet();
+ valueSet.setId(theUrl.substring(0, theUrl.lastIndexOf("/")));
+ valueSet.setUrl(theUrl);
+ addTerminologyResource(theUrl, valueSet);
+ return valueSet;
+ }
+ }
+}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/IValidateCodeProvidersR4.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersR4.java
similarity index 55%
rename from hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/IValidateCodeProvidersR4.java
rename to hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersR4.java
index fd03a8163ffa..87a3dacb1fc2 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/IValidateCodeProvidersR4.java
+++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/validation/IValidationProvidersR4.java
@@ -1,12 +1,29 @@
-package org.hl7.fhir.r4.validation;
+/*-
+ * #%L
+ * HAPI FHIR Test Utilities
+ * %%
+ * Copyright (C) 2014 - 2024 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%
+ */
+package ca.uhn.fhir.test.utilities.validation;
-import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import jakarta.servlet.http.HttpServletRequest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.BooleanType;
@@ -21,38 +38,29 @@
import java.util.List;
-public interface IValidateCodeProvidersR4 {
+public interface IValidationProvidersR4 {
@SuppressWarnings("unused")
- class MyCodeSystemProviderR4 implements IValidationProviders.IMyCodeSystemProvider {
- private UriType mySystemUrl;
- private CodeType myCode;
- private StringType myDisplay;
- private Exception myException;
- private Parameters myReturnParams;
+ class MyCodeSystemProviderR4 extends IValidationProviders.MyValidationProvider {
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
+ @Operation(name = "$validate-code", idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class),
@OperationParam(name = "display", type = StringType.class)
})
- public Parameters validateCode(
+ public IBaseParameters validateCode(
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl,
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay
) throws Exception {
- mySystemUrl = theCodeSystemUrl;
- myCode = theCode;
- myDisplay = theDisplay;
- if (myException != null) {
- throw myException;
- }
- return myReturnParams;
+ String url = theCodeSystemUrl != null ? theCodeSystemUrl.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$validate-code", url, code);
}
- @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= {
+ @Operation(name = "$lookup", idempotent = true, returnParameters= {
@OperationParam(name = "name", type = StringType.class, min = 1),
@OperationParam(name = "version", type = StringType.class),
@OperationParam(name = "display", type = StringType.class, min = 1),
@@ -69,54 +77,39 @@ public IBaseParameters lookup(
@OperationParam(name = "property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames,
RequestDetails theRequestDetails
) throws Exception {
- mySystemUrl = theSystem;
- myCode = theCode;
- if (myException != null) {
- throw myException;
- }
- return myReturnParams;
+ String url = theSystem != null ? theSystem.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$lookup", url, code);
}
-
@Override
public Class extends IBaseResource> getResourceType() {
return CodeSystem.class;
}
- public void setException(Exception theException) {
- myException = theException;
- }
- @Override
- public void setReturnParams(IBaseParameters theParameters) {
- myReturnParams = (Parameters) theParameters;
- }
@Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
+ Class getParameterType() {
+ return Parameters.class;
}
+
@Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
- public String getDisplay() {
- return myDisplay != null ? myDisplay.getValue() : null;
+ public CodeSystem addTerminologyResource(String theUrl) {
+ CodeSystem codeSystem = new CodeSystem();
+ codeSystem.setId(theUrl.substring(0, theUrl.lastIndexOf("/")));
+ codeSystem.setUrl(theUrl);
+ addTerminologyResource(theUrl, codeSystem);
+ return codeSystem;
}
}
@SuppressWarnings("unused")
- class MyValueSetProviderR4 implements IValidationProviders.IMyValueSetProvider {
- private Exception myException;
- private Parameters myReturnParams;
- private UriType mySystemUrl;
- private UriType myValueSetUrl;
- private CodeType myCode;
- private StringType myDisplay;
+ class MyValueSetProviderR4 extends IValidationProviders.MyValidationProvider {
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
+ @Operation(name = "$validate-code", idempotent = true, returnParameters = {
@OperationParam(name = "result", type = BooleanType.class, min = 1),
@OperationParam(name = "message", type = StringType.class),
@OperationParam(name = "display", type = StringType.class)
})
- public Parameters validateCode(
+ public IBaseParameters validateCode(
HttpServletRequest theServletRequest,
@IdParam(optional = true) IdType theId,
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
@@ -125,41 +118,25 @@ public Parameters validateCode(
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
@OperationParam(name = "valueSet") ValueSet theValueSet
) throws Exception {
- mySystemUrl = theSystem;
- myValueSetUrl = theValueSetUrl;
- myCode = theCode;
- myDisplay = theDisplay;
- if (myException != null) {
- throw myException;
- }
- return myReturnParams;
+ String url = theValueSetUrl != null ? theValueSetUrl.getValue() : null;
+ String code = theCode != null ? theCode.getValue() : null;
+ return getTerminologyResponse("$validate-code", url, code);
}
-
@Override
public Class extends IBaseResource> getResourceType() {
return ValueSet.class;
}
- public void setException(Exception theException) {
- myException = theException;
- }
- @Override
- public void setReturnParams(IBaseParameters theParameters) {
- myReturnParams = (Parameters) theParameters;
- }
@Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
+ Class getParameterType() {
+ return Parameters.class;
}
@Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
- @Override
- public String getValueSet() {
- return myValueSetUrl != null ? myValueSetUrl.getValueAsString() : null;
- }
- public String getDisplay() {
- return myDisplay != null ? myDisplay.getValue() : null;
+ public ValueSet addTerminologyResource(String theUrl) {
+ ValueSet valueSet = new ValueSet();
+ valueSet.setId(theUrl.substring(0, theUrl.lastIndexOf("/")));
+ valueSet.setUrl(theUrl);
+ addTerminologyResource(theUrl, valueSet);
+ return valueSet;
}
}
}
diff --git a/hapi-fhir-test-utilities/src/test/java/ca/uhn/fhir/test/utilities/UuidUtilsTest.java b/hapi-fhir-test-utilities/src/test/java/ca/uhn/fhir/test/utilities/UuidUtilsTest.java
new file mode 100644
index 000000000000..c7c26bdf1077
--- /dev/null
+++ b/hapi-fhir-test-utilities/src/test/java/ca/uhn/fhir/test/utilities/UuidUtilsTest.java
@@ -0,0 +1,29 @@
+package ca.uhn.fhir.test.utilities;
+
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNull;
+
+public class UuidUtilsTest {
+
+ @Test
+ void testFindsUuid() {
+ String xml = "";
+ String uuid = UuidUtils.findFirstUUID(xml);
+ assertEquals("cdb6dfa1-74b7-4ea9-88e0-d3afaef8c016", uuid);
+ }
+
+ @Test
+ void testFindsFirstUuid() {
+ String xml = "";
+ String uuid = UuidUtils.findFirstUUID(xml);
+ assertEquals("cdb6dfa1-74b7-4ea9-88e0-d3afaef8c016", uuid);
+ }
+
+ @Test
+ void testNoUuidReturnsNull() {
+ String xml = "";
+ assertNull(UuidUtils.findFirstUUID(xml));
+ }
+}
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CommonCodeSystemsTerminologyService.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CommonCodeSystemsTerminologyService.java
index 1b12e20ec62e..7a05e197ae63 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CommonCodeSystemsTerminologyService.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CommonCodeSystemsTerminologyService.java
@@ -190,7 +190,7 @@ protected CodeValidationResult getValidateCodeResultError(final String theMessag
return new CodeValidationResult()
.setSeverity(IssueSeverity.ERROR)
.setMessage(theMessage)
- .setCodeValidationIssues(Collections.singletonList(new CodeValidationIssue(
+ .setIssues(Collections.singletonList(new CodeValidationIssue(
theMessage,
IssueSeverity.ERROR,
CodeValidationIssueCode.INVALID,
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 67e553e3d3b7..a617e04c41b7 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
@@ -28,7 +28,6 @@
import org.hl7.fhir.r5.model.CanonicalType;
import org.hl7.fhir.r5.model.CodeSystem;
import org.hl7.fhir.r5.model.Enumerations;
-import org.hl7.fhir.utilities.validation.ValidationMessage;
import java.util.ArrayList;
import java.util.Collections;
@@ -258,7 +257,7 @@ public CodeValidationResult validateCodeInValueSet(
theValidationSupportContext, theValueSet, theCodeSystemUrlAndVersion, theCode);
} catch (ExpansionCouldNotBeCompletedInternallyException e) {
CodeValidationResult codeValidationResult = new CodeValidationResult();
- codeValidationResult.setSeverityCode("error");
+ codeValidationResult.setSeverity(IssueSeverity.ERROR);
String msg = "Failed to expand ValueSet '" + vsUrl + "' (in-memory). Could not validate code "
+ theCodeSystemUrlAndVersion + "#" + theCode;
@@ -267,7 +266,7 @@ public CodeValidationResult validateCodeInValueSet(
}
codeValidationResult.setMessage(msg);
- codeValidationResult.addCodeValidationIssue(e.getCodeValidationIssue());
+ codeValidationResult.addIssue(e.getCodeValidationIssue());
return codeValidationResult;
}
@@ -551,18 +550,18 @@ private CodeValidationResult validateCodeInExpandedValueSet(
if (valueSetResult != null) {
codeValidationResult = valueSetResult;
} else {
- ValidationMessage.IssueSeverity severity;
+ IValidationSupport.IssueSeverity severity;
String message;
CodeValidationIssueCode issueCode = CodeValidationIssueCode.CODE_INVALID;
CodeValidationIssueCoding issueCoding = CodeValidationIssueCoding.INVALID_CODE;
if ("fragment".equals(codeSystemResourceContentMode)) {
- severity = ValidationMessage.IssueSeverity.WARNING;
+ severity = IValidationSupport.IssueSeverity.WARNING;
message = "Unknown code in fragment CodeSystem '"
+ getFormattedCodeSystemAndCodeForMessage(
theCodeSystemUrlAndVersionToValidate, theCodeToValidate)
+ "'";
} else {
- severity = ValidationMessage.IssueSeverity.ERROR;
+ severity = IValidationSupport.IssueSeverity.ERROR;
message = "Unknown code '"
+ getFormattedCodeSystemAndCodeForMessage(
theCodeSystemUrlAndVersionToValidate, theCodeToValidate)
@@ -574,10 +573,9 @@ private CodeValidationResult validateCodeInExpandedValueSet(
}
codeValidationResult = new CodeValidationResult()
- .setSeverityCode(severity.toCode())
+ .setSeverity(severity)
.setMessage(message)
- .addCodeValidationIssue(new CodeValidationIssue(
- message, getIssueSeverityFromCodeValidationIssue(severity), issueCode, issueCoding));
+ .addIssue(new CodeValidationIssue(message, severity, issueCode, issueCoding));
}
return codeValidationResult;
@@ -589,19 +587,6 @@ private static String getFormattedCodeSystemAndCodeForMessage(
+ theCodeToValidate;
}
- private IValidationSupport.IssueSeverity getIssueSeverityFromCodeValidationIssue(
- ValidationMessage.IssueSeverity theSeverity) {
- switch (theSeverity) {
- case ERROR:
- return IValidationSupport.IssueSeverity.ERROR;
- case WARNING:
- return IValidationSupport.IssueSeverity.WARNING;
- case INFORMATION:
- return IValidationSupport.IssueSeverity.INFORMATION;
- }
- return null;
- }
-
private CodeValidationResult findCodeInExpansion(
String theCodeToValidate,
String theDisplayToValidate,
@@ -1123,8 +1108,8 @@ private boolean expandValueSetR5IncludeOrExclude(
new CodeValidationIssue(
theMessage,
IssueSeverity.ERROR,
- CodeValidationIssueCode.OTHER,
- CodeValidationIssueCoding.OTHER));
+ CodeValidationIssueCode.INVALID,
+ CodeValidationIssueCoding.VS_INVALID));
}
for (org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent next :
subExpansion.getExpansion().getContains()) {
@@ -1376,7 +1361,7 @@ private static CodeValidationResult createResultForDisplayMismatch(
.setCodeSystemVersion(theCodeSystemVersion)
.setDisplay(theExpectedDisplay);
if (issueSeverity != null) {
- codeValidationResult.setCodeValidationIssues(Collections.singletonList(new CodeValidationIssue(
+ codeValidationResult.setIssues(Collections.singletonList(new CodeValidationIssue(
message,
theIssueSeverityForCodeDisplayMismatch,
CodeValidationIssueCode.INVALID,
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java
index 370f8b423dd2..398eacc52a24 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/RemoteTerminologyServiceValidationSupport.java
@@ -28,6 +28,7 @@
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.CodeSystem;
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.OperationOutcome;
import org.hl7.fhir.r4.model.Parameters;
@@ -631,7 +632,7 @@ private CodeValidationResult createErrorCodeValidationResult(
return new CodeValidationResult()
.setSeverity(severity)
.setMessage(theMessage)
- .addCodeValidationIssue(new CodeValidationIssue(
+ .addIssue(new CodeValidationIssue(
theMessage, severity, theIssueCode, CodeValidationIssueCoding.INVALID_CODE));
}
@@ -680,13 +681,13 @@ private CodeValidationResult createCodeValidationResult(
createCodeValidationIssues(
(IBaseOperationOutcome) issuesValue.get(),
fhirContext.getVersion().getVersion())
- .ifPresent(i -> i.forEach(result::addCodeValidationIssue));
+ .ifPresent(i -> i.forEach(result::addIssue));
} else {
// create a validation issue out of the message
// this is a workaround to overcome an issue in the FHIR Validator library
// where ValueSet bindings are only reading issues but not messages
// @see https://github.com/hapifhir/org.hl7.fhir.core/issues/1766
- result.addCodeValidationIssue(createCodeValidationIssue(result.getMessage()));
+ result.addIssue(createCodeValidationIssue(result.getMessage()));
}
return result;
}
@@ -717,23 +718,42 @@ public static Optional> createCodeValidationIssu
private static Collection createCodeValidationIssuesR4(OperationOutcome theOperationOutcome) {
return theOperationOutcome.getIssue().stream()
- .map(issueComponent ->
- createCodeValidationIssue(issueComponent.getDetails().getText()))
+ .map(issueComponent -> {
+ String diagnostics = issueComponent.getDiagnostics();
+ IssueSeverity issueSeverity =
+ IssueSeverity.fromCode(issueComponent.getSeverity().toCode());
+ String issueTypeCode = issueComponent.getCode().toCode();
+ CodeableConcept details = issueComponent.getDetails();
+ CodeValidationIssue issue = new CodeValidationIssue(diagnostics, issueSeverity, issueTypeCode);
+ CodeValidationIssueDetails issueDetails = new CodeValidationIssueDetails(details.getText());
+ details.getCoding().forEach(coding -> issueDetails.addCoding(coding.getSystem(), coding.getCode()));
+ issue.setDetails(issueDetails);
+ return issue;
+ })
.collect(Collectors.toList());
}
private static Collection createCodeValidationIssuesDstu3(
org.hl7.fhir.dstu3.model.OperationOutcome theOperationOutcome) {
return theOperationOutcome.getIssue().stream()
- .map(issueComponent ->
- createCodeValidationIssue(issueComponent.getDetails().getText()))
+ .map(issueComponent -> {
+ String diagnostics = issueComponent.getDiagnostics();
+ IssueSeverity issueSeverity =
+ IssueSeverity.fromCode(issueComponent.getSeverity().toCode());
+ String issueTypeCode = issueComponent.getCode().toCode();
+ org.hl7.fhir.dstu3.model.CodeableConcept details = issueComponent.getDetails();
+ CodeValidationIssue issue = new CodeValidationIssue(diagnostics, issueSeverity, issueTypeCode);
+ CodeValidationIssueDetails issueDetails = new CodeValidationIssueDetails(details.getText());
+ details.getCoding().forEach(coding -> issueDetails.addCoding(coding.getSystem(), coding.getCode()));
+ issue.setDetails(issueDetails);
+ return issue;
+ })
.collect(Collectors.toList());
}
private static CodeValidationIssue createCodeValidationIssue(String theMessage) {
return new CodeValidationIssue(
theMessage,
- // assume issue type is OperationOutcome.IssueType#CODEINVALID as it is the only match
IssueSeverity.ERROR,
CodeValidationIssueCode.INVALID,
CodeValidationIssueCoding.INVALID_CODE);
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.java
index 1898292c4512..265debed058b 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.java
@@ -87,7 +87,7 @@ public CodeValidationResult validateCode(
result.setSeverity(null);
result.setMessage(null);
} else {
- result.addCodeValidationIssue(new CodeValidationIssue(
+ result.addIssue(new CodeValidationIssue(
theMessage,
myNonExistentCodeSystemSeverity,
CodeValidationIssueCode.NOT_FOUND,
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportUtils.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportUtils.java
index 7321f33d8c8e..7093ab2a7ff1 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportUtils.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportUtils.java
@@ -11,6 +11,17 @@ public final class ValidationSupportUtils {
private ValidationSupportUtils() {}
+ /**
+ * This method extracts a code system that can be (potentially) associated with a code when
+ * performing validation against a ValueSet. This method was created for internal purposes.
+ * Please use this method with care because it will only cover some
+ * use-cases (e.g. standard bindings) while for others it may not return correct results or return null.
+ * An incorrect result could be considered if the resource declares a code with a system, and you're calling
+ * this method to check a binding against a ValueSet that has nothing to do with that system.
+ * @param theValueSet the valueSet
+ * @param theCode the code
+ * @return the system which can be associated with the code
+ */
public static String extractCodeSystemForCode(IBaseResource theValueSet, String theCode) {
if (theValueSet instanceof org.hl7.fhir.dstu3.model.ValueSet) {
return extractCodeSystemForCodeDSTU3((org.hl7.fhir.dstu3.model.ValueSet) theValueSet, theCode);
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
index f0f3f41e7f9b..393d8ce1dc54 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
@@ -62,6 +62,7 @@
import java.util.Objects;
import java.util.Set;
+import static ca.uhn.fhir.context.support.IValidationSupport.CodeValidationIssueCoding.INVALID_DISPLAY;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toSet;
import static org.apache.commons.lang3.StringUtils.isBlank;
@@ -296,7 +297,7 @@ private ValidationResult convertValidationResult(
theResult.getCodeSystemVersion(),
conceptDefinitionComponent,
display,
- getIssuesForCodeValidation(theResult.getCodeValidationIssues()));
+ getIssuesForCodeValidation(theResult.getIssues()));
}
if (retVal == null) {
@@ -307,73 +308,36 @@ private ValidationResult convertValidationResult(
}
private List getIssuesForCodeValidation(
- List codeValidationIssues) {
- List issues = new ArrayList<>();
-
- for (IValidationSupport.CodeValidationIssue codeValidationIssue : codeValidationIssues) {
-
- CodeableConcept codeableConcept = new CodeableConcept().setText(codeValidationIssue.getMessage());
- codeableConcept.addCoding(
- "http://hl7.org/fhir/tools/CodeSystem/tx-issue-type",
- getIssueCodingFromCodeValidationIssue(codeValidationIssue),
- null);
-
- OperationOutcome.OperationOutcomeIssueComponent issue =
+ List theIssues) {
+ List issueComponents = new ArrayList<>();
+
+ for (IValidationSupport.CodeValidationIssue issue : theIssues) {
+ OperationOutcome.IssueSeverity severity =
+ OperationOutcome.IssueSeverity.fromCode(issue.getSeverity().getCode());
+ OperationOutcome.IssueType issueType =
+ OperationOutcome.IssueType.fromCode(issue.getType().getCode());
+ String diagnostics = issue.getDiagnostics();
+
+ IValidationSupport.CodeValidationIssueDetails details = issue.getDetails();
+ CodeableConcept codeableConcept = new CodeableConcept().setText(details.getText());
+ details.getCodings().forEach(detailCoding -> codeableConcept
+ .addCoding()
+ .setSystem(detailCoding.getSystem())
+ .setCode(detailCoding.getCode()));
+
+ OperationOutcome.OperationOutcomeIssueComponent issueComponent =
new OperationOutcome.OperationOutcomeIssueComponent()
- .setSeverity(getIssueSeverityFromCodeValidationIssue(codeValidationIssue))
- .setCode(getIssueTypeFromCodeValidationIssue(codeValidationIssue))
- .setDetails(codeableConcept);
- issue.getDetails().setText(codeValidationIssue.getMessage());
- issue.addExtension()
+ .setSeverity(severity)
+ .setCode(issueType)
+ .setDetails(codeableConcept)
+ .setDiagnostics(diagnostics);
+ issueComponent
+ .addExtension()
.setUrl("http://hl7.org/fhir/StructureDefinition/operationoutcome-message-id")
.setValue(new StringType("Terminology_PassThrough_TX_Message"));
- issues.add(issue);
- }
- return issues;
- }
-
- private String getIssueCodingFromCodeValidationIssue(IValidationSupport.CodeValidationIssue codeValidationIssue) {
- switch (codeValidationIssue.getCoding()) {
- case VS_INVALID:
- return "vs-invalid";
- case NOT_FOUND:
- return "not-found";
- case NOT_IN_VS:
- return "not-in-vs";
- case INVALID_CODE:
- return "invalid-code";
- case INVALID_DISPLAY:
- return "invalid-display";
- }
- return null;
- }
-
- private OperationOutcome.IssueType getIssueTypeFromCodeValidationIssue(
- IValidationSupport.CodeValidationIssue codeValidationIssue) {
- switch (codeValidationIssue.getCode()) {
- case NOT_FOUND:
- return OperationOutcome.IssueType.NOTFOUND;
- case CODE_INVALID:
- return OperationOutcome.IssueType.CODEINVALID;
- case INVALID:
- return OperationOutcome.IssueType.INVALID;
- }
- return null;
- }
-
- private OperationOutcome.IssueSeverity getIssueSeverityFromCodeValidationIssue(
- IValidationSupport.CodeValidationIssue codeValidationIssue) {
- switch (codeValidationIssue.getSeverity()) {
- case FATAL:
- return OperationOutcome.IssueSeverity.FATAL;
- case ERROR:
- return OperationOutcome.IssueSeverity.ERROR;
- case WARNING:
- return OperationOutcome.IssueSeverity.WARNING;
- case INFORMATION:
- return OperationOutcome.IssueSeverity.INFORMATION;
+ issueComponents.add(issueComponent);
}
- return null;
+ return issueComponents;
}
@Override
@@ -851,25 +815,22 @@ private IValidationSupport.CodeValidationResult validateCodeInValueSet(
.getRootValidationSupport()
.validateCodeInValueSet(
myValidationSupportContext, theValidationOptions, theSystem, theCode, theDisplay, theValueSet);
- if (result != null) {
+ if (result != null && theSystem != null) {
/* We got a value set result, which could be successful, or could contain errors/warnings. The code
might also be invalid in the code system, so we will check that as well and add those issues
to our result.
*/
IValidationSupport.CodeValidationResult codeSystemResult =
validateCodeInCodeSystem(theValidationOptions, theSystem, theCode, theDisplay);
- final boolean valueSetResultContainsInvalidDisplay = result.getCodeValidationIssues().stream()
- .anyMatch(codeValidationIssue -> codeValidationIssue.getCoding()
- == IValidationSupport.CodeValidationIssueCoding.INVALID_DISPLAY);
+ final boolean valueSetResultContainsInvalidDisplay = result.getIssues().stream()
+ .anyMatch(VersionSpecificWorkerContextWrapper::hasInvalidDisplayDetailCode);
if (codeSystemResult != null) {
- for (IValidationSupport.CodeValidationIssue codeValidationIssue :
- codeSystemResult.getCodeValidationIssues()) {
+ for (IValidationSupport.CodeValidationIssue codeValidationIssue : codeSystemResult.getIssues()) {
/* Value set validation should already have checked the display name. If we get INVALID_DISPLAY
issues from code system validation, they will only repeat what was already caught.
*/
- if (codeValidationIssue.getCoding() != IValidationSupport.CodeValidationIssueCoding.INVALID_DISPLAY
- || !valueSetResultContainsInvalidDisplay) {
- result.addCodeValidationIssue(codeValidationIssue);
+ if (!hasInvalidDisplayDetailCode(codeValidationIssue) || !valueSetResultContainsInvalidDisplay) {
+ result.addIssue(codeValidationIssue);
}
}
}
@@ -877,6 +838,10 @@ private IValidationSupport.CodeValidationResult validateCodeInValueSet(
return result;
}
+ private static boolean hasInvalidDisplayDetailCode(IValidationSupport.CodeValidationIssue theIssue) {
+ return theIssue.hasIssueDetailCode(INVALID_DISPLAY.getCode());
+ }
+
private IValidationSupport.CodeValidationResult validateCodeInCodeSystem(
ConceptValidationOptions theValidationOptions, String theSystem, String theCode, String theDisplay) {
return myValidationSupportContext
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java
index bb7eaf1c17ba..eac448ad0ebd 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/ILookupCodeTest.java
@@ -9,6 +9,7 @@
import ca.uhn.fhir.context.support.IValidationSupport.StringConceptProperty;
import ca.uhn.fhir.context.support.LookupCodeRequest;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.junit.jupiter.api.Test;
@@ -21,12 +22,12 @@
import static ca.uhn.fhir.context.support.IValidationSupport.TYPE_STRING;
import static java.util.stream.IntStream.range;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE_SYSTEM;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE_SYSTEM_NAME;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE_SYSTEM_VERSION;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.DISPLAY;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.LANGUAGE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM_NAME;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM_VERSION;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.DISPLAY;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.LANGUAGE;
import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.createConceptProperty;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
@@ -189,8 +190,6 @@ default void verifyLookupCodeResult(LookupCodeRequest theRequest, LookupCodeResu
// verify
assertNotNull(outcome);
- assertEquals(theRequest.getCode(), getLookupCodeProvider().getCode());
- assertEquals(theRequest.getSystem(), getLookupCodeProvider().getSystem());
assertEquals(theExpectedResult.isFound(), outcome.isFound());
assertEquals(theExpectedResult.getErrorMessage(), outcome.getErrorMessage());
assertEquals(theExpectedResult.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName());
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyLookupCodeTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyLookupCodeTest.java
index 5ba79bd3e6f9..95c4fd7d3b97 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyLookupCodeTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyLookupCodeTest.java
@@ -2,6 +2,7 @@
import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult;
import ca.uhn.fhir.context.support.LookupCodeRequest;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.junit.jupiter.api.Test;
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyValidateCodeTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyValidateCodeTest.java
index cb6bb02ac072..21c5d0dc5e74 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyValidateCodeTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IRemoteTerminologyValidateCodeTest.java
@@ -1,17 +1,76 @@
package org.hl7.fhir.common.hapi.validation;
+import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.support.IValidationSupport;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
+import org.junit.jupiter.api.Test;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.createCodeValidationIssues;
+
public interface IRemoteTerminologyValidateCodeTest extends IValidateCodeTest {
default List getCodeValidationIssues(IBaseOperationOutcome theOperationOutcome) {
// this method should be removed once support for issues is fully implemented across all validator types
Optional> issues = RemoteTerminologyServiceValidationSupport.createCodeValidationIssues(theOperationOutcome, getService().getFhirContext().getVersion().getVersion());
return issues.map(theCodeValidationIssues -> theCodeValidationIssues.stream().toList()).orElseGet(List::of);
}
+
+ @Test
+ default void createCodeValidationIssues_withCodeSystemOutcomeForInvalidCode_returnsAsExpected() {
+ IBaseOperationOutcome outcome = getCodeSystemInvalidCodeOutcome();
+ FhirVersionEnum versionEnum = getService().getFhirContext().getVersion().getVersion();
+ Optional> issuesOptional = createCodeValidationIssues(outcome, versionEnum);
+ assertThat(issuesOptional).isPresent();
+ assertThat(issuesOptional.get()).hasSize(1);
+ IValidationSupport.CodeValidationIssue issue = issuesOptional.get().iterator().next();
+ assertThat(issue.getType().getCode()).isEqualTo("code-invalid");
+ assertThat(issue.getSeverity().getCode()).isEqualTo("error");
+ assertThat(issue.getDetails().getCodings()).hasSize(1);
+ IValidationSupport.CodeValidationIssueCoding issueCoding = issue.getDetails().getCodings().get(0);
+ assertThat(issueCoding.getSystem()).isEqualTo("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type");
+ assertThat(issueCoding.getCode()).isEqualTo("invalid-code");
+ assertThat(issue.getDetails().getText()).isEqualTo("Unknown code 'CODE' in the CodeSystem 'http://code.system/url' version '1.0.0'");
+ assertThat(issue.getDiagnostics()).isNull();
+ }
+
+ @Test
+ default void createCodeValidationIssues_withValueSetOutcomeForInvalidCode_returnsAsExpected() {
+ IBaseOperationOutcome outcome = getValueSetInvalidCodeOutcome();
+ FhirVersionEnum versionEnum = getService().getFhirContext().getVersion().getVersion();
+ Optional> issuesOptional = createCodeValidationIssues(outcome, versionEnum);
+ assertThat(issuesOptional).isPresent();
+ assertThat(issuesOptional.get()).hasSize(2);
+ IValidationSupport.CodeValidationIssue issue = issuesOptional.get().iterator().next();
+ assertThat(issue.getType().getCode()).isEqualTo("code-invalid");
+ assertThat(issue.getSeverity().getCode()).isEqualTo("error");
+ assertThat(issue.getDetails().getCodings()).hasSize(1);
+ IValidationSupport.CodeValidationIssueCoding issueCoding = issue.getDetails().getCodings().get(0);
+ assertThat(issueCoding.getSystem()).isEqualTo("http://hl7.org/fhir/tools/CodeSystem/tx-issue-type");
+ assertThat(issueCoding.getCode()).isEqualTo("not-in-vs");
+ assertThat(issue.getDetails().getText()).isEqualTo("The provided code 'http://code.system/url#CODE' was not found in the value set 'http://value.set/url%7C1.0.0'");
+ assertThat(issue.getDiagnostics()).isNull();
+ }
+
+ @Test
+ default void createCodeValidationIssues_withValueSetOutcomeWithCustomDetailCode_returnsAsExpected() {
+ IBaseOperationOutcome outcome = getValueSetCustomDetailCodeOutcome();
+ FhirVersionEnum versionEnum = getService().getFhirContext().getVersion().getVersion();
+ Optional> issuesOptional = createCodeValidationIssues(outcome, versionEnum);
+ assertThat(issuesOptional).isPresent();
+ assertThat(issuesOptional.get()).hasSize(1);
+ IValidationSupport.CodeValidationIssue issue = issuesOptional.get().iterator().next();
+ assertThat(issue.getType().getCode()).isEqualTo("processing");
+ assertThat(issue.getSeverity().getCode()).isEqualTo("information");
+ assertThat(issue.getDetails().getCodings()).hasSize(1);
+ IValidationSupport.CodeValidationIssueCoding issueCoding = issue.getDetails().getCodings().get(0);
+ assertThat(issueCoding.getSystem()).isEqualTo("http://example.com/custom-issue-type");
+ assertThat(issueCoding.getCode()).isEqualTo("valueset-is-draft");
+ assertThat(issue.getDetails().getText()).isNull();
+ assertThat(issue.getDiagnostics()).isEqualTo("The ValueSet status is marked as draft.");
+ }
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidateCodeTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidateCodeTest.java
index 52dbf1177a86..53411b440fe6 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidateCodeTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidateCodeTest.java
@@ -4,6 +4,9 @@
import ca.uhn.fhir.context.support.IValidationSupport.CodeValidationResult;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.util.ClasspathUtil;
+import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseParameters;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -16,12 +19,13 @@
import java.util.stream.Stream;
import static ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity.ERROR;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE_SYSTEM;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.CODE_SYSTEM_VERSION;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.DISPLAY;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.ERROR_MESSAGE;
-import static org.hl7.fhir.common.hapi.validation.IValidationProviders.VALUE_SET_URL;
+import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_VALIDATE_CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM_VERSION;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.DISPLAY;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.ERROR_MESSAGE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.VALUE_SET_URL;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -31,21 +35,35 @@
public interface IValidateCodeTest {
- IValidationProviders.IMyCodeSystemProvider getCodeSystemProvider();
- IValidationProviders.IMyValueSetProvider getValueSetProvider();
+ IValidationProviders.IMyValidationProvider getCodeSystemProvider();
+ IValidationProviders.IMyValidationProvider getValueSetProvider();
IValidationSupport getService();
IBaseParameters createParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource);
String getCodeSystemError();
String getValueSetError();
IBaseOperationOutcome getCodeSystemInvalidCodeOutcome();
IBaseOperationOutcome getValueSetInvalidCodeOutcome();
+ IBaseOperationOutcome getValueSetCustomDetailCodeOutcome();
+
+ default IBaseOperationOutcome getCodeSystemInvalidCodeOutcome(Class extends IBaseOperationOutcome> theResourceClass) {
+ return getOutcome(theResourceClass, "/terminology/OperationOutcome-CodeSystem-invalid-code.json");
+ }
+ default IBaseOperationOutcome getValueSetInvalidCodeOutcome(Class extends IBaseOperationOutcome> theResourceClass) {
+ return getOutcome(theResourceClass, "/terminology/OperationOutcome-ValueSet-invalid-code.json");
+ }
+ default IBaseOperationOutcome getValueSetCustomDetailCodeOutcome(Class extends IBaseOperationOutcome> theResourceClass) {
+ return getOutcome(theResourceClass, "/terminology/OperationOutcome-ValueSet-custom-issue-detail.json");
+ }
+ default IBaseOperationOutcome getOutcome(Class extends IBaseOperationOutcome> theResourceClass, String theFile) {
+ return ClasspathUtil.loadResource(getService().getFhirContext(), theResourceClass, theFile);
+ }
default void createCodeSystemReturnParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
- getCodeSystemProvider().setReturnParams(createParameters(theResult, theDisplay, theMessage, theIssuesResource));
+ getCodeSystemProvider().addTerminologyResponse(OPERATION_VALIDATE_CODE, CODE_SYSTEM, CODE, createParameters(theResult, theDisplay, theMessage, theIssuesResource));
}
default void createValueSetReturnParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
- getValueSetProvider().setReturnParams(createParameters(theResult, theDisplay, theMessage, theIssuesResource));
+ getValueSetProvider().addTerminologyResponse(OPERATION_VALIDATE_CODE, VALUE_SET_URL, CODE, createParameters(theResult, theDisplay, theMessage, theIssuesResource));
}
@Test
@@ -91,8 +109,8 @@ default void validateCode_codeSystemAndValueSetUrlAreIncorrect_returnsValidation
String theValidationMessage,
String theCodeSystem,
String theValueSetUrl) {
- getCodeSystemProvider().setException(theException);
- getValueSetProvider().setException(theException);
+ getCodeSystemProvider().addException(OPERATION_VALIDATE_CODE, theCodeSystem, CODE, theException);
+ getValueSetProvider().addException(OPERATION_VALIDATE_CODE, theValueSetUrl, CODE, theException);
CodeValidationResult outcome = getService().validateCode(null, null, theCodeSystem, CODE, DISPLAY, theValueSetUrl);
verifyErrorResultFromException(outcome, theValidationMessage, theServerMessage);
@@ -105,7 +123,7 @@ default void verifyErrorResultFromException(CodeValidationResult outcome, String
for (String message : theMessages) {
assertTrue(outcome.getMessage().contains(message));
}
- assertFalse(outcome.getCodeValidationIssues().isEmpty());
+ assertFalse(outcome.getIssues().isEmpty());
}
@Test
@@ -130,11 +148,7 @@ default void validateCode_withValueSetSuccess_returnsCorrectly() {
assertEquals(DISPLAY, outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getValueSetProvider().getCode());
- assertEquals(DISPLAY, getValueSetProvider().getDisplay());
- assertEquals(VALUE_SET_URL, getValueSetProvider().getValueSet());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
@@ -147,9 +161,7 @@ default void validateCode_withCodeSystemSuccess_returnsCorrectly() {
assertEquals(DISPLAY, outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getCodeSystemProvider().getCode());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
@@ -165,10 +177,7 @@ default void validateCode_withCodeSystemProvidingMinimalInputs_ReturnsSuccess()
assertNull(outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getCodeSystemProvider().getCode());
- assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
@@ -184,15 +193,11 @@ default void validateCode_withCodeSystemSuccessWithMessageValue_returnsCorrectly
assertEquals(DISPLAY, outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getCodeSystemProvider().getCode());
- assertEquals(DISPLAY, getCodeSystemProvider().getDisplay());
- assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
- default void validateCode_withCodeSystemError_returnsCorrectly() {
+ default void validateCode_withCodeSystemErrorWithDiagnosticsWithIssues_returnsCorrectly() {
IBaseOperationOutcome invalidCodeOutcome = getCodeSystemInvalidCodeOutcome();
createCodeSystemReturnParameters(false, null, ERROR_MESSAGE, invalidCodeOutcome);
@@ -204,12 +209,12 @@ default void validateCode_withCodeSystemError_returnsCorrectly() {
// assertEquals(CODE, outcome.getCode());
assertEquals(ERROR, outcome.getSeverity());
assertEquals(getCodeSystemError(), outcome.getMessage());
- assertFalse(outcome.getCodeValidationIssues().isEmpty());
+ assertFalse(outcome.getIssues().isEmpty());
verifyIssues(invalidCodeOutcome, outcome);
}
@Test
- default void validateCode_withCodeSystemErrorAndIssues_returnsCorrectly() {
+ default void validateCode_withCodeSystemErrorWithDiagnosticsWithoutIssues_returnsCorrectly() {
createCodeSystemReturnParameters(false, null, ERROR_MESSAGE, null);
CodeValidationResult outcome = getService()
@@ -223,10 +228,32 @@ default void validateCode_withCodeSystemErrorAndIssues_returnsCorrectly() {
assertNull(outcome.getDisplay());
assertEquals(ERROR, outcome.getSeverity());
assertEquals(expectedError, outcome.getMessage());
- assertFalse(outcome.getCodeValidationIssues().isEmpty());
- assertEquals(1, outcome.getCodeValidationIssues().size());
- assertEquals(expectedError, outcome.getCodeValidationIssues().get(0).getMessage());
- assertEquals(ERROR, outcome.getCodeValidationIssues().get(0).getSeverity());
+ assertFalse(outcome.getIssues().isEmpty());
+ assertEquals(1, outcome.getIssues().size());
+ assertEquals(expectedError, outcome.getIssues().get(0).getDiagnostics());
+ assertEquals(ERROR, outcome.getIssues().get(0).getSeverity());
+ }
+
+ @Test
+ default void validateCode_withCodeSystemErrorWithoutDiagnosticsWithIssues_returnsCorrectly() {
+ IBaseOperationOutcome invalidCodeOutcome = getCodeSystemInvalidCodeOutcome();
+ createCodeSystemReturnParameters(false, null, null, invalidCodeOutcome);
+
+ CodeValidationResult outcome = getService()
+ .validateCode(null, null, CODE_SYSTEM, CODE, null, null);
+
+ String expectedError = getCodeSystemError();
+ assertNotNull(outcome);
+ assertEquals(CODE_SYSTEM, outcome.getCodeSystemName());
+ assertEquals(CODE_SYSTEM_VERSION, outcome.getCodeSystemVersion());
+ // assertEquals(CODE, outcome.getCode());
+ assertNull(outcome.getDisplay());
+ assertEquals(ERROR, outcome.getSeverity());
+ assertNull(outcome.getMessage());
+ assertFalse(outcome.getIssues().isEmpty());
+ assertEquals(1, outcome.getIssues().size());
+ assertNull(outcome.getIssues().get(0).getDiagnostics());
+ assertEquals(ERROR, outcome.getIssues().get(0).getSeverity());
}
@Test
@@ -242,10 +269,7 @@ default void validateCode_withValueSetProvidingMinimalInputsSuccess_returnsCorre
assertNull(outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getValueSetProvider().getCode());
- assertEquals(VALUE_SET_URL, getValueSetProvider().getValueSet());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
@@ -261,11 +285,7 @@ default void validateCode_withValueSetSuccessWithMessage_returnsCorrectly() {
assertEquals(DISPLAY, outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
- assertTrue(outcome.getCodeValidationIssues().isEmpty());
-
- assertEquals(CODE, getValueSetProvider().getCode());
- assertEquals(DISPLAY, getValueSetProvider().getDisplay());
- assertEquals(VALUE_SET_URL, getValueSetProvider().getValueSet());
+ assertTrue(outcome.getIssues().isEmpty());
}
@Test
@@ -283,13 +303,9 @@ default void validateCode_withValueSetError_returnsCorrectly() {
assertEquals(DISPLAY, outcome.getDisplay());
assertEquals(ERROR, outcome.getSeverity());
assertEquals(expectedError, outcome.getMessage());
- assertEquals(1, outcome.getCodeValidationIssues().size());
- assertEquals(expectedError, outcome.getCodeValidationIssues().get(0).getMessage());
- assertEquals(ERROR, outcome.getCodeValidationIssues().get(0).getSeverity());
-
- assertEquals(CODE, getValueSetProvider().getCode());
- assertEquals(DISPLAY, getValueSetProvider().getDisplay());
- assertEquals(VALUE_SET_URL, getValueSetProvider().getValueSet());
+ assertEquals(1, outcome.getIssues().size());
+ assertEquals(expectedError, outcome.getIssues().get(0).getDiagnostics());
+ assertEquals(ERROR, outcome.getIssues().get(0).getSeverity());
}
@Test
@@ -306,24 +322,28 @@ default void validateCode_withValueSetErrorWithIssues_returnsCorrectly() {
assertEquals(DISPLAY, outcome.getDisplay());
assertEquals(ERROR, outcome.getSeverity());
assertEquals(getValueSetError(), outcome.getMessage());
- assertFalse(outcome.getCodeValidationIssues().isEmpty());
+ assertFalse(outcome.getIssues().isEmpty());
verifyIssues(invalidCodeOutcome, outcome);
-
- assertEquals(CODE, getValueSetProvider().getCode());
- assertEquals(DISPLAY, getValueSetProvider().getDisplay());
- assertEquals(VALUE_SET_URL, getValueSetProvider().getValueSet());
}
default void verifyIssues(IBaseOperationOutcome theOperationOutcome, CodeValidationResult theResult) {
List issues = getCodeValidationIssues(theOperationOutcome);
- assertEquals(issues.size(), theResult.getCodeValidationIssues().size());
+ assertEquals(issues.size(), theResult.getIssues().size());
for (int i = 0; i < issues.size(); i++) {
IValidationSupport.CodeValidationIssue expectedIssue = issues.get(i);
- IValidationSupport.CodeValidationIssue actualIssue = theResult.getCodeValidationIssues().get(i);
- assertEquals(expectedIssue.getCode(), actualIssue.getCode());
+ IValidationSupport.CodeValidationIssue actualIssue = theResult.getIssues().get(i);
+ assertEquals(expectedIssue.getType().getCode(), actualIssue.getType().getCode());
assertEquals(expectedIssue.getSeverity(), actualIssue.getSeverity());
- assertEquals(expectedIssue.getCoding(), actualIssue.getCoding());
- assertEquals(expectedIssue.getMessage(), actualIssue.getMessage());
+ assertEquals(expectedIssue.getDetails().getText(), actualIssue.getDetails().getText());
+ assertEquals(expectedIssue.getDetails().getCodings().size(), actualIssue.getDetails().getCodings().size());
+ for (int index = 0; index < expectedIssue.getDetails().getCodings().size(); index++) {
+ IValidationSupport.CodeValidationIssueCoding expectedCoding = expectedIssue.getDetails().getCodings().get(index);
+ IValidationSupport.CodeValidationIssueCoding actualCoding = actualIssue.getDetails().getCodings().get(index);
+ assertEquals(expectedCoding.getSystem(), actualCoding.getSystem());
+ assertEquals(expectedCoding.getCode(), actualCoding.getCode());
+ }
+ assertEquals(expectedIssue.getDetails().getText(), actualIssue.getDetails().getText());
+ assertEquals(expectedIssue.getDiagnostics(), actualIssue.getDiagnostics());
}
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidationProviders.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidationProviders.java
deleted file mode 100644
index 1537f8e5c00b..000000000000
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/IValidationProviders.java
+++ /dev/null
@@ -1,39 +0,0 @@
-package org.hl7.fhir.common.hapi.validation;
-
-import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.rest.server.IResourceProvider;
-import org.hl7.fhir.instance.model.api.IBaseParameters;
-
-public interface IValidationProviders {
- String CODE_SYSTEM = "http://code.system/url";
- String CODE_SYSTEM_VERSION = "1.0.0";
- String CODE_SYSTEM_NAME = "Test Code System";
- String CODE = "CODE";
- String VALUE_SET_URL = "http://value.set/url";
- String DISPLAY = "Explanation for code TestCode.";
- String LANGUAGE = "en";
- String ERROR_MESSAGE = "This is an error message";
-
- interface IMyCodeSystemProvider extends IResourceProvider {
- String getCode();
- String getSystem();
- String getDisplay();
- void setException(Exception theException);
- void setReturnParams(IBaseParameters theParameters);
- }
-
- interface IMyLookupCodeProvider extends IResourceProvider {
- String getCode();
- String getSystem();
- void setLookupCodeResult(IValidationSupport.LookupCodeResult theLookupCodeResult);
- }
-
- interface IMyValueSetProvider extends IResourceProvider {
- String getCode();
- String getSystem();
- String getDisplay();
- String getValueSet();
- void setException(Exception theException);
- void setReturnParams(IBaseParameters theParameters);
- }
-}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapperTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapperTest.java
index 57aae8d96f99..cbc79fadc981 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapperTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapperTest.java
@@ -7,7 +7,6 @@
import ca.uhn.fhir.fhirpath.BaseValidationTestWithInlineMocks;
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
-
import org.hl7.fhir.r5.model.Resource;
import org.hl7.fhir.r5.model.StructureDefinition;
import org.hl7.fhir.r5.model.StructureDefinition.StructureDefinitionKind;
@@ -16,17 +15,18 @@
import org.junit.jupiter.api.Test;
import org.mockito.quality.Strictness;
+import java.util.List;
+
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.withSettings;
-import java.util.List;
-
public class VersionSpecificWorkerContextWrapperTest extends BaseValidationTestWithInlineMocks {
final byte[] EXPECTED_BINARY_CONTENT_1 = "dummyBinaryContent1".getBytes();
@@ -80,7 +80,7 @@ public void cacheResource_normally_executesWithoutException() {
}
@Test
- public void validateCode_normally_resolvesCodeSystemFromValueSet() {
+ public void validateCode_codeInValueSet_resolvesCodeSystemFromValueSet() {
// setup
IValidationSupport validationSupport = mockValidationSupport();
ValidationSupportContext mockContext = mockValidationSupportContext(validationSupport);
@@ -90,8 +90,7 @@ public void validateCode_normally_resolvesCodeSystemFromValueSet() {
ValueSet valueSet = new ValueSet();
valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system").addConcept().setCode("code0");
valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
- when(validationSupport.fetchResource(eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(valueSet);
- when(validationSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any())).thenReturn(new IValidationSupport.CodeValidationResult());
+ when(validationSupport.validateCodeInValueSet(any(), any(), any(), any(), any(), any())).thenReturn(mock(IValidationSupport.CodeValidationResult.class));
// execute
wrapper.validateCode(new ValidationOptions(), "code0", valueSet);
@@ -101,6 +100,26 @@ public void validateCode_normally_resolvesCodeSystemFromValueSet() {
verify(validationSupport, times(1)).validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), any());
}
+ @Test
+ public void validateCode_codeNotInValueSet_doesNotResolveSystem() {
+ // setup
+ IValidationSupport validationSupport = mockValidationSupport();
+ ValidationSupportContext mockContext = mockValidationSupportContext(validationSupport);
+ VersionCanonicalizer versionCanonicalizer = new VersionCanonicalizer(FhirContext.forR5Cached());
+ VersionSpecificWorkerContextWrapper wrapper = new VersionSpecificWorkerContextWrapper(mockContext, versionCanonicalizer);
+
+ ValueSet valueSet = new ValueSet();
+ valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system").addConcept().setCode("code0");
+ valueSet.getCompose().addInclude().setSystem("http://codesystems.com/system2").addConcept().setCode("code2");
+
+ // execute
+ wrapper.validateCode(new ValidationOptions(), "code1", valueSet);
+
+ // verify
+ verify(validationSupport, times(1)).validateCodeInValueSet(any(), any(), eq(null), eq("code1"), any(), any());
+ verify(validationSupport, never()).validateCode(any(), any(), any(), any(), any(), any());
+ }
+
@Test
public void isPrimitive_primitive() {
// setup
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu2/hapi/validation/FhirInstanceValidatorDstu2Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu2/hapi/validation/FhirInstanceValidatorDstu2Test.java
index da73c0be8000..5a53ba0ac3d4 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu2/hapi/validation/FhirInstanceValidatorDstu2Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu2/hapi/validation/FhirInstanceValidatorDstu2Test.java
@@ -4,7 +4,6 @@
import ca.uhn.fhir.context.support.ConceptValidationOptions;
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
import ca.uhn.fhir.context.support.IValidationSupport;
-import ca.uhn.fhir.context.support.ValidationSupportContext;
import ca.uhn.fhir.fhirpath.BaseValidationTestWithInlineMocks;
import ca.uhn.fhir.model.dstu2.composite.PeriodDt;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
@@ -28,10 +27,7 @@
import org.hl7.fhir.dstu2.model.QuestionnaireResponse;
import org.hl7.fhir.dstu2.model.QuestionnaireResponse.QuestionnaireResponseStatus;
import org.hl7.fhir.dstu2.model.StringType;
-import org.hl7.fhir.dstu3.model.CodeSystem;
-import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.junit.jupiter.api.AfterAll;
-import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@@ -41,9 +37,7 @@
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.Optional;
import java.util.Set;
import static org.assertj.core.api.Assertions.assertThat;
@@ -100,7 +94,7 @@ public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvoca
if (myValidConcepts.contains(system + "___" + code)) {
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
} else if (myValidSystems.contains(system)) {
- return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage("Unknown code");
+ return new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage("Unknown code");
} else {
retVal = null;
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
index ad6276f2761a..cfbeca68626a 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
@@ -58,7 +58,6 @@
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
-import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
@@ -229,10 +228,10 @@ public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvoca
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
} else if (myValidSystems.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message).setCodeValidationIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message).setIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
} else if (myValidSystemsNotReturningIssues.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message);
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message);
} else if (myCodeSystems.containsKey(system)) {
CodeSystem cs = myCodeSystems.get(system);
Optional found = cs.getConcept().stream().filter(t -> t.getCode().equals(code)).findFirst();
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/IValidateCodeProvidersDstu3.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/IValidateCodeProvidersDstu3.java
deleted file mode 100644
index 0c639e310ee2..000000000000
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/IValidateCodeProvidersDstu3.java
+++ /dev/null
@@ -1,159 +0,0 @@
-package org.hl7.fhir.dstu3.hapi.validation;
-
-import ca.uhn.fhir.jpa.model.util.JpaConstants;
-import ca.uhn.fhir.rest.annotation.IdParam;
-import ca.uhn.fhir.rest.annotation.Operation;
-import ca.uhn.fhir.rest.annotation.OperationParam;
-import ca.uhn.fhir.rest.api.server.RequestDetails;
-import jakarta.servlet.http.HttpServletRequest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
-import org.hl7.fhir.dstu3.model.BooleanType;
-import org.hl7.fhir.dstu3.model.CodeSystem;
-import org.hl7.fhir.dstu3.model.CodeType;
-import org.hl7.fhir.dstu3.model.Coding;
-import org.hl7.fhir.dstu3.model.IdType;
-import org.hl7.fhir.dstu3.model.Parameters;
-import org.hl7.fhir.dstu3.model.StringType;
-import org.hl7.fhir.dstu3.model.UriType;
-import org.hl7.fhir.dstu3.model.ValueSet;
-import org.hl7.fhir.instance.model.api.IBaseParameters;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-
-import java.util.List;
-
-public interface IValidateCodeProvidersDstu3 {
- @SuppressWarnings("unused")
- class MyCodeSystemProviderDstu3 implements IValidationProviders.IMyCodeSystemProvider {
- private UriType mySystemUrl;
- private CodeType myCode;
- private StringType myDisplay;
- private Exception myException;
- private Parameters myReturnParams;
-
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
- @OperationParam(name = "result", type = org.hl7.fhir.dstu3.model.BooleanType.class, min = 1),
- @OperationParam(name = "message", type = org.hl7.fhir.dstu3.model.StringType.class),
- @OperationParam(name = "display", type = org.hl7.fhir.dstu3.model.StringType.class)
- })
- public org.hl7.fhir.dstu3.model.Parameters validateCode(
- HttpServletRequest theServletRequest,
- @IdParam(optional = true) org.hl7.fhir.dstu3.model.IdType theId,
- @OperationParam(name = "url", min = 0, max = 1) org.hl7.fhir.dstu3.model.UriType theCodeSystemUrl,
- @OperationParam(name = "code", min = 0, max = 1) org.hl7.fhir.dstu3.model.CodeType theCode,
- @OperationParam(name = "display", min = 0, max = 1) org.hl7.fhir.dstu3.model.StringType theDisplay
- ) throws Exception {
- mySystemUrl = theCodeSystemUrl;
- myCode = theCode;
- myDisplay = theDisplay;
- if (myException != null) {
- throw myException;
- }
- return myReturnParams;
- }
-
- @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= {
- @OperationParam(name = "name", type = org.hl7.fhir.dstu3.model.StringType.class, min = 1),
- @OperationParam(name = "version", type = org.hl7.fhir.dstu3.model.StringType.class),
- @OperationParam(name = "display", type = org.hl7.fhir.dstu3.model.StringType.class, min = 1),
- @OperationParam(name = "abstract", type = org.hl7.fhir.dstu3.model.BooleanType.class, min = 1),
- @OperationParam(name = "property", type = org.hl7.fhir.dstu3.model.StringType.class, min = 0, max = OperationParam.MAX_UNLIMITED)
- })
- public IBaseParameters lookup(
- HttpServletRequest theServletRequest,
- @OperationParam(name = "code", max = 1) org.hl7.fhir.dstu3.model.CodeType theCode,
- @OperationParam(name = "system",max = 1) org.hl7.fhir.dstu3.model.UriType theSystem,
- @OperationParam(name = "coding", max = 1) Coding theCoding,
- @OperationParam(name = "version", max = 1) org.hl7.fhir.dstu3.model.StringType theVersion,
- @OperationParam(name = "displayLanguage", max = 1) org.hl7.fhir.dstu3.model.CodeType theDisplayLanguage,
- @OperationParam(name = "property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames,
- RequestDetails theRequestDetails
- ) {
- myCode = theCode;
- return myReturnParams;
- }
-
- @Override
- public Class extends IBaseResource> getResourceType() {
- return CodeSystem.class;
- }
-
- public void setException(Exception theException) {
- myException = theException;
- }
- @Override
- public void setReturnParams(IBaseParameters theParameters) {
- myReturnParams = (Parameters) theParameters;
- }
- @Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
- }
- @Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
- public String getDisplay() {
- return myDisplay != null ? myDisplay.getValue() : null;
- }
- }
-
- @SuppressWarnings("unused")
- class MyValueSetProviderDstu3 implements IValidationProviders.IMyValueSetProvider {
- private Exception myException;
- private Parameters myReturnParams;
- private UriType mySystemUrl;
- private UriType myValueSetUrl;
- private CodeType myCode;
- private StringType myDisplay;
-
- @Operation(name = "validate-code", idempotent = true, returnParameters = {
- @OperationParam(name = "result", type = BooleanType.class, min = 1),
- @OperationParam(name = "message", type = org.hl7.fhir.dstu3.model.StringType.class),
- @OperationParam(name = "display", type = org.hl7.fhir.dstu3.model.StringType.class)
- })
- public Parameters validateCode(
- HttpServletRequest theServletRequest,
- @IdParam(optional = true) IdType theId,
- @OperationParam(name = "url", min = 0, max = 1) org.hl7.fhir.dstu3.model.UriType theValueSetUrl,
- @OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
- @OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
- @OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
- @OperationParam(name = "valueSet") org.hl7.fhir.dstu3.model.ValueSet theValueSet
- ) throws Exception {
- mySystemUrl = theSystem;
- myValueSetUrl = theValueSetUrl;
- myCode = theCode;
- myDisplay = theDisplay;
- if (myException != null) {
- throw myException;
- }
- return myReturnParams;
- }
- @Override
- public Class extends IBaseResource> getResourceType() {
- return ValueSet.class;
- }
- public void setException(Exception theException) {
- myException = theException;
- }
- @Override
- public void setReturnParams(IBaseParameters theParameters) {
- myReturnParams = (Parameters) theParameters;
- }
- @Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
- }
- @Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
- @Override
- public String getValueSet() {
- return myValueSetUrl != null ? myValueSetUrl.getValueAsString() : null;
- }
- public String getDisplay() {
- return myDisplay != null ? myDisplay.getValue() : null;
- }
- }
-}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
index 7804b9df10f2..57591b31e763 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
@@ -41,7 +41,6 @@
import org.hl7.fhir.dstu3.model.UriType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
@@ -56,6 +55,8 @@
import java.util.List;
import java.util.stream.Collectors;
+import static ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity.ERROR;
+import static ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity.WARNING;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.BOOLEAN;
import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.CHOICE;
@@ -224,7 +225,7 @@ public void testCodedAnswer() {
when(myValSupport.validateCodeInValueSet(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), nullable(ValueSet.class)))
.thenReturn(new IValidationSupport.CodeValidationResult().setCode("code0"));
when(myValSupport.validateCodeInValueSet(any(), any(), eq("http://codesystems.com/system"), eq("code1"), any(), nullable(ValueSet.class)))
- .thenReturn(new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage("Unknown code"));
+ .thenReturn(new IValidationSupport.CodeValidationResult().setSeverity(ERROR).setMessage("Unknown code"));
CodeSystem codeSystem = new CodeSystem();
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
@@ -246,7 +247,7 @@ public void testCodedAnswer() {
when(myValSupport.validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), nullable(String.class)))
.thenReturn(new IValidationSupport.CodeValidationResult().setCode(CODE_ICC_SCHOOLTYPE_PT));
when(myValSupport.validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code1"), any(), nullable(String.class)))
- .thenReturn(new IValidationSupport.CodeValidationResult().setSeverityCode("warning").setMessage("Unknown code: http://codesystems.com/system / code1"));
+ .thenReturn(new IValidationSupport.CodeValidationResult().setSeverity(WARNING).setMessage("Unknown code: http://codesystems.com/system / code1"));
QuestionnaireResponse qa;
@@ -1034,7 +1035,7 @@ public void testOpenchoiceAnswer() {
when(myValSupport.validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code0"), any(), nullable(String.class)))
.thenReturn(new IValidationSupport.CodeValidationResult().setCode("code0"));
when(myValSupport.validateCode(any(), any(), eq("http://codesystems.com/system"), eq("code1"), any(), nullable(String.class)))
- .thenReturn(new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage("Unknown code"));
+ .thenReturn(new IValidationSupport.CodeValidationResult().setSeverity(ERROR).setMessage("Unknown code"));
CodeSystem codeSystem = new CodeSystem();
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java
index 6e98c4b31a94..56bc892c3d41 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java
@@ -12,9 +12,9 @@
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
import jakarta.servlet.http.HttpServletRequest;
import org.hl7.fhir.common.hapi.validation.IRemoteTerminologyLookupCodeTest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.CodeSystem;
@@ -164,8 +164,6 @@ void lookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IV
@SuppressWarnings("unused")
static class MyLookupCodeProviderDstu3 implements IValidationProviders.IMyLookupCodeProvider {
- private UriType mySystemUrl;
- private CodeType myCode;
private LookupCodeResult myLookupCodeResult;
@Override
@@ -190,8 +188,6 @@ public IBaseParameters lookup(
@OperationParam(name= " property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames,
RequestDetails theRequestDetails
) {
- myCode = theCode;
- mySystemUrl = theSystem;
if (theSystem == null) {
throw new InvalidRequestException(MessageFormat.format(MESSAGE_RESPONSE_INVALID, theCode));
}
@@ -205,15 +201,5 @@ public IBaseParameters lookup(
public Class extends IBaseResource> getResourceType() {
return CodeSystem.class;
}
-
- @Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
- }
-
- @Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
}
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeWithResponseFileDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeWithResponseFileDstu3Test.java
index 48a99f260d0b..4817542ef4dd 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeWithResponseFileDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeWithResponseFileDstu3Test.java
@@ -5,13 +5,10 @@
import ca.uhn.fhir.context.support.LookupCodeRequest;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
-import ca.uhn.fhir.util.ClasspathUtil;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersDstu3;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
-import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseParameters;
-import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -19,13 +16,15 @@
import java.util.List;
+import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_LOOKUP;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
public class RemoteTerminologyLookupCodeWithResponseFileDstu3Test {
private static final FhirContext ourCtx = FhirContext.forDstu3Cached();
- private IValidateCodeProvidersDstu3.MyCodeSystemProviderDstu3 myCodeSystemProvider;
+ private IValidationProvidersDstu3.MyCodeSystemProviderDstu3 myCodeSystemProvider;
@RegisterExtension
public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
@@ -36,7 +35,7 @@ public void before() {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true));
- myCodeSystemProvider = new IValidateCodeProvidersDstu3.MyCodeSystemProviderDstu3();
+ myCodeSystemProvider = new IValidationProvidersDstu3.MyCodeSystemProviderDstu3();
ourRestfulServerExtension.getRestfulServer().registerProviders(myCodeSystemProvider);
}
@@ -47,13 +46,10 @@ public void after() {
}
@Test
void lookupCode_withParametersOutput_convertsCorrectly() {
- String paramsAsString = ClasspathUtil.loadResource("/terminology/CodeSystem-lookup-output-with-subproperties.json");
- IBaseResource baseResource = ourCtx.newJsonParser().parseResource(paramsAsString);
- assertTrue(baseResource instanceof Parameters);
- Parameters resultParameters = (Parameters) baseResource;
- myCodeSystemProvider.setReturnParams(resultParameters);
+ String outputFile ="/terminology/CodeSystem-lookup-output-with-subproperties.json";
+ IBaseParameters resultParameters = myCodeSystemProvider.addTerminologyResponse(OPERATION_LOOKUP, CODE_SYSTEM, CODE, ourCtx, outputFile);
- LookupCodeRequest request = new LookupCodeRequest(IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, null, List.of("interfaces"));
+ LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, null, List.of("interfaces"));
// test
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, request);
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyValidateCodeDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyValidateCodeDstu3Test.java
index af4f39f09262..2f573ad3e5fc 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyValidateCodeDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyValidateCodeDstu3Test.java
@@ -4,16 +4,18 @@
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
-import ca.uhn.fhir.util.ClasspathUtil;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersDstu3;
import org.hl7.fhir.common.hapi.validation.IRemoteTerminologyValidateCodeTest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.dstu3.model.BooleanType;
+import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.OperationOutcome;
import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Resource;
import org.hl7.fhir.dstu3.model.StringType;
import org.hl7.fhir.dstu3.model.UriType;
+import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.AfterEach;
@@ -22,6 +24,11 @@
import java.util.List;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM_VERSION;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.ERROR_MESSAGE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.VALUE_SET_URL;
import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM;
import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET;
@@ -38,8 +45,8 @@ public class RemoteTerminologyValidateCodeDstu3Test implements IRemoteTerminolog
private static final FhirContext ourCtx = FhirContext.forDstu3Cached();
@RegisterExtension
public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
- private IValidateCodeProvidersDstu3.MyCodeSystemProviderDstu3 myCodeSystemProvider;
- private IValidateCodeProvidersDstu3.MyValueSetProviderDstu3 myValueSetProvider;
+ private IValidationProviders.MyValidationProvider myCodeSystemProvider;
+ private IValidationProviders.MyValidationProvider myValueSetProvider;
private RemoteTerminologyServiceValidationSupport mySvc;
private String myCodeSystemError, myValueSetError;
@@ -48,14 +55,14 @@ public void before() {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
myCodeSystemError = ourCtx.getLocalizer().getMessage(
RemoteTerminologyServiceValidationSupport.class,
- ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM, IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, baseUrl, IValidationProviders.ERROR_MESSAGE);
+ ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM, CODE_SYSTEM, CODE, baseUrl, ERROR_MESSAGE);
myValueSetError = ourCtx.getLocalizer().getMessage(
RemoteTerminologyServiceValidationSupport.class,
- ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET, IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, IValidationProviders.VALUE_SET_URL, baseUrl, IValidationProviders.ERROR_MESSAGE);
+ ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET, CODE_SYSTEM, CODE, VALUE_SET_URL, baseUrl, ERROR_MESSAGE);
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true));
- myCodeSystemProvider = new IValidateCodeProvidersDstu3.MyCodeSystemProviderDstu3();
- myValueSetProvider = new IValidateCodeProvidersDstu3.MyValueSetProviderDstu3();
+ myCodeSystemProvider = new IValidationProvidersDstu3.MyCodeSystemProviderDstu3();
+ myValueSetProvider = new IValidationProvidersDstu3.MyValueSetProviderDstu3();
ourRestfulServerExtension.getRestfulServer().registerProviders(myCodeSystemProvider, myValueSetProvider);
}
@@ -82,45 +89,40 @@ public String getValueSetError() {
}
@Override
- public IValidateCodeProvidersDstu3.MyCodeSystemProviderDstu3 getCodeSystemProvider() {
+ public IValidationProviders.IMyValidationProvider getCodeSystemProvider() {
return myCodeSystemProvider;
}
@Override
- public IValidateCodeProvidersDstu3.MyValueSetProviderDstu3 getValueSetProvider() {
+ public IValidationProviders.IMyValidationProvider getValueSetProvider() {
return myValueSetProvider;
}
@Override
public IBaseOperationOutcome getCodeSystemInvalidCodeOutcome() {
- return ClasspathUtil.loadResource(getService().getFhirContext(), OperationOutcome.class, "/terminology/OperationOutcome-CodeSystem-invalid-code.json");
+ return getCodeSystemInvalidCodeOutcome(OperationOutcome.class);
}
@Override
public IBaseOperationOutcome getValueSetInvalidCodeOutcome() {
- return ClasspathUtil.loadResource(getService().getFhirContext(), OperationOutcome.class, "/terminology/OperationOutcome-ValueSet-invalid-code.json");
+ return getValueSetInvalidCodeOutcome(OperationOutcome.class);
+ }
+
+ @Override
+ public IBaseOperationOutcome getValueSetCustomDetailCodeOutcome() {
+ return getValueSetCustomDetailCodeOutcome(OperationOutcome.class);
}
@Override
public Parameters createParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
Parameters parameters = new Parameters();
parameters.addParameter().setName("result").setValue(new BooleanType(theResult));
- parameters.addParameter().setName("code").setValue(new StringType(IValidationProviders.CODE));
- parameters.addParameter().setName("system").setValue(new UriType(IValidationProviders.CODE_SYSTEM));
- parameters.addParameter().setName("version").setValue(new StringType(IValidationProviders.CODE_SYSTEM_VERSION));
+ parameters.addParameter().setName("code").setValue(new StringType(CODE));
+ parameters.addParameter().setName("system").setValue(new UriType(CODE_SYSTEM));
+ parameters.addParameter().setName("version").setValue(new StringType(CODE_SYSTEM_VERSION));
parameters.addParameter().setName("display").setValue(new StringType(theDisplay));
parameters.addParameter().setName("message").setValue(new StringType(theMessage));
parameters.addParameter().setName("issues").setResource((Resource) theIssuesResource);
return parameters;
}
-
- @Override
- public void createCodeSystemReturnParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
- myCodeSystemProvider.setReturnParams(createParameters(theResult, theDisplay, theMessage, theIssuesResource));
- }
-
- @Override
- public void createValueSetReturnParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
- myValueSetProvider.setReturnParams(createParameters(theResult, theDisplay, theMessage, theIssuesResource));
- }
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/utils/FhirPathEngineR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/utils/FhirPathEngineR4Test.java
index 15bbc3a8bf35..1c2382b6aac1 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/utils/FhirPathEngineR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/utils/FhirPathEngineR4Test.java
@@ -54,6 +54,7 @@ public void testCrossResourceBoundaries() throws FHIRException {
List value;
+
value = ourCtx.newFhirPath().evaluate(o, "Observation.specimen", Base.class);
assertThat(value).hasSize(1);
value = ourCtx.newFhirPath().evaluate(o, "Observation.specimen.resolve()", Base.class);
@@ -65,6 +66,9 @@ public void testCrossResourceBoundaries() throws FHIRException {
assertEquals("2011-01-01", ((DateTimeType) value.get(0)).getValueAsString());
}
+
+
+
@Test
public void testComponentCode() {
String path = "(Observation.component.value.ofType(FHIR.Quantity)) ";
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
index d03c3aa974d8..fb46f7f80089 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
@@ -307,10 +307,10 @@ public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvoca
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
} else if (myValidSystems.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message).setCodeValidationIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message).setIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
} else if (myValidSystemsNotReturningIssues.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message);
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message);
} else {
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java
index d67966df6d46..382f621f547e 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java
@@ -11,9 +11,10 @@
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersR4;
import jakarta.servlet.http.HttpServletRequest;
import org.hl7.fhir.common.hapi.validation.IRemoteTerminologyLookupCodeTest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.instance.model.api.IBaseDatatype;
import org.hl7.fhir.instance.model.api.IBaseParameters;
@@ -52,7 +53,7 @@ public class RemoteTerminologyLookupCodeR4Test implements IRemoteTerminologyLook
@RegisterExtension
public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx);
- private IValidateCodeProvidersR4.MyCodeSystemProviderR4 myCodeSystemProvider;
+ private IValidationProvidersR4.MyCodeSystemProviderR4 myCodeSystemProvider;
private MyLookupCodeProviderR4 myLookupCodeProviderR4;
@BeforeEach
@@ -60,7 +61,7 @@ public void before() {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
mySvc.setBaseUrl(baseUrl);
mySvc.addClientInterceptor(new LoggingInterceptor(true));
- myCodeSystemProvider = new IValidateCodeProvidersR4.MyCodeSystemProviderR4();
+ myCodeSystemProvider = new IValidationProvidersR4.MyCodeSystemProviderR4();
myLookupCodeProviderR4 = new MyLookupCodeProviderR4();
ourRestfulServerExtension.getRestfulServer().registerProviders(myCodeSystemProvider, myLookupCodeProviderR4);
}
@@ -166,8 +167,6 @@ void lookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IV
@SuppressWarnings("unused")
static class MyLookupCodeProviderR4 implements IValidationProviders.IMyLookupCodeProvider {
- private UriType mySystemUrl;
- private CodeType myCode;
private LookupCodeResult myLookupCodeResult;
@Override
@@ -192,8 +191,6 @@ public IBaseParameters lookup(
@OperationParam(name = "property", max = OperationParam.MAX_UNLIMITED) List thePropertyNames,
RequestDetails theRequestDetails
) {
- myCode = theCode;
- mySystemUrl = theSystem;
if (theSystem == null) {
throw new InvalidRequestException(MessageFormat.format(MESSAGE_RESPONSE_INVALID, theCode));
}
@@ -206,15 +203,5 @@ public IBaseParameters lookup(
public Class extends IBaseResource> getResourceType() {
return CodeSystem.class;
}
-
- @Override
- public String getCode() {
- return myCode != null ? myCode.getValueAsString() : null;
- }
-
- @Override
- public String getSystem() {
- return mySystemUrl != null ? mySystemUrl.getValueAsString() : null;
- }
}
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeWithResponseFileR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeWithResponseFileR4Test.java
index 37eba91d0ca1..a0896bd8c4e7 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeWithResponseFileR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeWithResponseFileR4Test.java
@@ -5,12 +5,9 @@
import ca.uhn.fhir.context.support.LookupCodeRequest;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
-import ca.uhn.fhir.util.ClasspathUtil;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersR4;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.instance.model.api.IBaseParameters;
-import org.hl7.fhir.instance.model.api.IBaseResource;
-import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.StringType;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
@@ -19,13 +16,15 @@
import java.util.List;
+import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_LOOKUP;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
public class RemoteTerminologyLookupCodeWithResponseFileR4Test {
private static final FhirContext ourCtx = FhirContext.forR4Cached();
- private IValidateCodeProvidersR4.MyCodeSystemProviderR4 myCodeSystemProvider;
+ private IValidationProvidersR4.MyCodeSystemProviderR4 myCodeSystemProvider;
@RegisterExtension
public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
@@ -36,7 +35,7 @@ public void before() {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true));
- myCodeSystemProvider = new IValidateCodeProvidersR4.MyCodeSystemProviderR4();
+ myCodeSystemProvider = new IValidationProvidersR4.MyCodeSystemProviderR4();
ourRestfulServerExtension.getRestfulServer().registerProviders(myCodeSystemProvider);
}
@@ -48,13 +47,10 @@ public void after() {
@Test
void lookupCode_withParametersOutput_convertsCorrectly() {
- String paramsAsString = ClasspathUtil.loadResource("/terminology/CodeSystem-lookup-output-with-subproperties.json");
- IBaseResource baseResource = ourCtx.newJsonParser().parseResource(paramsAsString);
- assertTrue(baseResource instanceof Parameters);
- Parameters resultParameters = (Parameters) baseResource;
- myCodeSystemProvider.setReturnParams(resultParameters);
+ String outputFile ="/terminology/CodeSystem-lookup-output-with-subproperties.json";
+ IBaseParameters resultParameters = myCodeSystemProvider.addTerminologyResponse(OPERATION_LOOKUP, CODE_SYSTEM, CODE, ourCtx, outputFile);
- LookupCodeRequest request = new LookupCodeRequest(IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, null, List.of("interfaces"));
+ LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, null, List.of("interfaces"));
// test
IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, request);
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyValidateCodeR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyValidateCodeR4Test.java
index 08f6c251869d..ffd8045a8a53 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyValidateCodeR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyValidateCodeR4Test.java
@@ -2,8 +2,8 @@
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.IValidationSupport.CodeValidationResult;
+import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.parser.IJsonLikeParser;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IHttpRequest;
@@ -13,11 +13,11 @@
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
-import ca.uhn.fhir.util.ClasspathUtil;
+import ca.uhn.fhir.test.utilities.validation.IValidationProviders;
+import ca.uhn.fhir.test.utilities.validation.IValidationProvidersR4;
import ca.uhn.fhir.util.ParametersUtil;
import com.google.common.collect.Lists;
import org.hl7.fhir.common.hapi.validation.IRemoteTerminologyValidateCodeTest;
-import org.hl7.fhir.common.hapi.validation.IValidationProviders;
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -39,6 +39,12 @@
import java.util.List;
import java.util.stream.Stream;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.CODE_SYSTEM_VERSION;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.DISPLAY;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.ERROR_MESSAGE;
+import static ca.uhn.fhir.test.utilities.validation.IValidationProviders.VALUE_SET_URL;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM;
import static org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport.ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET;
@@ -61,8 +67,8 @@ public class RemoteTerminologyValidateCodeR4Test implements IRemoteTerminologyVa
private static final FhirContext ourCtx = FhirContext.forR4Cached();
@RegisterExtension
public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx);
- private IValidateCodeProvidersR4.MyCodeSystemProviderR4 myCodeSystemProvider;
- private IValidateCodeProvidersR4.MyValueSetProviderR4 myValueSetProvider;
+ private IValidationProviders.IMyValidationProvider myCodeSystemProvider;
+ private IValidationProviders.IMyValidationProvider myValueSetProvider;
private RemoteTerminologyServiceValidationSupport mySvc;
private String myCodeSystemError, myValueSetError;
@@ -71,14 +77,14 @@ public void before() {
String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort();
myCodeSystemError = ourCtx.getLocalizer().getMessage(
RemoteTerminologyServiceValidationSupport.class,
- ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM, IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, baseUrl, IValidationProviders.ERROR_MESSAGE);
+ ERROR_CODE_UNKNOWN_CODE_IN_CODE_SYSTEM, CODE_SYSTEM, CODE, baseUrl, ERROR_MESSAGE);
myValueSetError = ourCtx.getLocalizer().getMessage(
RemoteTerminologyServiceValidationSupport.class,
- ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET, IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, IValidationProviders.VALUE_SET_URL, baseUrl, IValidationProviders.ERROR_MESSAGE);
+ ERROR_CODE_UNKNOWN_CODE_IN_VALUE_SET, CODE_SYSTEM, CODE, VALUE_SET_URL, baseUrl, ERROR_MESSAGE);
mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, baseUrl);
mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true));
- myCodeSystemProvider = new IValidateCodeProvidersR4.MyCodeSystemProviderR4();
- myValueSetProvider = new IValidateCodeProvidersR4.MyValueSetProviderR4();
+ myCodeSystemProvider = new IValidationProvidersR4.MyCodeSystemProviderR4();
+ myValueSetProvider = new IValidationProvidersR4.MyValueSetProviderR4();
ourRestfulServerExtension.getRestfulServer().registerProviders(myCodeSystemProvider, myValueSetProvider);
}
@@ -95,12 +101,12 @@ public RemoteTerminologyServiceValidationSupport getService() {
}
@Override
- public IValidationProviders.IMyCodeSystemProvider getCodeSystemProvider() {
+ public IValidationProviders.IMyValidationProvider getCodeSystemProvider() {
return myCodeSystemProvider;
}
@Override
- public IValidationProviders.IMyValueSetProvider getValueSetProvider() {
+ public IValidationProviders.IMyValidationProvider getValueSetProvider() {
return myValueSetProvider;
}
@@ -116,51 +122,40 @@ public String getValueSetError() {
@Override
public IBaseOperationOutcome getCodeSystemInvalidCodeOutcome() {
- return ClasspathUtil.loadResource(getService().getFhirContext(), OperationOutcome.class, "/terminology/OperationOutcome-CodeSystem-invalid-code.json");
+ return getCodeSystemInvalidCodeOutcome(OperationOutcome.class);
}
@Override
public IBaseOperationOutcome getValueSetInvalidCodeOutcome() {
- return ClasspathUtil.loadResource(getService().getFhirContext(), OperationOutcome.class, "/terminology/OperationOutcome-ValueSet-invalid-code.json");
+ return getValueSetInvalidCodeOutcome(OperationOutcome.class);
}
@Override
- public List getCodeValidationIssues(IBaseOperationOutcome theOperationOutcome) {
- return ((OperationOutcome)theOperationOutcome).getIssue().stream()
- .map(issueComponent -> new IValidationSupport.CodeValidationIssue(
- issueComponent.getDetails().getText(),
- IValidationSupport.IssueSeverity.ERROR,
- /* assume issue type is OperationOutcome.IssueType#CODEINVALID as it is the only match */
- IValidationSupport.CodeValidationIssueCode.INVALID,
- IValidationSupport.CodeValidationIssueCoding.INVALID_CODE))
- .toList();
+ public IBaseOperationOutcome getValueSetCustomDetailCodeOutcome() {
+ return getValueSetCustomDetailCodeOutcome(OperationOutcome.class);
}
@Test
void validateCodeInValueSet_success() {
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
- CodeValidationResult outcome = mySvc.validateCodeInValueSet(null, new ConceptValidationOptions(), IValidationProviders.CODE_SYSTEM, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ CodeValidationResult outcome = mySvc.validateCodeInValueSet(null, new ConceptValidationOptions(), CODE_SYSTEM, CODE, DISPLAY, valueSet);
assertNotNull(outcome);
- assertEquals(IValidationProviders.CODE, outcome.getCode());
- assertEquals(IValidationProviders.DISPLAY, outcome.getDisplay());
+ assertEquals(CODE, outcome.getCode());
+ assertEquals(DISPLAY, outcome.getDisplay());
assertNull(outcome.getSeverity());
assertNull(outcome.getMessage());
-
- assertEquals(IValidationProviders.CODE, myValueSetProvider.getCode());
- assertEquals(IValidationProviders.DISPLAY, myValueSetProvider.getDisplay());
- assertEquals(IValidationProviders.VALUE_SET_URL, myValueSetProvider.getValueSet());
}
@Override
public Parameters createParameters(Boolean theResult, String theDisplay, String theMessage, IBaseResource theIssuesResource) {
Parameters parameters = new Parameters()
- .addParameter("code", IValidationProviders.CODE)
- .addParameter("system", IValidationProviders.CODE_SYSTEM)
- .addParameter("version", IValidationProviders.CODE_SYSTEM_VERSION)
+ .addParameter("code", CODE)
+ .addParameter("system", CODE_SYSTEM)
+ .addParameter("version", CODE_SYSTEM_VERSION)
.addParameter("display", theDisplay)
.addParameter("message", theMessage);
if (theResult != null) {
@@ -181,16 +176,16 @@ class ExtractCodeSystemFromValueSet {
@Test
void validateCodeInValueSet_uniqueComposeInclude() {
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
String systemUrl = "http://hl7.org/fhir/ValueSet/administrative-gender";
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
Collections.singletonList(new ValueSet.ConceptSetComponent().setSystem(systemUrl)) ));
CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
- new ConceptValidationOptions().setInferSystem(true), null, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
// validate service doesn't return error message (as when no code system is present)
assertNotNull(outcome);
@@ -211,16 +206,16 @@ public static Stream getRemoteTerminologyServerExceptions() {
@ParameterizedTest
@MethodSource(value = "getRemoteTerminologyServerExceptions")
void validateCodeInValueSet_systemNotPresent_returnsValidationResultWithError(Exception theException, String theServerMessage) {
- myValueSetProvider.setException(theException);
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ getValueSetProvider().addException("$validate-code", VALUE_SET_URL, CODE, theException);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
Lists.newArrayList(new ValueSet.ConceptSetComponent(), new ValueSet.ConceptSetComponent())));
CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
- new ConceptValidationOptions().setInferSystem(true), null, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
String unknownCodeForValueSetError = "Unknown code \"null#CODE\" for ValueSet with URL \"http://value.set/url\". The Remote Terminology server http://";
verifyErrorResultFromException(outcome, unknownCodeForValueSetError, theServerMessage);
@@ -230,11 +225,11 @@ void validateCodeInValueSet_systemNotPresent_returnsValidationResultWithError(Ex
@ParameterizedTest
@MethodSource(value = "getRemoteTerminologyServerExceptions")
void validateCodeInValueSet_systemPresentCodeNotPresent_returnsValidationResultWithError(Exception theException, String theServerMessage) {
- myValueSetProvider.setException(theException);
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ getValueSetProvider().addException(JpaConstants.OPERATION_VALIDATE_CODE, VALUE_SET_URL, CODE, theException);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
String systemUrl = "http://hl7.org/fhir/ValueSet/administrative-gender";
String systemUrl2 = "http://hl7.org/fhir/ValueSet/other-valueset";
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
@@ -243,7 +238,7 @@ void validateCodeInValueSet_systemPresentCodeNotPresent_returnsValidationResultW
new ValueSet.ConceptSetComponent().setSystem(systemUrl2))));
CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
- new ConceptValidationOptions().setInferSystem(true), null, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
String unknownCodeForValueSetError = "Unknown code \"null#CODE\" for ValueSet with URL \"http://value.set/url\". The Remote Terminology server http://";
verifyErrorResultFromException(outcome, unknownCodeForValueSetError, theServerMessage);
@@ -252,10 +247,10 @@ void validateCodeInValueSet_systemPresentCodeNotPresent_returnsValidationResultW
@Test
void validateCodeInValueSet_systemPresentCodePresentValidatesOKNoVersioned() {
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
String systemUrl = "http://hl7.org/fhir/ValueSet/administrative-gender";
String systemUrl2 = "http://hl7.org/fhir/ValueSet/other-valueset";
valueSet.setCompose(new ValueSet.ValueSetComposeComponent().setInclude(
@@ -264,14 +259,14 @@ void validateCodeInValueSet_systemPresentCodePresentValidatesOKNoVersioned() {
new ValueSet.ConceptSetComponent().setSystem(systemUrl2).setConcept(
Lists.newArrayList(
new ValueSet.ConceptReferenceComponent().setCode("not-the-code"),
- new ValueSet.ConceptReferenceComponent().setCode(IValidationProviders.CODE) )
+ new ValueSet.ConceptReferenceComponent().setCode(CODE) )
)) ));
TestClientInterceptor requestInterceptor = new TestClientInterceptor();
mySvc.addClientInterceptor(requestInterceptor);
CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
- new ConceptValidationOptions().setInferSystem(true), null, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
assertNotNull(outcome);
assertEquals(systemUrl2, requestInterceptor.getCapturedSystemParameter());
@@ -280,10 +275,10 @@ void validateCodeInValueSet_systemPresentCodePresentValidatesOKNoVersioned() {
@Test
void validateCodeInValueSet_systemPresentCodePresentValidatesOKVersioned() {
- createValueSetReturnParameters(true, IValidationProviders.DISPLAY, null, null);
+ createValueSetReturnParameters(true, DISPLAY, null, null);
ValueSet valueSet = new ValueSet();
- valueSet.setUrl(IValidationProviders.VALUE_SET_URL);
+ valueSet.setUrl(VALUE_SET_URL);
String systemUrl = "http://hl7.org/fhir/ValueSet/administrative-gender";
String systemVersion = "3.0.2";
String systemUrl2 = "http://hl7.org/fhir/ValueSet/other-valueset";
@@ -294,14 +289,14 @@ void validateCodeInValueSet_systemPresentCodePresentValidatesOKVersioned() {
new ValueSet.ConceptSetComponent().setSystem(systemUrl2).setVersion(system2Version).setConcept(
Lists.newArrayList(
new ValueSet.ConceptReferenceComponent().setCode("not-the-code"),
- new ValueSet.ConceptReferenceComponent().setCode(IValidationProviders.CODE) )
+ new ValueSet.ConceptReferenceComponent().setCode(CODE) )
)) ));
TestClientInterceptor requestInterceptor = new TestClientInterceptor();
mySvc.addClientInterceptor(requestInterceptor);
CodeValidationResult outcome = mySvc.validateCodeInValueSet(null,
- new ConceptValidationOptions().setInferSystem(true), null, IValidationProviders.CODE, IValidationProviders.DISPLAY, valueSet);
+ new ConceptValidationOptions().setInferSystem(true), null, CODE, DISPLAY, valueSet);
assertNotNull(outcome);
assertEquals(systemUrl2 + "|" + system2Version, requestInterceptor.getCapturedSystemParameter());
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4b/validation/FhirInstanceValidatorR4BTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4b/validation/FhirInstanceValidatorR4BTest.java
index ca55a41bf4c2..d5035a8048ef 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4b/validation/FhirInstanceValidatorR4BTest.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4b/validation/FhirInstanceValidatorR4BTest.java
@@ -31,6 +31,7 @@
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4b.conformance.ProfileUtilities;
import org.hl7.fhir.r4b.context.IWorkerContext;
+import org.hl7.fhir.r4b.fhirpath.FHIRPathEngine;
import org.hl7.fhir.r4b.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.r4b.model.AllergyIntolerance;
import org.hl7.fhir.r4b.model.Base;
@@ -61,7 +62,6 @@
import org.hl7.fhir.r4b.model.ValueSet;
import org.hl7.fhir.r4b.model.ValueSet.ValueSetExpansionComponent;
import org.hl7.fhir.r4b.terminologies.ValueSetExpander;
-import org.hl7.fhir.r4b.fhirpath.FHIRPathEngine;
import org.hl7.fhir.r5.test.utils.ClassesLoadedFlags;
import org.hl7.fhir.r5.utils.validation.IValidationPolicyAdvisor;
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
@@ -203,7 +203,7 @@ public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvoca
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
} else if (myValidSystems.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- return new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message).setCodeValidationIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
+ return new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message).setIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(message, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
} else {
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
index f0ea48686e17..abcb0f947046 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
@@ -48,7 +48,6 @@
import org.hl7.fhir.r5.utils.validation.IValidatorResourceFetcher;
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
import org.hl7.fhir.r5.utils.validation.constants.ReferenceValidationPolicy;
-import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
@@ -200,10 +199,10 @@ public IValidationSupport.CodeValidationResult answer(InvocationOnMock theInvoca
retVal = new IValidationSupport.CodeValidationResult().setCode(code);
} else if (myValidSystems.contains(system)) {
String theMessage = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(theMessage).setCodeValidationIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(theMessage, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(theMessage).setIssues(Collections.singletonList(new IValidationSupport.CodeValidationIssue(theMessage, IValidationSupport.IssueSeverity.ERROR, IValidationSupport.CodeValidationIssueCode.CODE_INVALID, IValidationSupport.CodeValidationIssueCoding.INVALID_CODE)));
} else if (myValidSystemsNotReturningIssues.contains(system)) {
final String message = "Unknown code (for '" + system + "#" + code + "')";
- retVal = new IValidationSupport.CodeValidationResult().setSeverityCode(ValidationMessage.IssueSeverity.ERROR.toCode()).setMessage(message);
+ retVal = new IValidationSupport.CodeValidationResult().setSeverity(IValidationSupport.IssueSeverity.ERROR).setMessage(message);
} else {
retVal = myDefaultValidationSupport.validateCode(new ValidationSupportContext(myDefaultValidationSupport), options, system, code, display, valueSetUrl);
}
diff --git a/hapi-fhir-validation/src/test/resources/terminology/OperationOutcome-ValueSet-custom-issue-detail.json b/hapi-fhir-validation/src/test/resources/terminology/OperationOutcome-ValueSet-custom-issue-detail.json
new file mode 100644
index 000000000000..0823a430cf83
--- /dev/null
+++ b/hapi-fhir-validation/src/test/resources/terminology/OperationOutcome-ValueSet-custom-issue-detail.json
@@ -0,0 +1,22 @@
+{
+ "resourceType": "OperationOutcome",
+ "issue": [
+ {
+ "severity": "information",
+ "code": "processing",
+ "details": {
+ "coding": [
+ {
+ "system": "http://example.com/custom-issue-type",
+ "code": "valueset-is-draft"
+ }
+ ]
+ },
+ "diagnostics": "The ValueSet status is marked as draft.",
+ "location": [
+ "Bundle",
+ "Line[1] Col[2]"
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/Configuration.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/Configuration.java
index 3fd0a49aa5e2..640bde8c9943 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/Configuration.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/Configuration.java
@@ -4,7 +4,7 @@
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.tinder.parser.BaseStructureSpreadsheetParser;
-import org.apache.commons.lang.WordUtils;
+import org.apache.commons.text.WordUtils;
import java.io.File;
import java.io.IOException;
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderGenericSingleFileMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderGenericSingleFileMojo.java
index e5a2816340fb..08fc8f2d7bbb 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderGenericSingleFileMojo.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderGenericSingleFileMojo.java
@@ -7,7 +7,7 @@
import ca.uhn.fhir.tinder.parser.BaseStructureParser;
import ca.uhn.fhir.tinder.parser.DatatypeGeneratorUsingSpreadsheet;
import ca.uhn.fhir.tinder.parser.TargetType;
-import org.apache.commons.lang.WordUtils;
+import org.apache.commons.text.WordUtils;
import org.apache.maven.model.Resource;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java
index 4503b47061f9..4f2fe43f8f6c 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java
@@ -6,7 +6,7 @@
import ca.uhn.fhir.tinder.parser.BaseStructureSpreadsheetParser;
import ca.uhn.fhir.tinder.parser.ResourceGeneratorUsingModel;
import ca.uhn.fhir.util.ClasspathUtil;
-import org.apache.commons.lang.WordUtils;
+import org.apache.commons.text.WordUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java
index 9819edcc795b..c8304187c85b 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ant/TinderGeneratorTask.java
@@ -33,7 +33,7 @@
import ca.uhn.fhir.tinder.parser.BaseStructureSpreadsheetParser;
import ca.uhn.fhir.tinder.parser.DatatypeGeneratorUsingSpreadsheet;
import ca.uhn.fhir.tinder.parser.TargetType;
-import org.apache.commons.lang.WordUtils;
+import org.apache.commons.text.WordUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Task;
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java
index 8de25b933767..69c30538f573 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java
@@ -8,8 +8,8 @@
import java.util.List;
import java.util.Map;
-import static org.apache.commons.lang.StringUtils.defaultString;
-import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang3.StringUtils.defaultString;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseElement {
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
index 7ac33c816932..fe8233c02b97 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java
@@ -1,7 +1,7 @@
package ca.uhn.fhir.tinder.model;
-import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.WordUtils;
import java.util.ArrayList;
import java.util.Collections;
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java
index 68b28b0b96bd..9e465ad18cf8 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java
@@ -25,9 +25,9 @@
import com.google.common.base.Charsets;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang.WordUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.text.WordUtils;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
@@ -56,8 +56,8 @@
import java.util.TreeMap;
import java.util.TreeSet;
-import static org.apache.commons.lang.StringUtils.defaultString;
-import static org.apache.commons.lang.StringUtils.isNotBlank;
+import static org.apache.commons.lang3.StringUtils.defaultString;
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseStructureParser {
diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingModel.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingModel.java
index 734a35822ab9..0f90505d77bd 100644
--- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingModel.java
+++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingModel.java
@@ -6,7 +6,7 @@
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
import ca.uhn.fhir.tinder.model.Resource;
import ca.uhn.fhir.tinder.model.SearchParameter;
-import org.apache.commons.lang.WordUtils;
+import org.apache.commons.text.WordUtils;
import org.apache.maven.plugin.MojoFailureException;
import java.io.File;
diff --git a/pom.xml b/pom.xml
index 31b2d0c455fe..9b19056b43d8 100644
--- a/pom.xml
+++ b/pom.xml
@@ -999,8 +999,8 @@
2.12.0
1.10.0
- 2.11.0
- 3.14.0
+ 2.17.0
+ 3.17.0
1.2
2.23.0
5.8.0
@@ -1013,15 +1013,15 @@
4.0.4
4.9.0
3.0.3
- 12.0.9
+ 12.0.14
3.0.2
5.10.1
0.64.8
9.4.0
- 6.4.1.Final
+ 6.4.10.Final
1.4.14
- 7.0.0.Final
+ 7.0.1.Final
9.8.0
2.2
@@ -1046,8 +1046,8 @@
2.2.22
2.0.13
2.19.0
- 6.1.8
- 2023.1.6
+ 6.1.14
+ 2024.0.5
4.3.10
3.2.6
2.0.6
@@ -1063,7 +1063,7 @@
1.0.8
- 3.13.0
+ 3.13.1
5.4.1
@@ -1673,7 +1673,7 @@
org.apache.velocity
velocity-engine-core
- 2.3
+ 2.4.1
org.awaitility