From a91490f1efa201bad77a2d55dd11b3707cf86fdd Mon Sep 17 00:00:00 2001 From: Jesse Bonzo <97121974+jbonzohln@users.noreply.github.com> Date: Mon, 29 Apr 2024 08:16:14 -0700 Subject: [PATCH 01/15] Update openapi index.css (#4556) * Update index.css Fixes https://github.com/hapifhir/hapi-fhir/issues/4555 * Add changelog --------- Co-authored-by: James Agnew --- .../uhn/hapi/fhir/changelog/7_4_0/4556-openapi-css.yaml | 6 ++++++ .../src/main/resources/ca/uhn/fhir/rest/openapi/index.css | 8 ++++++-- pom.xml | 4 ++++ 3 files changed, 16 insertions(+), 2 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/4556-openapi-css.yaml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/4556-openapi-css.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/4556-openapi-css.yaml new file mode 100644 index 00000000000..ee381ec204e --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/4556-openapi-css.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4556 +title: "The CSS file used by the OpenApiInterceptor to serve up the Swagger UI + component inadvertently blocked the authorization button evem when it was + wanted. This has been fixed. Thanks Jesse Bonzo for the contribution!" diff --git a/hapi-fhir-server-openapi/src/main/resources/ca/uhn/fhir/rest/openapi/index.css b/hapi-fhir-server-openapi/src/main/resources/ca/uhn/fhir/rest/openapi/index.css index c7b99216bc4..131ef859d0b 100644 --- a/hapi-fhir-server-openapi/src/main/resources/ca/uhn/fhir/rest/openapi/index.css +++ b/hapi-fhir-server-openapi/src/main/resources/ca/uhn/fhir/rest/openapi/index.css @@ -141,6 +141,10 @@ body } /* Disable the servers dropdown, which is useless here */ -.swagger-ui .scheme-container { - display: none; +.swagger-ui .scheme-container .servers-title { + display: none; +} + +.swagger-ui .scheme-container .servers { + display: none; } diff --git a/pom.xml b/pom.xml index deb48482f14..aaf265b0408 100644 --- a/pom.xml +++ b/pom.xml @@ -905,6 +905,10 @@ pano-smals pano-smals + + jbonzohln + Jesse Bonzo + From 22d7731d417fef7ce5f475f30f5b2c560805ba31 Mon Sep 17 00:00:00 2001 From: Gijs <32096862+thetrueoneshots@users.noreply.github.com> Date: Thu, 2 May 2024 20:42:27 +0200 Subject: [PATCH 02/15] 3986: Remove validation of max parameter lastn and add tests (#5737) * 3986: Remove validation of max parameter lastn and add tests * 3986: Add bug fix to changelog * 3986: Re-add removed import * Prepare for merge * Spotless --------- Co-authored-by: James Agnew --- .../7_4_0/3986-fix-lastn-max-parameter.yaml | 4 ++ .../BaseJpaResourceProviderObservation.java | 7 ++++ .../dstu3/ObservationLastnDstu3Test.java | 37 +++++++++++++++++++ pom.xml | 4 ++ 4 files changed, 52 insertions(+) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/3986-fix-lastn-max-parameter.yaml create mode 100644 hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ObservationLastnDstu3Test.java diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/3986-fix-lastn-max-parameter.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/3986-fix-lastn-max-parameter.yaml new file mode 100644 index 00000000000..c210f9075a8 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/3986-fix-lastn-max-parameter.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 3986 +title: "Removed the validation error of the `max` query parameter on the $lastn operation. Now, the $lastn operation can be invoked with the `max` query parameter. Contribution by Gijs Groenewegen (@thetrueoneshots)." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderObservation.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderObservation.java index 6674fe35d5d..d43f56a5c2a 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderObservation.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/BaseJpaResourceProviderObservation.java @@ -84,6 +84,13 @@ public abstract class BaseJpaResourceProviderObservationjbonzohln Jesse Bonzo + + thetrueoneshots + Gijs Groenewegen + From b555498c9b7824af67b219e5b7b85f7992aec991 Mon Sep 17 00:00:00 2001 From: holly-smile <166412459+holly-smile@users.noreply.github.com> Date: Fri, 3 May 2024 01:15:43 -0700 Subject: [PATCH 03/15] Remove unnecessary call to deleteAllSearchParams (#5901) * Remove unnecessary call to deleteAllSearchParams. Fixes #5900. * Regression test * Run spotless --- ...move-unnecessary-delete-search-params.yaml | 5 ++ .../expunge/JpaResourceExpungeService.java | 4 +- .../JpaResourceExpungeServiceTest.java | 59 +++++++++++++++++++ 3 files changed, 65 insertions(+), 3 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5900-remove-unnecessary-delete-search-params.yaml create mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/expunge/JpaResourceExpungeServiceTest.java diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5900-remove-unnecessary-delete-search-params.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5900-remove-unnecessary-delete-search-params.yaml new file mode 100644 index 00000000000..2ea05ae434d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5900-remove-unnecessary-delete-search-params.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5900 +jira: SMILE-7435 +title: "Remove unnecessary call to deleteAllSearchParams when $expunge is called on an already-deleted resource." diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/JpaResourceExpungeService.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/JpaResourceExpungeService.java index 4e8e3ea7e83..da5652af20e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/JpaResourceExpungeService.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/JpaResourceExpungeService.java @@ -298,7 +298,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService Date: Tue, 7 May 2024 18:23:03 -0400 Subject: [PATCH 04/15] Batch2 workchunk states hapi (#5851) * step 1 * updated batch 2 framework with READY state * spotless * remove entity manager * spotless * fixing up more tests for batch2 * updating documentation * cleanup * removing checkstyle violation * code review points * review points continued * review poitns finished * updating tests * updates * spotless * updated * step 1 * updated * sketch out test cases * basic state transition shell work * typos * spotless * adding spy override * fixing tests * spotless * changing comment to complete build * fixing some tests and adding a view * adding different paging mechanism * spotless * waiting step 1 * commit changes * remove text * review fixes * spotless * some tweaks * updating documentation and adding change log * spotless * added documentation * review comments 1 * more review fixes * spotless * fixing bug * fixing path * spotless * update state diagram * review points round 1 * revert * updating diag * review fixes round 2 * spotless * - Implemented GATE_WAITING state for the batch2 state machine. - This will be the initial status for all workchunks of a gated job. - made compatible with the equivalent "fake QUEUED" state in the Old batch2 implementation. - Updated corresponding docs. - added corresponding tests and changelog * Revert "- Implemented GATE_WAITING state for the batch2 state machine." This reverts commit 32a00f4b8169a11849611798adfd48138908e49c. * - Implemented GATE_WAITING state for the batch2 state machine. - This will be the initial status for all workchunks of a gated job. - made compatible with the equivalent "fake QUEUED" state in the Old batch2 implementation. - Updated corresponding docs. - added corresponding tests and changelog * fixing a bug * spotless * fixing * - fix merges conflicts - set first chunk to be always created in READY * - have only one path through the equeueReady method - fixed tests * - hid the over-powered transition function behind a proper state action * spotless * resolved review comments * fixing tests * resolved review comments * resolved review comments * resolved review comments * resolved review comments * resolved review comments * updating migration script number * fixed bugs * spotless * fix test high concurrency * fixing a test * code fix * fixing tests in bulkexportit * fixing tests * fixing tests * cleanup * completed instance will not be sent to the reduction step service * Revert "completed instance will not be sent to the reduction step service" This reverts commit aa149b669181f25f9262cb871627d7ec59369e5f. * Revert "Revert "completed instance will not be sent to the reduction step service"" This reverts commit e18f5796a165029d693bc5b6e0d882e429072d4e. * removing dead code * changed db query for step advance to take statuses as parameter instead * test fixes * spotless * test fix * spotless * fixing tests * migration fix * fixing test * testing pipeline with `testGroupBulkExportNotInGroup_DoesNotShowUp` disabled * fixing some tests * Add new race test for simultaneous queue/dequeue * re-enabling `testGroupBulkExportNotInGroup_DoesNotShowUp` * cascade tag deletes * test fixes * some logging * a test case * adding job id * more test code * marking purge checks * test fix * testing * pausing schedulers on cleanup * adding a wait * max thread count guarantee * fixing the tests again * removing dead code * spotless * checking * msg codes: * Fixing a test * review points * spotless * required pom values * step 1 of reduction ready * update * reductoin ready * annother test * spotless * cleanup * cleanup * simplifying check in reduction step * review fixes * updating version * using 7.3.1 * adding check * test finessing --------- Co-authored-by: leif stawnyczy Co-authored-by: Michael Buckley Co-authored-by: tyner --- hapi-deployable-pom/pom.xml | 2 +- hapi-fhir-android/pom.xml | 2 +- hapi-fhir-base/pom.xml | 2 +- .../ca/uhn/fhir/model/api/PagingIterator.java | 17 +- .../fhir/model/api/PagingIteratorTest.java | 2 +- hapi-fhir-bom/pom.xml | 4 +- hapi-fhir-checkstyle/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-api/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-app/pom.xml | 2 +- hapi-fhir-cli/pom.xml | 2 +- hapi-fhir-client-okhttp/pom.xml | 2 +- hapi-fhir-client/pom.xml | 2 +- hapi-fhir-converter/pom.xml | 2 +- hapi-fhir-dist/pom.xml | 2 +- hapi-fhir-docs/pom.xml | 2 +- ...ded-ready-state-to-batch2-work-chunks.yaml | 10 + ...7-add-poll-waiting-step-to-batch-jobs.yaml | 9 + ...ch2-framework-with-gate_waiting-state.yaml | 7 + .../docs/server_jpa_batch/batch2_states.md | 15 +- .../docs/server_jpa_batch/introduction.md | 54 ++- hapi-fhir-jacoco/pom.xml | 2 +- hapi-fhir-jaxrsserver-base/pom.xml | 2 +- hapi-fhir-jpa/pom.xml | 2 +- .../fhir/jpa/model/sched/IHapiScheduler.java | 11 + .../jpa/model/sched/ISchedulerService.java | 17 + .../uhn/fhir/jpa/sched/BaseHapiScheduler.java | 50 ++ .../jpa/sched/BaseSchedulerServiceImpl.java | 14 +- .../uhn/fhir/jpa/sched/HapiNullScheduler.java | 10 + hapi-fhir-jpaserver-base/pom.xml | 2 +- .../uhn/fhir/jpa/batch2/JobInstanceUtil.java | 2 + .../uhn/fhir/jpa/batch2/JpaBatch2Config.java | 3 + .../jpa/batch2/JpaJobPersistenceImpl.java | 155 +++++- ...Batch2WorkChunkMetadataViewRepository.java | 21 + .../dao/data/IBatch2WorkChunkRepository.java | 37 +- .../jpa/entity/Batch2WorkChunkEntity.java | 67 ++- .../entity/Batch2WorkChunkMetadataView.java | 123 +++++ .../tasks/HapiFhirJpaMigrationTasks.java | 17 + .../jpa/batch2/JpaJobPersistenceImplTest.java | 2 + ...DataExportJobSchedulingHelperImplTest.java | 15 +- .../pom.xml | 2 +- hapi-fhir-jpaserver-hfql/pom.xml | 2 +- hapi-fhir-jpaserver-ips/pom.xml | 2 +- hapi-fhir-jpaserver-mdm/pom.xml | 2 +- hapi-fhir-jpaserver-model/pom.xml | 2 +- .../ca/uhn/fhir/jpa/model/entity/BaseTag.java | 1 + .../fhir/jpa/model/entity/TagDefinition.java | 2 + hapi-fhir-jpaserver-searchparam/pom.xml | 2 +- hapi-fhir-jpaserver-subscription/pom.xml | 2 +- .../SubscriptionMatchingSubscriberTest.java | 2 +- hapi-fhir-jpaserver-test-dstu2/pom.xml | 2 +- .../dao/dstu2/FhirResourceDaoDstu2Test.java | 8 +- hapi-fhir-jpaserver-test-dstu3/pom.xml | 2 +- hapi-fhir-jpaserver-test-r4/pom.xml | 2 +- .../fhir/jpa/batch2/Batch2CoordinatorIT.java | 322 +++++++++++-- .../Batch2JobInstanceRepositoryTest.java | 11 +- .../Batch2JobMaintenanceDatabaseIT.java | 10 +- .../jpa/batch2/Batch2JobMaintenanceIT.java | 94 ++-- .../jpa/batch2/BulkDataErrorAbuseTest.java | 93 ++-- .../jpa/batch2/JobInstanceRepositoryTest.java | 3 - .../jpa/batch2/JpaJobPersistenceImplTest.java | 455 ++++++++++++++---- .../uhn/fhir/jpa/bulk/BulkDataExportTest.java | 15 +- .../fhir/jpa/dao/r4/FhirSystemDaoR4Test.java | 5 +- .../fhir/jpa/delete/job/ReindexJobTest.java | 13 +- .../r4/AuthorizationInterceptorJpaR4Test.java | 10 +- ...sourceProviderCustomSearchParamR4Test.java | 3 + .../r4/ResourceProviderR4BundleTest.java | 67 ++- .../r4/ResourceProviderR4CodeSystemTest.java | 15 + .../reindex/ResourceReindexSvcImplTest.java | 26 +- .../term/job/TermCodeSystemDeleteJobTest.java | 5 +- .../fhir/testjob/TestJobDefinitionUtils.java | 67 +++ .../fhir/testjob/models/FirstStepOutput.java | 9 + .../testjob/models/ReductionStepOutput.java | 9 + .../testjob/models/TestJobParameters.java | 9 + hapi-fhir-jpaserver-test-r4b/pom.xml | 2 +- hapi-fhir-jpaserver-test-r5/pom.xml | 2 +- hapi-fhir-jpaserver-test-utilities/pom.xml | 2 +- .../ca/uhn/fhir/jpa/test/BaseJpaR4Test.java | 37 +- .../ca/uhn/fhir/jpa/test/BaseJpaTest.java | 13 +- .../ca/uhn/fhir/jpa/test/Batch2JobHelper.java | 90 +++- .../config/Batch2FastSchedulerConfig.java | 23 + .../fhir/jpa/test/config/TestR4Config.java | 10 +- hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 2 +- hapi-fhir-server-cds-hooks/pom.xml | 2 +- hapi-fhir-server-mdm/pom.xml | 2 +- hapi-fhir-server-openapi/pom.xml | 2 +- hapi-fhir-server/pom.xml | 2 +- .../hapi-fhir-caching-api/pom.xml | 2 +- .../hapi-fhir-caching-caffeine/pom.xml | 4 +- .../hapi-fhir-caching-guava/pom.xml | 2 +- .../hapi-fhir-caching-testing/pom.xml | 2 +- hapi-fhir-serviceloaders/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../hapi-fhir-spring-boot-samples/pom.xml | 2 +- .../hapi-fhir-spring-boot-starter/pom.xml | 2 +- hapi-fhir-spring-boot/pom.xml | 2 +- hapi-fhir-sql-migrate/pom.xml | 2 +- hapi-fhir-storage-batch2-jobs/pom.xml | 2 +- .../pom.xml | 8 +- ...tractIJobPersistenceSpecificationTest.java | 106 +++- .../test/IInstanceStateTransitions.java | 30 ++ .../batch2/test/IJobMaintenanceActions.java | 234 +++++++++ .../hapi/fhir/batch2/test/ITestFixture.java | 19 +- .../test/IWorkChunkErrorActionsTests.java | 1 - .../test/IWorkChunkStateTransitions.java | 436 ++++++++++++++++- .../batch2/test/IWorkChunkStorageTests.java | 230 ++++++++- .../batch2/test/WorkChunkTestConstants.java | 4 +- .../JobMaintenanceStateInformation.java | 269 +++++++++++ hapi-fhir-storage-batch2/pom.xml | 2 +- .../uhn/fhir/batch2/api/IJobPersistence.java | 48 +- .../batch2/api/IWorkChunkPersistence.java | 25 +- .../batch2/api/RetryChunkLaterException.java | 33 ++ .../coordinator/JobCoordinatorImpl.java | 33 +- .../fhir/batch2/coordinator/JobDataSink.java | 28 +- .../batch2/coordinator/JobStepExecutor.java | 6 + .../ReductionStepExecutorServiceImpl.java | 9 +- .../fhir/batch2/coordinator/StepExecutor.java | 13 + .../WorkChannelMessageHandler.java | 6 +- .../maintenance/JobInstanceProcessor.java | 263 +++++++--- .../uhn/fhir/batch2/model/JobDefinition.java | 7 + .../uhn/fhir/batch2/model/JobWorkCursor.java | 4 + .../ca/uhn/fhir/batch2/model/WorkChunk.java | 170 +++---- .../batch2/model/WorkChunkCreateEvent.java | 15 +- .../fhir/batch2/model/WorkChunkMetadata.java | 109 +++++ .../batch2/model/WorkChunkStatusEnum.java | 51 +- .../java/ca/uhn/fhir/batch2/package-info.java | 37 +- .../batch2/progress/InstanceProgress.java | 3 + .../JobInstanceProgressCalculator.java | 2 + .../coordinator/JobCoordinatorImplTest.java | 16 +- .../batch2/coordinator/JobDataSinkTest.java | 12 +- .../ReductionStepExecutorServiceImplTest.java | 30 +- .../coordinator/WorkChunkProcessorTest.java | 2 +- .../JobMaintenanceServiceImplTest.java | 201 +++++++- hapi-fhir-storage-cr/pom.xml | 2 +- hapi-fhir-storage-mdm/pom.xml | 2 +- hapi-fhir-storage-test-utilities/pom.xml | 2 +- hapi-fhir-storage/pom.xml | 2 +- hapi-fhir-structures-dstu2.1/pom.xml | 2 +- hapi-fhir-structures-dstu2/pom.xml | 2 +- hapi-fhir-structures-dstu3/pom.xml | 2 +- hapi-fhir-structures-hl7org-dstu2/pom.xml | 2 +- hapi-fhir-structures-r4/pom.xml | 2 +- .../interceptor/ConsentInterceptorTest.java | 4 +- hapi-fhir-structures-r4b/pom.xml | 2 +- hapi-fhir-structures-r5/pom.xml | 2 +- hapi-fhir-test-utilities/pom.xml | 2 +- .../LogbackLevelOverrideExtension.java | 10 +- hapi-fhir-testpage-overlay/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-validation-resources-dstu2/pom.xml | 2 +- hapi-fhir-validation-resources-dstu3/pom.xml | 2 +- hapi-fhir-validation-resources-r4/pom.xml | 2 +- hapi-fhir-validation-resources-r4b/pom.xml | 2 +- hapi-fhir-validation-resources-r5/pom.xml | 2 +- hapi-fhir-validation/pom.xml | 2 +- hapi-tinder-plugin/pom.xml | 2 +- hapi-tinder-test/pom.xml | 2 +- pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- 163 files changed, 3957 insertions(+), 758 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5745-added-ready-state-to-batch2-work-chunks.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5767-add-poll-waiting-step-to-batch-jobs.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5818-update-batch2-framework-with-gate_waiting-state.yaml create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkMetadataViewRepository.java create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkMetadataView.java create mode 100644 hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/TestJobDefinitionUtils.java create mode 100644 hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/FirstStepOutput.java create mode 100644 hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/ReductionStepOutput.java create mode 100644 hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/TestJobParameters.java create mode 100644 hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/Batch2FastSchedulerConfig.java create mode 100644 hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IJobMaintenanceActions.java create mode 100644 hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/support/JobMaintenanceStateInformation.java create mode 100644 hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/RetryChunkLaterException.java create mode 100644 hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkMetadata.java diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 83b6cb38520..f3f866d46a1 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 87706cf277d..2dd9942ba2a 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index ed0a9fc6da4..188e9bcbe27 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/PagingIterator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/PagingIterator.java index eeb9dd233da..4aeb07531f4 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/PagingIterator.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/model/api/PagingIterator.java @@ -26,13 +26,16 @@ import java.util.LinkedList; import java.util.NoSuchElementException; import java.util.function.Consumer; +/** + * This paging iterator only works with already ordered queries + */ public class PagingIterator implements Iterator { public interface PageFetcher { void fetchNextPage(int thePageIndex, int theBatchSize, Consumer theConsumer); } - static final int PAGE_SIZE = 100; + static final int DEFAULT_PAGE_SIZE = 100; private int myPage; @@ -42,8 +45,16 @@ public class PagingIterator implements Iterator { private final PageFetcher myFetcher; + private final int myPageSize; + public PagingIterator(PageFetcher theFetcher) { + this(DEFAULT_PAGE_SIZE, theFetcher); + } + + public PagingIterator(int thePageSize, PageFetcher theFetcher) { + assert thePageSize > 0 : "Page size must be a positive value"; myFetcher = theFetcher; + myPageSize = thePageSize; } @Override @@ -66,9 +77,9 @@ public class PagingIterator implements Iterator { private void fetchNextBatch() { if (!myIsFinished && myCurrentBatch.isEmpty()) { - myFetcher.fetchNextPage(myPage, PAGE_SIZE, myCurrentBatch::add); + myFetcher.fetchNextPage(myPage, myPageSize, myCurrentBatch::add); myPage++; - myIsFinished = myCurrentBatch.size() < PAGE_SIZE; + myIsFinished = myCurrentBatch.size() < myPageSize; } } } diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/model/api/PagingIteratorTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/model/api/PagingIteratorTest.java index 340d7464684..6cd51910a1f 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/model/api/PagingIteratorTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/model/api/PagingIteratorTest.java @@ -62,7 +62,7 @@ public class PagingIteratorTest { public void next_fetchTest_fetchesAndReturns() { // 3 cases to make sure we get the edge cases for (int adj : new int[] { -1, 0, 1 }) { - int size = PagingIterator.PAGE_SIZE + adj; + int size = PagingIterator.DEFAULT_PAGE_SIZE + adj; myPagingIterator = createPagingIterator(size); diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index f05fea85c67..11be6c4e547 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -4,7 +4,7 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT pom HAPI FHIR BOM @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 69c0460cccf..edeebb36033 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index ee43373d473..a6301421773 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index ec3ae13b3f0..5a80f6e818b 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index f7053e7e873..f3ad5743264 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 35617f0402f..4038b5c527e 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index e974a566096..a13e2b42330 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index a14196db410..62951f59897 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index 3dda194c646..2e78389b1ec 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index 41acfef29b0..b60a2d29aa1 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5745-added-ready-state-to-batch2-work-chunks.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5745-added-ready-state-to-batch2-work-chunks.yaml new file mode 100644 index 00000000000..e293b0a5f43 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5745-added-ready-state-to-batch2-work-chunks.yaml @@ -0,0 +1,10 @@ +--- +type: add +issue: 5745 +title: "Added another state to the Batch2 work chunk state machine: `READY`. + This work chunk state will be the initial state on creation. + Once queued for delivery, they will transition to `QUEUED`. + The exception is for ReductionStep chunks (because reduction steps + are not read off of the queue, but executed by the maintenance job + inline. +" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5767-add-poll-waiting-step-to-batch-jobs.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5767-add-poll-waiting-step-to-batch-jobs.yaml new file mode 100644 index 00000000000..1d14dee8c60 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5767-add-poll-waiting-step-to-batch-jobs.yaml @@ -0,0 +1,9 @@ +--- +type: add +issue: 5767 +title: "Added new `POLL_WAITING` state for WorkChunks in batch jobs. + Also added RetryChunkLaterException for jobs that have steps that + need to be retried at a later time (can be provided optionally to exception). + If a step throws this new exception, it will be set with the new + `POLL_WAITING` status and retried at a later time. +" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5818-update-batch2-framework-with-gate_waiting-state.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5818-update-batch2-framework-with-gate_waiting-state.yaml new file mode 100644 index 00000000000..197f01bf9f5 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5818-update-batch2-framework-with-gate_waiting-state.yaml @@ -0,0 +1,7 @@ +--- +type: add +issue: 5818 +title: "Added another state to the Batch2 work chunk state machine: `GATE_WAITING`. + This work chunk state will be the initial state on creation for gated jobs. + Once all chunks are completed for the previous step, they will transition to `READY`. +" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md index b11e7187ce5..e085a33f7e0 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md @@ -47,24 +47,35 @@ stateDiagram-v2 title: Batch2 Job Work Chunk state transitions --- stateDiagram-v2 + state GATE_WAITING + state READY + state REDUCTION_READY state QUEUED state on_receive <> state IN_PROGRESS state ERROR + state POLL_WAITING state execute <> state FAILED state COMPLETED direction LR - [*] --> QUEUED : on create + [*] --> READY : on create - normal or gated jobs first chunks + [*] --> GATE_WAITING : on create - gated jobs for all but the first chunks of the first step + GATE_WAITING --> READY : on gate release - gated + GATE_WAITING --> REDUCTION_READY : on gate release for the final reduction step (all reduction jobs are gated) + QUEUED --> READY : on gate release - gated (for compatibility with legacy QUEUED state up to Hapi-fhir version 7.1) + READY --> QUEUED : placed on kafka (maint.) + POLL_WAITING --> READY : after a poll delay on a POLL_WAITING work chunk has elapsed %% worker processing states - QUEUED --> on_receive : on deque by worker + QUEUED --> on_receive : on deque by worker on_receive --> IN_PROGRESS : start execution IN_PROGRESS --> execute: execute execute --> ERROR : on re-triable error execute --> COMPLETED : success\n maybe trigger instance first_step_finished execute --> FAILED : on unrecoverable \n or too many errors + execute --> POLL_WAITING : job step has throw a RetryChunkLaterException and must be tried again after the provided poll delay %% temporary error state until retry ERROR --> on_receive : exception rollback\n triggers redelivery diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/introduction.md index ce8dbc4a1f0..1c3bb485c21 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/introduction.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/introduction.md @@ -19,36 +19,54 @@ A HAPI-FHIR batch job definition consists of a job name, version, parameter json After a job has been defined, *instances* of that job can be submitted for batch processing by populating a `JobInstanceStartRequest` with the job name and job parameters json and then submitting that request to the Batch Job Coordinator. The Batch Job Coordinator will then store two records in the database: -- Job Instance with status QUEUED: that is the parent record for all data concerning this job -- Batch Work Chunk with status QUEUED: this describes the first "chunk" of work required for this job. The first Batch Work Chunk contains no data. +- Job Instance with status `QUEUED`: that is the parent record for all data concerning this job +- Batch Work Chunk with status `READY`: this describes the first "chunk" of work required for this job. The first Batch Work Chunk contains no data. -Lastly the Batch Job Coordinator publishes a message to the Batch Notification Message Channel (named `batch2-work-notification`) to inform worker threads that this first chunk of work is now ready for processing. +### The Maintenance Job -### Job Processing - First Step +A Scheduled Job runs periodically (once a minute). For each Job Instance in the database, it: -HAPI-FHIR Batch Jobs run based on job notification messages. The process is kicked off by the first chunk of work. When this notification message arrives, the message handler makes a single call to the first step defined in the job definition, passing in the job parameters as input. +1. Calculates job progress (% of work chunks in `COMPLETE` status). If the job is finished, purges any left over work chunks still in the database. +1. Moves all `POLL_WAITING` work chunks to `READY` if their `nextPollTime` has expired. +1. Calculates job progress (% of work chunks in `COMPLETE` status). If the job is finished, purges any leftover work chunks still in the database. +1. Cleans up any complete, failed, or cancelled jobs that need to be removed. +1. When the current step is complete, moves any gated jobs onto their next step and updates all chunks in `GATE_WAITING` to `READY`. If the the job is being moved to its final reduction step, chunks are moved from `GATE_WAITING` to `REDUCTION_READY`. +1. If the final step of a gated job is a reduction step, a reduction step execution will be triggered. All workchunks for the job in `REDUCTION_READY` will be consumed at this point. +1. Moves all `READY` work chunks into the `QUEUED` state and publishes a message to the Batch Notification Message Channel to inform worker threads that a work chunk is now ready for processing. \* -The handler then does the following: -1. Change the work chunk status from QUEUED to IN_PROGRESS -2. Change the Job Instance status from QUEUED to IN_PROGRESS -3. If the Job Instance is cancelled, change the status to CANCELLED and abort processing. -4. The first step of the job definition is executed with the job parameters -5. This step creates new work chunks. For each work chunk it creates, it json serializes the work chunk data, stores it in the database, and publishes a new message to the Batch Notification Message Channel to notify worker threads that there are new work chunks waiting to be processed. -6. If the step succeeded, the work chunk status is changed from IN_PROGRESS to COMPLETED, and the data it contained is deleted. -7. If the step failed, the work chunk status is changed from IN_PROGRESS to either ERRORED or FAILED depending on the severity of the error. +\* An exception is for the final reduction step, where work chunks are not published to the Batch Notification Message Channel, +but instead processed inline. -### Job Processing - Middle steps +### Batch Notification Message Handler -Middle Steps in the job definition are executed in the same way, except instead of only using the Job Parameters as input, they use both the Job Parameters and the Work Chunk data produced from the previous step. +HAPI-FHIR Batch Jobs run based on job notification messages of the Batch Notification Message Channel (named `batch2-work-notification`). -### Job Processing - Final Step +When a notification message arrives, the handler does the following: + +1. Change the work chunk status from `QUEUED` to `IN_PROGRESS` +1. Change the Job Instance status from `QUEUED` to `IN_PROGRESS` +1. If the Job Instance is cancelled, change the status to `CANCELLED` and abort processing +1. If the step creates new work chunks, each work chunk will be created in either the `GATE_WAITING` state (for gated jobs) or `READY` state (for non-gated jobs) and will be handled in the next maintenance job pass. +1. If the step succeeds, the work chunk status is changed from `IN_PROGRESS` to `COMPLETED`, and the data it contained is deleted. +1. If the step throws a `RetryChunkLaterException`, the work chunk status is changed from `IN_PROGRESS` to `POLL_WAITING`, and a `nextPollTime` value will be set. +1. If the step fails, the work chunk status is changed from `IN_PROGRESS` to either `ERRORED` or `FAILED`, depending on the severity of the error. + +### First Step + +The first step in a job definition is executed with just the job parameters. + +### Middle steps + +Middle Steps in the job definition are executed using the initial Job Parameters and the Work Chunk data produced from the previous step. + +### Final Step The final step operates the same way as the middle steps, except it does not produce any new work chunks. ### Gated Execution -If a Job Definition is set to having Gated Execution, then all work chunks for one step must be COMPLETED before any work chunks for the next step may begin. +If a Job Definition is set to having Gated Execution, then all work chunks for a step must be `COMPLETED` before any work chunks for the next step may begin. ### Job Instance Completion -A Batch Job Maintenance Service runs every minute to monitor the status of all Job Instances and the Job Instance is transitioned to either COMPLETED, ERRORED or FAILED according to the status of all outstanding work chunks for that job instance. If the job instance is still IN_PROGRESS this maintenance service also estimates the time remaining to complete the job. +A Batch Job Maintenance Service runs every minute to monitor the status of all Job Instances and the Job Instance is transitioned to either `COMPLETED`, `ERRORED` or `FAILED` according to the status of all outstanding work chunks for that job instance. If the job instance is still `IN_PROGRESS` this maintenance service also estimates the time remaining to complete the job. diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 2079a6bb970..3ba709907e0 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index 7077325c2c6..a36f270f1ca 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index b7dd29597aa..fd28ff49ed0 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/IHapiScheduler.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/IHapiScheduler.java index f2084bfa7c8..f9cb5e6c020 100644 --- a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/IHapiScheduler.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/IHapiScheduler.java @@ -37,6 +37,17 @@ public interface IHapiScheduler { void logStatusForUnitTest(); + /** + * Pauses this scheduler (and thus all scheduled jobs). + * To restart call {@link #unpause()} + */ + void pause(); + + /** + * Restarts this scheduler after {@link #pause()} + */ + void unpause(); + void scheduleJob(long theIntervalMillis, ScheduledJobDefinition theJobDefinition); Set getJobKeysForUnitTest() throws SchedulerException; diff --git a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/ISchedulerService.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/ISchedulerService.java index c058198e03c..5ff1057937c 100644 --- a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/ISchedulerService.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/model/sched/ISchedulerService.java @@ -32,6 +32,20 @@ public interface ISchedulerService { void logStatusForUnitTest(); + /** + * Pauses the scheduler so no new jobs will run. + * Useful in tests when cleanup needs to happen but scheduled jobs may + * be running + */ + @VisibleForTesting + void pause(); + + /** + * Restarts the scheduler after a previous call to {@link #pause()}. + */ + @VisibleForTesting + void unpause(); + /** * This task will execute locally (and should execute on all nodes of the cluster if there is a cluster) * @param theIntervalMillis How many milliseconds between passes should this job run @@ -52,6 +66,9 @@ public interface ISchedulerService { @VisibleForTesting Set getClusteredJobKeysForUnitTest() throws SchedulerException; + @VisibleForTesting + boolean isSchedulingDisabled(); + boolean isStopping(); /** diff --git a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseHapiScheduler.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseHapiScheduler.java index 916bebe93fa..f8def318609 100644 --- a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseHapiScheduler.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseHapiScheduler.java @@ -29,6 +29,7 @@ import com.google.common.collect.Sets; import jakarta.annotation.Nonnull; import org.apache.commons.lang3.Validate; import org.quartz.JobDataMap; +import org.quartz.JobExecutionContext; import org.quartz.JobKey; import org.quartz.ScheduleBuilder; import org.quartz.Scheduler; @@ -44,11 +45,14 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import java.util.List; import java.util.Properties; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; +import static org.apache.commons.lang3.StringUtils.isNotBlank; + public abstract class BaseHapiScheduler implements IHapiScheduler { private static final Logger ourLog = LoggerFactory.getLogger(BaseHapiScheduler.class); @@ -151,6 +155,42 @@ public abstract class BaseHapiScheduler implements IHapiScheduler { } } + public void pause() { + int delay = 100; + String errorMsg = null; + Throwable ex = null; + try { + int count = 0; + myScheduler.standby(); + while (count < 3) { + if (!hasRunningJobs()) { + break; + } + Thread.sleep(delay); + count++; + } + if (count >= 3) { + errorMsg = "Scheduler on standby. But after " + (count + 1) * delay + + " ms there are still jobs running. Execution will continue, but may cause bugs."; + } + } catch (Exception x) { + ex = x; + errorMsg = "Failed to set to standby. Execution will continue, but may cause bugs."; + } + + if (isNotBlank(errorMsg)) { + if (ex != null) { + ourLog.warn(errorMsg, ex); + } else { + ourLog.warn(errorMsg); + } + } + } + + public void unpause() { + start(); + } + @Override public void clear() throws SchedulerException { myScheduler.clear(); @@ -168,6 +208,16 @@ public abstract class BaseHapiScheduler implements IHapiScheduler { } } + private boolean hasRunningJobs() { + try { + List currentlyExecutingJobs = myScheduler.getCurrentlyExecutingJobs(); + ourLog.info("Checking for running jobs. Found {} running.", currentlyExecutingJobs); + return !currentlyExecutingJobs.isEmpty(); + } catch (SchedulerException ex) { + throw new RuntimeException(Msg.code(2521) + " Failed during check for scheduled jobs", ex); + } + } + @Override public void scheduleJob(long theIntervalMillis, ScheduledJobDefinition theJobDefinition) { Validate.isTrue(theIntervalMillis >= 100); diff --git a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseSchedulerServiceImpl.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseSchedulerServiceImpl.java index 358aa408176..89036097ecf 100644 --- a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseSchedulerServiceImpl.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/BaseSchedulerServiceImpl.java @@ -136,7 +136,7 @@ public abstract class BaseSchedulerServiceImpl implements ISchedulerService { return retval; } - private boolean isSchedulingDisabled() { + public boolean isSchedulingDisabled() { return !isLocalSchedulingEnabled() || isSchedulingDisabledForUnitTests(); } @@ -198,6 +198,18 @@ public abstract class BaseSchedulerServiceImpl implements ISchedulerService { myClusteredScheduler.logStatusForUnitTest(); } + @Override + public void pause() { + myLocalScheduler.pause(); + myClusteredScheduler.pause(); + } + + @Override + public void unpause() { + myLocalScheduler.unpause(); + myClusteredScheduler.unpause(); + } + @Override public void scheduleLocalJob(long theIntervalMillis, ScheduledJobDefinition theJobDefinition) { scheduleJob("local", myLocalScheduler, theIntervalMillis, theJobDefinition); diff --git a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/HapiNullScheduler.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/HapiNullScheduler.java index 349174eacfd..77c7217e850 100644 --- a/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/HapiNullScheduler.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/sched/HapiNullScheduler.java @@ -53,6 +53,16 @@ public class HapiNullScheduler implements IHapiScheduler { @Override public void logStatusForUnitTest() {} + @Override + public void pause() { + // nothing to do + } + + @Override + public void unpause() { + // nothing to do + } + @Override public void scheduleJob(long theIntervalMillis, ScheduledJobDefinition theJobDefinition) { ourLog.debug("Skipping scheduling job {} since scheduling is disabled", theJobDefinition.getId()); diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 6cf0698fa2e..d4995828336 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobInstanceUtil.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobInstanceUtil.java index c2db708638a..51698299f79 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobInstanceUtil.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JobInstanceUtil.java @@ -123,6 +123,8 @@ class JobInstanceUtil { retVal.setErrorMessage(theEntity.getErrorMessage()); retVal.setErrorCount(theEntity.getErrorCount()); retVal.setRecordsProcessed(theEntity.getRecordsProcessed()); + retVal.setNextPollTime(theEntity.getNextPollTime()); + retVal.setPollAttempts(theEntity.getPollAttempts()); // note: may be null out if queried NoData retVal.setData(theEntity.getSerializedData()); retVal.setWarningMessage(theEntity.getWarningMessage()); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java index 056a546b5c9..f73a88570f3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaBatch2Config.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.batch2.config.BaseBatch2Config; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.jpa.bulk.export.job.BulkExportJobConfig; import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; +import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkMetadataViewRepository; import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import jakarta.persistence.EntityManager; @@ -39,12 +40,14 @@ public class JpaBatch2Config extends BaseBatch2Config { public IJobPersistence batch2JobInstancePersister( IBatch2JobInstanceRepository theJobInstanceRepository, IBatch2WorkChunkRepository theWorkChunkRepository, + IBatch2WorkChunkMetadataViewRepository theWorkChunkMetadataViewRepo, IHapiTransactionService theTransactionService, EntityManager theEntityManager, IInterceptorBroadcaster theInterceptorBroadcaster) { return new JpaJobPersistenceImpl( theJobInstanceRepository, theWorkChunkRepository, + theWorkChunkMetadataViewRepo, theTransactionService, theEntityManager, theInterceptorBroadcaster); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java index 48140f8477c..5ea89d2adb4 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java @@ -28,16 +28,19 @@ import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent; import ca.uhn.fhir.batch2.model.WorkChunkCreateEvent; import ca.uhn.fhir.batch2.model.WorkChunkErrorEvent; +import ca.uhn.fhir.batch2.model.WorkChunkMetadata; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import ca.uhn.fhir.batch2.models.JobInstanceFetchRequest; 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.jpa.dao.data.IBatch2JobInstanceRepository; +import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkMetadataViewRepository; import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity; import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity; +import ca.uhn.fhir.jpa.entity.Batch2WorkChunkMetadataView; import ca.uhn.fhir.model.api.PagingIterator; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; @@ -64,7 +67,10 @@ import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.support.TransactionSynchronizationManager; +import java.time.Instant; +import java.util.Collections; import java.util.Date; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -85,6 +91,7 @@ public class JpaJobPersistenceImpl implements IJobPersistence { private final IBatch2JobInstanceRepository myJobInstanceRepository; private final IBatch2WorkChunkRepository myWorkChunkRepository; + private final IBatch2WorkChunkMetadataViewRepository myWorkChunkMetadataViewRepo; private final EntityManager myEntityManager; private final IHapiTransactionService myTransactionService; private final IInterceptorBroadcaster myInterceptorBroadcaster; @@ -95,13 +102,15 @@ public class JpaJobPersistenceImpl implements IJobPersistence { public JpaJobPersistenceImpl( IBatch2JobInstanceRepository theJobInstanceRepository, IBatch2WorkChunkRepository theWorkChunkRepository, + IBatch2WorkChunkMetadataViewRepository theWorkChunkMetadataViewRepo, IHapiTransactionService theTransactionService, EntityManager theEntityManager, IInterceptorBroadcaster theInterceptorBroadcaster) { - Validate.notNull(theJobInstanceRepository); - Validate.notNull(theWorkChunkRepository); + Validate.notNull(theJobInstanceRepository, "theJobInstanceRepository"); + Validate.notNull(theWorkChunkRepository, "theWorkChunkRepository"); myJobInstanceRepository = theJobInstanceRepository; myWorkChunkRepository = theWorkChunkRepository; + myWorkChunkMetadataViewRepo = theWorkChunkMetadataViewRepo; myTransactionService = theTransactionService; myEntityManager = theEntityManager; myInterceptorBroadcaster = theInterceptorBroadcaster; @@ -120,23 +129,46 @@ public class JpaJobPersistenceImpl implements IJobPersistence { entity.setSerializedData(theBatchWorkChunk.serializedData); entity.setCreateTime(new Date()); entity.setStartTime(new Date()); - entity.setStatus(WorkChunkStatusEnum.QUEUED); + entity.setStatus(getOnCreateStatus(theBatchWorkChunk)); + ourLog.debug("Create work chunk {}/{}/{}", entity.getInstanceId(), entity.getId(), entity.getTargetStepId()); ourLog.trace( "Create work chunk data {}/{}: {}", entity.getInstanceId(), entity.getId(), entity.getSerializedData()); myTransactionService.withSystemRequestOnDefaultPartition().execute(() -> myWorkChunkRepository.save(entity)); + return entity.getId(); } + /** + * Gets the initial onCreate state for the given workchunk. + * Gated job chunks start in GATE_WAITING; they will be transitioned to READY during maintenance pass when all + * chunks in the previous step are COMPLETED. + * Non gated job chunks start in READY + */ + private static WorkChunkStatusEnum getOnCreateStatus(WorkChunkCreateEvent theBatchWorkChunk) { + if (theBatchWorkChunk.isGatedExecution) { + return WorkChunkStatusEnum.GATE_WAITING; + } else { + return WorkChunkStatusEnum.READY; + } + } + @Override @Transactional(propagation = Propagation.REQUIRED) public Optional onWorkChunkDequeue(String theChunkId) { + // take a lock on the chunk id to ensure that the maintenance run isn't doing anything. + Batch2WorkChunkEntity chunkLock = + myEntityManager.find(Batch2WorkChunkEntity.class, theChunkId, LockModeType.PESSIMISTIC_WRITE); + // remove from the current state to avoid stale data. + myEntityManager.detach(chunkLock); + // NOTE: Ideally, IN_PROGRESS wouldn't be allowed here. On chunk failure, we probably shouldn't be allowed. // But how does re-run happen if k8s kills a processor mid run? List priorStates = List.of(WorkChunkStatusEnum.QUEUED, WorkChunkStatusEnum.ERRORED, WorkChunkStatusEnum.IN_PROGRESS); int rowsModified = myWorkChunkRepository.updateChunkStatusForStart( theChunkId, new Date(), WorkChunkStatusEnum.IN_PROGRESS, priorStates); + if (rowsModified == 0) { ourLog.info("Attempting to start chunk {} but it was already started.", theChunkId); return Optional.empty(); @@ -288,6 +320,22 @@ public class JpaJobPersistenceImpl implements IJobPersistence { .collect(Collectors.toList())); } + @Override + public void enqueueWorkChunkForProcessing(String theChunkId, Consumer theCallback) { + int updated = myWorkChunkRepository.updateChunkStatus( + theChunkId, WorkChunkStatusEnum.READY, WorkChunkStatusEnum.QUEUED); + theCallback.accept(updated); + } + + @Override + public int updatePollWaitingChunksForJobIfReady(String theInstanceId) { + return myWorkChunkRepository.updateWorkChunksForPollWaiting( + theInstanceId, + Date.from(Instant.now()), + Set.of(WorkChunkStatusEnum.POLL_WAITING), + WorkChunkStatusEnum.READY); + } + @Override @Transactional(propagation = Propagation.REQUIRES_NEW) public List fetchRecentInstances(int thePageSize, int thePageIndex) { @@ -333,6 +381,16 @@ public class JpaJobPersistenceImpl implements IJobPersistence { }); } + @Override + public void onWorkChunkPollDelay(String theChunkId, Date theDeadline) { + int updated = myWorkChunkRepository.updateWorkChunkNextPollTime( + theChunkId, WorkChunkStatusEnum.POLL_WAITING, Set.of(WorkChunkStatusEnum.IN_PROGRESS), theDeadline); + + if (updated != 1) { + ourLog.warn("Expected to update 1 work chunk's poll delay; but found {}", updated); + } + } + @Override public void onWorkChunkFailed(String theChunkId, String theErrorMessage) { ourLog.info("Marking chunk {} as failed with message: {}", theChunkId, theErrorMessage); @@ -383,24 +441,23 @@ public class JpaJobPersistenceImpl implements IJobPersistence { } @Override - @Transactional(propagation = Propagation.REQUIRES_NEW) - public boolean canAdvanceInstanceToNextStep(String theInstanceId, String theCurrentStepId) { + public Set getDistinctWorkChunkStatesForJobAndStep( + String theInstanceId, String theCurrentStepId) { + if (getRunningJob(theInstanceId) == null) { + return Collections.unmodifiableSet(new HashSet<>()); + } + return myWorkChunkRepository.getDistinctStatusesForStep(theInstanceId, theCurrentStepId); + } + + private Batch2JobInstanceEntity getRunningJob(String theInstanceId) { Optional instance = myJobInstanceRepository.findById(theInstanceId); if (instance.isEmpty()) { - return false; + return null; } if (instance.get().getStatus().isEnded()) { - return false; + return null; } - Set statusesForStep = - myWorkChunkRepository.getDistinctStatusesForStep(theInstanceId, theCurrentStepId); - - ourLog.debug( - "Checking whether gated job can advanced to next step. [instanceId={}, currentStepId={}, statusesForStep={}]", - theInstanceId, - theCurrentStepId, - statusesForStep); - return statusesForStep.isEmpty() || statusesForStep.equals(Set.of(WorkChunkStatusEnum.COMPLETED)); + return instance.get(); } private void fetchChunks( @@ -428,18 +485,16 @@ public class JpaJobPersistenceImpl implements IJobPersistence { } @Override - public List fetchAllChunkIdsForStepWithStatus( - String theInstanceId, String theStepId, WorkChunkStatusEnum theStatusEnum) { - return myTransactionService - .withSystemRequest() - .withPropagation(Propagation.REQUIRES_NEW) - .execute(() -> myWorkChunkRepository.fetchAllChunkIdsForStepWithStatus( - theInstanceId, theStepId, theStatusEnum)); + public void updateInstanceUpdateTime(String theInstanceId) { + myJobInstanceRepository.updateInstanceUpdateTime(theInstanceId, new Date()); } @Override - public void updateInstanceUpdateTime(String theInstanceId) { - myJobInstanceRepository.updateInstanceUpdateTime(theInstanceId, new Date()); + public WorkChunk createWorkChunk(WorkChunk theWorkChunk) { + if (theWorkChunk.getId() == null) { + theWorkChunk.setId(UUID.randomUUID().toString()); + } + return toChunk(myWorkChunkRepository.save(Batch2WorkChunkEntity.fromWorkChunk(theWorkChunk))); } /** @@ -458,6 +513,15 @@ public class JpaJobPersistenceImpl implements IJobPersistence { .map(this::toChunk); } + @Override + public Page fetchAllWorkChunkMetadataForJobInStates( + Pageable thePageable, String theInstanceId, Set theStates) { + Page page = + myWorkChunkMetadataViewRepo.fetchWorkChunkMetadataForJobInStates(thePageable, theInstanceId, theStates); + + return page.map(Batch2WorkChunkMetadataView::toChunkMetadata); + } + @Override public boolean updateInstance(String theInstanceId, JobInstanceUpdateCallback theModifier) { Batch2JobInstanceEntity instanceEntity = @@ -542,4 +606,45 @@ public class JpaJobPersistenceImpl implements IJobPersistence { myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_BATCH_JOB_CREATE, params); } } + + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public boolean advanceJobStepAndUpdateChunkStatus( + String theJobInstanceId, String theNextStepId, boolean theIsReductionStep) { + boolean changed = updateInstance(theJobInstanceId, instance -> { + if (instance.getCurrentGatedStepId().equals(theNextStepId)) { + // someone else beat us here. No changes + return false; + } + ourLog.debug("Moving gated instance {} to the next step {}.", theJobInstanceId, theNextStepId); + instance.setCurrentGatedStepId(theNextStepId); + return true; + }); + + if (changed) { + ourLog.debug( + "Updating chunk status from GATE_WAITING to READY for gated instance {} in step {}.", + theJobInstanceId, + theNextStepId); + WorkChunkStatusEnum nextStep = + theIsReductionStep ? WorkChunkStatusEnum.REDUCTION_READY : WorkChunkStatusEnum.READY; + // when we reach here, the current step id is equal to theNextStepId + // Up to 7.1, gated jobs' work chunks are created in status QUEUED but not actually queued for the + // workers. + // In order to keep them compatible, turn QUEUED chunks into READY, too. + // TODO: 'QUEUED' from the IN clause will be removed after 7.6.0. + int numChanged = myWorkChunkRepository.updateAllChunksForStepWithStatus( + theJobInstanceId, + theNextStepId, + List.of(WorkChunkStatusEnum.GATE_WAITING, WorkChunkStatusEnum.QUEUED), + nextStep); + ourLog.debug( + "Updated {} chunks of gated instance {} for step {} from fake QUEUED to READY.", + numChanged, + theJobInstanceId, + theNextStepId); + } + + return changed; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkMetadataViewRepository.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkMetadataViewRepository.java new file mode 100644 index 00000000000..2c759143ef6 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IBatch2WorkChunkMetadataViewRepository.java @@ -0,0 +1,21 @@ +package ca.uhn.fhir.jpa.dao.data; + +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import ca.uhn.fhir.jpa.entity.Batch2WorkChunkMetadataView; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; + +import java.util.Collection; + +public interface IBatch2WorkChunkMetadataViewRepository extends JpaRepository { + + @Query("SELECT v FROM Batch2WorkChunkMetadataView v WHERE v.myInstanceId = :instanceId AND v.myStatus IN :states " + + " ORDER BY v.myInstanceId, v.myTargetStepId, v.myStatus, v.mySequence, v.myId ASC") + Page fetchWorkChunkMetadataForJobInStates( + Pageable thePageRequest, + @Param("instanceId") String theInstanceId, + @Param("states") Collection theStates); +} 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 053fc35f89e..0dc9243290e 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 @@ -49,7 +49,8 @@ public interface IBatch2WorkChunkRepository @Query("SELECT new Batch2WorkChunkEntity(" + "e.myId, e.mySequence, e.myJobDefinitionId, e.myJobDefinitionVersion, e.myInstanceId, e.myTargetStepId, e.myStatus," + "e.myCreateTime, e.myStartTime, e.myUpdateTime, e.myEndTime," - + "e.myErrorMessage, e.myErrorCount, e.myRecordsProcessed, e.myWarningMessage" + + "e.myErrorMessage, e.myErrorCount, e.myRecordsProcessed, e.myWarningMessage," + + "e.myNextPollTime, e.myPollAttempts" + ") FROM Batch2WorkChunkEntity e WHERE e.myInstanceId = :instanceId ORDER BY e.mySequence ASC, e.myId ASC") List fetchChunksNoData(Pageable thePageRequest, @Param("instanceId") String theInstanceId); @@ -75,6 +76,24 @@ public interface IBatch2WorkChunkRepository @Param("status") WorkChunkStatusEnum theInProgress, @Param("warningMessage") String theWarningMessage); + @Modifying + @Query( + "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myNextPollTime = :nextPollTime, e.myPollAttempts = e.myPollAttempts + 1 WHERE e.myId = :id AND e.myStatus IN(:states)") + int updateWorkChunkNextPollTime( + @Param("id") String theChunkId, + @Param("status") WorkChunkStatusEnum theStatus, + @Param("states") Set theInitialStates, + @Param("nextPollTime") Date theNextPollTime); + + @Modifying + @Query( + "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myNextPollTime = null WHERE e.myInstanceId = :instanceId AND e.myStatus IN(:states) AND e.myNextPollTime <= :pollTime") + int updateWorkChunksForPollWaiting( + @Param("instanceId") String theInstanceId, + @Param("pollTime") Date theTime, + @Param("states") Set theInitialStates, + @Param("status") WorkChunkStatusEnum theNewStatus); + @Modifying @Query( "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :status, e.myEndTime = :et, e.mySerializedData = null, e.mySerializedDataVc = null, e.myErrorMessage = :em WHERE e.myId IN(:ids)") @@ -102,6 +121,22 @@ public interface IBatch2WorkChunkRepository @Param("status") WorkChunkStatusEnum theInProgress, @Param("startStatuses") Collection theStartStatuses); + @Modifying + @Query("UPDATE Batch2WorkChunkEntity e SET e.myStatus = :newStatus WHERE e.myId = :id AND e.myStatus = :oldStatus") + int updateChunkStatus( + @Param("id") String theChunkId, + @Param("oldStatus") WorkChunkStatusEnum theOldStatus, + @Param("newStatus") WorkChunkStatusEnum theNewStatus); + + @Modifying + @Query( + "UPDATE Batch2WorkChunkEntity e SET e.myStatus = :newStatus WHERE e.myInstanceId = :instanceId AND e.myTargetStepId = :stepId AND e.myStatus IN ( :oldStatuses )") + int updateAllChunksForStepWithStatus( + @Param("instanceId") String theInstanceId, + @Param("stepId") String theStepId, + @Param("oldStatuses") List theOldStatuses, + @Param("newStatus") WorkChunkStatusEnum theNewStatus); + @Modifying @Query("DELETE FROM Batch2WorkChunkEntity e WHERE e.myInstanceId = :instanceId") int deleteAllForInstance(@Param("instanceId") String theInstanceId); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java index 42281ac475f..ff34c74b6fd 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkEntity.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.jpa.entity; +import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import jakarta.persistence.Basic; import jakarta.persistence.Column; @@ -50,7 +51,10 @@ import static org.apache.commons.lang3.StringUtils.left; @Entity @Table( name = "BT2_WORK_CHUNK", - indexes = {@Index(name = "IDX_BT2WC_II_SEQ", columnList = "INSTANCE_ID,SEQ")}) + indexes = { + @Index(name = "IDX_BT2WC_II_SEQ", columnList = "INSTANCE_ID,SEQ"), + @Index(name = "IDX_BT2WC_II_SI_S_SEQ_ID", columnList = "INSTANCE_ID,TGT_STEP_ID,STAT,SEQ,ID") + }) public class Batch2WorkChunkEntity implements Serializable { public static final int ERROR_MSG_MAX_LENGTH = 500; @@ -125,6 +129,19 @@ public class Batch2WorkChunkEntity implements Serializable { @Column(name = "WARNING_MSG", length = WARNING_MSG_MAX_LENGTH, nullable = true) private String myWarningMessage; + /** + * The next time the work chunk can attempt to rerun its work step. + */ + @Column(name = "NEXT_POLL_TIME", nullable = true) + @Temporal(TemporalType.TIMESTAMP) + private Date myNextPollTime; + + /** + * The number of times the work chunk has had its state set back to POLL_WAITING. + */ + @Column(name = "POLL_ATTEMPTS", nullable = true) + private int myPollAttempts; + /** * Default constructor for Hibernate. */ @@ -148,7 +165,9 @@ public class Batch2WorkChunkEntity implements Serializable { String theErrorMessage, int theErrorCount, Integer theRecordsProcessed, - String theWarningMessage) { + String theWarningMessage, + Date theNextPollTime, + Integer thePollAttempts) { myId = theId; mySequence = theSequence; myJobDefinitionId = theJobDefinitionId; @@ -164,6 +183,32 @@ public class Batch2WorkChunkEntity implements Serializable { myErrorCount = theErrorCount; myRecordsProcessed = theRecordsProcessed; myWarningMessage = theWarningMessage; + myNextPollTime = theNextPollTime; + myPollAttempts = thePollAttempts; + } + + public static Batch2WorkChunkEntity fromWorkChunk(WorkChunk theWorkChunk) { + Batch2WorkChunkEntity entity = new Batch2WorkChunkEntity( + theWorkChunk.getId(), + theWorkChunk.getSequence(), + theWorkChunk.getJobDefinitionId(), + theWorkChunk.getJobDefinitionVersion(), + theWorkChunk.getInstanceId(), + theWorkChunk.getTargetStepId(), + theWorkChunk.getStatus(), + theWorkChunk.getCreateTime(), + theWorkChunk.getStartTime(), + theWorkChunk.getUpdateTime(), + theWorkChunk.getEndTime(), + theWorkChunk.getErrorMessage(), + theWorkChunk.getErrorCount(), + theWorkChunk.getRecordsProcessed(), + theWorkChunk.getWarningMessage(), + theWorkChunk.getNextPollTime(), + theWorkChunk.getPollAttempts()); + entity.setSerializedData(theWorkChunk.getData()); + + return entity; } public int getErrorCount() { @@ -299,6 +344,22 @@ public class Batch2WorkChunkEntity implements Serializable { myInstanceId = theInstanceId; } + public Date getNextPollTime() { + return myNextPollTime; + } + + public void setNextPollTime(Date theNextPollTime) { + myNextPollTime = theNextPollTime; + } + + public int getPollAttempts() { + return myPollAttempts; + } + + public void setPollAttempts(int thePollAttempts) { + myPollAttempts = thePollAttempts; + } + @Override public String toString() { return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) @@ -318,6 +379,8 @@ public class Batch2WorkChunkEntity implements Serializable { .append("status", myStatus) .append("errorMessage", myErrorMessage) .append("warningMessage", myWarningMessage) + .append("nextPollTime", myNextPollTime) + .append("pollAttempts", myPollAttempts) .toString(); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkMetadataView.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkMetadataView.java new file mode 100644 index 00000000000..4034a13f7cd --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/Batch2WorkChunkMetadataView.java @@ -0,0 +1,123 @@ +package ca.uhn.fhir.jpa.entity; + +import ca.uhn.fhir.batch2.model.WorkChunkMetadata; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import org.hibernate.annotations.Immutable; +import org.hibernate.annotations.Subselect; + +import java.io.Serializable; + +import static ca.uhn.fhir.batch2.model.JobDefinition.ID_MAX_LENGTH; + +/** + * A view for a Work Chunk that contains only the most necessary information + * to satisfy the no-data path. + */ +@Entity +@Immutable +@Subselect("SELECT e.id as id, " + + " e.seq as seq," + + " e.stat as state, " + + " e.instance_id as instance_id, " + + " e.definition_id as job_definition_id, " + + " e.definition_ver as job_definition_version, " + + " e.tgt_step_id as target_step_id " + + "FROM BT2_WORK_CHUNK e") +public class Batch2WorkChunkMetadataView implements Serializable { + + @Id + @Column(name = "ID", length = ID_MAX_LENGTH) + private String myId; + + @Column(name = "SEQ", nullable = false) + private int mySequence; + + @Column(name = "STATE", length = ID_MAX_LENGTH, nullable = false) + @Enumerated(EnumType.STRING) + private WorkChunkStatusEnum myStatus; + + @Column(name = "INSTANCE_ID", length = ID_MAX_LENGTH, nullable = false) + private String myInstanceId; + + @Column(name = "JOB_DEFINITION_ID", length = ID_MAX_LENGTH, nullable = false) + private String myJobDefinitionId; + + @Column(name = "JOB_DEFINITION_VERSION", nullable = false) + private int myJobDefinitionVersion; + + @Column(name = "TARGET_STEP_ID", length = ID_MAX_LENGTH, nullable = false) + private String myTargetStepId; + + public String getId() { + return myId; + } + + public void setId(String theId) { + myId = theId; + } + + public int getSequence() { + return mySequence; + } + + public void setSequence(int theSequence) { + mySequence = theSequence; + } + + public WorkChunkStatusEnum getStatus() { + return myStatus; + } + + public void setStatus(WorkChunkStatusEnum theStatus) { + myStatus = theStatus; + } + + public String getInstanceId() { + return myInstanceId; + } + + public void setInstanceId(String theInstanceId) { + myInstanceId = theInstanceId; + } + + public String getJobDefinitionId() { + return myJobDefinitionId; + } + + public void setJobDefinitionId(String theJobDefinitionId) { + myJobDefinitionId = theJobDefinitionId; + } + + public int getJobDefinitionVersion() { + return myJobDefinitionVersion; + } + + public void setJobDefinitionVersion(int theJobDefinitionVersion) { + myJobDefinitionVersion = theJobDefinitionVersion; + } + + public String getTargetStepId() { + return myTargetStepId; + } + + public void setTargetStepId(String theTargetStepId) { + myTargetStepId = theTargetStepId; + } + + public WorkChunkMetadata toChunkMetadata() { + WorkChunkMetadata metadata = new WorkChunkMetadata(); + metadata.setId(getId()); + metadata.setInstanceId(getInstanceId()); + metadata.setSequence(getSequence()); + metadata.setStatus(getStatus()); + metadata.setJobDefinitionId(getJobDefinitionId()); + metadata.setJobDefinitionVersion(getJobDefinitionVersion()); + metadata.setTargetStepId(getTargetStepId()); + return metadata; + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 86e27081679..3c421278e10 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -293,6 +293,23 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { // This fix will work for MSSQL or Oracle. version.addTask(new ForceIdMigrationFixTask(version.getRelease(), "20231222.1")); + + // add index to Batch2WorkChunkEntity + Builder.BuilderWithTableName workChunkTable = version.onTable("BT2_WORK_CHUNK"); + + workChunkTable + .addIndex("20240321.1", "IDX_BT2WC_II_SI_S_SEQ_ID") + .unique(false) + .withColumns("INSTANCE_ID", "TGT_STEP_ID", "STAT", "SEQ", "ID"); + + // add columns to Batch2WorkChunkEntity + Builder.BuilderWithTableName batch2WorkChunkTable = version.onTable("BT2_WORK_CHUNK"); + + batch2WorkChunkTable + .addColumn("20240322.1", "NEXT_POLL_TIME") + .nullable() + .type(ColumnTypeEnum.DATE_TIMESTAMP); + batch2WorkChunkTable.addColumn("20240322.2", "POLL_ATTEMPTS").nullable().type(ColumnTypeEnum.INT); } private void init680_Part2() { diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java index ba013f714bc..14b21559d52 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImplTest.java @@ -4,6 +4,7 @@ import ca.uhn.fhir.batch2.api.JobOperationResultJson; import ca.uhn.fhir.batch2.model.FetchJobInstancesRequest; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; @@ -31,6 +32,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/bulk/export/svc/BulkDataExportJobSchedulingHelperImplTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/bulk/export/svc/BulkDataExportJobSchedulingHelperImplTest.java index f7c90efb7c8..56e1080adab 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/bulk/export/svc/BulkDataExportJobSchedulingHelperImplTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/bulk/export/svc/BulkDataExportJobSchedulingHelperImplTest.java @@ -30,6 +30,8 @@ import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionTemplate; import jakarta.annotation.Nonnull; + +import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; import java.time.temporal.ChronoUnit; @@ -43,6 +45,7 @@ import java.util.stream.IntStream; import static org.exparity.hamcrest.date.DateMatchers.within; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; @@ -97,7 +100,17 @@ public class BulkDataExportJobSchedulingHelperImplTest { verify(myJpaJobPersistence, never()).deleteInstanceAndChunks(anyString()); final Date cutoffDate = myCutoffCaptor.getValue(); - assertEquals(DateUtils.truncate(computeDateFromConfig(expectedRetentionHours), Calendar.SECOND), DateUtils.truncate(cutoffDate, Calendar.SECOND)); + Date expectedCutoff = computeDateFromConfig(expectedRetentionHours); + verifyDatesWithinSeconds(expectedCutoff, cutoffDate, 2); + } + + private void verifyDatesWithinSeconds(Date theExpected, Date theActual, int theSeconds) { + Instant expectedInstant = theExpected.toInstant(); + Instant actualInstant = theActual.toInstant(); + + String msg = String.format("Expected time not within %d s", theSeconds); + assertTrue(expectedInstant.plus(theSeconds, ChronoUnit.SECONDS).isAfter(actualInstant), msg); + assertTrue(expectedInstant.minus(theSeconds, ChronoUnit.SECONDS).isBefore(actualInstant), msg); } @Test diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index bb2281e78d6..157c68d5c0c 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-hfql/pom.xml b/hapi-fhir-jpaserver-hfql/pom.xml index 1bdf1f4d5eb..706d5ca1335 100644 --- a/hapi-fhir-jpaserver-hfql/pom.xml +++ b/hapi-fhir-jpaserver-hfql/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml index 164b0a28831..ca914b4b1bd 100644 --- a/hapi-fhir-jpaserver-ips/pom.xml +++ b/hapi-fhir-jpaserver-ips/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index 1a7598268ab..3030cb455b6 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 2cee62cefaf..d2028f332ae 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BaseTag.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BaseTag.java index 54d2405fba3..0bf655a77ae 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BaseTag.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BaseTag.java @@ -31,6 +31,7 @@ public abstract class BaseTag extends BasePartitionable implements Serializable private static final long serialVersionUID = 1L; + // many baseTags -> one tag definition @ManyToOne(cascade = {}) @JoinColumn(name = "TAG_ID", nullable = false) private TagDefinition myTag; diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java index fe3868c8313..ad4e6309508 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/TagDefinition.java @@ -67,12 +67,14 @@ public class TagDefinition implements Serializable { @Column(name = "TAG_ID") private Long myId; + // one tag definition -> many resource tags @OneToMany( cascade = {}, fetch = FetchType.LAZY, mappedBy = "myTag") private Collection myResources; + // one tag definition -> many history @OneToMany( cascade = {}, fetch = FetchType.LAZY, diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index f0e7c3a6b94..87f9dd268b2 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index a79817e0242..e608341ec73 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriberTest.java b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriberTest.java index 1c0dcd424e5..3581da0a156 100644 --- a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriberTest.java +++ b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/module/subscriber/SubscriptionMatchingSubscriberTest.java @@ -505,7 +505,7 @@ public class SubscriptionMatchingSubscriberTest extends BaseBlockingQueueSubscri subscriber.matchActiveSubscriptionsAndDeliver(message); - verify(myCanonicalSubscription, atLeastOnce()).getSendDeleteMessages(); + verify(myCanonicalSubscription).getSendDeleteMessages(); } @Test diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index a95f7d93414..ccc242c944d 100644 --- a/hapi-fhir-jpaserver-test-dstu2/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java index 1d0902574bf..c27ecc6bc2d 100644 --- a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java +++ b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2Test.java @@ -2209,28 +2209,28 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test { p.addName().addFamily(methodName); IIdType id1 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); p = new Patient(); p.addIdentifier().setSystem("urn:system2").setValue(methodName); p.addName().addFamily(methodName); IIdType id2 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); p = new Patient(); p.addIdentifier().setSystem("urn:system3").setValue(methodName); p.addName().addFamily(methodName); IIdType id3 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); p = new Patient(); p.addIdentifier().setSystem("urn:system4").setValue(methodName); p.addName().addFamily(methodName); IIdType id4 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); SearchParameterMap pm; List actual; diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index c94281fbf8f..bb969873766 100644 --- a/hapi-fhir-jpaserver-test-dstu3/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index a9b47640828..cc21ea5b56e 100644 --- a/hapi-fhir-jpaserver-test-r4/pom.xml +++ b/hapi-fhir-jpaserver-test-r4/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java index 2e304e08373..f09f823f7a5 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2CoordinatorIT.java @@ -10,6 +10,7 @@ import ca.uhn.fhir.batch2.api.IJobStepWorker; import ca.uhn.fhir.batch2.api.ILastJobStepWorker; import ca.uhn.fhir.batch2.api.IReductionStepWorker; import ca.uhn.fhir.batch2.api.JobExecutionFailedException; +import ca.uhn.fhir.batch2.api.RetryChunkLaterException; import ca.uhn.fhir.batch2.api.RunOutcome; import ca.uhn.fhir.batch2.api.StepExecutionDetails; import ca.uhn.fhir.batch2.api.VoidModel; @@ -27,15 +28,20 @@ import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory; import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.Batch2JobHelper; +import ca.uhn.fhir.jpa.test.config.Batch2FastSchedulerConfig; +import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.model.api.IModelJson; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor; import ca.uhn.fhir.util.JsonUtil; import ca.uhn.test.concurrency.PointcutLatch; +import ca.uhn.test.util.LogbackCaptureTestExtension; import com.fasterxml.jackson.annotation.JsonProperty; import jakarta.annotation.Nonnull; 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.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; @@ -43,11 +49,21 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Page; import org.springframework.data.domain.Sort; +import org.springframework.messaging.MessageHandler; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.TestPropertySource; +import org.testcontainers.shaded.org.awaitility.Awaitility; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.ArrayList; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; @@ -60,6 +76,13 @@ import static org.junit.jupiter.api.Assertions.assertSame; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +@ContextConfiguration(classes = { + Batch2FastSchedulerConfig.class +}) +@TestPropertySource(properties = { + // These tests require scheduling to work + UnregisterScheduledProcessor.SCHEDULING_DISABLED_EQUALS_FALSE +}) public class Batch2CoordinatorIT extends BaseJpaR4Test { private static final Logger ourLog = LoggerFactory.getLogger(Batch2CoordinatorIT.class); @@ -81,6 +104,9 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @Autowired IJobPersistence myJobPersistence; + @RegisterExtension + LogbackCaptureTestExtension myLogbackCaptureTestExtension = new LogbackCaptureTestExtension(); + private final PointcutLatch myFirstStepLatch = new PointcutLatch("First Step"); private final PointcutLatch myLastStepLatch = new PointcutLatch("Last Step"); private IJobCompletionHandler myCompletionHandler; @@ -91,6 +117,10 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { return RunOutcome.SUCCESS; } + static { + TestR4Config.ourMaxThreads = 100; + } + @Override @BeforeEach public void before() throws Exception { @@ -117,7 +147,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { // final step ILastJobStepWorker last = (step, sink) -> RunOutcome.SUCCESS; // job definition - String jobId = new Exception().getStackTrace()[0].getMethodName(); + String jobId = getMethodNameForJobId(); JobDefinition jd = JobDefinition.newBuilder() .setJobDefinitionId(jobId) .setJobDescription("test job") @@ -183,7 +213,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { IJobStepWorker firstStep = (step, sink) -> callLatch(myFirstStepLatch, step); IJobStepWorker lastStep = (step, sink) -> fail(); - String jobId = new Exception().getStackTrace()[0].getMethodName(); + String jobId = getMethodNameForJobId(); JobDefinition definition = buildGatedJobDefinition(jobId, firstStep, lastStep); myJobDefinitionRegistry.addJobDefinition(definition); @@ -192,6 +222,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myFirstStepLatch.setExpectedCount(1); Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); + myBatch2JobHelper.runMaintenancePass(); myFirstStepLatch.awaitExpected(); myBatch2JobHelper.awaitJobCompletion(startResponse.getInstanceId()); @@ -216,11 +247,10 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myFirstStepLatch.setExpectedCount(1); myLastStepLatch.setExpectedCount(1); String batchJobId = myJobCoordinator.startInstance(new SystemRequestDetails(), request).getInstanceId(); + myBatch2JobHelper.runMaintenancePass(); myFirstStepLatch.awaitExpected(); - myBatch2JobHelper.assertFastTracking(batchJobId); - // Since there was only one chunk, the job should proceed without requiring a maintenance pass myBatch2JobHelper.awaitJobCompletion(batchJobId); myLastStepLatch.awaitExpected(); @@ -234,10 +264,92 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { assertEquals(1.0, jobInstance.getProgress()); } + /** + * This test verifies that if we have a workchunks being processed by the queue, + * and the maintenance job kicks in, it won't necessarily advance the steps. + */ @Test - public void reductionStepFailing_willFailJob() throws InterruptedException { + public void gatedJob_whenMaintenanceRunHappensDuringMsgProcessing_doesNotAdvance() throws InterruptedException { // setup - String jobId = new Exception().getStackTrace()[0].getMethodName(); + // we disable the scheduler because multiple schedulers running simultaneously + // might cause database collisions we do not expect (not what we're testing) + myBatch2JobHelper.enableMaintenanceRunner(false); + String jobId = getMethodNameForJobId(); + int chunksToMake = 5; + AtomicInteger secondGateCounter = new AtomicInteger(); + AtomicBoolean reductionCheck = new AtomicBoolean(false); + // we will listen into the message queue so we can force actions on it + MessageHandler handler = message -> { + /* + * We will force a run of the maintenance job + * to simulate the situation in which a chunk is + * still being processed by the WorkChunkMessageHandler + * (and thus, not available yet). + */ + myBatch2JobHelper.forceRunMaintenancePass(); + }; + + buildAndDefine3StepReductionJob(jobId, new IReductionStepHandler() { + + @Override + public void firstStep(StepExecutionDetails theStep, IJobDataSink theDataSink) { + for (int i = 0; i < chunksToMake; i++) { + theDataSink.accept(new FirstStepOutput()); + } + } + + @Override + public void secondStep(StepExecutionDetails theStep, IJobDataSink theDataSink) { + // no new chunks + SecondStepOutput output = new SecondStepOutput(); + theDataSink.accept(output); + } + + @Override + public void reductionStepConsume(ChunkExecutionDetails theChunkDetails, IJobDataSink theDataSink) { + // we expect to get one here + int val = secondGateCounter.getAndIncrement(); + } + + @Override + public void reductionStepRun(StepExecutionDetails theStepExecutionDetails, IJobDataSink theDataSink) { + reductionCheck.set(true); + theDataSink.accept(new ReductionStepOutput(new ArrayList<>())); + } + }); + + try { + myWorkChannel.subscribe(handler); + + // test + JobInstanceStartRequest request = buildRequest(jobId); + myFirstStepLatch.setExpectedCount(1); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); + + String instanceId = startResponse.getInstanceId(); + + // wait + myBatch2JobHelper.awaitJobCompletion(instanceId); + + // verify + Optional instanceOp = myJobPersistence.fetchInstance(instanceId); + assertTrue(instanceOp.isPresent()); + JobInstance jobInstance = instanceOp.get(); + assertTrue(reductionCheck.get()); + assertEquals(chunksToMake, secondGateCounter.get()); + + assertEquals(StatusEnum.COMPLETED, jobInstance.getStatus()); + assertEquals(1.0, jobInstance.getProgress()); + } finally { + myWorkChannel.unsubscribe(handler); + myBatch2JobHelper.enableMaintenanceRunner(true); + } + } + + @Test + public void reductionStepFailing_willFailJob() { + // setup + String jobId = getMethodNameForJobId(); int totalChunks = 3; AtomicInteger chunkCounter = new AtomicInteger(); String error = "this is an error"; @@ -292,22 +404,17 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @Test public void testJobWithReductionStepFiresCompletionHandler() throws InterruptedException { // setup - String jobId = new Exception().getStackTrace()[0].getMethodName(); + String jobId = getMethodNameForJobId(); String testInfo = "test"; int totalCalls = 2; AtomicInteger secondStepInt = new AtomicInteger(); AtomicBoolean completionBool = new AtomicBoolean(); - AtomicBoolean jobStatusBool = new AtomicBoolean(); - myCompletionHandler = (params) -> { - // ensure our completion handler fires + // ensure our completion handler gets the right status + assertEquals(StatusEnum.COMPLETED, params.getInstance().getStatus()); completionBool.getAndSet(true); - - if (StatusEnum.COMPLETED.equals(params.getInstance().getStatus())){ - jobStatusBool.getAndSet(true); - } }; buildAndDefine3StepReductionJob(jobId, new IReductionStepHandler() { @@ -351,10 +458,11 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); String instanceId = startResponse.getInstanceId(); + myBatch2JobHelper.runMaintenancePass(); myFirstStepLatch.awaitExpected(); assertNotNull(instanceId); - myBatch2JobHelper.awaitGatedStepId(FIRST_STEP_ID, instanceId); + myBatch2JobHelper.awaitGatedStepId(SECOND_STEP_ID, instanceId); // wait for last step to finish ourLog.info("Setting last step latch"); @@ -362,17 +470,16 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { // waiting myBatch2JobHelper.awaitJobCompletion(instanceId); - myLastStepLatch.awaitExpected(); ourLog.info("awaited the last step"); + myLastStepLatch.awaitExpected(); // verify Optional instanceOp = myJobPersistence.fetchInstance(instanceId); assertTrue(instanceOp.isPresent()); JobInstance jobInstance = instanceOp.get(); - // ensure our completion handler fires with the up-to-date job instance + // ensure our completion handler fired assertTrue(completionBool.get()); - assertTrue(jobStatusBool.get()); assertEquals(StatusEnum.COMPLETED, jobInstance.getStatus()); assertEquals(1.0, jobInstance.getProgress()); @@ -382,7 +489,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @ValueSource(booleans = {true, false}) public void testJobDefinitionWithReductionStepIT(boolean theDelayReductionStepBool) throws InterruptedException { // setup - String jobId = new Exception().getStackTrace()[0].getMethodName() + "_" + theDelayReductionStepBool; + String jobId = getMethodNameForJobId() + "_" + theDelayReductionStepBool; String testInfo = "test"; AtomicInteger secondStepInt = new AtomicInteger(); @@ -441,12 +548,12 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { JobInstanceStartRequest request = buildRequest(jobId); myFirstStepLatch.setExpectedCount(1); Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); - String instanceId = startResponse.getInstanceId(); + myBatch2JobHelper.runMaintenancePass(); myFirstStepLatch.awaitExpected(); assertNotNull(instanceId); - myBatch2JobHelper.awaitGatedStepId(FIRST_STEP_ID, instanceId); + myBatch2JobHelper.awaitGatedStepId(SECOND_STEP_ID, instanceId); // wait for last step to finish ourLog.info("Setting last step latch"); @@ -482,6 +589,95 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { assertEquals(1.0, jobInstance.getProgress()); } + @Test + public void testJobWithLongPollingStep() throws InterruptedException { + // create job definition + int callsToMake = 3; + int chunksToAwait = 2; + String jobId = getMethodNameForJobId(); + + ConcurrentHashMap chunkToCounter = new ConcurrentHashMap<>(); + HashMap chunkToCallsToMake = new HashMap<>(); + IJobStepWorker first = (step, sink) -> { + for (int i = 0; i < chunksToAwait; i++) { + String cv = "chunk" + i; + chunkToCallsToMake.put(cv, callsToMake); + sink.accept(new FirstStepOutput().setValue(cv)); + } + return RunOutcome.SUCCESS; + }; + + // step 2 + IJobStepWorker second = (step, sink) -> { + // simulate a call + Awaitility.await().atMost(100, TimeUnit.MICROSECONDS); + + // we use Batch2FastSchedulerConfig, so we have a fast scheduler + // that should catch and call repeatedly pretty quickly + String chunkValue = step.getData().myTestValue; + AtomicInteger pollCounter = chunkToCounter.computeIfAbsent(chunkValue, (key) -> { + return new AtomicInteger(); + }); + int count = pollCounter.getAndIncrement(); + + if (chunkToCallsToMake.get(chunkValue) <= count) { + sink.accept(new SecondStepOutput()); + return RunOutcome.SUCCESS; + } + throw new RetryChunkLaterException(Duration.of(200, ChronoUnit.MILLIS)); + }; + + // step 3 + ILastJobStepWorker last = (step, sink) -> { + myLastStepLatch.call(1); + return RunOutcome.SUCCESS; + }; + + JobDefinition jd = JobDefinition.newBuilder() + .setJobDefinitionId(jobId) + .setJobDescription("test job") + .setJobDefinitionVersion(TEST_JOB_VERSION) + .setParametersType(TestJobParameters.class) + .gatedExecution() + .addFirstStep( + FIRST_STEP_ID, + "First step", + FirstStepOutput.class, + first + ) + .addIntermediateStep(SECOND_STEP_ID, + "Second step", + SecondStepOutput.class, + second) + .addLastStep( + LAST_STEP_ID, + "Final step", + last + ) + .completionHandler(myCompletionHandler) + .build(); + myJobDefinitionRegistry.addJobDefinition(jd); + + // test + JobInstanceStartRequest request = buildRequest(jobId); + myLastStepLatch.setExpectedCount(chunksToAwait); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); + String instanceId = startResponse.getInstanceId(); + + // waiting for the job + myBatch2JobHelper.awaitJobCompletion(startResponse); + // ensure final step fired + myLastStepLatch.awaitExpected(); + + // verify + assertEquals(chunksToAwait, chunkToCounter.size()); + for (Map.Entry set : chunkToCounter.entrySet()) { + // +1 because after 0 indexing; it will make callsToMake failed calls (0, 1... callsToMake) + // and one more successful call (callsToMake + 1) + assertEquals(callsToMake + 1, set.getValue().get()); + } + } + @Test public void testFirstStepToSecondStep_doubleChunk_doesNotFastTrack() throws InterruptedException { IJobStepWorker firstStep = (step, sink) -> { @@ -491,7 +687,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { }; IJobStepWorker lastStep = (step, sink) -> callLatch(myLastStepLatch, step); - String jobDefId = new Exception().getStackTrace()[0].getMethodName(); + String jobDefId = getMethodNameForJobId(); JobDefinition definition = buildGatedJobDefinition(jobDefId, firstStep, lastStep); myJobDefinitionRegistry.addJobDefinition(definition); @@ -501,6 +697,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { myFirstStepLatch.setExpectedCount(1); Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); String instanceId = startResponse.getInstanceId(); + myBatch2JobHelper.runMaintenancePass(); myFirstStepLatch.awaitExpected(); myLastStepLatch.setExpectedCount(2); @@ -513,14 +710,14 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @Test - public void JobExecutionFailedException_CausesInstanceFailure() { + public void jobExecutionFailedException_CausesInstanceFailure() { // setup IJobStepWorker firstStep = (step, sink) -> { throw new JobExecutionFailedException("Expected Test Exception"); }; IJobStepWorker lastStep = (step, sink) -> fail(); - String jobDefId = new Exception().getStackTrace()[0].getMethodName(); + String jobDefId = getMethodNameForJobId(); JobDefinition definition = buildGatedJobDefinition(jobDefId, firstStep, lastStep); myJobDefinitionRegistry.addJobDefinition(definition); @@ -538,36 +735,47 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { @Test public void testUnknownException_KeepsInProgress_CanCancelManually() throws InterruptedException { // setup - IJobStepWorker firstStep = (step, sink) -> { - callLatch(myFirstStepLatch, step); - throw new RuntimeException("Expected Test Exception"); - }; - IJobStepWorker lastStep = (step, sink) -> fail(); - String jobDefId = new Exception().getStackTrace()[0].getMethodName(); - JobDefinition definition = buildGatedJobDefinition(jobDefId, firstStep, lastStep); + // we want to control the maintenance runner ourselves in this case + // to prevent intermittent test failures + myJobMaintenanceService.enableMaintenancePass(false); - myJobDefinitionRegistry.addJobDefinition(definition); + try { + IJobStepWorker firstStep = (step, sink) -> { + callLatch(myFirstStepLatch, step); + throw new RuntimeException("Expected Test Exception"); + }; + IJobStepWorker lastStep = (step, sink) -> fail(); - JobInstanceStartRequest request = buildRequest(jobDefId); + String jobDefId = getMethodNameForJobId(); + JobDefinition definition = buildGatedJobDefinition(jobDefId, firstStep, lastStep); - // execute - ourLog.info("Starting job"); - myFirstStepLatch.setExpectedCount(1); - Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); - String instanceId = startResponse.getInstanceId(); - myFirstStepLatch.awaitExpected(); + myJobDefinitionRegistry.addJobDefinition(definition); - // validate - myBatch2JobHelper.awaitJobInProgress(instanceId); + JobInstanceStartRequest request = buildRequest(jobDefId); - // execute - ourLog.info("Cancel job {}", instanceId); - myJobCoordinator.cancelInstance(instanceId); - ourLog.info("Cancel job {} done", instanceId); + // execute + ourLog.info("Starting job"); + myFirstStepLatch.setExpectedCount(1); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), request); + String instanceId = startResponse.getInstanceId(); + myBatch2JobHelper.forceRunMaintenancePass(); + myFirstStepLatch.awaitExpected(); - // validate - myBatch2JobHelper.awaitJobCancelled(instanceId); + // validate + myBatch2JobHelper.awaitJobHasStatusWithForcedMaintenanceRuns(instanceId, StatusEnum.IN_PROGRESS); + + // execute + ourLog.info("Cancel job {}", instanceId); + myJobCoordinator.cancelInstance(instanceId); + ourLog.info("Cancel job {} done", instanceId); + + // validate + myBatch2JobHelper.awaitJobHasStatusWithForcedMaintenanceRuns(instanceId, + StatusEnum.CANCELLED); + } finally { + myJobMaintenanceService.enableMaintenancePass(true); + } } @Test @@ -586,7 +794,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { return RunOutcome.SUCCESS; }; // job definition - String jobDefId = new Exception().getStackTrace()[0].getMethodName(); + String jobDefId = getMethodNameForJobId(); JobDefinition jd = JobDefinition.newBuilder() .setJobDefinitionId(jobDefId) .setJobDescription("test job") @@ -629,6 +837,15 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { return request; } + /** + * Returns the method name of the calling method for a unique job id. + * It is best this is called from the test method directly itself, and never + * delegate to a separate child method.s + */ + private String getMethodNameForJobId() { + return new Exception().getStackTrace()[1].getMethodName(); + } + @Nonnull private JobDefinition buildGatedJobDefinition(String theJobId, IJobStepWorker theFirstStep, IJobStepWorker theLastStep) { return JobDefinition.newBuilder() @@ -723,6 +940,7 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { ) .completionHandler(myCompletionHandler) .build(); + myJobDefinitionRegistry.removeJobDefinition(theJobId, 1); myJobDefinitionRegistry.addJobDefinition(jd); } @@ -732,8 +950,16 @@ public class Batch2CoordinatorIT extends BaseJpaR4Test { } static class FirstStepOutput implements IModelJson { + @JsonProperty("test") + private String myTestValue; + FirstStepOutput() { } + + public FirstStepOutput setValue(String theV) { + myTestValue = theV; + return this; + } } static class SecondStepOutput implements IModelJson { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobInstanceRepositoryTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobInstanceRepositoryTest.java index 1605ada7de8..01e0ab868f9 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobInstanceRepositoryTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobInstanceRepositoryTest.java @@ -1,12 +1,10 @@ package ca.uhn.fhir.jpa.batch2; import ca.uhn.fhir.batch2.model.StatusEnum; -import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.CsvSource; -import org.springframework.beans.factory.annotation.Autowired; import java.util.Arrays; import java.util.Date; @@ -18,9 +16,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public class Batch2JobInstanceRepositoryTest extends BaseJpaR4Test { - @Autowired - IBatch2JobInstanceRepository myBatch2JobInstanceRepository; - @ParameterizedTest @CsvSource({ "QUEUED, FAILED, QUEUED, true, normal transition", @@ -38,16 +33,16 @@ public class Batch2JobInstanceRepositoryTest extends BaseJpaR4Test { entity.setStatus(theCurrentState); entity.setCreateTime(new Date()); entity.setDefinitionId("definition_id"); - myBatch2JobInstanceRepository.save(entity); + myJobInstanceRepository.save(entity); // when int changeCount = runInTransaction(()-> - myBatch2JobInstanceRepository.updateInstanceStatusIfIn(jobId, theTargetState, theAllowedPriorStates)); + myJobInstanceRepository.updateInstanceStatusIfIn(jobId, theTargetState, theAllowedPriorStates)); // then Batch2JobInstanceEntity readBack = runInTransaction(() -> - myBatch2JobInstanceRepository.findById(jobId).orElseThrow()); + myJobInstanceRepository.findById(jobId).orElseThrow()); if (theExpectedSuccessFlag) { assertEquals(1, changeCount, "The change happened"); assertEquals(theTargetState, readBack.getStatus()); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceDatabaseIT.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceDatabaseIT.java index 8030e908f5a..f5143b9ffbc 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceDatabaseIT.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceDatabaseIT.java @@ -27,6 +27,7 @@ import ca.uhn.fhir.model.api.IModelJson; import ca.uhn.fhir.util.JsonUtil; import ca.uhn.test.concurrency.IPointcutLatch; import ca.uhn.test.concurrency.PointcutLatch; +import jakarta.annotation.Nonnull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; @@ -39,7 +40,6 @@ import org.springframework.messaging.MessageChannel; import org.springframework.messaging.support.ChannelInterceptor; import org.springframework.transaction.support.TransactionTemplate; -import jakarta.annotation.Nonnull; import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -358,10 +358,10 @@ public class Batch2JobMaintenanceDatabaseIT extends BaseJpaR4Test { WorkChunkExpectation expectation = new WorkChunkExpectation( """ -chunk1, FIRST, COMPLETED -chunk2, SECOND, QUEUED -chunk3, LAST, QUEUED -""", + chunk1, FIRST, COMPLETED + chunk2, SECOND, QUEUED + chunk3, LAST, QUEUED + """, "" ); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceIT.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceIT.java index 6f989437e6e..c39c72f609c 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceIT.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/Batch2JobMaintenanceIT.java @@ -11,17 +11,26 @@ import ca.uhn.fhir.batch2.api.VoidModel; import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry; import ca.uhn.fhir.batch2.maintenance.JobMaintenanceServiceImpl; import ca.uhn.fhir.batch2.model.JobDefinition; +import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; import ca.uhn.fhir.batch2.model.JobWorkNotificationJsonMessage; +import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.jpa.subscription.channel.api.ChannelConsumerSettings; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory; import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.Batch2JobHelper; +import ca.uhn.fhir.jpa.test.config.Batch2FastSchedulerConfig; import ca.uhn.fhir.model.api.IModelJson; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor; +import ca.uhn.fhir.testjob.TestJobDefinitionUtils; +import ca.uhn.fhir.testjob.models.FirstStepOutput; +import ca.uhn.fhir.testjob.models.ReductionStepOutput; +import ca.uhn.fhir.testjob.models.TestJobParameters; import ca.uhn.test.concurrency.PointcutLatch; import com.fasterxml.jackson.annotation.JsonProperty; +import jakarta.annotation.Nonnull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -31,8 +40,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import jakarta.annotation.Nonnull; -import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; @@ -41,9 +48,9 @@ import static org.junit.jupiter.api.Assertions.assertTrue; /** * The on-enter actions are defined in - * {@link ca.uhn.fhir.batch2.progress.JobInstanceStatusUpdater#handleStatusChange} + * {@link ca.uhn.fhir.batch2.progress.JobInstanceStatusUpdater#handleStatusChange(JobInstance)}} * {@link ca.uhn.fhir.batch2.progress.InstanceProgress#updateStatus(JobInstance)} - * {@link JobInstanceProcessor#cleanupInstance()} + * {@link ca.uhn.fhir.batch2.maintenance.JobInstanceProcessor#cleanupInstance()} * For chunks: * {@link ca.uhn.fhir.jpa.batch2.JpaJobPersistenceImpl#onWorkChunkCreate} @@ -53,13 +60,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; @TestPropertySource(properties = { UnregisterScheduledProcessor.SCHEDULING_DISABLED_EQUALS_FALSE }) -@ContextConfiguration(classes = {Batch2JobMaintenanceIT.SpringConfig.class}) +@ContextConfiguration(classes = {Batch2FastSchedulerConfig.class}) public class Batch2JobMaintenanceIT extends BaseJpaR4Test { private static final Logger ourLog = LoggerFactory.getLogger(Batch2JobMaintenanceIT.class); - public static final int TEST_JOB_VERSION = 1; - public static final String FIRST_STEP_ID = "first-step"; - public static final String LAST_STEP_ID = "last-step"; @Autowired JobDefinitionRegistry myJobDefinitionRegistry; @Autowired @@ -87,6 +91,7 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { @BeforeEach public void before() { + myStorageSettings.setJobFastTrackingEnabled(true); myCompletionHandler = details -> {}; myWorkChannel = (LinkedBlockingChannel) myChannelFactory.getOrCreateReceiver(CHANNEL_NAME, JobWorkNotificationJsonMessage.class, new ChannelConsumerSettings()); JobMaintenanceServiceImpl jobMaintenanceService = (JobMaintenanceServiceImpl) myJobMaintenanceService; @@ -99,7 +104,6 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { @AfterEach public void after() { myWorkChannel.clearInterceptorsForUnitTest(); - myStorageSettings.setJobFastTrackingEnabled(true); JobMaintenanceServiceImpl jobMaintenanceService = (JobMaintenanceServiceImpl) myJobMaintenanceService; jobMaintenanceService.setMaintenanceJobStartedCallback(() -> {}); } @@ -122,7 +126,8 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { myFirstStepLatch.setExpectedCount(1); myLastStepLatch.setExpectedCount(1); - String batchJobId = myJobCoordinator.startInstance(request).getInstanceId(); + String batchJobId = myJobCoordinator.startInstance(new SystemRequestDetails(), request).getInstanceId(); + myFirstStepLatch.awaitExpected(); myBatch2JobHelper.assertFastTracking(batchJobId); @@ -156,12 +161,12 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { public void testFirstStepToSecondStepFasttrackingDisabled_singleChunkDoesNotFasttrack() throws InterruptedException { myStorageSettings.setJobFastTrackingEnabled(false); - IJobStepWorker firstStep = (step, sink) -> { - sink.accept(new Batch2JobMaintenanceIT.FirstStepOutput()); + IJobStepWorker firstStep = (step, sink) -> { + sink.accept(new FirstStepOutput()); callLatch(myFirstStepLatch, step); return RunOutcome.SUCCESS; }; - IJobStepWorker lastStep = (step, sink) -> callLatch(myLastStepLatch, step); + IJobStepWorker lastStep = (step, sink) -> callLatch(myLastStepLatch, step); String jobDefId = new Exception().getStackTrace()[0].getMethodName(); @@ -173,7 +178,7 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { myFirstStepLatch.setExpectedCount(1); myLastStepLatch.setExpectedCount(1); - String batchJobId = myJobCoordinator.startInstance(request).getInstanceId(); + String batchJobId = myJobCoordinator.startInstance(new SystemRequestDetails(), request).getInstanceId(); myFirstStepLatch.awaitExpected(); myBatch2JobHelper.assertFastTracking(batchJobId); @@ -200,65 +205,20 @@ public class Batch2JobMaintenanceIT extends BaseJpaR4Test { @Nonnull private JobDefinition buildGatedJobDefinition(String theJobId, IJobStepWorker theFirstStep, IJobStepWorker theLastStep) { - return JobDefinition.newBuilder() - .setJobDefinitionId(theJobId) - .setJobDescription("test job") - .setJobDefinitionVersion(TEST_JOB_VERSION) - .setParametersType(TestJobParameters.class) - .gatedExecution() - .addFirstStep( - FIRST_STEP_ID, - "Test first step", - FirstStepOutput.class, - theFirstStep - ) - .addLastStep( - LAST_STEP_ID, - "Test last step", - theLastStep - ) - .completionHandler(myCompletionHandler) - .build(); + return TestJobDefinitionUtils.buildGatedJobDefinition( + theJobId, + theFirstStep, + theLastStep, + myCompletionHandler + ); } - static class TestJobParameters implements IModelJson { - TestJobParameters() { - } - } - - static class FirstStepOutput implements IModelJson { - FirstStepOutput() { - } - } - - static class SecondStepOutput implements IModelJson { - @JsonProperty("test") - private String myTestValue; - - SecondStepOutput() { - } - - public void setValue(String theV) { - myTestValue = theV; - } - } - - static class ReductionStepOutput implements IModelJson { + static class OurReductionStepOutput extends ReductionStepOutput { @JsonProperty("result") private List myResult; - ReductionStepOutput(List theResult) { + OurReductionStepOutput(List theResult) { myResult = theResult; } } - - static class SpringConfig { - @Autowired - IJobMaintenanceService myJobMaintenanceService; - - @PostConstruct - void fastScheduler() { - ((JobMaintenanceServiceImpl)myJobMaintenanceService).setScheduledJobFrequencyMillis(200); - } - } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/BulkDataErrorAbuseTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/BulkDataErrorAbuseTest.java index b8b16b4670f..e4fded6cc3e 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/BulkDataErrorAbuseTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/BulkDataErrorAbuseTest.java @@ -1,7 +1,6 @@ package ca.uhn.fhir.jpa.batch2; import ca.uhn.fhir.batch2.api.IJobCoordinator; -import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; @@ -10,10 +9,13 @@ import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.Batch2JobDefinitionConstants; import ca.uhn.fhir.util.JsonUtil; import com.google.common.collect.Sets; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Group; @@ -36,13 +38,16 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.BlockingQueue; +import java.util.concurrent.CompletionService; import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; +import static org.awaitility.Awaitility.await; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.emptyOrNullString; import static org.hamcrest.Matchers.equalTo; @@ -64,6 +69,7 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { @BeforeEach void beforeEach() { + ourLog.info("BulkDataErrorAbuseTest.beforeEach"); afterPurgeDatabase(); } @@ -93,7 +99,7 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { duAbuseTest(Integer.MAX_VALUE); } - private void duAbuseTest(int taskExecutions) throws InterruptedException, ExecutionException { + private void duAbuseTest(int taskExecutions) { // Create some resources Patient patient = new Patient(); patient.setId("PING1"); @@ -133,18 +139,19 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { ExecutorService executorService = new ThreadPoolExecutor(workerCount, workerCount, 0L, TimeUnit.MILLISECONDS, workQueue); + CompletionService completionService = new ExecutorCompletionService<>(executorService); ourLog.info("Starting task creation"); - List> futures = new ArrayList<>(); + int maxFuturesToProcess = 500; for (int i = 0; i < taskExecutions; i++) { - futures.add(executorService.submit(() -> { + completionService.submit(() -> { String instanceId = null; try { instanceId = startJob(options); // Run a scheduled pass to build the export - myBatch2JobHelper.awaitJobCompletion(instanceId, 60); + myBatch2JobHelper.awaitJobCompletion(instanceId, 10); verifyBulkExportResults(instanceId, List.of("Patient/PING1", "Patient/PING2"), Collections.singletonList("Patient/PNING3")); @@ -153,14 +160,11 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { ourLog.error("Caught an error during processing instance {}", instanceId, theError); throw new InternalErrorException("Caught an error during processing instance " + instanceId, theError); } - })); + }); // Don't let the list of futures grow so big we run out of memory - if (futures.size() > 1000) { - while (futures.size() > 500) { - // This should always return true, but it'll throw an exception if we failed - assertTrue(futures.remove(0).get()); - } + if (i != 0 && i % maxFuturesToProcess == 0) { + executeFutures(completionService, maxFuturesToProcess); } } @@ -168,18 +172,53 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { // wait for completion to avoid stranding background tasks. executorService.shutdown(); - assertTrue(executorService.awaitTermination(60, TimeUnit.SECONDS), "Finished before timeout"); + await() + .atMost(60, TimeUnit.SECONDS) + .until(() -> { + return executorService.isTerminated() && executorService.isShutdown(); + }); // verify that all requests succeeded ourLog.info("All tasks complete. Verify results."); - for (var next : futures) { - // This should always return true, but it'll throw an exception if we failed - assertTrue(next.get()); - } + executeFutures(completionService, taskExecutions % maxFuturesToProcess); + + executorService.shutdown(); + await() + .atMost(60, TimeUnit.SECONDS) + .until(() -> { + return executorService.isTerminated() && executorService.isShutdown(); + }); ourLog.info("Finished task execution"); } + private void executeFutures(CompletionService theCompletionService, int theTotal) { + List errors = new ArrayList<>(); + int count = 0; + + while (count + errors.size() < theTotal) { + try { + Future future = theCompletionService.take(); + boolean r = future.get(); + assertTrue(r); + count++; + } catch (Exception ex) { + // we will run all the threads to completion, even if we have errors; + // this is so we don't have background threads kicking around with + // partial changes. + // we either do this, or shutdown the completion service in an + // "inelegant" manner, dropping all threads (which we aren't doing) + ourLog.error("Failed after checking " + count + " futures"); + errors.add(ex.getMessage()); + } + } + + if (!errors.isEmpty()) { + fail(String.format("Failed to execute futures. Found %d errors :\n", errors.size()) + + String.join(", ", errors)); + } + } + private void verifyBulkExportResults(String theInstanceId, List theContainedList, List theExcludedList) { // Iterate over the files @@ -196,7 +235,6 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { String resourceType = file.getKey(); List binaryIds = file.getValue(); for (var nextBinaryId : binaryIds) { - Binary binary = myBinaryDao.read(new IdType(nextBinaryId), mySrd); assertEquals(Constants.CT_FHIR_NDJSON, binary.getContentType()); @@ -207,18 +245,17 @@ public class BulkDataErrorAbuseTest extends BaseResourceProviderR4Test { .lines().toList(); ourLog.debug("Export job {} file {} line-count: {}", theInstanceId, nextBinaryId, lines.size()); - lines.stream() - .map(line -> myFhirContext.newJsonParser().parseResource(line)) - .map(r -> r.getIdElement().toUnqualifiedVersionless()) - .forEach(nextId -> { - if (!resourceType.equals(nextId.getResourceType())) { - fail("Found resource of type " + nextId.getResourceType() + " in file for type " + resourceType); - } else { - if (!foundIds.add(nextId.getValue())) { - fail("Found duplicate ID: " + nextId.getValue()); - } + for (String line : lines) { + IBaseResource resource = myFhirContext.newJsonParser().parseResource(line); + IIdType nextId = resource.getIdElement().toUnqualifiedVersionless(); + if (!resourceType.equals(nextId.getResourceType())) { + fail("Found resource of type " + nextId.getResourceType() + " in file for type " + resourceType); + } else { + if (!foundIds.add(nextId.getValue())) { + fail("Found duplicate ID: " + nextId.getValue()); } - }); + } + } } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JobInstanceRepositoryTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JobInstanceRepositoryTest.java index 2485daacc91..cd95d6faf27 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JobInstanceRepositoryTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/batch2/JobInstanceRepositoryTest.java @@ -4,7 +4,6 @@ import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.model.FetchJobInstancesRequest; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.StatusEnum; -import ca.uhn.fhir.jpa.dao.data.IBatch2JobInstanceRepository; import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import org.junit.jupiter.api.AfterEach; @@ -23,8 +22,6 @@ import static org.hamcrest.Matchers.hasSize; public class JobInstanceRepositoryTest extends BaseJpaR4Test { - @Autowired - private IBatch2JobInstanceRepository myJobInstanceRepository; @Autowired private IJobPersistence myJobPersistenceSvc; private static final String PARAMS = "{\"param1\":\"value1\"}"; 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 90654ff9bc1..fa492384b37 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 @@ -1,9 +1,15 @@ package ca.uhn.fhir.jpa.batch2; +import ca.uhn.fhir.batch2.api.IJobMaintenanceService; import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.JobOperationResultJson; +import ca.uhn.fhir.batch2.api.RunOutcome; +import ca.uhn.fhir.batch2.channel.BatchJobSender; +import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry; import ca.uhn.fhir.batch2.jobs.imprt.NdJsonFileJson; +import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent; @@ -18,26 +24,34 @@ import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity; import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; +import ca.uhn.fhir.jpa.test.Batch2JobHelper; +import ca.uhn.fhir.jpa.test.config.Batch2FastSchedulerConfig; +import ca.uhn.fhir.testjob.TestJobDefinitionUtils; +import ca.uhn.fhir.testjob.models.FirstStepOutput; import ca.uhn.fhir.util.JsonUtil; import ca.uhn.hapi.fhir.batch2.test.AbstractIJobPersistenceSpecificationTest; import ca.uhn.hapi.fhir.batch2.test.configs.SpyOverrideConfig; +import ca.uhn.test.concurrency.PointcutLatch; import com.google.common.collect.ImmutableList; import com.google.common.collect.Iterators; +import jakarta.annotation.Nonnull; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Import; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Sort; +import org.springframework.test.context.ContextConfiguration; import org.springframework.transaction.PlatformTransactionManager; -import jakarta.annotation.Nonnull; import java.time.Instant; import java.time.LocalDateTime; import java.time.ZoneId; @@ -60,15 +74,25 @@ import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; @TestMethodOrder(MethodOrderer.MethodName.class) +@ContextConfiguration(classes = { + Batch2FastSchedulerConfig.class +}) @Import(SpyOverrideConfig.class) public class JpaJobPersistenceImplTest extends BaseJpaR4Test { public static final String JOB_DEFINITION_ID = "definition-id"; - public static final String TARGET_STEP_ID = "step-id"; + public static final String FIRST_STEP_ID = TestJobDefinitionUtils.FIRST_STEP_ID; + public static final String LAST_STEP_ID = TestJobDefinitionUtils.LAST_STEP_ID; public static final String DEF_CHUNK_ID = "definition-chunkId"; - public static final String STEP_CHUNK_ID = "step-chunkId"; + public static final String STEP_CHUNK_ID = TestJobDefinitionUtils.FIRST_STEP_ID; public static final int JOB_DEF_VER = 1; public static final int SEQUENCE_NUMBER = 1; public static final String CHUNK_DATA = "{\"key\":\"value\"}"; @@ -80,6 +104,25 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { @Autowired private IBatch2JobInstanceRepository myJobInstanceRepository; + @Autowired + public Batch2JobHelper myBatch2JobHelper; + + // this is our spy + @Autowired + private BatchJobSender myBatchSender; + + @Autowired + private IJobMaintenanceService myMaintenanceService; + + @Autowired + public JobDefinitionRegistry myJobDefinitionRegistry; + + @AfterEach + public void after() { + myJobDefinitionRegistry.removeJobDefinition(JOB_DEFINITION_ID, JOB_DEF_VER); + myMaintenanceService.enableMaintenancePass(true); + } + @Test public void testDeleteInstance() { // Setup @@ -87,7 +130,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { JobInstance instance = createInstance(); String instanceId = mySvc.storeNewInstance(instance); for (int i = 0; i < 10; i++) { - storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, i, JsonUtil.serialize(new NdJsonFileJson().setNdJsonText("{}"))); + storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, i, JsonUtil.serialize(new NdJsonFileJson().setNdJsonText("{}")), false); } // Execute @@ -102,8 +145,13 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { }); } - private String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData) { - WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, JOB_DEF_VER, theTargetStepId, theInstanceId, theSequence, theSerializedData); + private String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData, boolean theGatedExecution) { + WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, TestJobDefinitionUtils.TEST_JOB_VERSION, theTargetStepId, theInstanceId, theSequence, theSerializedData, theGatedExecution); + return mySvc.onWorkChunkCreate(batchWorkChunk); + } + + private String storeFirstWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData) { + WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, TestJobDefinitionUtils.TEST_JOB_VERSION, theTargetStepId, theInstanceId, theSequence, theSerializedData, false); return mySvc.onWorkChunkCreate(batchWorkChunk); } @@ -113,7 +161,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { String instanceId = mySvc.storeNewInstance(instance); runInTransaction(() -> { - Batch2JobInstanceEntity instanceEntity = myJobInstanceRepository.findById(instanceId).orElseThrow(IllegalStateException::new); + Batch2JobInstanceEntity instanceEntity = findInstanceByIdOrThrow(instanceId); assertEquals(StatusEnum.QUEUED, instanceEntity.getStatus()); }); @@ -126,7 +174,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertEquals(instance.getReport(), foundInstance.getReport()); runInTransaction(() -> { - Batch2JobInstanceEntity instanceEntity = myJobInstanceRepository.findById(instanceId).orElseThrow(IllegalStateException::new); + Batch2JobInstanceEntity instanceEntity = findInstanceByIdOrThrow(instanceId); assertEquals(StatusEnum.QUEUED, instanceEntity.getStatus()); }); } @@ -213,12 +261,14 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { @ParameterizedTest @MethodSource("provideStatuses") - public void testStartChunkOnlyWorksOnValidChunks(WorkChunkStatusEnum theStatus, boolean theShouldBeStartedByConsumer) { + public void testStartChunkOnlyWorksOnValidChunks(WorkChunkStatusEnum theStatus, boolean theShouldBeStartedByConsumer) throws InterruptedException { // Setup JobInstance instance = createInstance(); + myMaintenanceService.enableMaintenancePass(false); String instanceId = mySvc.storeNewInstance(instance); - storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, CHUNK_DATA); - WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(JOB_DEFINITION_ID, JOB_DEF_VER, TARGET_STEP_ID, instanceId, 0, CHUNK_DATA); + + storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, CHUNK_DATA, false); + WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(JOB_DEFINITION_ID, JOB_DEF_VER, FIRST_STEP_ID, instanceId, 0, CHUNK_DATA, false); String chunkId = mySvc.onWorkChunkCreate(batchWorkChunk); Optional byId = myWorkChunkRepository.findById(chunkId); Batch2WorkChunkEntity entity = byId.get(); @@ -230,7 +280,9 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { // Verify boolean chunkStarted = workChunk.isPresent(); - assertEquals(chunkStarted, theShouldBeStartedByConsumer); + assertEquals(theShouldBeStartedByConsumer, chunkStarted); + verify(myBatchSender, never()) + .sendWorkChannelMessage(any()); } @Test @@ -344,46 +396,185 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { @Test public void testUpdateTime() { // Setup - JobInstance instance = createInstance(); + boolean isGatedExecution = false; + JobInstance instance = createInstance(true, isGatedExecution); String instanceId = mySvc.storeNewInstance(instance); - Date updateTime = runInTransaction(() -> new Date(myJobInstanceRepository.findById(instanceId).orElseThrow().getUpdateTime().getTime())); + Date updateTime = runInTransaction(() -> new Date(findInstanceByIdOrThrow(instanceId).getUpdateTime().getTime())); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); // Test runInTransaction(() -> mySvc.updateInstanceUpdateTime(instanceId)); // Verify - Date updateTime2 = runInTransaction(() -> new Date(myJobInstanceRepository.findById(instanceId).orElseThrow().getUpdateTime().getTime())); + Date updateTime2 = runInTransaction(() -> new Date(findInstanceByIdOrThrow(instanceId).getUpdateTime().getTime())); assertNotEquals(updateTime, updateTime2); } + @Test + public void advanceJobStepAndUpdateChunkStatus_forGatedJobWithoutReduction_updatesCurrentStepAndChunkStatus() { + // setup + boolean isGatedExecution = true; + JobInstance instance = createInstance(true, isGatedExecution); + String instanceId = mySvc.storeNewInstance(instance); + String chunkIdSecondStep1 = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, null, isGatedExecution); + String chunkIdSecondStep2 = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, null, isGatedExecution); + + runInTransaction(() -> assertEquals(FIRST_STEP_ID, findInstanceByIdOrThrow(instanceId).getCurrentGatedStepId())); + + // execute + runInTransaction(() -> { + boolean changed = mySvc.advanceJobStepAndUpdateChunkStatus(instanceId, LAST_STEP_ID, false); + assertTrue(changed); + }); + + // verify + runInTransaction(() -> { + assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(chunkIdSecondStep1).getStatus()); + assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(chunkIdSecondStep2).getStatus()); + assertEquals(LAST_STEP_ID, findInstanceByIdOrThrow(instanceId).getCurrentGatedStepId()); + }); + } + + @Test + public void advanceJobStepAndUpdateChunkStatus_whenAlreadyInTargetStep_DoesNotUpdateStepOrChunks() { + // setup + boolean isGatedExecution = true; + JobInstance instance = createInstance(true, isGatedExecution); + String instanceId = mySvc.storeNewInstance(instance); + String chunkIdSecondStep1 = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, null, isGatedExecution); + String chunkIdSecondStep2 = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, null, isGatedExecution); + + runInTransaction(() -> assertEquals(FIRST_STEP_ID, findInstanceByIdOrThrow(instanceId).getCurrentGatedStepId())); + + // execute + runInTransaction(() -> { + boolean changed = mySvc.advanceJobStepAndUpdateChunkStatus(instanceId, FIRST_STEP_ID, false); + assertFalse(changed); + }); + + // verify + runInTransaction(() -> { + assertEquals(WorkChunkStatusEnum.GATE_WAITING, findChunkByIdOrThrow(chunkIdSecondStep1).getStatus()); + assertEquals(WorkChunkStatusEnum.GATE_WAITING, findChunkByIdOrThrow(chunkIdSecondStep2).getStatus()); + assertEquals(FIRST_STEP_ID, findInstanceByIdOrThrow(instanceId).getCurrentGatedStepId()); + }); + } + @Test public void testFetchUnknownWork() { assertFalse(myWorkChunkRepository.findById("FOO").isPresent()); } - @Test - public void testStoreAndFetchWorkChunk_NoData() { - JobInstance instance = createInstance(); + @ParameterizedTest + @CsvSource({ + "false, READY, QUEUED", + "true, GATE_WAITING, QUEUED" + }) + public void testStoreAndFetchWorkChunk_withOrWithoutGatedExecutionNoData_createdAndTransitionToExpectedStatus(boolean theGatedExecution, WorkChunkStatusEnum theExpectedStatusOnCreate, WorkChunkStatusEnum theExpectedStatusAfterTransition) throws InterruptedException { + // setup + JobInstance instance = createInstance(true, theGatedExecution); + + // when + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(1); + myMaintenanceService.enableMaintenancePass(false); String instanceId = mySvc.storeNewInstance(instance); - String id = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, null); + // execute & verify + String firstChunkId = storeFirstWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, null); + // mark the first chunk as COMPLETED to allow step advance + runInTransaction(() -> myWorkChunkRepository.updateChunkStatus(firstChunkId, WorkChunkStatusEnum.READY, WorkChunkStatusEnum.COMPLETED)); + + String id = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, null, theGatedExecution); + runInTransaction(() -> assertEquals(theExpectedStatusOnCreate, findChunkByIdOrThrow(id).getStatus())); + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> assertEquals(theExpectedStatusAfterTransition, findChunkByIdOrThrow(id).getStatus())); WorkChunk chunk = mySvc.onWorkChunkDequeue(id).orElseThrow(IllegalArgumentException::new); + // assert null since we did not input any data when creating the chunks assertNull(chunk.getData()); + + latch.awaitExpected(); + verify(myBatchSender).sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); + } + + @Test + public void testStoreAndFetchWorkChunk_withGatedJobMultipleChunk_correctTransitions() throws InterruptedException { + // setup + boolean isGatedExecution = true; + String expectedFirstChunkData = "IAmChunk1"; + String expectedSecondChunkData = "IAmChunk2"; + JobInstance instance = createInstance(true, isGatedExecution); + myMaintenanceService.enableMaintenancePass(false); + String instanceId = mySvc.storeNewInstance(instance); + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(2); + + // execute & verify + String firstChunkId = storeFirstWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, expectedFirstChunkData); + String secondChunkId = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, expectedSecondChunkData, isGatedExecution); + + runInTransaction(() -> { + // check chunks created in expected states + assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(firstChunkId).getStatus()); + assertEquals(WorkChunkStatusEnum.GATE_WAITING, findChunkByIdOrThrow(secondChunkId).getStatus()); + }); + + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> { + assertEquals(WorkChunkStatusEnum.QUEUED, findChunkByIdOrThrow(firstChunkId).getStatus()); + // maintenance should not affect chunks in step 2 + assertEquals(WorkChunkStatusEnum.GATE_WAITING, findChunkByIdOrThrow(secondChunkId).getStatus()); + }); + + WorkChunk actualFirstChunkData = mySvc.onWorkChunkDequeue(firstChunkId).orElseThrow(IllegalArgumentException::new); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, findChunkByIdOrThrow(firstChunkId).getStatus())); + assertEquals(expectedFirstChunkData, actualFirstChunkData.getData()); + + mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(firstChunkId, 50, 0)); + runInTransaction(() -> { + assertEquals(WorkChunkStatusEnum.COMPLETED, findChunkByIdOrThrow(firstChunkId).getStatus()); + assertEquals(WorkChunkStatusEnum.GATE_WAITING, findChunkByIdOrThrow(secondChunkId).getStatus()); + }); + + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> { + assertEquals(WorkChunkStatusEnum.COMPLETED, findChunkByIdOrThrow(firstChunkId).getStatus()); + // now that all chunks for step 1 is COMPLETED, should enqueue chunks in step 2 + assertEquals(WorkChunkStatusEnum.QUEUED, findChunkByIdOrThrow(secondChunkId).getStatus()); + }); + + WorkChunk actualSecondChunkData = mySvc.onWorkChunkDequeue(secondChunkId).orElseThrow(IllegalArgumentException::new); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, findChunkByIdOrThrow(secondChunkId).getStatus())); + assertEquals(expectedSecondChunkData, actualSecondChunkData.getData()); + + latch.awaitExpected(); + verify(myBatchSender, times(2)) + .sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); } @Test void testStoreAndFetchChunksForInstance_NoData() { // given + boolean isGatedExecution = false; JobInstance instance = createInstance(); String instanceId = mySvc.storeNewInstance(instance); - String queuedId = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, "some data"); - String erroredId = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 1, "some more data"); - String completedId = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 2, "some more data"); + String queuedId = storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, "some data", isGatedExecution); + String erroredId = storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 1, "some more data", isGatedExecution); + String completedId = storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 2, "some more data", isGatedExecution); mySvc.onWorkChunkDequeue(erroredId); WorkChunkErrorEvent parameters = new WorkChunkErrorEvent(erroredId, "Our error message"); @@ -407,9 +598,9 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertEquals(JOB_DEFINITION_ID, workChunk.getJobDefinitionId()); assertEquals(JOB_DEF_VER, workChunk.getJobDefinitionVersion()); assertEquals(instanceId, workChunk.getInstanceId()); - assertEquals(TARGET_STEP_ID, workChunk.getTargetStepId()); + assertEquals(FIRST_STEP_ID, workChunk.getTargetStepId()); assertEquals(0, workChunk.getSequence()); - assertEquals(WorkChunkStatusEnum.QUEUED, workChunk.getStatus()); + assertEquals(WorkChunkStatusEnum.READY, workChunk.getStatus()); assertNotNull(workChunk.getCreateTime()); @@ -418,7 +609,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertNull(workChunk.getEndTime()); assertNull(workChunk.getErrorMessage()); assertEquals(0, workChunk.getErrorCount()); - assertEquals(null, workChunk.getRecordsProcessed()); + assertNull(workChunk.getRecordsProcessed()); } { @@ -426,7 +617,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertEquals(WorkChunkStatusEnum.ERRORED, workChunk1.getStatus()); assertEquals("Our error message", workChunk1.getErrorMessage()); assertEquals(1, workChunk1.getErrorCount()); - assertEquals(null, workChunk1.getRecordsProcessed()); + assertNull(workChunk1.getRecordsProcessed()); assertNotNull(workChunk1.getEndTime()); } @@ -438,18 +629,35 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertNull(workChunk2.getErrorMessage()); assertEquals(0, workChunk2.getErrorCount()); } - } - - @Test - public void testStoreAndFetchWorkChunk_WithData() { - JobInstance instance = createInstance(); + @ParameterizedTest + @CsvSource({ + "false, READY, QUEUED", + "true, GATE_WAITING, QUEUED" + }) + public void testStoreAndFetchWorkChunk_withOrWithoutGatedExecutionwithData_createdAndTransitionToExpectedStatus(boolean theGatedExecution, WorkChunkStatusEnum theExpectedCreatedStatus, WorkChunkStatusEnum theExpectedTransitionStatus) throws InterruptedException { + // setup + JobInstance instance = createInstance(true, theGatedExecution); + myMaintenanceService.enableMaintenancePass(false); String instanceId = mySvc.storeNewInstance(instance); + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(1); - String id = storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, CHUNK_DATA); + // execute & verify + String firstChunkId = storeFirstWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, null); + // mark the first chunk as COMPLETED to allow step advance + runInTransaction(() -> myWorkChunkRepository.updateChunkStatus(firstChunkId, WorkChunkStatusEnum.READY, WorkChunkStatusEnum.COMPLETED)); + + String id = storeWorkChunk(JOB_DEFINITION_ID, LAST_STEP_ID, instanceId, 0, CHUNK_DATA, theGatedExecution); assertNotNull(id); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, myWorkChunkRepository.findById(id).orElseThrow(IllegalArgumentException::new).getStatus())); + runInTransaction(() -> assertEquals(theExpectedCreatedStatus, findChunkByIdOrThrow(id).getStatus())); + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> assertEquals(theExpectedTransitionStatus, findChunkByIdOrThrow(id).getStatus())); WorkChunk chunk = mySvc.onWorkChunkDequeue(id).orElseThrow(IllegalArgumentException::new); assertEquals(36, chunk.getInstanceId().length()); @@ -458,19 +666,30 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus()); assertEquals(CHUNK_DATA, chunk.getData()); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, myWorkChunkRepository.findById(id).orElseThrow(IllegalArgumentException::new).getStatus())); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, findChunkByIdOrThrow(id).getStatus())); + latch.awaitExpected(); + verify(myBatchSender).sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); } @Test - public void testMarkChunkAsCompleted_Success() { - JobInstance instance = createInstance(); + public void testMarkChunkAsCompleted_Success() throws InterruptedException { + boolean isGatedExecution = false; + myMaintenanceService.enableMaintenancePass(false); + JobInstance instance = createInstance(true, isGatedExecution); String instanceId = mySvc.storeNewInstance(instance); - String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, CHUNK_DATA); + String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, CHUNK_DATA, isGatedExecution); assertNotNull(chunkId); + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(1); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new).getStatus())); - - sleepUntilTimeChanges(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(chunkId).getStatus())); + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, findChunkByIdOrThrow(chunkId).getStatus())); WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new); assertEquals(SEQUENCE_NUMBER, chunk.getSequence()); @@ -480,13 +699,13 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertNull(chunk.getEndTime()); assertNull(chunk.getRecordsProcessed()); assertNotNull(chunk.getData()); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new).getStatus())); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, findChunkByIdOrThrow(chunkId).getStatus())); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(chunkId, 50, 0)); runInTransaction(() -> { - Batch2WorkChunkEntity entity = myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new); + Batch2WorkChunkEntity entity = findChunkByIdOrThrow(chunkId); assertEquals(WorkChunkStatusEnum.COMPLETED, entity.getStatus()); assertEquals(50, entity.getRecordsProcessed()); assertNotNull(entity.getCreateTime()); @@ -496,63 +715,41 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime()); assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime()); }); - } - - @Test - public void testGatedAdvancementByStatus() { - // Setup - JobInstance instance = createInstance(); - String instanceId = mySvc.storeNewInstance(instance); - String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null); - mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(chunkId, 0, 0)); - - boolean canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); - assertTrue(canAdvance); - - //Storing a new chunk with QUEUED should prevent advancement. - String newChunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null); - - canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); - assertFalse(canAdvance); - - //Toggle it to complete - mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(newChunkId, 50, 0)); - canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); - assertTrue(canAdvance); - - //Create a new chunk and set it in progress. - String newerChunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null); - mySvc.onWorkChunkDequeue(newerChunkId); - canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); - assertFalse(canAdvance); - - //Toggle IN_PROGRESS to complete - mySvc.onWorkChunkCompletion(new WorkChunkCompletionEvent(newerChunkId, 50, 0)); - canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); - assertTrue(canAdvance); + latch.awaitExpected(); + verify(myBatchSender).sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); } @Test public void testMarkChunkAsCompleted_Error() { - JobInstance instance = createInstance(); + boolean isGatedExecution = false; + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(1); + myMaintenanceService.enableMaintenancePass(false); + + JobInstance instance = createInstance(true, isGatedExecution); String instanceId = mySvc.storeNewInstance(instance); - String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null); + String chunkId = storeWorkChunk(JOB_DEFINITION_ID, TestJobDefinitionUtils.FIRST_STEP_ID, instanceId, SEQUENCE_NUMBER, null, isGatedExecution); assertNotNull(chunkId); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new).getStatus())); - - sleepUntilTimeChanges(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(chunkId).getStatus())); + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, findChunkByIdOrThrow(chunkId).getStatus())); WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new); assertEquals(SEQUENCE_NUMBER, chunk.getSequence()); assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus()); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); WorkChunkErrorEvent request = new WorkChunkErrorEvent(chunkId).setErrorMsg("This is an error message"); mySvc.onWorkChunkError(request); runInTransaction(() -> { - Batch2WorkChunkEntity entity = myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new); + Batch2WorkChunkEntity entity = findChunkByIdOrThrow(chunkId); assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus()); assertEquals("This is an error message", entity.getErrorMessage()); assertNotNull(entity.getCreateTime()); @@ -568,7 +765,7 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { WorkChunkErrorEvent request2 = new WorkChunkErrorEvent(chunkId).setErrorMsg("This is an error message 2"); mySvc.onWorkChunkError(request2); runInTransaction(() -> { - Batch2WorkChunkEntity entity = myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new); + Batch2WorkChunkEntity entity = findChunkByIdOrThrow(chunkId); assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus()); assertEquals("This is an error message 2", entity.getErrorMessage()); assertNotNull(entity.getCreateTime()); @@ -582,28 +779,39 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { List chunks = ImmutableList.copyOf(mySvc.fetchAllWorkChunksIterator(instanceId, true)); assertEquals(1, chunks.size()); assertEquals(2, chunks.get(0).getErrorCount()); + + verify(myBatchSender).sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); } @Test - public void testMarkChunkAsCompleted_Fail() { - JobInstance instance = createInstance(); + public void testMarkChunkAsCompleted_Fail() throws InterruptedException { + boolean isGatedExecution = false; + myMaintenanceService.enableMaintenancePass(false); + JobInstance instance = createInstance(true, isGatedExecution); String instanceId = mySvc.storeNewInstance(instance); - String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null); + String chunkId = storeWorkChunk(DEF_CHUNK_ID, STEP_CHUNK_ID, instanceId, SEQUENCE_NUMBER, null, isGatedExecution); assertNotNull(chunkId); + PointcutLatch latch = new PointcutLatch("senderlatch"); + doAnswer(a -> { + latch.call(1); + return Void.class; + }).when(myBatchSender).sendWorkChannelMessage(any(JobWorkNotification.class)); + latch.setExpectedCount(1); - runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new).getStatus())); - - sleepUntilTimeChanges(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.READY, findChunkByIdOrThrow(chunkId).getStatus())); + myBatch2JobHelper.runMaintenancePass(); + runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, findChunkByIdOrThrow(chunkId).getStatus())); WorkChunk chunk = mySvc.onWorkChunkDequeue(chunkId).orElseThrow(IllegalArgumentException::new); assertEquals(SEQUENCE_NUMBER, chunk.getSequence()); assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus()); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); mySvc.onWorkChunkFailed(chunkId, "This is an error message"); runInTransaction(() -> { - Batch2WorkChunkEntity entity = myWorkChunkRepository.findById(chunkId).orElseThrow(IllegalArgumentException::new); + Batch2WorkChunkEntity entity = findChunkByIdOrThrow(chunkId); assertEquals(WorkChunkStatusEnum.FAILED, entity.getStatus()); assertEquals("This is an error message", entity.getErrorMessage()); assertNotNull(entity.getCreateTime()); @@ -612,6 +820,10 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertTrue(entity.getCreateTime().getTime() < entity.getStartTime().getTime()); assertTrue(entity.getStartTime().getTime() < entity.getEndTime().getTime()); }); + latch.awaitExpected(); + verify(myBatchSender) + .sendWorkChannelMessage(any()); + clearInvocations(myBatchSender); } @Test @@ -626,7 +838,8 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { "stepId", instanceId, 0, - "{}" + "{}", + false ); String id = mySvc.onWorkChunkCreate(chunk); chunkIds.add(id); @@ -674,15 +887,57 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { .orElseThrow(IllegalArgumentException::new)); } + private JobInstance createInstance() { + return createInstance(false, false); + } @Nonnull - private JobInstance createInstance() { + private JobInstance createInstance(boolean theCreateJobDefBool, boolean theCreateGatedJob) { JobInstance instance = new JobInstance(); instance.setJobDefinitionId(JOB_DEFINITION_ID); instance.setStatus(StatusEnum.QUEUED); instance.setJobDefinitionVersion(JOB_DEF_VER); instance.setParameters(CHUNK_DATA); instance.setReport("TEST"); + + if (theCreateJobDefBool) { + JobDefinition jobDef; + + if (theCreateGatedJob) { + jobDef = TestJobDefinitionUtils.buildGatedJobDefinition( + JOB_DEFINITION_ID, + (step, sink) -> { + sink.accept(new FirstStepOutput()); + return RunOutcome.SUCCESS; + }, + (step, sink) -> { + return RunOutcome.SUCCESS; + }, + theDetails -> { + + } + ); + instance.setCurrentGatedStepId(jobDef.getFirstStepId()); + } else { + jobDef = TestJobDefinitionUtils.buildJobDefinition( + JOB_DEFINITION_ID, + (step, sink) -> { + sink.accept(new FirstStepOutput()); + return RunOutcome.SUCCESS; + }, + (step, sink) -> { + return RunOutcome.SUCCESS; + }, + theDetails -> { + + } + ); + } + if (myJobDefinitionRegistry.getJobDefinition(jobDef.getJobDefinitionId(), jobDef.getJobDefinitionVersion()).isEmpty()) { + myJobDefinitionRegistry.addJobDefinition(jobDef); + } + } + return instance; } @@ -719,4 +974,12 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { Arguments.of(WorkChunkStatusEnum.COMPLETED, false) ); } + + private Batch2JobInstanceEntity findInstanceByIdOrThrow(String instanceId) { + return myJobInstanceRepository.findById(instanceId).orElseThrow(IllegalStateException::new); + } + + private Batch2WorkChunkEntity findChunkByIdOrThrow(String secondChunkId) { + return myWorkChunkRepository.findById(secondChunkId).orElseThrow(IllegalArgumentException::new); + } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java index 1d0f89c493f..810c27bc900 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportTest.java @@ -13,7 +13,6 @@ import ca.uhn.fhir.jpa.api.model.BulkExportJobResults; import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import ca.uhn.fhir.jpa.batch2.JpaJobPersistenceImpl; import ca.uhn.fhir.jpa.dao.data.IBatch2WorkChunkRepository; -import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.rest.api.Constants; @@ -31,7 +30,6 @@ import ca.uhn.fhir.util.JsonUtil; import com.google.common.collect.Sets; import jakarta.annotation.Nonnull; import org.apache.commons.io.LineIterator; -import org.apache.commons.lang3.StringUtils; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPost; @@ -72,7 +70,6 @@ import org.mockito.Spy; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.data.domain.PageRequest; import java.io.IOException; import java.io.StringReader; @@ -85,10 +82,9 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.stream.Stream; -import static ca.uhn.fhir.batch2.jobs.export.BulkExportAppCtx.CREATE_REPORT_STEP; -import static ca.uhn.fhir.batch2.jobs.export.BulkExportAppCtx.WRITE_TO_BINARIES; import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TagsInlineTest.createSearchParameterForInlineSecurity; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.awaitility.Awaitility.await; @@ -477,7 +473,8 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { verifyBulkExportResults(options, ids, new ArrayList<>()); assertFalse(valueSet.isEmpty()); - assertEquals(ids.size(), valueSet.size()); + assertEquals(ids.size(), valueSet.size(), + "Expected " + String.join(", ", ids) + ". Actual : " + String.join(", ", valueSet)); for (String id : valueSet) { // should start with our value from the key-value pairs assertTrue(id.startsWith(value)); @@ -898,6 +895,7 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { options.setResourceTypes(Sets.newHashSet("Patient", "Observation", "CarePlan", "MedicationAdministration", "ServiceRequest")); options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); options.setOutputFormat(Constants.CT_FHIR_NDJSON); + verifyBulkExportResults(options, List.of("Patient/P1", carePlanId, medAdminId, sevReqId, obsSubId, obsPerId), Collections.emptyList()); } @@ -1096,7 +1094,6 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { String resourceType = file.getKey(); List binaryIds = file.getValue(); for (var nextBinaryId : binaryIds) { - String nextBinaryIdPart = new IdType(nextBinaryId).getIdPart(); assertThat(nextBinaryIdPart, matchesPattern("[a-zA-Z0-9]{32}")); @@ -1105,6 +1102,7 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { String nextNdJsonFileContent = new String(binary.getContent(), Constants.CHARSET_UTF8); try (var iter = new LineIterator(new StringReader(nextNdJsonFileContent))) { + AtomicBoolean gate = new AtomicBoolean(false); iter.forEachRemaining(t -> { if (isNotBlank(t)) { IBaseResource next = myFhirContext.newJsonParser().parseResource(t); @@ -1117,7 +1115,10 @@ public class BulkDataExportTest extends BaseResourceProviderR4Test { } } } + gate.set(true); }); + await().atMost(400, TimeUnit.MILLISECONDS) + .until(gate::get); } catch (IOException e) { fail(e.toString()); } 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 93dc9dfc6e3..a628a79539b 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 @@ -93,7 +93,6 @@ import org.springframework.transaction.support.TransactionTemplate; import jakarta.annotation.Nonnull; import java.io.IOException; import java.io.InputStream; -import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.nio.charset.StandardCharsets; import java.util.Arrays; @@ -582,13 +581,13 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest { p.addName().setFamily("family"); final IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualified(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); ValueSet vs = new ValueSet(); vs.setUrl("http://foo"); myValueSetDao.create(vs, mySrd); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); ResourceTable entity = new TransactionTemplate(myTxManager).execute(t -> myEntityManager.find(ResourceTable.class, id.getIdPartAsLong())); assertEquals(Long.valueOf(1), entity.getIndexStatus()); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java index 77cbd0d21ce..d033d703d17 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/delete/job/ReindexJobTest.java @@ -18,7 +18,10 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.PatientReindexTestHelper; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; +import jakarta.annotation.PostConstruct; +import jakarta.persistence.Query; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Patient; @@ -30,8 +33,6 @@ import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; import org.springframework.beans.factory.annotation.Autowired; -import jakarta.annotation.PostConstruct; -import jakarta.persistence.Query; import java.util.Date; import java.util.List; import java.util.stream.Stream; @@ -263,7 +264,7 @@ public class ReindexJobTest extends BaseJpaR4Test { .setOptimizeStorage(ReindexParameters.OptimizeStorageModeEnum.CURRENT_VERSION) .setReindexSearchParameters(ReindexParameters.ReindexSearchParametersEnum.NONE) ); - Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(startRequest); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), startRequest); JobInstance outcome = myBatch2JobHelper.awaitJobCompletion(startResponse); assertEquals(10, outcome.getCombinedRecordsProcessed()); @@ -358,7 +359,7 @@ public class ReindexJobTest extends BaseJpaR4Test { myReindexTestHelper.createObservationWithAlleleExtension(Observation.ObservationStatus.FINAL); } - sleepUntilTimeChanges(); + sleepUntilTimeChange(); myReindexTestHelper.createAlleleSearchParameter(); mySearchParamRegistry.forceRefresh(); @@ -390,7 +391,7 @@ public class ReindexJobTest extends BaseJpaR4Test { JobInstanceStartRequest startRequest = new JobInstanceStartRequest(); startRequest.setJobDefinitionId(ReindexAppCtx.JOB_REINDEX); startRequest.setParameters(new ReindexJobParameters()); - Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(startRequest); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), startRequest); JobInstance myJob = myBatch2JobHelper.awaitJobCompletion(startResponse); assertEquals(StatusEnum.COMPLETED, myJob.getStatus()); @@ -445,7 +446,7 @@ public class ReindexJobTest extends BaseJpaR4Test { JobInstanceStartRequest startRequest = new JobInstanceStartRequest(); startRequest.setJobDefinitionId(ReindexAppCtx.JOB_REINDEX); startRequest.setParameters(new ReindexJobParameters()); - Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(startRequest); + Batch2JobStartResponse startResponse = myJobCoordinator.startInstance(new SystemRequestDetails(), startRequest); JobInstance outcome = myBatch2JobHelper.awaitJobFailure(startResponse); // Verify diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorJpaR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorJpaR4Test.java index ac93db3d643..422db3d6fe7 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorJpaR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/AuthorizationInterceptorJpaR4Test.java @@ -82,6 +82,7 @@ import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.startsWith; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -440,8 +441,9 @@ public class AuthorizationInterceptorJpaR4Test extends BaseResourceProviderR4Tes }.setValidationSupport(myValidationSupport)); // Should be ok - myClient.read().resource(Observation.class).withId("Observation/allowed").execute(); + Observation result = myClient.read().resource(Observation.class).withId("Observation/allowed").execute(); + assertNotNull(result); } @Test @@ -463,8 +465,10 @@ public class AuthorizationInterceptorJpaR4Test extends BaseResourceProviderR4Tes }.setValidationSupport(myValidationSupport)); // Should be ok - myClient.read().resource(Patient.class).withId("Patient/P").execute(); - myClient.read().resource(Observation.class).withId("Observation/O").execute(); + Patient pat = myClient.read().resource(Patient.class).withId("Patient/P").execute(); + Observation obs = myClient.read().resource(Observation.class).withId("Observation/O").execute(); + assertNotNull(pat); + assertNotNull(obs); } /** diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderCustomSearchParamR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderCustomSearchParamR4Test.java index f6b9cd4b9df..b0239d24ee3 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderCustomSearchParamR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderCustomSearchParamR4Test.java @@ -244,12 +244,15 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide mySearchParameterDao.create(fooSp, mySrd); runInTransaction(() -> { + myBatch2JobHelper.forceRunMaintenancePass(); + List allJobs = myBatch2JobHelper.findJobsByDefinition(ReindexAppCtx.JOB_REINDEX); assertEquals(1, allJobs.size()); assertEquals(1, allJobs.get(0).getParameters(ReindexJobParameters.class).getPartitionedUrls().size()); assertEquals("Patient?", allJobs.get(0).getParameters(ReindexJobParameters.class).getPartitionedUrls().get(0).getUrl()); }); + myBatch2JobHelper.awaitNoJobsRunning(); } @Test diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java index 2b9f3891249..1136f192cc9 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java @@ -3,9 +3,11 @@ package ca.uhn.fhir.jpa.provider.r4; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; +import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; +import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; @@ -24,19 +26,32 @@ import org.junit.jupiter.api.Test; import java.io.IOException; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.CompletionService; +import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; +import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4BundleTest.class); + private static final int DESIRED_MAX_THREADS = 5; + + static { + if (TestR4Config.ourMaxThreads == null || TestR4Config.ourMaxThreads < DESIRED_MAX_THREADS) { + TestR4Config.ourMaxThreads = DESIRED_MAX_THREADS; + } + } + @BeforeEach @Override public void before() throws Exception { @@ -52,6 +67,7 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { myStorageSettings.setBundleBatchPoolSize(JpaStorageSettings.DEFAULT_BUNDLE_BATCH_POOL_SIZE); myStorageSettings.setBundleBatchMaxPoolSize(JpaStorageSettings.DEFAULT_BUNDLE_BATCH_MAX_POOL_SIZE); } + /** * See #401 */ @@ -69,14 +85,13 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { Bundle retBundle = myClient.read().resource(Bundle.class).withId(id).execute(); - ourLog.debug(myFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(retBundle)); + ourLog.debug(myFhirContext.newXmlParser().setPrettyPrint(true).encodeResourceToString(retBundle)); assertEquals("http://foo/", bundle.getEntry().get(0).getFullUrl()); } @Test public void testProcessMessage() { - Bundle bundle = new Bundle(); bundle.setType(BundleType.MESSAGE); @@ -117,22 +132,41 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { } - @Test - public void testHighConcurrencyWorks() throws IOException, InterruptedException { + public void testHighConcurrencyWorks() throws IOException { List bundles = new ArrayList<>(); for (int i =0 ; i < 10; i ++) { bundles.add(myFhirContext.newJsonParser().parseResource(Bundle.class, IOUtils.toString(getClass().getResourceAsStream("/r4/identical-tags-batch.json"), Charsets.UTF_8))); } - ExecutorService tpe = Executors.newFixedThreadPool(4); - for (Bundle bundle :bundles) { - tpe.execute(() -> myClient.transaction().withBundle(bundle).execute()); - } - tpe.shutdown(); - tpe.awaitTermination(100, TimeUnit.SECONDS); - } + int desiredMaxThreads = DESIRED_MAX_THREADS - 1; + int maxThreads = TestR4Config.getMaxThreads(); + // we want strictly > because we want at least 1 extra thread hanging around for + // any spun off processes needed internally during the transaction + assertTrue(maxThreads > desiredMaxThreads, String.format("Wanted > %d threads, but we only have %d available", desiredMaxThreads, maxThreads)); + ExecutorService tpe = Executors.newFixedThreadPool(desiredMaxThreads); + CompletionService completionService = new ExecutorCompletionService<>(tpe); + for (Bundle bundle : bundles) { + completionService.submit(() -> myClient.transaction().withBundle(bundle).execute()); + } + + int count = 0; + int expected = bundles.size(); + while (count < expected) { + try { + completionService.take(); + count++; + } catch (Exception ex) { + ourLog.error(ex.getMessage()); + fail(ex.getMessage()); + } + } + + tpe.shutdown(); + await().atMost(100, TimeUnit.SECONDS) + .until(tpe::isShutdown); + } @Test public void testBundleBatchWithSingleThread() { @@ -144,8 +178,9 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { Bundle input = new Bundle(); input.setType(BundleType.BATCH); - for (String id : ids) - input.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl(id); + for (String id : ids) { + input.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl(id); + } Bundle output = myClient.transaction().withBundle(input).execute(); @@ -158,9 +193,8 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { for (BundleEntryComponent bundleEntry : bundleEntries) { assertEquals(ids.get(i++), bundleEntry.getResource().getIdElement().toUnqualifiedVersionless().getValueAsString()); } - - } + @Test public void testBundleBatchWithError() { List ids = createPatients(5); @@ -351,7 +385,8 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { bundle.getEntry().forEach(entry -> carePlans.add((CarePlan) entry.getResource())); // Post CarePlans should not get: HAPI-2006: Unable to perform PUT, URL provided is invalid... - myClient.transaction().withResources(carePlans).execute(); + List result = myClient.transaction().withResources(carePlans).execute(); + assertFalse(result.isEmpty()); } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemTest.java index 06693388bee..c7dff314553 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4CodeSystemTest.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.term.TermTestUtil; +import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import org.apache.commons.io.IOUtils; @@ -26,10 +27,13 @@ import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.transaction.annotation.Transactional; import java.io.IOException; +import java.util.concurrent.TimeUnit; +import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -37,12 +41,16 @@ import static org.junit.jupiter.api.Assertions.fail; public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test { + private static final String SYSTEM_PARENTCHILD = "http://parentchild"; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4CodeSystemTest.class); private static final String CS_ACME_URL = "http://acme.org"; private Long parentChildCsId; private IIdType myCsId; + @Autowired + private ITermDeferredStorageSvc myITermDeferredStorageSvc; + @BeforeEach @Transactional public void before02() throws IOException { @@ -63,6 +71,13 @@ public class ResourceProviderR4CodeSystemTest extends BaseResourceProviderR4Test DaoMethodOutcome parentChildCsOutcome = myCodeSystemDao.create(parentChildCs); parentChildCsId = ((ResourceTable) parentChildCsOutcome.getEntity()).getId(); + // ensure all terms are loaded + await().atMost(5, TimeUnit.SECONDS) + .until(() -> { + myBatch2JobHelper.forceRunMaintenancePass(); + myITermDeferredStorageSvc.saveDeferred(); + return myITermDeferredStorageSvc.isStorageQueueEmpty(true); + }); } @Test diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ResourceReindexSvcImplTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ResourceReindexSvcImplTest.java index 2fcf5b19b1e..1cd96f9a46a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ResourceReindexSvcImplTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/reindex/ResourceReindexSvcImplTest.java @@ -30,22 +30,22 @@ public class ResourceReindexSvcImplTest extends BaseJpaR4Test { // Setup createPatient(withActiveFalse()); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Date start = new Date(); Long id0 = createPatient(withActiveFalse()).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Long id1 = createPatient(withActiveFalse()).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Date beforeLastInRange = new Date(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Long id2 = createObservation(withObservationCode("http://foo", "bar")).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Date end = new Date(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); createPatient(withActiveFalse()); @@ -103,26 +103,26 @@ public class ResourceReindexSvcImplTest extends BaseJpaR4Test { // Setup final Long patientId0 = createPatient(withActiveFalse()).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); // Start of resources within range Date start = new Date(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Long patientId1 = createPatient(withActiveFalse()).getIdPartAsLong(); createObservation(withObservationCode("http://foo", "bar")); createObservation(withObservationCode("http://foo", "bar")); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Date beforeLastInRange = new Date(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Long patientId2 = createPatient(withActiveFalse()).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); Date end = new Date(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); // End of resources within range createObservation(withObservationCode("http://foo", "bar")); final Long patientId3 = createPatient(withActiveFalse()).getIdPartAsLong(); - sleepUntilTimeChanges(); + sleepUntilTimeChange(); // Execute diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/job/TermCodeSystemDeleteJobTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/job/TermCodeSystemDeleteJobTest.java index 9b541282fa0..7f7897869d2 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/job/TermCodeSystemDeleteJobTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/term/job/TermCodeSystemDeleteJobTest.java @@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.term.ZipCollectionBuilder; import ca.uhn.fhir.jpa.term.models.TermCodeSystemDeleteJobParameters; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.jpa.test.Batch2JobHelper; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.util.JsonUtil; @@ -127,7 +128,7 @@ public class TermCodeSystemDeleteJobTest extends BaseJpaR4Test { JobInstanceStartRequest request = new JobInstanceStartRequest(); request.setJobDefinitionId(TERM_CODE_SYSTEM_DELETE_JOB_NAME); request.setParameters(JsonUtil.serialize(parameters)); - Batch2JobStartResponse response = myJobCoordinator.startInstance(request); + Batch2JobStartResponse response = myJobCoordinator.startInstance(new SystemRequestDetails(), request); myBatch2JobHelper.awaitJobCompletion(response); @@ -147,7 +148,7 @@ public class TermCodeSystemDeleteJobTest extends BaseJpaR4Test { request.setParameters(new TermCodeSystemDeleteJobParameters()); // no pid InvalidRequestException exception = assertThrows(InvalidRequestException.class, () -> { - myJobCoordinator.startInstance(request); + myJobCoordinator.startInstance(new SystemRequestDetails(), request); }); assertTrue(exception.getMessage().contains("Invalid Term Code System PID 0"), exception.getMessage()); } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/TestJobDefinitionUtils.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/TestJobDefinitionUtils.java new file mode 100644 index 00000000000..230edc6881c --- /dev/null +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/TestJobDefinitionUtils.java @@ -0,0 +1,67 @@ +package ca.uhn.fhir.testjob; + +import ca.uhn.fhir.batch2.api.IJobCompletionHandler; +import ca.uhn.fhir.batch2.api.IJobStepWorker; +import ca.uhn.fhir.batch2.api.VoidModel; +import ca.uhn.fhir.batch2.model.JobDefinition; +import ca.uhn.fhir.model.api.IModelJson; +import ca.uhn.fhir.testjob.models.FirstStepOutput; +import ca.uhn.fhir.testjob.models.TestJobParameters; + +@SuppressWarnings({"unchecked", "rawtypes"}) +public class TestJobDefinitionUtils { + + public static final int TEST_JOB_VERSION = 1; + public static final String FIRST_STEP_ID = "first-step"; + public static final String LAST_STEP_ID = "last-step"; + + /** + * Creates a test job definition. + * This job will not be gated. + */ + public static JobDefinition buildJobDefinition( + String theJobId, + IJobStepWorker theFirstStep, + IJobStepWorker theLastStep, + IJobCompletionHandler theCompletionHandler) { + return getJobBuilder(theJobId, theFirstStep, theLastStep, theCompletionHandler).build(); + } + + /** + * Creates a test job defintion. + * This job will be gated. + */ + public static JobDefinition buildGatedJobDefinition( + String theJobId, + IJobStepWorker theFirstStep, + IJobStepWorker theLastStep, + IJobCompletionHandler theCompletionHandler) { + return getJobBuilder(theJobId, theFirstStep, theLastStep, theCompletionHandler) + .gatedExecution().build(); + } + + private static JobDefinition.Builder getJobBuilder( + String theJobId, + IJobStepWorker theFirstStep, + IJobStepWorker theLastStep, + IJobCompletionHandler theCompletionHandler + ) { + return JobDefinition.newBuilder() + .setJobDefinitionId(theJobId) + .setJobDescription("test job") + .setJobDefinitionVersion(TEST_JOB_VERSION) + .setParametersType(TestJobParameters.class) + .addFirstStep( + FIRST_STEP_ID, + "Test first step", + FirstStepOutput.class, + theFirstStep + ) + .addLastStep( + LAST_STEP_ID, + "Test last step", + theLastStep + ) + .completionHandler(theCompletionHandler); + } +} diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/FirstStepOutput.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/FirstStepOutput.java new file mode 100644 index 00000000000..34cefc682f8 --- /dev/null +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/FirstStepOutput.java @@ -0,0 +1,9 @@ +package ca.uhn.fhir.testjob.models; + +import ca.uhn.fhir.model.api.IModelJson; + +/** + * Sample first step output for test job defintions created in {@link ca.uhn.fhir.testjob.TestJobDefinitionUtils} + */ +public class FirstStepOutput implements IModelJson { +} diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/ReductionStepOutput.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/ReductionStepOutput.java new file mode 100644 index 00000000000..62e2a101188 --- /dev/null +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/ReductionStepOutput.java @@ -0,0 +1,9 @@ +package ca.uhn.fhir.testjob.models; + +import ca.uhn.fhir.model.api.IModelJson; + +/** + * Sample output object for reduction steps for test job created in {@link ca.uhn.fhir.testjob.TestJobDefinitionUtils} + */ +public class ReductionStepOutput implements IModelJson { +} diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/TestJobParameters.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/TestJobParameters.java new file mode 100644 index 00000000000..6fb3aa8650c --- /dev/null +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/testjob/models/TestJobParameters.java @@ -0,0 +1,9 @@ +package ca.uhn.fhir.testjob.models; + +import ca.uhn.fhir.model.api.IModelJson; + +/** + * Sample job parameters; these are used for jobs created in {@link ca.uhn.fhir.testjob.TestJobDefinitionUtils} + */ +public class TestJobParameters implements IModelJson { +} diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index 8a2cd86b95d..0c26dd83b61 100644 --- a/hapi-fhir-jpaserver-test-r4b/pom.xml +++ b/hapi-fhir-jpaserver-test-r4b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml index 0c7622cb1df..b3dc3455ff3 100644 --- a/hapi-fhir-jpaserver-test-r5/pom.xml +++ b/hapi-fhir-jpaserver-test-r5/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index b756a6dbbd0..5aad3443ecb 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaR4Test.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaR4Test.java index 33d536600c1..ae49003702d 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaR4Test.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaR4Test.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.jpa.test; +import ca.uhn.fhir.batch2.api.IJobMaintenanceService; import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.IValidationSupport; @@ -218,6 +219,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.empty; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.fail; @ExtendWith(SpringExtension.class) @@ -247,7 +249,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil @Autowired protected ISearchDao mySearchEntityDao; @Autowired - private IBatch2JobInstanceRepository myJobInstanceRepository; + protected IBatch2JobInstanceRepository myJobInstanceRepository; @Autowired private IBatch2WorkChunkRepository myWorkChunkRepository; @@ -553,11 +555,18 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil @Autowired protected TestDaoSearch myTestDaoSearch; + @Autowired + protected IJobMaintenanceService myJobMaintenanceService; + @RegisterExtension private final PreventDanglingInterceptorsExtension myPreventDanglingInterceptorsExtension = new PreventDanglingInterceptorsExtension(()-> myInterceptorRegistry); @AfterEach() + @Order(0) public void afterCleanupDao() { + // make sure there are no running jobs + assertFalse(myBatch2JobHelper.hasRunningJobs()); + myStorageSettings.setExpireSearchResults(new JpaStorageSettings().isExpireSearchResults()); myStorageSettings.setEnforceReferentialIntegrityOnDelete(new JpaStorageSettings().isEnforceReferentialIntegrityOnDelete()); myStorageSettings.setExpireSearchResultsAfterMillis(new JpaStorageSettings().getExpireSearchResultsAfterMillis()); @@ -572,6 +581,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil myPagingProvider.setMaximumPageSize(BasePagingProvider.DEFAULT_MAX_PAGE_SIZE); myPartitionSettings.setPartitioningEnabled(false); + ourLog.info("1 - " + getClass().getSimpleName() + ".afterCleanupDao"); } @Override @@ -580,6 +590,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil public void afterResetInterceptors() { super.afterResetInterceptors(); myInterceptorRegistry.unregisterInterceptor(myPerformanceTracingLoggingInterceptor); + + ourLog.info("2 - " + getClass().getSimpleName() + ".afterResetInterceptors"); } @AfterEach @@ -590,6 +602,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil TermConceptMappingSvcImpl.clearOurLastResultsFromTranslationWithReverseCache(); TermDeferredStorageSvcImpl termDeferredStorageSvc = AopTestUtils.getTargetObject(myTerminologyDeferredStorageSvc); termDeferredStorageSvc.clearDeferred(); + + ourLog.info("4 - " + getClass().getSimpleName() + ".afterClearTerminologyCaches"); } @BeforeEach @@ -613,6 +627,21 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil @AfterEach public void afterPurgeDatabase() { + /* + * We have to stop all scheduled jobs or they will + * interfere with the database cleanup! + */ + ourLog.info("Pausing Schedulers"); + mySchedulerService.pause(); + + myTerminologyDeferredStorageSvc.logQueueForUnitTest(); + if (!myTermDeferredStorageSvc.isStorageQueueEmpty(true)) { + ourLog.warn("There is deferred terminology storage stuff still in the queue. Please verify your tests clean up ok."); + if (myTermDeferredStorageSvc instanceof TermDeferredStorageSvcImpl t) { + t.clearDeferred(); + } + } + boolean registeredStorageInterceptor = false; if (myMdmStorageInterceptor != null && !myInterceptorService.getAllRegisteredInterceptors().contains(myMdmStorageInterceptor)) { myInterceptorService.registerInterceptor(myMdmStorageInterceptor); @@ -635,6 +664,11 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil myInterceptorService.unregisterInterceptor(myMdmStorageInterceptor); } } + + // restart the jobs + ourLog.info("Restarting the schedulers"); + mySchedulerService.unpause(); + ourLog.info("5 - " + getClass().getSimpleName() + ".afterPurgeDatabases"); } @BeforeEach @@ -819,6 +853,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil @AfterEach public void afterEachClearCaches() { myJpaValidationSupportChainR4.invalidateCaches(); + ourLog.info("3 - " + getClass().getSimpleName() + ".afterEachClearCaches"); } private static void flattenExpansionHierarchy(List theFlattenedHierarchy, List theCodes, String thePrefix) { diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaTest.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaTest.java index 8a6890d96ae..b8af987a9f2 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/BaseJpaTest.java @@ -69,6 +69,7 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken; import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamUri; import ca.uhn.fhir.jpa.model.entity.ResourceLink; import ca.uhn.fhir.jpa.model.entity.ResourceTable; +import ca.uhn.fhir.jpa.model.sched.ISchedulerService; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; @@ -77,6 +78,7 @@ import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc; import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc; import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader; import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry; +import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc; import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener; import ca.uhn.fhir.jpa.util.MemoryCacheService; import ca.uhn.fhir.rest.api.server.IBundleProvider; @@ -243,6 +245,8 @@ public abstract class BaseJpaTest extends BaseTest { protected ITermConceptPropertyDao myTermConceptPropertyDao; @Autowired private MemoryCacheService myMemoryCacheService; + @Autowired + protected ISchedulerService mySchedulerService; @Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT) @Autowired private IValidationSupport myJpaPersistedValidationSupport; @@ -256,6 +260,8 @@ public abstract class BaseJpaTest extends BaseTest { private IResourceHistoryTableDao myResourceHistoryTableDao; @Autowired private DaoRegistry myDaoRegistry; + @Autowired + protected ITermDeferredStorageSvc myTermDeferredStorageSvc; private final List myRegisteredInterceptors = new ArrayList<>(1); @SuppressWarnings("BusyWait") @@ -291,7 +297,7 @@ public abstract class BaseJpaTest extends BaseTest { } @SuppressWarnings("BusyWait") - protected static void purgeDatabase(JpaStorageSettings theStorageSettings, IFhirSystemDao theSystemDao, IResourceReindexingSvc theResourceReindexingSvc, ISearchCoordinatorSvc theSearchCoordinatorSvc, ISearchParamRegistry theSearchParamRegistry, IBulkDataExportJobSchedulingHelper theBulkDataJobActivator) { + public static void purgeDatabase(JpaStorageSettings theStorageSettings, IFhirSystemDao theSystemDao, IResourceReindexingSvc theResourceReindexingSvc, ISearchCoordinatorSvc theSearchCoordinatorSvc, ISearchParamRegistry theSearchParamRegistry, IBulkDataExportJobSchedulingHelper theBulkDataJobActivator) { theSearchCoordinatorSvc.cancelAllActiveSearches(); theResourceReindexingSvc.cancelAndPurgeAllJobs(); theBulkDataJobActivator.cancelAndPurgeAllJobs(); @@ -303,6 +309,7 @@ public abstract class BaseJpaTest extends BaseTest { for (int count = 0; ; count++) { try { + ourLog.info("Calling Expunge count {}", count); theSystemDao.expunge(new ExpungeOptions().setExpungeEverything(true), new SystemRequestDetails()); break; } catch (Exception e) { @@ -595,9 +602,9 @@ public abstract class BaseJpaTest extends BaseTest { } /** - * Sleep until at least 1 ms has elapsed + * Sleep until time change on the clocks */ - public void sleepUntilTimeChanges() { + public void sleepUntilTimeChange() { StopWatch sw = new StopWatch(); await().until(() -> sw.getMillis() > 0); } diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java index 204da1cd32e..37d58f02776 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/Batch2JobHelper.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.batch2.api.IJobMaintenanceService; import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.batch2.models.JobInstanceFetchRequest; import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import org.awaitility.Awaitility; import org.awaitility.core.ConditionTimeoutException; @@ -32,10 +33,13 @@ import org.slf4j.LoggerFactory; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.thymeleaf.util.ArrayUtils; +import java.time.Duration; +import java.time.temporal.ChronoUnit; import java.util.Collection; import java.util.HashMap; import java.util.List; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Collectors; import static org.awaitility.Awaitility.await; @@ -89,10 +93,12 @@ public class Batch2JobHelper { public JobInstance awaitJobHasStatus(String theInstanceId, int theSecondsToWait, StatusEnum... theExpectedStatus) { assert !TransactionSynchronizationManager.isActualTransactionActive(); + AtomicInteger checkCount = new AtomicInteger(); try { await() .atMost(theSecondsToWait, TimeUnit.SECONDS) .until(() -> { + checkCount.getAndIncrement(); boolean inFinalStatus = false; if (ArrayUtils.contains(theExpectedStatus, StatusEnum.COMPLETED) && !ArrayUtils.contains(theExpectedStatus, StatusEnum.FAILED)) { inFinalStatus = hasStatus(theInstanceId, StatusEnum.FAILED); @@ -113,7 +119,9 @@ public class Batch2JobHelper { .map(t -> t.getInstanceId() + " " + t.getJobDefinitionId() + "/" + t.getStatus().name()) .collect(Collectors.joining("\n")); String currentStatus = myJobCoordinator.getInstance(theInstanceId).getStatus().name(); - fail("Job " + theInstanceId + " still has status " + currentStatus + " - All statuses:\n" + statuses); + fail("Job " + theInstanceId + " still has status " + currentStatus + + " after " + checkCount.get() + " checks in " + theSecondsToWait + " seconds." + + " - All statuses:\n" + statuses); } return myJobCoordinator.getInstance(theInstanceId); } @@ -162,8 +170,39 @@ public class Batch2JobHelper { return awaitJobHasStatus(theInstanceId, StatusEnum.ERRORED, StatusEnum.FAILED); } + public void awaitJobHasStatusWithForcedMaintenanceRuns(String theInstanceId, StatusEnum theStatusEnum) { + AtomicInteger counter = new AtomicInteger(); + try { + await() + .atMost(Duration.of(10, ChronoUnit.SECONDS)) + .until(() -> { + counter.getAndIncrement(); + forceRunMaintenancePass(); + return hasStatus(theInstanceId, theStatusEnum); + }); + } catch (ConditionTimeoutException ex) { + StatusEnum status = getStatus(theInstanceId); + String msg = String.format( + "Job %s has state %s after 10s timeout and %d checks", + theInstanceId, + status.name(), + counter.get() + ); + } + } + public void awaitJobInProgress(String theInstanceId) { - await().until(() -> checkStatusWithMaintenancePass(theInstanceId, StatusEnum.IN_PROGRESS)); + try { + await() + .atMost(Duration.of(10, ChronoUnit.SECONDS)) + .until(() -> checkStatusWithMaintenancePass(theInstanceId, StatusEnum.IN_PROGRESS)); + } catch (ConditionTimeoutException ex) { + StatusEnum statusEnum = getStatus(theInstanceId); + String msg = String.format("Job %s still has status %s after 10 seconds.", + theInstanceId, + statusEnum.name()); + fail(msg); + } } public void assertNotFastTracking(String theInstanceId) { @@ -175,7 +214,21 @@ public class Batch2JobHelper { } public void awaitGatedStepId(String theExpectedGatedStepId, String theInstanceId) { - await().until(() -> theExpectedGatedStepId.equals(myJobCoordinator.getInstance(theInstanceId).getCurrentGatedStepId())); + try { + await().until(() -> { + String currentGatedStepId = myJobCoordinator.getInstance(theInstanceId).getCurrentGatedStepId(); + return theExpectedGatedStepId.equals(currentGatedStepId); + }); + } catch (ConditionTimeoutException ex) { + JobInstance instance = myJobCoordinator.getInstance(theInstanceId); + String msg = String.format("Instance %s of Job %s never got to step %s. Current step %s, current status %s.", + theInstanceId, + instance.getJobDefinitionId(), + theExpectedGatedStepId, + instance.getCurrentGatedStepId(), + instance.getStatus().name()); + fail(msg); + } } public long getCombinedRecordsProcessed(String theInstanceId) { @@ -223,6 +276,33 @@ public class Batch2JobHelper { awaitNoJobsRunning(false); } + public boolean hasRunningJobs() { + HashMap map = new HashMap<>(); + List jobs = myJobCoordinator.getInstances(1000, 1); + // "All Jobs" assumes at least one job exists + if (jobs.isEmpty()) { + return false; + } + + for (JobInstance job : jobs) { + if (job.getStatus().isIncomplete()) { + map.put(job.getInstanceId(), job.getJobDefinitionId() + " : " + job.getStatus().name()); + } + } + + if (!map.isEmpty()) { + ourLog.error( + "Found Running Jobs " + + map.keySet().stream() + .map(k -> k + " : " + map.get(k)) + .collect(Collectors.joining("\n")) + ); + + return true; + } + return false; + } + public void awaitNoJobsRunning(boolean theExpectAtLeastOneJobToExist) { HashMap map = new HashMap<>(); Awaitility.await().atMost(10, TimeUnit.SECONDS) @@ -255,6 +335,10 @@ public class Batch2JobHelper { myJobMaintenanceService.runMaintenancePass(); } + public void enableMaintenanceRunner(boolean theEnabled) { + myJobMaintenanceService.enableMaintenancePass(theEnabled); + } + /** * Forces a run of the maintenance pass without waiting for * the semaphore to release diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/Batch2FastSchedulerConfig.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/Batch2FastSchedulerConfig.java new file mode 100644 index 00000000000..28e3ae6ea1d --- /dev/null +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/Batch2FastSchedulerConfig.java @@ -0,0 +1,23 @@ +package ca.uhn.fhir.jpa.test.config; + +import ca.uhn.fhir.batch2.api.IJobMaintenanceService; +import ca.uhn.fhir.batch2.maintenance.JobMaintenanceServiceImpl; +import jakarta.annotation.PostConstruct; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; + +/** + * A fast scheduler to use for Batch2 job Integration Tests. + * This scheduler will run every 200ms (instead of the default 1min) + * so that our ITs can complete in a sane amount of time. + */ +@Configuration +public class Batch2FastSchedulerConfig { + @Autowired + IJobMaintenanceService myJobMaintenanceService; + + @PostConstruct + void fastScheduler() { + ((JobMaintenanceServiceImpl)myJobMaintenanceService).setScheduledJobFrequencyMillis(200); + } +} diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/TestR4Config.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/TestR4Config.java index 3bae2e3ad1f..7fd84089838 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/TestR4Config.java +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/config/TestR4Config.java @@ -57,11 +57,7 @@ import java.sql.Connection; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; -import java.util.Deque; -import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; -import java.util.LinkedList; import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; @@ -85,6 +81,7 @@ import static org.junit.jupiter.api.Assertions.fail; public class TestR4Config { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestR4Config.class); + public static Integer ourMaxThreads; private final AtomicInteger myBorrowedConnectionCount = new AtomicInteger(0); private final AtomicInteger myReturnedConnectionCount = new AtomicInteger(0); @@ -96,7 +93,7 @@ public class TestR4Config { * starvation */ if (ourMaxThreads == null) { - ourMaxThreads = (int) (Math.random() * 6.0) + 3; + ourMaxThreads = (int) (Math.random() * 6.0) + 4; if (HapiTestSystemProperties.isSingleDbConnectionEnabled()) { ourMaxThreads = 1; @@ -108,7 +105,7 @@ public class TestR4Config { ourLog.warn("ourMaxThreads={}", ourMaxThreads); } - private Map myConnectionRequestStackTraces = Collections.synchronizedMap(new LinkedHashMap<>()); + private final Map myConnectionRequestStackTraces = Collections.synchronizedMap(new LinkedHashMap<>()); @Autowired TestHSearchAddInConfig.IHSearchConfigurer hibernateSearchConfigurer; @@ -300,5 +297,4 @@ public class TestR4Config { public static int getMaxThreads() { return ourMaxThreads; } - } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index cd7ce2cb444..bd83c065399 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-cds-hooks/pom.xml b/hapi-fhir-server-cds-hooks/pom.xml index 10ad59331cd..d5de58458b9 100644 --- a/hapi-fhir-server-cds-hooks/pom.xml +++ b/hapi-fhir-server-cds-hooks/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index a012bafd9b5..8be4eeef20e 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index a152e68cf96..91b0ba08703 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index e81d4d6c257..ffce06e1c4a 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml index b545d5e6ca6..60e63aab6ac 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml index a3eea68ca7a..8b0d686bf00 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index f009f0fb9e9..f932afeef76 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml index 0c262056280..e589b46af12 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml @@ -7,7 +7,7 @@ hapi-fhir ca.uhn.hapi.fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index fd2e15e3e75..fb776ba6387 100644 --- a/hapi-fhir-serviceloaders/pom.xml +++ b/hapi-fhir-serviceloaders/pom.xml @@ -5,7 +5,7 @@ hapi-deployable-pom ca.uhn.hapi.fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 7ac274198b7..c78e261e01a 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 07748abe01a..88f887381f2 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index c3cdf23bf3c..206beef0160 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index 3290e867a12..14cf689c7c2 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index bd198dfe7ae..e37aaba366e 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index 924eb57db31..af6174b4f59 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index 2b661d2f417..4b909f3288e 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 508e17fe930..88c51675f81 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 71238102505..863a09e4eb6 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-test-utilities/pom.xml b/hapi-fhir-storage-batch2-test-utilities/pom.xml index 8d57d1b7948..4f97d4da2b4 100644 --- a/hapi-fhir-storage-batch2-test-utilities/pom.xml +++ b/hapi-fhir-storage-batch2-test-utilities/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -17,6 +17,12 @@ HAPI FHIR JPA Server - Batch2 specification tests Batch2 is a framework for managing and executing long running "batch" jobs + + 17 + 17 + 17 + + ca.uhn.hapi.fhir diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/AbstractIJobPersistenceSpecificationTest.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/AbstractIJobPersistenceSpecificationTest.java index 230944b128a..da7b528c8c4 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/AbstractIJobPersistenceSpecificationTest.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/AbstractIJobPersistenceSpecificationTest.java @@ -20,24 +20,32 @@ package ca.uhn.hapi.fhir.batch2.test; +import ca.uhn.fhir.batch2.api.ChunkExecutionDetails; +import ca.uhn.fhir.batch2.api.IJobDataSink; import ca.uhn.fhir.batch2.api.IJobMaintenanceService; import ca.uhn.fhir.batch2.api.IJobPersistence; +import ca.uhn.fhir.batch2.api.IReductionStepWorker; +import ca.uhn.fhir.batch2.api.JobExecutionFailedException; import ca.uhn.fhir.batch2.api.RunOutcome; +import ca.uhn.fhir.batch2.api.StepExecutionDetails; +import ca.uhn.fhir.batch2.api.VoidModel; import ca.uhn.fhir.batch2.channel.BatchJobSender; import ca.uhn.fhir.batch2.coordinator.JobDefinitionRegistry; +import ca.uhn.fhir.batch2.model.ChunkOutcome; import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.StatusEnum; -import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkCreateEvent; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.StopWatch; +import ca.uhn.hapi.fhir.batch2.test.support.JobMaintenanceStateInformation; import ca.uhn.hapi.fhir.batch2.test.support.TestJobParameters; import ca.uhn.hapi.fhir.batch2.test.support.TestJobStep2InputType; import ca.uhn.hapi.fhir.batch2.test.support.TestJobStep3InputType; import ca.uhn.test.concurrency.PointcutLatch; import jakarta.annotation.Nonnull; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Nested; import org.mockito.ArgumentCaptor; @@ -64,7 +72,8 @@ import static org.mockito.Mockito.verify; * These tests are abstract, and do not depend on JPA. * Test setups should use the public batch2 api to create scenarios. */ -public abstract class AbstractIJobPersistenceSpecificationTest implements IInProgressActionsTests, IInstanceStateTransitions, ITestFixture, WorkChunkTestConstants { +public abstract class AbstractIJobPersistenceSpecificationTest + implements ITestFixture, IWorkChunkCommon, WorkChunkTestConstants, IJobMaintenanceActions, IInProgressActionsTests, IInstanceStateTransitions { private static final Logger ourLog = LoggerFactory.getLogger(AbstractIJobPersistenceSpecificationTest.class); @@ -91,38 +100,63 @@ public abstract class AbstractIJobPersistenceSpecificationTest implements IInPro return mySvc; } - public JobDefinition withJobDefinition(boolean theIsGatedBoolean) { + @Nonnull + public JobDefinition withJobDefinitionWithReductionStep() { JobDefinition.Builder builder = JobDefinition.newBuilder() - .setJobDefinitionId(theIsGatedBoolean ? GATED_JOB_DEFINITION_ID : JOB_DEFINITION_ID) + .setJobDefinitionId(GATED_JOB_DEFINITION_ID + "_reduction") .setJobDefinitionVersion(JOB_DEF_VER) + .gatedExecution() .setJobDescription("A job description") .setParametersType(TestJobParameters.class) - .addFirstStep(TARGET_STEP_ID, "the first step", TestJobStep2InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) - .addIntermediateStep("2nd-step-id", "the second step", TestJobStep3InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) - .addLastStep("last-step-id", "the final step", (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)); + .addFirstStep(FIRST_STEP_ID, "the first step", TestJobStep2InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) + .addIntermediateStep(SECOND_STEP_ID, "the second step", TestJobStep3InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) + .addFinalReducerStep(LAST_STEP_ID, "reduction step", VoidModel.class, new IReductionStepWorker() { + @NotNull + @Override + public ChunkOutcome consume(ChunkExecutionDetails theChunkDetails) { + return ChunkOutcome.SUCCESS(); + } + + @NotNull + @Override + public RunOutcome run(@NotNull StepExecutionDetails theStepExecutionDetails, @NotNull IJobDataSink theDataSink) throws JobExecutionFailedException { + return RunOutcome.SUCCESS; + } + }); + return builder.build(); + } + + @Nonnull + public JobDefinition withJobDefinition(boolean theIsGatedBoolean) { + JobDefinition.Builder builder = JobDefinition.newBuilder() + .setJobDefinitionId(theIsGatedBoolean ? GATED_JOB_DEFINITION_ID : JOB_DEFINITION_ID) + .setJobDefinitionVersion(JOB_DEF_VER) + .setJobDescription("A job description") + .setParametersType(TestJobParameters.class) + .addFirstStep(FIRST_STEP_ID, "the first step", TestJobStep2InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) + .addIntermediateStep(SECOND_STEP_ID, "the second step", TestJobStep3InputType.class, (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)) + .addLastStep(LAST_STEP_ID, "the final step", (theStepExecutionDetails, theDataSink) -> new RunOutcome(0)); if (theIsGatedBoolean) { builder.gatedExecution(); } return builder.build(); } - @AfterEach - public void after() { - myJobDefinitionRegistry.removeJobDefinition(JOB_DEFINITION_ID, JOB_DEF_VER); - - // clear invocations on the batch sender from previous jobs that might be - // kicking around - Mockito.clearInvocations(myBatchJobSender); - } - @Override public ITestFixture getTestManager() { return this; } - @Override - public void enableMaintenanceRunner(boolean theToEnable) { - myMaintenanceService.enableMaintenancePass(theToEnable); + @AfterEach + public void after() { + myJobDefinitionRegistry.removeJobDefinition(JOB_DEFINITION_ID, JOB_DEF_VER); + + // re-enable our runner after every test (just in case) + myMaintenanceService.enableMaintenancePass(true); + + // clear invocations on the batch sender from previous jobs that might be + // kicking around + Mockito.clearInvocations(myBatchJobSender); } @Nested @@ -167,11 +201,19 @@ public abstract class AbstractIJobPersistenceSpecificationTest implements IInPro instance.setJobDefinitionVersion(JOB_DEF_VER); instance.setParameters(CHUNK_DATA); instance.setReport("TEST"); + if (jobDefinition.isGatedExecution()) { + instance.setCurrentGatedStepId(jobDefinition.getFirstStepId()); + } return instance; } - public String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData) { - WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, JOB_DEF_VER, theTargetStepId, theInstanceId, theSequence, theSerializedData); + public String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData, boolean theGatedExecution) { + WorkChunkCreateEvent batchWorkChunk = new WorkChunkCreateEvent(theJobDefinitionId, JOB_DEF_VER, theTargetStepId, theInstanceId, theSequence, theSerializedData, theGatedExecution); + return mySvc.onWorkChunkCreate(batchWorkChunk); + } + + public String storeFirstWorkChunk(JobDefinition theJobDefinition, String theInstanceId) { + WorkChunkCreateEvent batchWorkChunk = WorkChunkCreateEvent.firstChunk(theJobDefinition, theInstanceId); return mySvc.onWorkChunkCreate(batchWorkChunk); } @@ -230,11 +272,20 @@ public abstract class AbstractIJobPersistenceSpecificationTest implements IInPro return chunkId; } - @Override - public abstract WorkChunk freshFetchWorkChunk(String theChunkId); - public String createChunk(String theInstanceId) { - return storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, theInstanceId, 0, CHUNK_DATA); + return storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, theInstanceId, 0, CHUNK_DATA, false); + } + + public String createChunk(String theInstanceId, boolean theGatedExecution) { + return storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, theInstanceId, 0, CHUNK_DATA, theGatedExecution); + } + + public String createFirstChunk(JobDefinition theJobDefinition, String theJobInstanceId){ + return storeFirstWorkChunk(theJobDefinition, theJobInstanceId); + } + + public void enableMaintenanceRunner(boolean theToEnable) { + myMaintenanceService.enableMaintenancePass(theToEnable); } public PointcutLatch disableWorkChunkMessageHandler() { @@ -254,4 +305,9 @@ public abstract class AbstractIJobPersistenceSpecificationTest implements IInPro verify(myBatchJobSender, times(theNumberOfTimes)) .sendWorkChannelMessage(notificationCaptor.capture()); } + + @Override + public void createChunksInStates(JobMaintenanceStateInformation theJobMaintenanceStateInformation) { + theJobMaintenanceStateInformation.initialize(mySvc); + } } diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IInstanceStateTransitions.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IInstanceStateTransitions.java index 377b603eabb..89e99aaa125 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IInstanceStateTransitions.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IInstanceStateTransitions.java @@ -26,6 +26,8 @@ import ca.uhn.fhir.batch2.maintenance.JobInstanceProcessor; import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.batch2.model.WorkChunk; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; @@ -34,6 +36,9 @@ import org.slf4j.LoggerFactory; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.emptyString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.not; import static org.hamcrest.Matchers.equalTo; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -42,6 +47,31 @@ import static org.junit.jupiter.api.Assertions.assertNull; public interface IInstanceStateTransitions extends IWorkChunkCommon, WorkChunkTestConstants { Logger ourLog = LoggerFactory.getLogger(IInstanceStateTransitions.class); + @Test + default void createInstance_createsInQueuedWithChunkInReady() { + // given + JobDefinition jd = getTestManager().withJobDefinition(false); + + // when + IJobPersistence.CreateResult createResult = + getTestManager().newTxTemplate().execute(status-> + getTestManager().getSvc().onCreateWithFirstChunk(jd, "{}")); + + // then + ourLog.info("job and chunk created {}", createResult); + assertNotNull(createResult); + assertThat(createResult.jobInstanceId, not(emptyString())); + assertThat(createResult.workChunkId, not(emptyString())); + + JobInstance jobInstance = getTestManager().freshFetchJobInstance(createResult.jobInstanceId); + assertThat(jobInstance.getStatus(), equalTo(StatusEnum.QUEUED)); + assertThat(jobInstance.getParameters(), equalTo("{}")); + + WorkChunk firstChunk = getTestManager().freshFetchWorkChunk(createResult.workChunkId); + assertThat(firstChunk.getStatus(), equalTo(WorkChunkStatusEnum.READY)); + assertNull(firstChunk.getData(), "First chunk data is null - only uses parameters"); + } + @Test default void testCreateInstance_firstChunkDequeued_movesToInProgress() { // given diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IJobMaintenanceActions.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IJobMaintenanceActions.java new file mode 100644 index 00000000000..cb561ad87a1 --- /dev/null +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IJobMaintenanceActions.java @@ -0,0 +1,234 @@ +package ca.uhn.hapi.fhir.batch2.test; + +import ca.uhn.fhir.batch2.model.JobDefinition; +import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.hapi.fhir.batch2.test.support.JobMaintenanceStateInformation; +import ca.uhn.test.concurrency.PointcutLatch; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public interface IJobMaintenanceActions extends IWorkChunkCommon, WorkChunkTestConstants { + + Logger ourLog = LoggerFactory.getLogger(IJobMaintenanceActions.class); + + @BeforeEach + default void before() { + getTestManager().enableMaintenanceRunner(false); + } + + @Test + default void test_gatedJob_stepReady_stepAdvances() throws InterruptedException { + // setup + String initialState = """ + # chunks ready - move to queued + 1|COMPLETED + 2|READY,2|QUEUED + 2|READY,2|QUEUED + """; + int numToTransition = 2; + PointcutLatch sendLatch = getTestManager().disableWorkChunkMessageHandler(); + sendLatch.setExpectedCount(numToTransition); + JobMaintenanceStateInformation result = setupGatedWorkChunkTransitionTest(initialState, true); + getTestManager().createChunksInStates(result); + + // test + getTestManager().runMaintenancePass(); + + // verify + getTestManager().verifyWorkChunkMessageHandlerCalled(sendLatch, numToTransition); + verifyWorkChunkFinalStates(result); + } + + @ParameterizedTest + @ValueSource(strings = { + """ + 1|COMPLETED + 2|GATE_WAITING + """, + """ + # Chunk already queued -> waiting for complete + 1|COMPLETED + 2|QUEUED + """, + """ + # Chunks in progress, complete, errored -> cannot advance + 1|COMPLETED + 2|COMPLETED + 2|ERRORED + 2|IN_PROGRESS + """, + """ + # Chunk in errored/already queued -> cannot advance + 1|COMPLETED + 2|ERRORED # equivalent of QUEUED + 2|COMPLETED + """, + """ + # Not all steps ready to advance + # Latch Count: 1 + 1|COMPLETED + 2|READY,2|QUEUED # a single ready chunk + 2|IN_PROGRESS + """, + """ + # Previous step not ready -> do not advance + 1|COMPLETED + 2|COMPLETED + 2|IN_PROGRESS + 3|GATE_WAITING + 3|GATE_WAITING + """, + """ + # when current step is not all queued, should queue READY chunks + # Latch Count: 1 + 1|COMPLETED + 2|READY,2|QUEUED + 2|QUEUED + 2|COMPLETED + 2|ERRORED + 2|FAILED + 2|IN_PROGRESS + 3|GATE_WAITING + 3|QUEUED + """, + """ + # when current step is all queued but not done, should not proceed + 1|COMPLETED + 2|COMPLETED + 2|QUEUED + 2|COMPLETED + 2|ERRORED + 2|FAILED + 2|IN_PROGRESS + 3|GATE_WAITING + 3|GATE_WAITING + """ + }) + default void testGatedStep2NotReady_stepNotAdvanceToStep3(String theChunkState) throws InterruptedException { + // setup + int expectedLatchCount = getLatchCountFromState(theChunkState); + PointcutLatch sendingLatch = getTestManager().disableWorkChunkMessageHandler(); + sendingLatch.setExpectedCount(expectedLatchCount); + JobMaintenanceStateInformation state = setupGatedWorkChunkTransitionTest(theChunkState, true); + + getTestManager().createChunksInStates(state); + + // test + getTestManager().runMaintenancePass(); + + // verify + // nothing ever queued -> nothing ever sent to queue + getTestManager().verifyWorkChunkMessageHandlerCalled(sendingLatch, expectedLatchCount); + assertEquals(SECOND_STEP_ID, getJobInstanceFromState(state).getCurrentGatedStepId()); + verifyWorkChunkFinalStates(state); + } + + /** + * Returns the expected latch count specified in the state. Defaults to 0 if not found. + * Expected format: # Latch Count: {} + * e.g. # Latch Count: 3 + */ + private int getLatchCountFromState(String theState){ + String keyStr = "# Latch Count: "; + int index = theState.indexOf(keyStr); + return index == -1 ? 0 : theState.charAt(index + keyStr.length()) - '0'; + } + + @ParameterizedTest + @ValueSource(strings = { + """ + # new code only + 1|COMPLETED + 2|COMPLETED + 2|COMPLETED + 3|GATE_WAITING,3|QUEUED + 3|GATE_WAITING,3|QUEUED + """, + """ + # OLD code only + 1|COMPLETED + 2|COMPLETED + 2|COMPLETED + 3|QUEUED,3|QUEUED + 3|QUEUED,3|QUEUED + """, + """ + # mixed code + 1|COMPLETED + 2|COMPLETED + 2|COMPLETED + 3|GATE_WAITING,3|QUEUED + 3|QUEUED,3|QUEUED + """ + }) + default void testGatedStep2ReadyToAdvance_advanceToStep3(String theChunkState) throws InterruptedException { + // setup + PointcutLatch sendingLatch = getTestManager().disableWorkChunkMessageHandler(); + sendingLatch.setExpectedCount(2); + JobMaintenanceStateInformation state = setupGatedWorkChunkTransitionTest(theChunkState, true); + getTestManager().createChunksInStates(state); + + // test + getTestManager().runMaintenancePass(); + + // verify + getTestManager().verifyWorkChunkMessageHandlerCalled(sendingLatch, 2); + assertEquals(LAST_STEP_ID, getJobInstanceFromState(state).getCurrentGatedStepId()); + verifyWorkChunkFinalStates(state); + } + + @Test + default void test_ungatedJob_queuesReadyChunks() throws InterruptedException { + // setup + String state = """ + # READY chunks should transition; others should stay + 1|COMPLETED + 2|READY,2|QUEUED + 2|READY,2|QUEUED + 2|COMPLETED + 2|IN_PROGRESS + 3|IN_PROGRESS + """; + int expectedTransitions = 2; + JobMaintenanceStateInformation result = setupGatedWorkChunkTransitionTest(state, false); + + PointcutLatch sendLatch = getTestManager().disableWorkChunkMessageHandler(); + sendLatch.setExpectedCount(expectedTransitions); + getTestManager().createChunksInStates(result); + + // TEST run job maintenance - force transition + getTestManager().enableMaintenanceRunner(true); + + getTestManager().runMaintenancePass(); + + // verify + getTestManager().verifyWorkChunkMessageHandlerCalled(sendLatch, expectedTransitions); + verifyWorkChunkFinalStates(result); + } + + private JobMaintenanceStateInformation setupGatedWorkChunkTransitionTest(String theChunkState, boolean theIsGated) { + // get the job def and store the instance + JobDefinition definition = getTestManager().withJobDefinition(theIsGated); + String instanceId = getTestManager().createAndStoreJobInstance(definition); + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation(instanceId, definition, theChunkState); + + ourLog.info("Starting test case \n {}", theChunkState); + // display comments if there are any + ourLog.info(String.join(", ", stateInformation.getLineComments())); + return stateInformation; + } + + private void verifyWorkChunkFinalStates(JobMaintenanceStateInformation theStateInformation) { + theStateInformation.verifyFinalStates(getTestManager().getSvc()); + } + + private JobInstance getJobInstanceFromState(JobMaintenanceStateInformation state) { + return getTestManager().freshFetchJobInstance(state.getInstanceId()); + } +} diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/ITestFixture.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/ITestFixture.java index fdb75990f0d..0ae2302ff40 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/ITestFixture.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/ITestFixture.java @@ -23,6 +23,7 @@ import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.WorkChunk; +import ca.uhn.hapi.fhir.batch2.test.support.JobMaintenanceStateInformation; import ca.uhn.hapi.fhir.batch2.test.support.TestJobParameters; import ca.uhn.test.concurrency.PointcutLatch; import org.springframework.transaction.PlatformTransactionManager; @@ -36,12 +37,14 @@ public interface ITestFixture { WorkChunk freshFetchWorkChunk(String theChunkId); - String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData); + String storeWorkChunk(String theJobDefinitionId, String theTargetStepId, String theInstanceId, int theSequence, String theSerializedData, boolean theGatedExecution); void runInTransaction(Runnable theRunnable); void sleepUntilTimeChanges(); + JobDefinition withJobDefinitionWithReductionStep(); + JobDefinition withJobDefinition(boolean theIsGatedJob); TransactionTemplate newTxTemplate(); @@ -61,6 +64,14 @@ public interface ITestFixture { */ String createChunk(String theJobInstanceId); + String createChunk(String theJobInstanceId, boolean theGatedExecution); + + /** + * Create chunk as the first chunk of a job. + * @return the id of the created chunk + */ + String createFirstChunk(JobDefinition theJobDefinition, String theJobInstanceId); + /** * Enable/disable the maintenance runner (So it doesn't run on a scheduler) */ @@ -81,4 +92,10 @@ public interface ITestFixture { * @param theNumberOfTimes the number of invocations to expect */ void verifyWorkChunkMessageHandlerCalled(PointcutLatch theSendingLatch, int theNumberOfTimes) throws InterruptedException; + + /** + * Uses the JobMaintenanceStateInformation to setup a test. + * @param theJobMaintenanceStateInformation + */ + void createChunksInStates(JobMaintenanceStateInformation theJobMaintenanceStateInformation); } diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkErrorActionsTests.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkErrorActionsTests.java index 092f4092599..0768ed19541 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkErrorActionsTests.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkErrorActionsTests.java @@ -31,7 +31,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; public interface IWorkChunkErrorActionsTests extends IWorkChunkCommon, WorkChunkTestConstants { - /** * The consumer will retry after a retryable error is thrown */ diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStateTransitions.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStateTransitions.java index 7f906173df9..d4dff0d44d4 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStateTransitions.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStateTransitions.java @@ -19,23 +19,82 @@ */ package ca.uhn.hapi.fhir.batch2.test; +import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import ca.uhn.hapi.fhir.batch2.test.support.JobMaintenanceStateInformation; +import ca.uhn.hapi.fhir.batch2.test.support.TestJobParameters; +import ca.uhn.test.concurrency.LockstepEnumPhaser; import ca.uhn.test.concurrency.PointcutLatch; +import org.apache.commons.lang3.concurrent.BasicThreadFactory; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import static org.junit.jupiter.api.Assertions.assertEquals; +import java.time.Duration; +import java.time.Instant; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Nested public interface IWorkChunkStateTransitions extends IWorkChunkCommon, WorkChunkTestConstants { Logger ourLog = LoggerFactory.getLogger(IWorkChunkStateTransitions.class); - @Test - default void chunkReceived_queuedToInProgress() throws InterruptedException { + @BeforeEach + default void before() { + getTestManager().enableMaintenanceRunner(false); + } + + @ParameterizedTest + @CsvSource({ + "false, READY", + "true, GATE_WAITING" + }) + default void chunkCreation_nonFirstChunk_isInExpectedStatus(boolean theGatedExecution, WorkChunkStatusEnum expectedStatus) { String jobInstanceId = getTestManager().createAndStoreJobInstance(null); - String myChunkId = getTestManager().createChunk(jobInstanceId); + String myChunkId = getTestManager().createChunk(jobInstanceId, theGatedExecution); + + WorkChunk fetchedWorkChunk = getTestManager().freshFetchWorkChunk(myChunkId); + assertEquals(expectedStatus, fetchedWorkChunk.getStatus(), "New chunks are " + expectedStatus); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + default void chunkCreation_firstChunk_isInReady(boolean theGatedExecution) { + JobDefinition jobDef = getTestManager().withJobDefinition(theGatedExecution); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + String myChunkId = getTestManager().createFirstChunk(jobDef, jobInstanceId); + + WorkChunk fetchedWorkChunk = getTestManager().freshFetchWorkChunk(myChunkId); + // the first chunk of both gated and non-gated job should start in READY + assertEquals(WorkChunkStatusEnum.READY, fetchedWorkChunk.getStatus(), "New chunks are " + WorkChunkStatusEnum.READY); + } + + @Test + default void chunkReceived_forNongatedJob_queuedToInProgress() throws InterruptedException { + PointcutLatch sendLatch = getTestManager().disableWorkChunkMessageHandler(); + sendLatch.setExpectedCount(1); + + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + String myChunkId = getTestManager().createChunk(jobInstanceId, false); getTestManager().runMaintenancePass(); // the worker has received the chunk, and marks it started. @@ -47,5 +106,374 @@ public interface IWorkChunkStateTransitions extends IWorkChunkCommon, WorkChunkT // verify the db was updated too WorkChunk fetchedWorkChunk = getTestManager().freshFetchWorkChunk(myChunkId); assertEquals(WorkChunkStatusEnum.IN_PROGRESS, fetchedWorkChunk.getStatus()); + getTestManager().verifyWorkChunkMessageHandlerCalled(sendLatch, 1); + } + + /** + * Tests transitions to a known ready state for gated jobs. + * for most jobs, this is READY. For reduction step jobs, this is REDUCTION_READY + */ + @ParameterizedTest + @ValueSource(booleans = { true, false }) + default void advanceJobStepAndUpdateChunkStatus_forGatedJob_updatesBothGATE_WAITINGAndQUEUEDChunksToAnExpectedREADYState(boolean theIsReductionStep) { + // setup + getTestManager().disableWorkChunkMessageHandler(); + + WorkChunkStatusEnum nextState = theIsReductionStep ? WorkChunkStatusEnum.REDUCTION_READY : WorkChunkStatusEnum.READY; + String state = String.format(""" + 1|COMPLETED + 2|COMPLETED + 3|GATE_WAITING,3|%s + 3|QUEUED,3|%s + """, nextState.name(), nextState.name()); + + JobDefinition jobDef = theIsReductionStep ? getTestManager().withJobDefinitionWithReductionStep() : getTestManager().withJobDefinition(true); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation(jobInstanceId, jobDef, state); + getTestManager().createChunksInStates(info); + assertEquals(SECOND_STEP_ID, getTestManager().freshFetchJobInstance(jobInstanceId).getCurrentGatedStepId()); + + // execute + getTestManager().runInTransaction(() -> getTestManager().getSvc().advanceJobStepAndUpdateChunkStatus(jobInstanceId, LAST_STEP_ID, theIsReductionStep)); + + // verify + assertEquals(LAST_STEP_ID, getTestManager().freshFetchJobInstance(jobInstanceId).getCurrentGatedStepId()); + info.verifyFinalStates(getTestManager().getSvc()); + } + + @ParameterizedTest + @ValueSource(strings = { + """ + 1|COMPLETED + 2|COMPLETED + 3|READY + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|REDUCTION_READY + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|IN_PROGRESS + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|POLL_WAITING + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|ERRORED + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|FAILED + """, + """ + 1|COMPLETED + 2|COMPLETED + 3|COMPLETED + """ + }) + default void advanceJobStepAndUpdateChunkStatus_reductionJobWithInvalidStates_doNotTransition(String theState) { + // setup + getTestManager().disableWorkChunkMessageHandler(); + + JobDefinition jobDef = getTestManager().withJobDefinitionWithReductionStep(); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation(jobInstanceId, jobDef, theState); + getTestManager().createChunksInStates(info); + assertEquals(SECOND_STEP_ID, getTestManager().freshFetchJobInstance(jobInstanceId).getCurrentGatedStepId()); + + // execute + getTestManager().runInTransaction(() -> { + getTestManager().getSvc().advanceJobStepAndUpdateChunkStatus(jobInstanceId, LAST_STEP_ID, true); + }); + + // verify + assertEquals(LAST_STEP_ID, getTestManager().freshFetchJobInstance(jobInstanceId).getCurrentGatedStepId()); + info.verifyFinalStates(getTestManager().getSvc()); + } + + @Test + default void enqueueWorkChunkForProcessing_enqueuesOnlyREADYChunks() throws InterruptedException { + // setup + getTestManager().disableWorkChunkMessageHandler(); + + StringBuilder sb = new StringBuilder(); + // first step is always complete + sb.append("1|COMPLETED"); + for (WorkChunkStatusEnum status : WorkChunkStatusEnum.values()) { + if (!sb.isEmpty()) { + sb.append("\n"); + } + // second step for all other workchunks + sb.append("2|") + .append(status.name()); + } + String state = sb.toString(); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDef); + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation( + instanceId, + jobDef, + state + ); + getTestManager().createChunksInStates(stateInformation); + + // test + PointcutLatch latch = new PointcutLatch(new Exception().getStackTrace()[0].getMethodName()); + latch.setExpectedCount(stateInformation.getInitialWorkChunks().size()); + for (WorkChunk chunk : stateInformation.getInitialWorkChunks()) { + getTestManager().getSvc().enqueueWorkChunkForProcessing(chunk.getId(), updated -> { + // should not update non-ready chunks + ourLog.info("Enqueuing chunk with state {}; updated {}", chunk.getStatus().name(), updated); + int expected = chunk.getStatus() == WorkChunkStatusEnum.READY ? 1 : 0; + assertEquals(expected, updated); + latch.call(1); + }); + } + latch.awaitExpected(); + } + + /** + * Nasty test for a nasty bug. + * We use the transactional-outbox pattern to guarantee at-least-once delivery to the kafka queue by sending to + * kafka before the READY->QUEUED tx commits. + * BUT, kakfa is so fast, the listener may deque before the transition. Our listener is confused if the chunk + * is still in READY. + * This test uses a lock-step phaser to create this scenario, and makes sure the dequeue is lock-consistent with the enqueue. + * + */ + @Test + default void testSimultaneousDeque_beforeEnqueCommit_doesNotDropChunk() throws ExecutionException, InterruptedException, TimeoutException { + // given + PointcutLatch pointcutLatch = getTestManager().disableWorkChunkMessageHandler(); + getTestManager().enableMaintenanceRunner(false); + + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation( + jobInstanceId, + jobDef, + """ + 2|READY,2|IN_PROGRESS + """ + ); + stateInformation.initialize(getTestManager().getSvc()); + String chunkId = stateInformation.getInitialWorkChunks() + .stream().findFirst().orElseThrow().getId(); + + enum Steps { + STARTING, SENT_TO_KAFA_BEFORE_COMMIT, COMMIT_QUEUED_STATUS, FINISHED + } + LockstepEnumPhaser phaser = new LockstepEnumPhaser<>(3, Steps.class); + phaser.assertInPhase(Steps.STARTING); + + // test + ExecutorService workerThreads = Executors.newFixedThreadPool(2, new BasicThreadFactory.Builder().namingPattern("Deque-race-%d").build()); + try { + + // thread 1 - mimic the maintenance queueing a chunk notification to kafka + workerThreads.submit(()-> getTestManager().getSvc().enqueueWorkChunkForProcessing(chunkId, (i)->{ + phaser.arriveAndAwaitSharedEndOf(Steps.STARTING); + ourLog.info("Fake send chunk to kafka {}", chunkId); + phaser.arriveAndAwaitSharedEndOf(Steps.SENT_TO_KAFA_BEFORE_COMMIT); + // wait for listener to "receive" our notification + phaser.arriveAndAwaitSharedEndOf(Steps.COMMIT_QUEUED_STATUS); + // wait here. + })); + + // thread 2 - mimic the kafka listener receiving a notification before the maintenance tx has committed + Future> dequeueResult = workerThreads.submit(() -> { + phaser.arriveAndAwaitSharedEndOf(Steps.STARTING); + phaser.arriveAndAwaitSharedEndOf(Steps.SENT_TO_KAFA_BEFORE_COMMIT); + phaser.arriveAndDeregister(); + Optional workChunk = getTestManager().getSvc().onWorkChunkDequeue(chunkId); + + return workChunk; + }); + + phaser.arriveAndAwaitSharedEndOf(Steps.STARTING); + phaser.arriveAndAwaitSharedEndOf(Steps.SENT_TO_KAFA_BEFORE_COMMIT); + // wait while the deque tries to run + Thread.sleep(100); + phaser.arriveAndAwaitSharedEndOf(Steps.COMMIT_QUEUED_STATUS); + Optional workChunk = dequeueResult.get(1, TimeUnit.SECONDS); + + assertTrue(workChunk.isPresent(), "Found the chunk despite being simultaneous"); + stateInformation.verifyFinalStates(getTestManager().getSvc()); + + } finally { + workerThreads.shutdownNow(); + pointcutLatch.clear(); + + } + + } + + + @ParameterizedTest + @ValueSource(strings = { + "2|READY", + "2|QUEUED", + //"2|GATED,", // TODO - update/enable when gated status is available + "2|POLL_WAITING", + "2|ERRORED", + "2|FAILED", + "2|COMPLETED" + }) + default void onWorkChunkPollDelay_withNoInProgressChunks_doNotTransitionNorSetTime(String theState) { + // setup + getTestManager().disableWorkChunkMessageHandler(); + getTestManager().enableMaintenanceRunner(false); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + // the time we set it to + Date newTime = Date.from( + Instant.now().plus(Duration.ofSeconds(100)) + ); + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation( + jobInstanceId, + jobDef, + theState + ); + stateInformation.initialize(getTestManager().getSvc()); + + String chunkId = stateInformation.getInitialWorkChunks() + .stream().findFirst().orElseThrow().getId(); + + // test + getTestManager().getSvc().onWorkChunkPollDelay(chunkId, newTime); + + // verify + stateInformation.verifyFinalStates(getTestManager().getSvc(), chunk -> assertNull(chunk.getNextPollTime())); + } + + @Test + default void onWorkChunkPollDelay_withInProgressChunks_transitionsAndSetsNewTime() { + // setup + getTestManager().disableWorkChunkMessageHandler(); + getTestManager().enableMaintenanceRunner(false); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + // the time we set it to + Date newTime = Date.from( + Instant.now().plus(Duration.ofSeconds(100)) + ); + + String state = "2|IN_PROGRESS,2|POLL_WAITING"; + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation( + jobInstanceId, jobDef, + state + ); + stateInformation.initialize(getTestManager().getSvc()); + + String chunkId = stateInformation.getInitialWorkChunks() + .stream().findFirst().orElseThrow().getId(); + + // test + getTestManager().getSvc().onWorkChunkPollDelay(chunkId, newTime); + + // verify + stateInformation.verifyFinalStates(getTestManager().getSvc(), (chunk) -> { + // verify the time has been set + assertEquals(newTime, chunk.getNextPollTime()); + assertEquals(1, chunk.getPollAttempts()); + }); + } + + @Test + default void updatePollWaitingChunksForJobIfReady_pollWaitingChunkWithExpiredTime_transition() { + updatePollWaitingChunksForJobIfReady_POLL_WAITING_chunksTest(true); + } + + @Test + default void updatePollWaitingChunksForJobIfReady_pollWaitingChunkWithNonExpiredTime_doesNotTransition() { + updatePollWaitingChunksForJobIfReady_POLL_WAITING_chunksTest(false); + } + + private void updatePollWaitingChunksForJobIfReady_POLL_WAITING_chunksTest(boolean theDeadlineIsExpired) { + // setup + getTestManager().disableWorkChunkMessageHandler(); + getTestManager().enableMaintenanceRunner(false); + String state = "1|POLL_WAITING"; + if (theDeadlineIsExpired) { + state += ",1|READY"; + } + + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation( + jobInstanceId, + jobDef, + state + ); + Date nextPollTime = theDeadlineIsExpired ? + Date.from(Instant.now().minus(Duration.ofSeconds(10))) : Date.from(Instant.now().plus(Duration.ofSeconds(10))); + stateInformation.addWorkChunkModifier(chunk -> chunk.setNextPollTime(nextPollTime)); + stateInformation.initialize(getTestManager().getSvc()); + + // test + int updateCount = getTestManager().getSvc().updatePollWaitingChunksForJobIfReady(jobInstanceId); + + // verify + if (theDeadlineIsExpired) { + assertEquals(1, updateCount); + } else { + assertEquals(0, updateCount); + } + stateInformation.verifyFinalStates(getTestManager().getSvc()); + } + + /** + * Only POLL_WAITING chunks should be able to transition to READY via + * updatePollWaitingChunksForJobIfReady + */ + @ParameterizedTest + @ValueSource(strings = { + "2|READY", + // "2|GATED", // TODO - update/enable whenever gated status is ready + "2|QUEUED", + "2|IN_PROGRESS", + "2|ERRORED", + "2|FAILED", + "2|COMPLETED" + }) + default void updatePollWaitingChunksForJobIfReady_withNoPollWaitingChunks_doNotTransitionNorUpdateTime(String theState) { + // setup + getTestManager().disableWorkChunkMessageHandler(); + getTestManager().enableMaintenanceRunner(false); + + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String jobInstanceId = getTestManager().createAndStoreJobInstance(jobDef); + + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation(jobInstanceId, + jobDef, + theState); + stateInformation.addWorkChunkModifier((chunk) -> { + // make sure time is in the past, so we aren't testing the + // time <= now aspect + chunk.setNextPollTime( + Date.from(Instant.now().minus(Duration.ofSeconds(10))) + ); + }); + stateInformation.initialize(getTestManager().getSvc()); + + // test + int updateCount = getTestManager().getSvc().updatePollWaitingChunksForJobIfReady(jobInstanceId); + + // verify + assertEquals(0, updateCount); + stateInformation.verifyFinalStates(getTestManager().getSvc()); } } diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStorageTests.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStorageTests.java index 0174dcaabdf..392898c4332 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStorageTests.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/IWorkChunkStorageTests.java @@ -21,22 +21,250 @@ package ca.uhn.hapi.fhir.batch2.test; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.WorkChunk; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertNull; +import ca.uhn.fhir.batch2.model.JobDefinition; +import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent; +import ca.uhn.fhir.batch2.model.WorkChunkErrorEvent; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import ca.uhn.hapi.fhir.batch2.test.support.JobMaintenanceStateInformation; +import ca.uhn.test.concurrency.PointcutLatch; +import com.google.common.collect.ImmutableList; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import java.util.Date; +import java.util.Iterator; +import java.util.List; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@Nested public interface IWorkChunkStorageTests extends IWorkChunkCommon, WorkChunkTestConstants { + @BeforeEach + default void before() { + getTestManager().enableMaintenanceRunner(false); + } + @Test default void testStoreAndFetchWorkChunk_NoData() { JobInstance instance = createInstance(); String instanceId = getTestManager().getSvc().storeNewInstance(instance); - String id = getTestManager().storeWorkChunk(JOB_DEFINITION_ID, TARGET_STEP_ID, instanceId, 0, null); + String id = getTestManager().storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, null, false); getTestManager().runInTransaction(() -> { WorkChunk chunk = getTestManager().freshFetchWorkChunk(id); assertNull(chunk.getData()); }); } + + @ParameterizedTest + @CsvSource({ + "false, READY", + "true, GATE_WAITING" + }) + default void testWorkChunkCreate_inExpectedStatus(boolean theGatedExecution, WorkChunkStatusEnum expectedStatus) { + JobInstance instance = createInstance(); + String instanceId = getTestManager().getSvc().storeNewInstance(instance); + + String id = getTestManager().storeWorkChunk(JOB_DEFINITION_ID, FIRST_STEP_ID, instanceId, 0, CHUNK_DATA, theGatedExecution); + assertNotNull(id); + + getTestManager().runInTransaction(() -> assertEquals(expectedStatus, getTestManager().freshFetchWorkChunk(id).getStatus())); + } + + @Test + default void testNonGatedWorkChunkInReady_IsQueuedDuringMaintenance() throws InterruptedException { + // setup + int expectedCalls = 1; + PointcutLatch sendingLatch = getTestManager().disableWorkChunkMessageHandler(); + sendingLatch.setExpectedCount(expectedCalls); + String state = "1|READY,1|QUEUED"; + JobDefinition jobDefinition = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDefinition); + JobMaintenanceStateInformation stateInformation = new JobMaintenanceStateInformation(instanceId, jobDefinition, state); + + getTestManager().createChunksInStates(stateInformation); + String id = stateInformation.getInitialWorkChunks().stream().findFirst().orElseThrow().getId(); + + // verify created in ready + getTestManager().runInTransaction(() -> assertEquals(WorkChunkStatusEnum.READY, getTestManager().freshFetchWorkChunk(id).getStatus())); + + // test + getTestManager().runMaintenancePass(); + + // verify it's in QUEUED now + stateInformation.verifyFinalStates(getTestManager().getSvc()); + getTestManager().verifyWorkChunkMessageHandlerCalled(sendingLatch, expectedCalls); + } + + @Test + default void testStoreAndFetchWorkChunk_WithData() { + // setup + getTestManager().disableWorkChunkMessageHandler(); + JobDefinition jobDefinition = getTestManager().withJobDefinition(false); + JobInstance instance = createInstance(); + String instanceId = getTestManager().getSvc().storeNewInstance(instance); + + // we're not transitioning this state; we're just checking storage of data + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation(instanceId, jobDefinition, "1|QUEUED"); + info.addWorkChunkModifier((chunk) -> { + chunk.setData(CHUNK_DATA); + }); + + getTestManager().createChunksInStates(info); + String id = info.getInitialWorkChunks().stream().findFirst().orElseThrow().getId(); + + // verify created in QUEUED + getTestManager().runInTransaction(() -> assertEquals(WorkChunkStatusEnum.QUEUED, getTestManager().freshFetchWorkChunk(id).getStatus())); + + // test; manually dequeue chunk + WorkChunk chunk = getTestManager().getSvc().onWorkChunkDequeue(id).orElseThrow(IllegalArgumentException::new); + + // verify + assertEquals(36, chunk.getInstanceId().length()); + assertEquals(JOB_DEFINITION_ID, chunk.getJobDefinitionId()); + assertEquals(JOB_DEF_VER, chunk.getJobDefinitionVersion()); + assertEquals(WorkChunkStatusEnum.IN_PROGRESS, chunk.getStatus()); + assertEquals(CHUNK_DATA, chunk.getData()); + + getTestManager().runInTransaction(() -> assertEquals(WorkChunkStatusEnum.IN_PROGRESS, getTestManager().freshFetchWorkChunk(id).getStatus())); + } + + @Test + default void testMarkChunkAsCompleted_Success() { + // setup + String state = "2|IN_PROGRESS,2|COMPLETED"; + getTestManager().disableWorkChunkMessageHandler(); + + JobDefinition jobDefinition = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDefinition); + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation(instanceId, jobDefinition, state); + info.addWorkChunkModifier(chunk -> { + chunk.setCreateTime(new Date()); + chunk.setData(CHUNK_DATA); + }); + getTestManager().createChunksInStates(info); + + String chunkId = info.getInitialWorkChunks().stream().findFirst().orElseThrow().getId(); + + // run test + getTestManager().runInTransaction(() -> getTestManager().getSvc().onWorkChunkCompletion(new WorkChunkCompletionEvent(chunkId, 50, 0))); + + // verify + info.verifyFinalStates(getTestManager().getSvc()); + WorkChunk entity = getTestManager().freshFetchWorkChunk(chunkId); + assertEquals(WorkChunkStatusEnum.COMPLETED, entity.getStatus()); + assertEquals(50, entity.getRecordsProcessed()); + assertNotNull(entity.getCreateTime()); + assertNull(entity.getData()); + } + + @Test + default void testMarkChunkAsCompleted_Error() { + // setup + String state = "1|IN_PROGRESS,1|ERRORED"; + getTestManager().disableWorkChunkMessageHandler(); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDef); + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation( + instanceId, jobDef, state + ); + getTestManager().createChunksInStates(info); + String chunkId = info.getInitialWorkChunks().stream().findFirst().orElseThrow().getId(); + + // test + WorkChunkErrorEvent request = new WorkChunkErrorEvent(chunkId, ERROR_MESSAGE_A); + getTestManager().getSvc().onWorkChunkError(request); + getTestManager().runInTransaction(() -> { + WorkChunk entity = getTestManager().freshFetchWorkChunk(chunkId); + assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus()); + assertEquals(ERROR_MESSAGE_A, entity.getErrorMessage()); + assertEquals(1, entity.getErrorCount()); + }); + + // Mark errored again + + WorkChunkErrorEvent request2 = new WorkChunkErrorEvent(chunkId, "This is an error message 2"); + getTestManager().getSvc().onWorkChunkError(request2); + getTestManager().runInTransaction(() -> { + WorkChunk entity = getTestManager().freshFetchWorkChunk(chunkId); + assertEquals(WorkChunkStatusEnum.ERRORED, entity.getStatus()); + assertEquals("This is an error message 2", entity.getErrorMessage()); + assertEquals(2, entity.getErrorCount()); + }); + + List chunks = ImmutableList.copyOf(getTestManager().getSvc().fetchAllWorkChunksIterator(instanceId, true)); + assertEquals(1, chunks.size()); + assertEquals(2, chunks.get(0).getErrorCount()); + + info.verifyFinalStates(getTestManager().getSvc()); + } + + @Test + default void testMarkChunkAsCompleted_Fail() { + // setup + String state = "1|IN_PROGRESS,1|FAILED"; + getTestManager().disableWorkChunkMessageHandler(); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDef); + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation( + instanceId, jobDef, state + ); + getTestManager().createChunksInStates(info); + String chunkId = info.getInitialWorkChunks().stream().findFirst().orElseThrow().getId(); + + // test + getTestManager().getSvc().onWorkChunkFailed(chunkId, "This is an error message"); + + // verify + getTestManager().runInTransaction(() -> { + WorkChunk entity = getTestManager().freshFetchWorkChunk(chunkId); + assertEquals(WorkChunkStatusEnum.FAILED, entity.getStatus()); + assertEquals("This is an error message", entity.getErrorMessage()); + }); + + info.verifyFinalStates(getTestManager().getSvc()); + } + + @Test + default void markWorkChunksWithStatusAndWipeData_marksMultipleChunksWithStatus_asExpected() { + // setup + String state = """ + 1|IN_PROGRESS,1|COMPLETED + 1|ERRORED,1|COMPLETED + 1|QUEUED,1|COMPLETED + 1|IN_PROGRESS,1|COMPLETED + """; + getTestManager().disableWorkChunkMessageHandler(); + JobDefinition jobDef = getTestManager().withJobDefinition(false); + String instanceId = getTestManager().createAndStoreJobInstance(jobDef); + JobMaintenanceStateInformation info = new JobMaintenanceStateInformation( + instanceId, jobDef, state + ); + getTestManager().createChunksInStates(info); + List chunkIds = info.getInitialWorkChunks().stream().map(WorkChunk::getId) + .collect(Collectors.toList()); + + getTestManager().runInTransaction(() -> getTestManager().getSvc().markWorkChunksWithStatusAndWipeData(instanceId, chunkIds, WorkChunkStatusEnum.COMPLETED, null)); + + Iterator reducedChunks = getTestManager().getSvc().fetchAllWorkChunksIterator(instanceId, true); + + while (reducedChunks.hasNext()) { + WorkChunk reducedChunk = reducedChunks.next(); + assertTrue(chunkIds.contains(reducedChunk.getId())); + assertEquals(WorkChunkStatusEnum.COMPLETED, reducedChunk.getStatus()); + } + } } diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/WorkChunkTestConstants.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/WorkChunkTestConstants.java index 8ab0157e52b..10df1376af9 100644 --- a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/WorkChunkTestConstants.java +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/WorkChunkTestConstants.java @@ -24,7 +24,9 @@ public interface WorkChunkTestConstants { // we use a separate id for gated jobs because these job definitions might not // be cleaned up after any given test run String GATED_JOB_DEFINITION_ID = "gated_job_def_id"; - public static final String TARGET_STEP_ID = "step-id"; + public static final String FIRST_STEP_ID = "step-id"; + public static final String SECOND_STEP_ID = "2nd-step-id"; + public static final String LAST_STEP_ID = "last-step-id"; public static final String DEF_CHUNK_ID = "definition-chunkId"; public static final int JOB_DEF_VER = 1; public static final int SEQUENCE_NUMBER = 1; diff --git a/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/support/JobMaintenanceStateInformation.java b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/support/JobMaintenanceStateInformation.java new file mode 100644 index 00000000000..d83ca179928 --- /dev/null +++ b/hapi-fhir-storage-batch2-test-utilities/src/main/java/ca/uhn/hapi/fhir/batch2/test/support/JobMaintenanceStateInformation.java @@ -0,0 +1,269 @@ +package ca.uhn.hapi.fhir.batch2.test.support; + +import ca.uhn.fhir.batch2.api.IJobPersistence; +import ca.uhn.fhir.batch2.model.JobDefinition; +import ca.uhn.fhir.batch2.model.JobDefinitionStep; +import ca.uhn.fhir.batch2.model.WorkChunk; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.apache.commons.lang3.StringUtils.isEmpty; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +/** + * This class is used to help set up and verify WorkChunk transitions. + * + * Creating this object requires an instanceid (of a stored instance), and jobdefinition (of stored job defintion) + * and a state string. + * + * State strings are defined as follows: + * "step-name-or-step-index,INITIAL_STATE|step-name-or-step-index,FINAL_STATE" + * + * where "step-name-or-step-index" is the name or index of a step in the provided + * JobDefinition; the step that the work chunk should start in. + * + * If no final state/step name is provided, no transition is assumed. + * + * Further, comments can be added to the state string, but must be started by a "#". + * + * Eg: + * 1,READY|1,QUEUED # will create an initial work chunk in the READY state in step 1. + * # validation will verify that this workchunk has been transitioned to QUEUED. + */ +public class JobMaintenanceStateInformation { + + private static final Logger ourLog = LoggerFactory.getLogger(JobMaintenanceStateInformation.class); + + private static final String COMMENT_PATTERN = "(#.*)$"; + + private final List myLineComments = new ArrayList<>(); + + private final List myInitialWorkChunks = new ArrayList<>(); + + private final List myFinalWorkChunk = new ArrayList<>(); + + private final JobDefinition myJobDefinition; + + private final String myInstanceId; + + private Consumer myWorkChunkModifier = (chunk) -> {}; + + public JobMaintenanceStateInformation( + String theInstanceId, + JobDefinition theJobDefinition, + String theStateUnderTest) { + myInstanceId = theInstanceId; + myJobDefinition = theJobDefinition; + + setState(theStateUnderTest); + } + + public void addWorkChunkModifier(Consumer theModifier) { + myWorkChunkModifier = theModifier; + } + + public List getLineComments() { + return myLineComments; + } + + public List getInitialWorkChunks() { + return myInitialWorkChunks; + } + + public List getFinalWorkChunk() { + return myFinalWorkChunk; + } + + public JobDefinition getJobDefinition() { + return myJobDefinition; + } + + public String getInstanceId() { + return myInstanceId; + } + + public void verifyFinalStates(IJobPersistence theJobPersistence) { + verifyFinalStates(theJobPersistence, (chunk) -> {}); + } + + public void verifyFinalStates(IJobPersistence theJobPersistence, Consumer theChunkConsumer) { + assertEquals(getInitialWorkChunks().size(), getFinalWorkChunk().size()); + + HashMap workchunkMap = new HashMap<>(); + for (WorkChunk fs : getFinalWorkChunk()) { + workchunkMap.put(fs.getId(), fs); + } + + // fetch all workchunks + Iterator workChunkIterator = theJobPersistence.fetchAllWorkChunksIterator(getInstanceId(), true); + List workchunks = new ArrayList<>(); + workChunkIterator.forEachRemaining(workchunks::add); + + assertEquals(workchunks.size(), workchunkMap.size()); + workchunks.forEach(c -> ourLog.info("Returned " + c.toString())); + + for (WorkChunk wc : workchunks) { + WorkChunk expected = workchunkMap.get(wc.getId()); + assertNotNull(expected); + + // verify status and step id + assertEquals(expected.getTargetStepId(), wc.getTargetStepId()); + assertEquals(expected.getStatus(), wc.getStatus()); + theChunkConsumer.accept(wc); + } + } + + public void initialize(IJobPersistence theJobPersistence) { + // should have as many input workchunks as output workchunks + // unless we have newly created ones somewhere + assertEquals(getInitialWorkChunks().size(), getFinalWorkChunk().size()); + + Set stepIds = new HashSet<>(); + for (int i = 0; i < getInitialWorkChunks().size(); i++) { + WorkChunk workChunk = getInitialWorkChunks().get(i); + myWorkChunkModifier.accept(workChunk); + WorkChunk saved = theJobPersistence.createWorkChunk(workChunk); + ourLog.info("Created WorkChunk: " + saved.toString()); + workChunk.setId(saved.getId()); + + getFinalWorkChunk().get(i) + .setId(saved.getId()); + + stepIds.add(workChunk.getTargetStepId()); + } + // if it's a gated job, we'll manually set the step id for the instance + JobDefinition jobDef = getJobDefinition(); + if (jobDef.isGatedExecution()) { + AtomicReference latestStepId = new AtomicReference<>(); + int totalSteps = jobDef.getSteps().size(); + // ignore the last step since tests in gated jobs needs the current step to be the second-last step + for (int i = totalSteps - 2; i >= 0; i--) { + JobDefinitionStep step = jobDef.getSteps().get(i); + if (stepIds.contains(step.getStepId())) { + latestStepId.set(step.getStepId()); + break; + } + } + // should def have a value + assertNotNull(latestStepId.get()); + String instanceId = getInstanceId(); + theJobPersistence.updateInstance(instanceId, instance -> { + instance.setCurrentGatedStepId(latestStepId.get()); + return true; + }); + } + } + + private void setState(String theState) { + String[] chunkLines = theState.split("\n"); + Pattern pattern = Pattern.compile(COMMENT_PATTERN); + for (String chunkLine : chunkLines) { + String line = chunkLine.trim(); + Matcher matcher = pattern.matcher(line); + if (matcher.find()) { + String comment = matcher.group(0); + line = line.replaceAll(comment, ""); + if (isEmpty(line)) { + myLineComments.add(line); + continue; + } + // else - inline comment: eg: 1|Complete # comment + } + + addWorkChunkStates(line); + } + } + + /** + * Parses the line according to: + * (work chunk step id)|(workchunk initial state)|optionally:(work chunk final state) + */ + private void addWorkChunkStates(String theLine) { + if (theLine.contains(",")) { + // has final state + String[] states = theLine.split(","); + + int len = states.length; + if (len != 2) { + throw new RuntimeException("Unexpected number of state transitions. Expected 2, found " + states.length); + } + + addWorkChunkBasedOnState(states[0], chunk -> { + myInitialWorkChunks.add(chunk); + }); + addWorkChunkBasedOnState(states[1], chunk -> { + myFinalWorkChunk.add(chunk); + }); + } else { + // does not have final state; no change + addWorkChunkBasedOnState(theLine, chunk -> { + myInitialWorkChunks.add(chunk); + myFinalWorkChunk.add(chunk); + }); + } + } + + private void addWorkChunkBasedOnState(String theLine, Consumer theAdder) { + String[] parts = theLine.split("\\|"); + int len = parts.length; + if (len < 2) { + throw new RuntimeException("Unable to parse line " + theLine + " into initial and final states"); + } + + String stepId = getJobStepId(parts[0]); + + WorkChunkStatusEnum initialStatus = WorkChunkStatusEnum.valueOf(parts[1].trim()); + WorkChunk chunk = createBaseWorkChunk(); + chunk.setStatus(initialStatus); + chunk.setTargetStepId(stepId); + theAdder.accept(chunk); + } + + private String getJobStepId(String theIndexId) { + try { + // -1 because code is 0 indexed, but people think in 1 indexed + int index = Integer.parseInt(theIndexId.trim()) - 1; + + if (index >= myJobDefinition.getSteps().size()) { + throw new RuntimeException("Unable to find step with index " + index); + } + + int counter = 0; + for (JobDefinitionStep step : myJobDefinition.getSteps()) { + if (counter == index) { + return step.getStepId(); + } + counter++; + } + + // will never happen + throw new RuntimeException("Could not find step for index " + theIndexId); + } catch (NumberFormatException ex) { + ourLog.info("Encountered non-number {}; This will be treated as the step id itself", theIndexId); + return theIndexId; + } + } + + private WorkChunk createBaseWorkChunk() { + WorkChunk chunk = new WorkChunk(); + chunk.setJobDefinitionId(myJobDefinition.getJobDefinitionId()); + chunk.setInstanceId(myInstanceId); + chunk.setJobDefinitionVersion(myJobDefinition.getJobDefinitionVersion()); + chunk.setCreateTime(new Date()); + return chunk; + } +} diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 41c53b9e27e..5d2047f4996 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java index 3807e3e136f..196b94ccec3 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IJobPersistence.java @@ -25,7 +25,10 @@ import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.model.WorkChunkCreateEvent; +import ca.uhn.fhir.batch2.model.WorkChunkMetadata; +import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import ca.uhn.fhir.batch2.models.JobInstanceFetchRequest; +import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import org.apache.commons.lang3.builder.ToStringBuilder; import org.slf4j.Logger; @@ -41,6 +44,7 @@ import java.util.Iterator; import java.util.List; import java.util.Optional; import java.util.Set; +import java.util.function.Consumer; import java.util.stream.Stream; /** @@ -86,6 +90,18 @@ public interface IJobPersistence extends IWorkChunkPersistence { // on implementations @Transactional(propagation = Propagation.REQUIRES_NEW) List fetchInstances(int thePageSize, int thePageIndex); + @Transactional(propagation = Propagation.REQUIRES_NEW) + void enqueueWorkChunkForProcessing(String theChunkId, Consumer theCallback); + + /** + * Updates all Work Chunks in POLL_WAITING if their nextPollTime <= now + * for the given Job Instance. + * @param theInstanceId the instance id + * @return the number of updated chunks + */ + @Transactional + int updatePollWaitingChunksForJobIfReady(String theInstanceId); + /** * Fetch instances ordered by myCreateTime DESC */ @@ -112,8 +128,12 @@ public interface IJobPersistence extends IWorkChunkPersistence { // on implementations @Transactional(propagation = Propagation.REQUIRES_NEW) Page fetchJobInstances(JobInstanceFetchRequest theRequest); - // on implementations @Transactional(propagation = Propagation.REQUIRES_NEW) - boolean canAdvanceInstanceToNextStep(String theInstanceId, String theCurrentStepId); + /** + * Returns set of all distinct states for the specified job instance id + * and step id. + */ + @Transactional + Set getDistinctWorkChunkStatesForJobAndStep(String theInstanceId, String theCurrentStepId); /** * Fetch all chunks for a given instance. @@ -131,6 +151,16 @@ public interface IJobPersistence extends IWorkChunkPersistence { */ Stream fetchAllWorkChunksForStepStream(String theInstanceId, String theStepId); + /** + * Fetches an iterator that retrieves WorkChunkMetadata from the db. + * @param theInstanceId instance id of job of interest + * @param theStates states of interset + * @return an iterator for the workchunks + */ + @Transactional(propagation = Propagation.SUPPORTS) + Page fetchAllWorkChunkMetadataForJobInStates( + Pageable thePageable, String theInstanceId, Set theStates); + /** * Callback to update a JobInstance within a locked transaction. * Return true from the callback if the record write should continue, or false if @@ -256,4 +286,18 @@ public interface IJobPersistence extends IWorkChunkPersistence { return markInstanceAsStatusWhenStatusIn( theJobInstanceId, StatusEnum.IN_PROGRESS, Collections.singleton(StatusEnum.QUEUED)); } + + @VisibleForTesting + WorkChunk createWorkChunk(WorkChunk theWorkChunk); + + /** + * Atomically advance the given job to the given step and change the status of all QUEUED and GATE_WAITING chunks + * in the next step to READY + * @param theJobInstanceId the id of the job instance to be updated + * @param theNextStepId the id of the next job step + * @return whether any changes were made + */ + @Transactional(propagation = Propagation.REQUIRES_NEW) + boolean advanceJobStepAndUpdateChunkStatus( + String theJobInstanceId, String theNextStepId, boolean theIsReductionStepBoolean); } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IWorkChunkPersistence.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IWorkChunkPersistence.java index 0bde5e4d524..1bfd5c9d62b 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IWorkChunkPersistence.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/IWorkChunkPersistence.java @@ -27,6 +27,7 @@ import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import org.springframework.transaction.annotation.Propagation; import org.springframework.transaction.annotation.Transactional; +import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Optional; @@ -55,7 +56,8 @@ public interface IWorkChunkPersistence { * The first state event, as the chunk is created. * This method should be atomic and should only * return when the chunk has been successfully stored in the database. - * Chunk should be stored with a status of {@link WorkChunkStatusEnum#QUEUED} + * Chunk should be stored with a status of {@link WorkChunkStatusEnum#READY} or + * {@link WorkChunkStatusEnum#GATE_WAITING} for ungated and gated jobs, respectively. * * @param theBatchWorkChunk the batch work chunk to be stored * @return a globally unique identifier for this chunk. @@ -84,6 +86,17 @@ public interface IWorkChunkPersistence { // on impl - @Transactional(propagation = Propagation.REQUIRES_NEW) WorkChunkStatusEnum onWorkChunkError(WorkChunkErrorEvent theParameters); + /** + * Updates the specified Work Chunk to set the next polling interval. + * It wil also: + * * update the poll attempts + * * sets the workchunk status to POLL_WAITING (if it's not already in this state) + * @param theChunkId the id of the chunk to update + * @param theNewDeadline the time when polling should be redone + */ + @Transactional + void onWorkChunkPollDelay(String theChunkId, Date theNewDeadline); + /** * An unrecoverable error. * Transition to {@link WorkChunkStatusEnum#FAILED} @@ -130,14 +143,4 @@ public interface IWorkChunkPersistence { */ @Transactional(propagation = Propagation.MANDATORY, readOnly = true) Stream fetchAllWorkChunksForStepStream(String theInstanceId, String theStepId); - - /** - * Fetch chunk ids for starting a gated step. - * - * @param theInstanceId the job - * @param theStepId the step that is starting - * @return the WorkChunk ids - */ - List fetchAllChunkIdsForStepWithStatus( - String theInstanceId, String theStepId, WorkChunkStatusEnum theStatusEnum); } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/RetryChunkLaterException.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/RetryChunkLaterException.java new file mode 100644 index 00000000000..33217b87f66 --- /dev/null +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/api/RetryChunkLaterException.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.batch2.api; + +import java.time.Duration; +import java.time.temporal.ChronoUnit; + +/** + * Exception that is thrown when a polling step needs to be retried at a later + * time. + */ +public class RetryChunkLaterException extends RuntimeException { + + private static final Duration ONE_MINUTE = Duration.of(1, ChronoUnit.MINUTES); + + /** + * The delay to wait (in ms) for the next poll call. + * For now, it's a constant, but we hold it here in + * case we want to change this behaviour in the future. + */ + private final Duration myNextPollDuration; + + public RetryChunkLaterException() { + this(ONE_MINUTE); + } + + public RetryChunkLaterException(Duration theDuration) { + super(); + this.myNextPollDuration = theDuration; + } + + public Duration getNextPollDuration() { + return myNextPollDuration; + } +} diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java index d7d13c624da..751b096f8a1 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java @@ -28,7 +28,6 @@ import ca.uhn.fhir.batch2.model.FetchJobInstancesRequest; import ca.uhn.fhir.batch2.model.JobDefinition; import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; -import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.models.JobInstanceFetchRequest; import ca.uhn.fhir.i18n.Msg; @@ -48,8 +47,6 @@ import org.slf4j.Logger; import org.springframework.data.domain.Page; import org.springframework.messaging.MessageHandler; import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.support.TransactionSynchronization; -import org.springframework.transaction.support.TransactionSynchronizationManager; import java.util.Arrays; import java.util.HashSet; @@ -143,44 +140,18 @@ public class JobCoordinatorImpl implements IJobCoordinator { myJobParameterJsonValidator.validateJobParameters(theRequestDetails, theStartRequest, jobDefinition); + // we only create the first chunk amd job here + // JobMaintenanceServiceImpl.doMaintenancePass will handle the rest IJobPersistence.CreateResult instanceAndFirstChunk = myTransactionService .withSystemRequestOnDefaultPartition() .withPropagation(Propagation.REQUIRES_NEW) .execute(() -> myJobPersistence.onCreateWithFirstChunk(jobDefinition, theStartRequest.getParameters())); - JobWorkNotification workNotification = JobWorkNotification.firstStepNotification( - jobDefinition, instanceAndFirstChunk.jobInstanceId, instanceAndFirstChunk.workChunkId); - sendBatchJobWorkNotificationAfterCommit(workNotification); - Batch2JobStartResponse response = new Batch2JobStartResponse(); response.setInstanceId(instanceAndFirstChunk.jobInstanceId); return response; } - /** - * In order to make sure that the data is actually in the DB when JobWorkNotification is handled, - * this method registers a transaction synchronization that sends JobWorkNotification to Job WorkChannel - * if and when the current database transaction is successfully committed. - * If the transaction is rolled back, the JobWorkNotification will not be sent to the job WorkChannel. - */ - private void sendBatchJobWorkNotificationAfterCommit(final JobWorkNotification theJobWorkNotification) { - if (TransactionSynchronizationManager.isSynchronizationActive()) { - TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { - @Override - public int getOrder() { - return 0; - } - - @Override - public void afterCommit() { - myBatchJobSender.sendWorkChannelMessage(theJobWorkNotification); - } - }); - } else { - myBatchJobSender.sendWorkChannelMessage(theJobWorkNotification); - } - } - /** * Cache will be used if an identical job is QUEUED or IN_PROGRESS. Otherwise a new one will kickoff. */ diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobDataSink.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobDataSink.java index 525db23a96f..0c067ef7a7c 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobDataSink.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobDataSink.java @@ -50,9 +50,10 @@ class JobDataSink myTargetStep; private final AtomicInteger myChunkCounter = new AtomicInteger(0); private final AtomicReference myLastChunkId = new AtomicReference<>(); - private final boolean myGatedExecution; private final IHapiTransactionService myHapiTransactionService; + private final boolean myGatedExecution; + JobDataSink( @Nonnull BatchJobSender theBatchJobSender, @Nonnull IJobPersistence theJobPersistence, @@ -66,8 +67,8 @@ class JobDataSink { + if (updated == 1) { + JobWorkNotification workNotification = new JobWorkNotification( + myJobDefinitionId, myJobDefinitionVersion, instanceId, targetStepId, chunkId); + myBatchJobSender.sendWorkChannelMessage(workNotification); + } else { + ourLog.error( + "Expected to have updated 1 workchunk, but instead found {}. Chunk is not sent to queue.", + updated); + } + }); } } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobStepExecutor.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobStepExecutor.java index a39dccb9a75..7d1026841dd 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobStepExecutor.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobStepExecutor.java @@ -75,6 +75,12 @@ public class JobStepExecutor { myJobPersistence.updateInstance(instance.getInstanceId(), theInstance -> { @@ -337,10 +337,13 @@ public class ReductionStepExecutorServiceImpl implements IReductionStepExecutorS ReductionStepChunkProcessingResponse theResponseObject, JobWorkCursor theJobWorkCursor) { - if (!theChunk.getStatus().isIncomplete()) { + /* + * Reduction steps are done inline and only on gated jobs. + */ + if (theChunk.getStatus() == WorkChunkStatusEnum.COMPLETED) { // This should never happen since jobs with reduction are required to be gated ourLog.error( - "Unexpected chunk {} with status {} found while reducing {}. No chunks feeding into a reduction step should be complete.", + "Unexpected chunk {} with status {} found while reducing {}. No chunks feeding into a reduction step should be in a state other than READY.", theChunk.getId(), theChunk.getStatus(), theInstance); diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutor.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutor.java index 2a599d0e6d9..a092c55ce2a 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutor.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/StepExecutor.java @@ -23,6 +23,7 @@ import ca.uhn.fhir.batch2.api.IJobPersistence; import ca.uhn.fhir.batch2.api.IJobStepWorker; import ca.uhn.fhir.batch2.api.JobExecutionFailedException; import ca.uhn.fhir.batch2.api.JobStepFailedException; +import ca.uhn.fhir.batch2.api.RetryChunkLaterException; import ca.uhn.fhir.batch2.api.RunOutcome; import ca.uhn.fhir.batch2.api.StepExecutionDetails; import ca.uhn.fhir.batch2.model.WorkChunkCompletionEvent; @@ -34,6 +35,10 @@ import ca.uhn.fhir.util.Logs; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; + public class StepExecutor { private static final Logger ourLog = Logs.getBatchTroubleshootingLog(); private final IJobPersistence myJobPersistence; @@ -57,6 +62,14 @@ public class StepExecutor { try { outcome = theStepWorker.run(theStepExecutionDetails, theDataSink); Validate.notNull(outcome, "Step theWorker returned null: %s", theStepWorker.getClass()); + } catch (RetryChunkLaterException ex) { + Date nextPollTime = Date.from(Instant.now().plus(ex.getNextPollDuration())); + ourLog.debug( + "Polling job encountered; will retry chunk {} after after {}s", + theStepExecutionDetails.getChunkId(), + ex.getNextPollDuration().get(ChronoUnit.SECONDS)); + myJobPersistence.onWorkChunkPollDelay(theStepExecutionDetails.getChunkId(), nextPollTime); + return false; } catch (JobExecutionFailedException e) { ourLog.error( "Unrecoverable failure executing job {} step {} chunk {}", diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/WorkChannelMessageHandler.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/WorkChannelMessageHandler.java index b5cacf9fedf..7edff129858 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/WorkChannelMessageHandler.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/WorkChannelMessageHandler.java @@ -251,8 +251,10 @@ class WorkChannelMessageHandler implements MessageHandler { processingPreparation.ifPresentOrElse( // all the setup is happy and committed. Do the work. process -> process.myStepExector.executeStep(), - // discard the chunk - () -> ourLog.debug("Discarding chunk notification {}", workNotification)); + () -> { + // discard the chunk + ourLog.debug("Discarding chunk notification {}", workNotification); + }); } /** diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobInstanceProcessor.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobInstanceProcessor.java index 32a3ca79cb9..e08de1fb277 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobInstanceProcessor.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobInstanceProcessor.java @@ -28,21 +28,30 @@ import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobWorkCursor; import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.StatusEnum; +import ca.uhn.fhir.batch2.model.WorkChunkMetadata; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import ca.uhn.fhir.batch2.progress.JobInstanceProgressCalculator; import ca.uhn.fhir.batch2.progress.JobInstanceStatusUpdater; import ca.uhn.fhir.model.api.IModelJson; +import ca.uhn.fhir.model.api.PagingIterator; import ca.uhn.fhir.util.Logs; import ca.uhn.fhir.util.StopWatch; import org.apache.commons.lang3.time.DateUtils; import org.slf4j.Logger; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import java.util.Iterator; import java.util.List; +import java.util.Optional; +import java.util.Set; public class JobInstanceProcessor { private static final Logger ourLog = Logs.getBatchTroubleshootingLog(); public static final long PURGE_THRESHOLD = 7L * DateUtils.MILLIS_PER_DAY; + // 10k; we want to get as many as we can + private static final int WORK_CHUNK_METADATA_BATCH_SIZE = 10000; private final IJobPersistence myJobPersistence; private final BatchJobSender myBatchJobSender; private final JobChunkProgressAccumulator myProgressAccumulator; @@ -84,8 +93,38 @@ public class JobInstanceProcessor { // reload after update theInstance = myJobPersistence.fetchInstance(myInstanceId).orElseThrow(); } + + JobDefinition jobDefinition = + myJobDefinitionegistry.getJobDefinitionOrThrowException(theInstance); + + // move POLL_WAITING -> READY + processPollingChunks(theInstance.getInstanceId()); + // determine job progress; delete CANCELED/COMPLETE/FAILED jobs that are no longer needed cleanupInstance(theInstance); - triggerGatedExecutions(theInstance); + // move gated jobs to the next step, if needed + // moves GATE_WAITING / QUEUED (legacy) chunks to: + // READY (for regular gated jobs) + // REDUCTION_READY (if it's the final reduction step) + triggerGatedExecutions(theInstance, jobDefinition); + + if (theInstance.hasGatedStep() && theInstance.isRunning()) { + Optional updatedInstance = myJobPersistence.fetchInstance(theInstance.getInstanceId()); + + if (updatedInstance.isEmpty()) { + return; + } + + JobWorkCursor jobWorkCursor = JobWorkCursor.fromJobDefinitionAndRequestedStepId( + jobDefinition, updatedInstance.get().getCurrentGatedStepId()); + if (jobWorkCursor.isReductionStep()) { + // Reduction step work chunks should never be sent to the queue but to its specific service instead. + triggerReductionStep(theInstance, jobWorkCursor); + return; + } + } + + // enqueue all READY chunks + enqueueReadyChunks(theInstance, jobDefinition); ourLog.debug("Finished job processing: {} - {}", myInstanceId, stopWatch); } @@ -156,8 +195,10 @@ public class JobInstanceProcessor { return false; } - private void triggerGatedExecutions(JobInstance theInstance) { - if (!theInstance.isRunning()) { + private void triggerGatedExecutions(JobInstance theInstance, JobDefinition theJobDefinition) { + // QUEUE'd jobs that are gated need to start; this step will do that + if (!theInstance.isRunning() + && (theInstance.getStatus() != StatusEnum.QUEUED && theJobDefinition.isGatedExecution())) { ourLog.debug( "JobInstance {} is not in a \"running\" state. Status {}", theInstance.getInstanceId(), @@ -169,89 +210,183 @@ public class JobInstanceProcessor { return; } - JobDefinition jobDefinition = - myJobDefinitionegistry.getJobDefinitionOrThrowException(theInstance); - JobWorkCursor jobWorkCursor = - JobWorkCursor.fromJobDefinitionAndRequestedStepId(jobDefinition, theInstance.getCurrentGatedStepId()); - - // final step - if (jobWorkCursor.isFinalStep() && !jobWorkCursor.isReductionStep()) { - ourLog.debug("Job instance {} is in final step and it's not a reducer step", theInstance.getInstanceId()); - return; - } - + JobWorkCursor jobWorkCursor = JobWorkCursor.fromJobDefinitionAndRequestedStepId( + theJobDefinition, theInstance.getCurrentGatedStepId()); String instanceId = theInstance.getInstanceId(); String currentStepId = jobWorkCursor.getCurrentStepId(); - boolean shouldAdvance = myJobPersistence.canAdvanceInstanceToNextStep(instanceId, currentStepId); - if (shouldAdvance) { - String nextStepId = jobWorkCursor.nextStep.getStepId(); - ourLog.info( - "All processing is complete for gated execution of instance {} step {}. Proceeding to step {}", - instanceId, - currentStepId, - nextStepId); + boolean canAdvance = canAdvanceGatedJob(theInstance); + if (canAdvance) { + if (!jobWorkCursor.isFinalStep()) { + // all other gated job steps except for final steps - final steps does not need to be advanced + String nextStepId = jobWorkCursor.nextStep.getStepId(); + ourLog.info( + "All processing is complete for gated execution of instance {} step {}. Proceeding to step {}", + instanceId, + currentStepId, + nextStepId); - if (jobWorkCursor.nextStep.isReductionStep()) { - JobWorkCursor nextJobWorkCursor = JobWorkCursor.fromJobDefinitionAndRequestedStepId( - jobDefinition, jobWorkCursor.nextStep.getStepId()); - myReductionStepExecutorService.triggerReductionStep(instanceId, nextJobWorkCursor); + processChunksForNextGatedSteps(theInstance, theJobDefinition, nextStepId); } else { - // otherwise, continue processing as expected - processChunksForNextSteps(theInstance, nextStepId); + ourLog.info( + "Ready to advance gated execution of instance {} but already at the final step {}. Not proceeding to advance steps.", + instanceId, + jobWorkCursor.getCurrentStepId()); } } else { + String stepId = jobWorkCursor.nextStep != null + ? jobWorkCursor.nextStep.getStepId() + : jobWorkCursor.getCurrentStepId(); ourLog.debug( "Not ready to advance gated execution of instance {} from step {} to {}.", instanceId, currentStepId, - jobWorkCursor.nextStep.getStepId()); + stepId); } } - private void processChunksForNextSteps(JobInstance theInstance, String nextStepId) { + private boolean canAdvanceGatedJob(JobInstance theInstance) { + // make sure our instance still exists + if (myJobPersistence.fetchInstance(theInstance.getInstanceId()).isEmpty()) { + // no more job + return false; + } + String currentGatedStepId = theInstance.getCurrentGatedStepId(); + + Set workChunkStatuses = myJobPersistence.getDistinctWorkChunkStatesForJobAndStep( + theInstance.getInstanceId(), currentGatedStepId); + + if (workChunkStatuses.isEmpty()) { + // no work chunks = no output + // trivial to advance to next step + ourLog.info("No workchunks for {} in step id {}", theInstance.getInstanceId(), currentGatedStepId); + return true; + } + + // all workchunks for the current step are in COMPLETED -> proceed. + return workChunkStatuses.equals(Set.of(WorkChunkStatusEnum.COMPLETED)); + } + + protected PagingIterator getReadyChunks() { + return new PagingIterator<>(WORK_CHUNK_METADATA_BATCH_SIZE, (index, batchsize, consumer) -> { + Pageable pageable = Pageable.ofSize(batchsize).withPage(index); + Page results = myJobPersistence.fetchAllWorkChunkMetadataForJobInStates( + pageable, myInstanceId, Set.of(WorkChunkStatusEnum.READY)); + for (WorkChunkMetadata metadata : results) { + consumer.accept(metadata); + } + }); + } + + /** + * Trigger the reduction step for the given job instance. Reduction step chunks should never be queued. + */ + private void triggerReductionStep(JobInstance theInstance, JobWorkCursor jobWorkCursor) { String instanceId = theInstance.getInstanceId(); - List queuedChunksForNextStep = - myProgressAccumulator.getChunkIdsWithStatus(instanceId, nextStepId, WorkChunkStatusEnum.QUEUED); + ourLog.debug("Triggering Reduction step {} of instance {}.", jobWorkCursor.getCurrentStepId(), instanceId); + myReductionStepExecutorService.triggerReductionStep(instanceId, jobWorkCursor); + } + + /** + * Chunks are initially created in READY state. + * We will move READY chunks to QUEUE'd and send them to the queue/topic (kafka) + * for processing. + */ + private void enqueueReadyChunks(JobInstance theJobInstance, JobDefinition theJobDefinition) { + Iterator iter = getReadyChunks(); + + int counter = 0; + while (iter.hasNext()) { + WorkChunkMetadata metadata = iter.next(); + + /* + * For each chunk id + * * Move to QUEUE'd + * * Send to topic + * * flush changes + * * commit + */ + updateChunkAndSendToQueue(metadata); + counter++; + } + ourLog.debug( + "Encountered {} READY work chunks for job {} of type {}", + counter, + theJobInstance.getInstanceId(), + theJobDefinition.getJobDefinitionId()); + } + + /** + * Updates the Work Chunk and sends it to the queue. + * + * Because ReductionSteps are done inline by the maintenance pass, + * those will not be sent to the queue (but they will still have their + * status updated from READY -> QUEUED). + * + * Returns true after processing. + */ + private void updateChunkAndSendToQueue(WorkChunkMetadata theChunk) { + String chunkId = theChunk.getId(); + myJobPersistence.enqueueWorkChunkForProcessing(chunkId, updated -> { + ourLog.info("Updated {} workchunk with id {}", updated, chunkId); + if (updated == 1) { + sendNotification(theChunk); + } else { + // means the work chunk is likely already gone... + // we'll log and skip it. If it's still in the DB, the next pass + // will pick it up. Otherwise, it's no longer important + ourLog.error( + "Job Instance {} failed to transition work chunk with id {} from READY to QUEUED; found {}, expected 1; skipping work chunk.", + theChunk.getInstanceId(), + theChunk.getId(), + updated); + } + }); + } + + private void sendNotification(WorkChunkMetadata theChunk) { + // send to the queue + // we use current step id because it has not been moved to the next step (yet) + JobWorkNotification workNotification = new JobWorkNotification( + theChunk.getJobDefinitionId(), + theChunk.getJobDefinitionVersion(), + theChunk.getInstanceId(), + theChunk.getTargetStepId(), + theChunk.getId()); + myBatchJobSender.sendWorkChannelMessage(workNotification); + } + + private void processChunksForNextGatedSteps( + JobInstance theInstance, JobDefinition theJobDefinition, String nextStepId) { + String instanceId = theInstance.getInstanceId(); + + List gateWaitingChunksForNextStep = myProgressAccumulator.getChunkIdsWithStatus( + instanceId, nextStepId, WorkChunkStatusEnum.GATE_WAITING, WorkChunkStatusEnum.QUEUED); int totalChunksForNextStep = myProgressAccumulator.getTotalChunkCountForInstanceAndStep(instanceId, nextStepId); - if (totalChunksForNextStep != queuedChunksForNextStep.size()) { + if (totalChunksForNextStep != gateWaitingChunksForNextStep.size()) { ourLog.debug( - "Total ProgressAccumulator QUEUED chunk count does not match QUEUED chunk size! [instanceId={}, stepId={}, totalChunks={}, queuedChunks={}]", + "Total ProgressAccumulator GATE_WAITING chunk count does not match GATE_WAITING chunk size! [instanceId={}, stepId={}, totalChunks={}, queuedChunks={}]", instanceId, nextStepId, totalChunksForNextStep, - queuedChunksForNextStep.size()); - } - // Note on sequence: we don't have XA transactions, and are talking to two stores (JPA + Queue) - // Sequence: 1 - So we run the query to minimize the work overlapping. - List chunksToSubmit = - myJobPersistence.fetchAllChunkIdsForStepWithStatus(instanceId, nextStepId, WorkChunkStatusEnum.QUEUED); - // Sequence: 2 - update the job step so the workers will process them. - boolean changed = myJobPersistence.updateInstance(instanceId, instance -> { - if (instance.getCurrentGatedStepId().equals(nextStepId)) { - // someone else beat us here. No changes - return false; - } - instance.setCurrentGatedStepId(nextStepId); - return true; - }); - if (!changed) { - // we collided with another maintenance job. - ourLog.warn("Skipping gate advance to {} for instance {} - already advanced.", nextStepId, instanceId); - return; + gateWaitingChunksForNextStep.size()); } - // DESIGN GAP: if we die here, these chunks will never be queued. - // Need a WAITING stage before QUEUED for chunks, so we can catch them. + JobWorkCursor jobWorkCursor = + JobWorkCursor.fromJobDefinitionAndRequestedStepId(theJobDefinition, nextStepId); + + // update the job step so the workers will process them. + // Sets all chunks from QUEUED/GATE_WAITING -> READY (REDUCTION_READY for reduction jobs) + myJobPersistence.advanceJobStepAndUpdateChunkStatus(instanceId, nextStepId, jobWorkCursor.isReductionStep()); + } + + /** + * Moves all POLL_WAITING work chunks to READY for work chunks whose + * nextPollTime has expired. + */ + private void processPollingChunks(String theInstanceId) { + int updatedChunkCount = myJobPersistence.updatePollWaitingChunksForJobIfReady(theInstanceId); - // Sequence: 3 - send the notifications - for (String nextChunkId : chunksToSubmit) { - JobWorkNotification workNotification = new JobWorkNotification(theInstance, nextStepId, nextChunkId); - myBatchJobSender.sendWorkChannelMessage(workNotification); - } ourLog.debug( - "Submitted a batch of chunks for processing. [chunkCount={}, instanceId={}, stepId={}]", - chunksToSubmit.size(), - instanceId, - nextStepId); + "Moved {} Work Chunks in POLL_WAITING to READY for Job Instance {}", updatedChunkCount, theInstanceId); } } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobDefinition.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobDefinition.java index d10ca861a3f..43c6d8387cb 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobDefinition.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobDefinition.java @@ -145,6 +145,13 @@ public class JobDefinition { return myGatedExecution; } + public JobDefinitionStep getStepById(String theId) { + return getSteps().stream() + .filter(s -> s.getStepId().equals(theId)) + .findFirst() + .orElse(null); + } + public boolean isLastStepReduction() { int stepCount = getSteps().size(); return stepCount >= 1 && getSteps().get(stepCount - 1).isReductionStep(); diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobWorkCursor.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobWorkCursor.java index 94db85defaf..687127caad1 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobWorkCursor.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/JobWorkCursor.java @@ -104,6 +104,10 @@ public class JobWorkCursor= 1); - myJobDefinitionVersion = theJobDefinitionVersion; - return this; - } - - public String getTargetStepId() { - return myTargetStepId; - } - - public WorkChunk setTargetStepId(String theTargetStepId) { - Validate.notBlank(theTargetStepId); - myTargetStepId = theTargetStepId; - return this; - } - public String getData() { return myData; } @@ -199,33 +180,6 @@ public class WorkChunk implements IModelJson { return JsonUtil.deserialize(getData(), theType); } - public String getInstanceId() { - return myInstanceId; - } - - public WorkChunk setInstanceId(String theInstanceId) { - myInstanceId = theInstanceId; - return this; - } - - public String getId() { - return myId; - } - - public WorkChunk setId(String theId) { - Validate.notBlank(theId); - myId = theId; - return this; - } - - public int getSequence() { - return mySequence; - } - - public void setSequence(int theSequence) { - mySequence = theSequence; - } - public Date getCreateTime() { return myCreateTime; } @@ -251,6 +205,22 @@ public class WorkChunk implements IModelJson { myUpdateTime = theUpdateTime; } + public Date getNextPollTime() { + return myNextPollTime; + } + + public void setNextPollTime(Date theNextPollTime) { + myNextPollTime = theNextPollTime; + } + + public int getPollAttempts() { + return myPollAttempts; + } + + public void setPollAttempts(int thePollAttempts) { + myPollAttempts = thePollAttempts; + } + public String getWarningMessage() { return myWarningMessage; } @@ -263,19 +233,23 @@ public class WorkChunk implements IModelJson { @Override public String toString() { ToStringBuilder b = new ToStringBuilder(this); - b.append("Id", myId); - b.append("Sequence", mySequence); - b.append("Status", myStatus); - b.append("JobDefinitionId", myJobDefinitionId); - b.append("JobDefinitionVersion", myJobDefinitionVersion); - b.append("TargetStepId", myTargetStepId); - b.append("InstanceId", myInstanceId); + b.append("Id", getId()); + b.append("Sequence", getSequence()); + b.append("Status", getStatus()); + b.append("JobDefinitionId", getJobDefinitionId()); + b.append("JobDefinitionVersion", getJobDefinitionVersion()); + b.append("TargetStepId", getTargetStepId()); + b.append("InstanceId", getInstanceId()); b.append("Data", isNotBlank(myData) ? "(present)" : "(absent)"); b.append("CreateTime", myCreateTime); b.append("StartTime", myStartTime); b.append("EndTime", myEndTime); b.append("UpdateTime", myUpdateTime); b.append("RecordsProcessed", myRecordsProcessed); + if (myNextPollTime != null) { + b.append("NextPollTime", myNextPollTime); + } + b.append("PollAttempts", myPollAttempts); if (isNotBlank(myErrorMessage)) { b.append("ErrorMessage", myErrorMessage); } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkCreateEvent.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkCreateEvent.java index 95e07c87761..c2b489016b7 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkCreateEvent.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkCreateEvent.java @@ -36,6 +36,7 @@ public class WorkChunkCreateEvent { public final String instanceId; public final int sequence; public final String serializedData; + public final boolean isGatedExecution; /** * Constructor @@ -52,20 +53,28 @@ public class WorkChunkCreateEvent { @Nonnull String theTargetStepId, @Nonnull String theInstanceId, int theSequence, - @Nullable String theSerializedData) { + @Nullable String theSerializedData, + boolean theGatedExecution) { jobDefinitionId = theJobDefinitionId; jobDefinitionVersion = theJobDefinitionVersion; targetStepId = theTargetStepId; instanceId = theInstanceId; sequence = theSequence; serializedData = theSerializedData; + isGatedExecution = theGatedExecution; } + /** + * Creates the WorkChunkCreateEvent for the first chunk of a job. + */ public static WorkChunkCreateEvent firstChunk(JobDefinition theJobDefinition, String theInstanceId) { String firstStepId = theJobDefinition.getFirstStepId(); String jobDefinitionId = theJobDefinition.getJobDefinitionId(); int jobDefinitionVersion = theJobDefinition.getJobDefinitionVersion(); - return new WorkChunkCreateEvent(jobDefinitionId, jobDefinitionVersion, firstStepId, theInstanceId, 0, null); + // the first chunk of a job is always READY, no matter whether the job is gated + boolean isGatedExecution = false; + return new WorkChunkCreateEvent( + jobDefinitionId, jobDefinitionVersion, firstStepId, theInstanceId, 0, null, isGatedExecution); } @Override @@ -83,6 +92,7 @@ public class WorkChunkCreateEvent { .append(instanceId, that.instanceId) .append(sequence, that.sequence) .append(serializedData, that.serializedData) + .append(isGatedExecution, that.isGatedExecution) .isEquals(); } @@ -95,6 +105,7 @@ public class WorkChunkCreateEvent { .append(instanceId) .append(sequence) .append(serializedData) + .append(isGatedExecution) .toHashCode(); } } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkMetadata.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkMetadata.java new file mode 100644 index 00000000000..e06384bff75 --- /dev/null +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkMetadata.java @@ -0,0 +1,109 @@ +package ca.uhn.fhir.batch2.model; + +import ca.uhn.fhir.model.api.IModelJson; +import com.fasterxml.jackson.annotation.JsonProperty; +import org.apache.commons.lang3.Validate; + +public class WorkChunkMetadata implements IModelJson { + + @JsonProperty("id") + private String myId; + + @JsonProperty("sequence") + // TODO MB danger - these repeat with a job or even a single step. They start at 0 for every parent chunk. Review + // after merge. + private int mySequence; + + @JsonProperty("status") + private WorkChunkStatusEnum myStatus; + + @JsonProperty("jobDefinitionId") + private String myJobDefinitionId; + + @JsonProperty("jobDefinitionVersion") + private int myJobDefinitionVersion; + + @JsonProperty("targetStepId") + private String myTargetStepId; + + @JsonProperty("instanceId") + private String myInstanceId; + + public WorkChunkStatusEnum getStatus() { + return myStatus; + } + + public WorkChunkMetadata setStatus(WorkChunkStatusEnum theStatus) { + myStatus = theStatus; + return this; + } + + public String getJobDefinitionId() { + return myJobDefinitionId; + } + + public WorkChunkMetadata setJobDefinitionId(String theJobDefinitionId) { + Validate.notBlank(theJobDefinitionId); + myJobDefinitionId = theJobDefinitionId; + return this; + } + + public int getJobDefinitionVersion() { + return myJobDefinitionVersion; + } + + public WorkChunkMetadata setJobDefinitionVersion(int theJobDefinitionVersion) { + Validate.isTrue(theJobDefinitionVersion >= 1); + myJobDefinitionVersion = theJobDefinitionVersion; + return this; + } + + public String getTargetStepId() { + return myTargetStepId; + } + + public WorkChunkMetadata setTargetStepId(String theTargetStepId) { + Validate.notBlank(theTargetStepId); + myTargetStepId = theTargetStepId; + return this; + } + + public String getInstanceId() { + return myInstanceId; + } + + public WorkChunkMetadata setInstanceId(String theInstanceId) { + myInstanceId = theInstanceId; + return this; + } + + public String getId() { + return myId; + } + + public WorkChunkMetadata setId(String theId) { + Validate.notBlank(theId); + myId = theId; + return this; + } + + public int getSequence() { + return mySequence; + } + + public void setSequence(int theSequence) { + mySequence = theSequence; + } + + public WorkChunk toWorkChunk() { + WorkChunk workChunk = new WorkChunk(); + workChunk.setId(getId()); + workChunk.setStatus(getStatus()); + workChunk.setInstanceId(getInstanceId()); + workChunk.setJobDefinitionId(getJobDefinitionId()); + workChunk.setJobDefinitionVersion(getJobDefinitionVersion()); + workChunk.setSequence(getSequence()); + workChunk.setTargetStepId(getTargetStepId()); + return workChunk; + } +} diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkStatusEnum.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkStatusEnum.java index f23fdf4c153..161c3b42a83 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkStatusEnum.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/WorkChunkStatusEnum.java @@ -31,11 +31,45 @@ import java.util.Set; * @see hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md */ public enum WorkChunkStatusEnum { - // wipmb For 6.8 Add WAITING for gated, and READY for in db, but not yet sent to channel. + /** + * The initial state all workchunks start in for non-gated jobs. + */ + READY, + /** + * The initial state all workchunks start in for gated jobs. + */ + GATE_WAITING, + /** + * Workchunk is ready for reduction pass. + * It will not be QUEUED, but consumed inline by reduction pass. + */ + REDUCTION_READY, + /** + * The state of workchunks that have been sent to the queue; + * or of workchunks that are about to be processed in a final + * reduction step (these workchunks are never queued) + */ QUEUED, + /** + * The state of workchunks that are doing work. + */ IN_PROGRESS, + /** + * A workchunk status for workchunks that are doing long-polling work + * that will not complete in a reasonably short amount of time + */ + POLL_WAITING, + /** + * A transient state on retry when a chunk throws an error, but hasn't FAILED yet. Will move back to IN_PROGRESS on retry. + */ ERRORED, + /** + * Chunk has failed with a non-retriable error, or has run out of retry attempts. + */ FAILED, + /** + * The state of workchunks that have finished their job's step. + */ COMPLETED; private static final EnumMap> ourPriorStates; @@ -56,12 +90,25 @@ public enum WorkChunkStatusEnum { return (this != WorkChunkStatusEnum.COMPLETED); } + public boolean isAReadyState() { + return this == WorkChunkStatusEnum.READY || this == WorkChunkStatusEnum.REDUCTION_READY; + } + public Set getNextStates() { switch (this) { + case GATE_WAITING: + return EnumSet.of(READY); + case READY: + return EnumSet.of(QUEUED); + case REDUCTION_READY: + // currently no support for POLL_WAITING reduction steps + return EnumSet.of(COMPLETED, FAILED); case QUEUED: return EnumSet.of(IN_PROGRESS); case IN_PROGRESS: - return EnumSet.of(IN_PROGRESS, ERRORED, FAILED, COMPLETED); + return EnumSet.of(IN_PROGRESS, ERRORED, FAILED, COMPLETED, POLL_WAITING); + case POLL_WAITING: + return EnumSet.of(POLL_WAITING, READY); case ERRORED: return EnumSet.of(IN_PROGRESS, FAILED, COMPLETED); // terminal states diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/package-info.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/package-info.java index 49a7bbb12de..bc335f199d1 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/package-info.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/package-info.java @@ -48,11 +48,41 @@ * * Job and chunk processing follow state machines described {@link hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa_batch/batch2_states.md} * Chunks have a simple {@link ca.uhn.fhir.batch2.model.WorkChunkStatusEnum state system} with states - * QUEUED, IN_PROGRESS, ERRORED, FAILED, COMPLETED. - * The initial state is QUEUED, and the final states are FAILED, and COMPLETED: + * READY, QUEUED, IN_PROGRESS, ERRORED, FAILED, COMPLETED. + * The initial state is READY, and the final states are FAILED, and COMPLETED. + * + * There are 2 primary systems in play during Batch2 Jobs. A Maintenance Job and the Batch2 Job Notification topic. + * + * The Maintenance Job + * + * This runs every minute and does the following: * *
    - *
  • Chunks are created QUEUED (NB - should be READY or WAITING) and notification is posted to the channel for non-gated steps.
  • + *
  • Moves POLL_WAITING work chunks to READY if their nextPollTime has expired.
  • + *
  • Moves READY work chunks to QUEUE and publishes it to the Batch2 Notification topic
  • + *
  • Calculates job progress (% of workchunks in complete status).
  • + *
  • If the job is finished, purges any left over work chunks.
  • + *
  • Cleans up any complete, failed, or cancelled jobs.
  • + *
  • Moves any gated jobs onto their next step.
  • + *
  • If the final step of a (gated) job is a reduction step, a reduction step execution will be triggered.
  • + *
+ * + * Processing the Messages + * + *
    + *
  • Change the work chunk from QUEUED to IN_PROGRESS
  • + *
  • Change the Job Instance status from QUEUED to IN_PROGRESS
  • + *
  • If the Job Instance is cancelled, change the status to CANCELLED and abort processing
  • + *
  • If the step creates new work chunks, each work chunk will be created in the READY state
  • + *
  • If the step succeeds, the work chunk status is changed from IN_PROGRESS to COMPLETE
  • + *
  • If the step throws a RetryChunkLaterException, the work chunk status is changed from IN_PROGRESS to POLL_WAITING and a nextPollTime value set.
  • + *
  • If the step fails, the work chunk status is changed from IN_PROGRESS to either ERRORED or FAILED depending on the severity of the error
  • + *
+ * + * The job lifecycle + * + *
    + *
  • Chunks are created READY (NB - should be READY or WAITING) and notification is posted to the channel for non-gated steps.
  • *
  • * Workers receive a notification and advance QUEUED->IN_PROGRESS. * {@link ca.uhn.fhir.batch2.api.IWorkChunkPersistence#onWorkChunkDequeue(String)} @@ -60,6 +90,7 @@ *
  • * On normal execution, the chunk advances IN_PROGRESS->COMPLETED {@link ca.uhn.fhir.batch2.api.IWorkChunkPersistence#onWorkChunkCompletion}
  • *
  • On a retryiable error, IN_PROGRESS->ERROR with an error message and the chunk is put back on the queue. {@link ca.uhn.fhir.batch2.api.IWorkChunkPersistence#onWorkChunkError}
  • + *
  • On a RetryChunkLaterException, IN_PROGRESS->POLL_WAITING with a nextPollTime set. The chunk is *not* put back on the queue, but is left for the maintenance job to manage.
  • *
  • On a hard failure, or too many errors, IN_PROGRESS->FAILED with the error message. {@link ca.uhn.fhir.batch2.api.IWorkChunkPersistence#onWorkChunkFailed}
  • *
* diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/InstanceProgress.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/InstanceProgress.java index 790ed970c1a..c38c7a5cc09 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/InstanceProgress.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/InstanceProgress.java @@ -73,7 +73,10 @@ public class InstanceProgress { statusToCountMap.put(theChunk.getStatus(), statusToCountMap.getOrDefault(theChunk.getStatus(), 0) + 1); switch (theChunk.getStatus()) { + case GATE_WAITING: + case READY: case QUEUED: + case POLL_WAITING: case IN_PROGRESS: myIncompleteChunkCount++; break; diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceProgressCalculator.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceProgressCalculator.java index 348fd30e540..fcaecb1ce2f 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceProgressCalculator.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceProgressCalculator.java @@ -57,6 +57,7 @@ public class JobInstanceProgressCalculator { StopWatch stopWatch = new StopWatch(); ourLog.trace("calculating progress: {}", theInstanceId); + // calculate progress based on number of work chunks in COMPLETE state InstanceProgress instanceProgress = calculateInstanceProgress(theInstanceId); myJobPersistence.updateInstance(theInstanceId, currentInstance -> { @@ -97,6 +98,7 @@ public class JobInstanceProgressCalculator { while (workChunkIterator.hasNext()) { WorkChunk next = workChunkIterator.next(); + // global stats myProgressAccumulator.addChunk(next); // instance stats diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java index ebd682f2386..959cb3e0569 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java @@ -26,6 +26,7 @@ import ca.uhn.fhir.jpa.dao.tx.NonTransactionalHapiTransactionService; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelReceiver; import ca.uhn.fhir.jpa.subscription.channel.impl.LinkedBlockingChannel; import ca.uhn.fhir.model.api.IModelJson; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import com.google.common.collect.Lists; import org.junit.jupiter.api.AfterEach; @@ -54,6 +55,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -73,7 +75,7 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { private JobDefinitionRegistry myJobDefinitionRegistry; @Mock private IJobMaintenanceService myJobMaintenanceService; - private IHapiTransactionService myTransactionService = new NonTransactionalHapiTransactionService(); + private final IHapiTransactionService myTransactionService = new NonTransactionalHapiTransactionService(); @Captor private ArgumentCaptor> myStep1ExecutionDetailsCaptor; @Captor @@ -144,7 +146,6 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { assertEquals(PASSWORD_VALUE, params.getPassword()); verify(myJobInstancePersister, times(1)).onWorkChunkCompletion(new WorkChunkCompletionEvent(CHUNK_ID, 50, 0)); - verify(myBatchJobSender, times(2)).sendWorkChannelMessage(any()); } private void setupMocks(JobDefinition theJobDefinition, WorkChunk theWorkChunk) { @@ -183,7 +184,7 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { .thenReturn(Arrays.asList(existingInProgInstance)); // test - Batch2JobStartResponse startResponse = mySvc.startInstance(startRequest); + Batch2JobStartResponse startResponse = mySvc.startInstance(new SystemRequestDetails(), startRequest); // verify assertEquals(inProgressInstanceId, startResponse.getInstanceId()); // make sure it's the completed one @@ -467,7 +468,7 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { JobInstanceStartRequest startRequest = new JobInstanceStartRequest(); startRequest.setJobDefinitionId(JOB_DEFINITION_ID); startRequest.setParameters(new TestJobParameters().setParam1(PARAM_1_VALUE).setParam2(PARAM_2_VALUE).setPassword(PASSWORD_VALUE)); - mySvc.startInstance(startRequest); + mySvc.startInstance(new SystemRequestDetails(), startRequest); // Verify @@ -476,12 +477,7 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { assertSame(jobDefinition, myJobDefinitionCaptor.getValue()); assertEquals(startRequest.getParameters(), myParametersJsonCaptor.getValue()); - verify(myBatchJobSender, times(1)).sendWorkChannelMessage(myJobWorkNotificationCaptor.capture()); - assertEquals(CHUNK_ID, myJobWorkNotificationCaptor.getAllValues().get(0).getChunkId()); - assertEquals(JOB_DEFINITION_ID, myJobWorkNotificationCaptor.getAllValues().get(0).getJobDefinitionId()); - assertEquals(1, myJobWorkNotificationCaptor.getAllValues().get(0).getJobDefinitionVersion()); - assertEquals(STEP_1, myJobWorkNotificationCaptor.getAllValues().get(0).getTargetStepId()); - + verify(myBatchJobSender, never()).sendWorkChannelMessage(any()); verifyNoMoreInteractions(myJobInstancePersister); verifyNoMoreInteractions(myStep1Worker); verifyNoMoreInteractions(myStep2Worker); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobDataSinkTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobDataSinkTest.java index 5b2f89dae96..fd28ccae545 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobDataSinkTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobDataSinkTest.java @@ -29,12 +29,18 @@ import org.mockito.junit.jupiter.MockitoExtension; import jakarta.annotation.Nonnull; import java.util.ArrayList; import java.util.List; +import java.util.function.Consumer; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -99,6 +105,11 @@ class JobDataSinkTest { // execute // Let's test our first step worker by calling run on it: when(myJobPersistence.onWorkChunkCreate(myBatchWorkChunkCaptor.capture())).thenReturn(CHUNK_ID); + doAnswer(args -> { + Consumer consumer = args.getArgument(1); + consumer.accept(1); + return 1; + }).when(myJobPersistence).enqueueWorkChunkForProcessing(anyString(), any()); JobInstance instance = JobInstance.fromInstanceId(JOB_INSTANCE_ID); StepExecutionDetails details = new StepExecutionDetails<>(new TestJobParameters().setParam1("" + PID_COUNT), null, instance, CHUNK_ID); JobWorkCursor cursor = new JobWorkCursor<>(job, true, firstStep, lastStep); @@ -112,7 +123,6 @@ class JobDataSinkTest { // theDataSink.accept(output) called by firstStepWorker above calls two services. Let's validate them both. verify(myBatchJobSender).sendWorkChannelMessage(myJobWorkNotificationCaptor.capture()); - JobWorkNotification notification = myJobWorkNotificationCaptor.getValue(); assertEquals(JOB_DEF_ID, notification.getJobDefinitionId()); assertEquals(JOB_INSTANCE_ID, notification.getInstanceId()); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/ReductionStepExecutorServiceImplTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/ReductionStepExecutorServiceImplTest.java index 22aa7ba9c30..e080586547c 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/ReductionStepExecutorServiceImplTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/ReductionStepExecutorServiceImplTest.java @@ -20,6 +20,8 @@ import ca.uhn.fhir.jpa.dao.tx.NonTransactionalHapiTransactionService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.EnumSource; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; @@ -62,10 +64,6 @@ public class ReductionStepExecutorServiceImplTest { private IJobPersistence myJobPersistence; @Mock private IReductionStepWorker myReductionStepWorker; - // @Mock -// private JobDefinitionStep myPreviousStep; -// @Mock -// private JobDefinitionStep myCurrentStep; private ReductionStepExecutorServiceImpl mySvc; private final JobDefinitionRegistry myJobDefinitionRegistry = new JobDefinitionRegistry(); @@ -74,13 +72,19 @@ public class ReductionStepExecutorServiceImplTest { mySvc = new ReductionStepExecutorServiceImpl(myJobPersistence, myTransactionService, myJobDefinitionRegistry); } - @Test + // QUEUED, IN_PROGRESS are supported because of backwards compatibility + // these statuses will stop being supported after 7.6 + @SuppressWarnings({"unchecked", "rawtypes"}) + @ParameterizedTest + @EnumSource(value = WorkChunkStatusEnum.class, names = { "REDUCTION_READY", "QUEUED", "IN_PROGRESS" }) public void doExecution_reductionWithChunkFailed_marksAllFutureChunksAsFailedButPreviousAsSuccess() { // setup List chunkIds = Arrays.asList("chunk1", "chunk2"); List chunks = new ArrayList<>(); for (String id : chunkIds) { - chunks.add(createWorkChunk(id)); + WorkChunk chunk = createWorkChunk(id); + chunk.setStatus(WorkChunkStatusEnum.REDUCTION_READY); + chunks.add(chunk); } JobInstance jobInstance = getTestJobInstance(); jobInstance.setStatus(StatusEnum.IN_PROGRESS); @@ -125,20 +129,21 @@ public class ReductionStepExecutorServiceImplTest { assertEquals(WorkChunkStatusEnum.FAILED, statuses.get(1)); } - + @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void doExecution_reductionStepWithValidInput_executesAsExpected() { // setup List chunkIds = Arrays.asList("chunk1", "chunk2"); List chunks = new ArrayList<>(); for (String id : chunkIds) { - chunks.add(createWorkChunk(id)); + WorkChunk chunk = createWorkChunk(id); + chunk.setStatus(WorkChunkStatusEnum.REDUCTION_READY); + chunks.add(chunk); } JobInstance jobInstance = getTestJobInstance(); jobInstance.setStatus(StatusEnum.IN_PROGRESS); JobWorkCursor workCursor = mock(JobWorkCursor.class); - // when when(workCursor.getCurrentStep()).thenReturn((JobDefinitionStep) createJobDefinition().getSteps().get(1)); when(workCursor.getJobDefinition()).thenReturn(createJobDefinition()); @@ -176,14 +181,17 @@ public class ReductionStepExecutorServiceImplTest { } - + @SuppressWarnings({"unchecked", "rawtypes"}) @Test public void doExecution_reductionStepWithErrors_returnsFalseAndMarksPreviousChunksFailed() { // setup List chunkIds = Arrays.asList("chunk1", "chunk2"); List chunks = new ArrayList<>(); for (String id : chunkIds) { - chunks.add(createWorkChunk(id)); + WorkChunk chunk = createWorkChunk(id); + // reduction steps are done with REDUCTION_READY workchunks + chunk.setStatus(WorkChunkStatusEnum.REDUCTION_READY); + chunks.add(chunk); } JobInstance jobInstance = getTestJobInstance(); jobInstance.setStatus(StatusEnum.IN_PROGRESS); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/WorkChunkProcessorTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/WorkChunkProcessorTest.java index 10f1a007e5c..e107cf106f3 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/WorkChunkProcessorTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/WorkChunkProcessorTest.java @@ -488,7 +488,7 @@ public class WorkChunkProcessorTest { WorkChunk chunk = new WorkChunk(); chunk.setInstanceId(INSTANCE_ID); chunk.setId(theId); - chunk.setStatus(WorkChunkStatusEnum.QUEUED); + chunk.setStatus(WorkChunkStatusEnum.READY); chunk.setData(JsonUtil.serialize( new StepInputData() )); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/maintenance/JobMaintenanceServiceImplTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/maintenance/JobMaintenanceServiceImplTest.java index ba11ac13560..f901ee885c2 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/maintenance/JobMaintenanceServiceImplTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/maintenance/JobMaintenanceServiceImplTest.java @@ -15,11 +15,11 @@ import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobWorkNotification; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; +import ca.uhn.fhir.batch2.model.WorkChunkMetadata; import ca.uhn.fhir.batch2.model.WorkChunkStatusEnum; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.model.sched.ISchedulerService; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelProducer; -import ca.uhn.fhir.util.Logs; import ca.uhn.test.util.LogbackCaptureTestExtension; import ch.qos.logback.classic.Level; import ch.qos.logback.classic.Logger; @@ -36,20 +36,29 @@ import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; import org.springframework.messaging.Message; +import org.springframework.transaction.PlatformTransactionManager; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Optional; +import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.function.Consumer; import java.util.stream.Collectors; import static ca.uhn.fhir.batch2.coordinator.JobCoordinatorImplTest.createWorkChunkStep1; +import static ca.uhn.fhir.batch2.coordinator.JobCoordinatorImplTest.createWorkChunkStep2; +import static ca.uhn.fhir.batch2.coordinator.JobCoordinatorImplTest.createWorkChunkStep3; import static org.awaitility.Awaitility.await; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -59,7 +68,10 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -85,6 +97,8 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { private JobDefinitionRegistry myJobDefinitionRegistry; @Mock private IChannelProducer myWorkChannelProducer; + @Mock + private PlatformTransactionManager myTransactionService; @Captor private ArgumentCaptor> myMessageCaptor; @Captor @@ -102,7 +116,8 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { myJobDefinitionRegistry, batchJobSender, myJobExecutorSvc, - myReductionStepExecutorService); + myReductionStepExecutorService + ); myStorageSettings.setJobFastTrackingEnabled(true); } @@ -114,11 +129,14 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { ); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), eq(false))) .thenReturn(chunks.iterator()); + Page page = getPageOfData(chunks); myJobDefinitionRegistry.addJobDefinition(createJobDefinition()); JobInstance instance = createInstance(); when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(List.of(instance)); when(myJobPersistence.fetchInstance(INSTANCE_ID)).thenReturn(Optional.of(instance)); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(INSTANCE_ID), any())) + .thenReturn(page); mySvc.runMaintenancePass(); @@ -153,7 +171,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.IN_PROGRESS).setStartTime(parseTime("2022-02-12T14:00:02-04:00")), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.IN_PROGRESS).setStartTime(parseTime("2022-02-12T14:00:03-04:00")), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25), - JobCoordinatorImplTest.createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) + createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) ); myJobDefinitionRegistry.addJobDefinition(createJobDefinition()); JobInstance instance = createInstance(); @@ -161,6 +179,8 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), eq(false))) .thenReturn(chunks.iterator()); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(instance.getInstanceId()), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenReturn(Page.empty()); stubUpdateInstanceCallback(instance); mySvc.runMaintenancePass(); @@ -175,6 +195,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { assertNull(instance.getEndTime()); assertEquals("00:10:00", instance.getEstimatedTimeRemaining()); + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(instance.getInstanceId())); verifyNoMoreInteractions(myJobPersistence); } @@ -194,7 +215,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.IN_PROGRESS).setStartTime(parseTime("2022-02-12T14:00:02-04:00")).setErrorCount(2), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.IN_PROGRESS).setStartTime(parseTime("2022-02-12T14:00:03-04:00")).setErrorCount(2), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25), - JobCoordinatorImplTest.createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) + createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) ); myJobDefinitionRegistry.addJobDefinition(createJobDefinition()); JobInstance instance = createInstance(); @@ -203,6 +224,8 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), eq(false))) .thenReturn(chunks.iterator()); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(instance.getInstanceId()), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenReturn(Page.empty()); stubUpdateInstanceCallback(instance); // Execute @@ -217,30 +240,40 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { assertEquals(50, instance.getCombinedRecordsProcessed()); assertEquals(0.08333333333333333, instance.getCombinedRecordsProcessedPerSecond()); + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(instance.getInstanceId())); verifyNoMoreInteractions(myJobPersistence); } @Test public void testInProgress_GatedExecution_FirstStepComplete() { // Setup + List completedChunks = List.of(createWorkChunkStep1().setStatus(WorkChunkStatusEnum.COMPLETED).setId(CHUNK_ID)); + List chunks = Arrays.asList( - JobCoordinatorImplTest.createWorkChunkStep1().setStatus(WorkChunkStatusEnum.COMPLETED).setId(CHUNK_ID + "abc"), - JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.QUEUED).setId(CHUNK_ID), + JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.GATE_WAITING).setId(CHUNK_ID), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.QUEUED).setId(CHUNK_ID_2) ); - when (myJobPersistence.canAdvanceInstanceToNextStep(any(), any())).thenReturn(true); myJobDefinitionRegistry.addJobDefinition(createJobDefinition(JobDefinition.Builder::gatedExecution)); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), eq(false))) .thenReturn(chunks.iterator()); - - when(myJobPersistence.fetchAllChunkIdsForStepWithStatus(eq(INSTANCE_ID), eq(STEP_2), eq(WorkChunkStatusEnum.QUEUED))) - .thenReturn(chunks.stream().filter(c->c.getTargetStepId().equals(STEP_2)).map(WorkChunk::getId).collect(Collectors.toList())); + when(myJobPersistence.getDistinctWorkChunkStatesForJobAndStep(anyString(), anyString())) + .thenReturn(completedChunks.stream().map(WorkChunk::getStatus).collect(Collectors.toSet())); JobInstance instance1 = createInstance(); instance1.setCurrentGatedStepId(STEP_1); when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance1)); when(myJobPersistence.fetchInstance(INSTANCE_ID)).thenReturn(Optional.of(instance1)); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), anyString(), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenAnswer((args) -> { + // new page every time (called more than once) + return getPageOfData(new ArrayList<>(chunks)); + }); + doAnswer(a -> { + Consumer callback = a.getArgument(1); + callback.accept(1); + return null; + }).when(myJobPersistence).enqueueWorkChunkForProcessing(anyString(), any()); stubUpdateInstanceCallback(instance1); // Execute @@ -248,7 +281,9 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { // Verify verify(myWorkChannelProducer, times(2)).send(myMessageCaptor.capture()); - verify(myJobPersistence, times(2)).updateInstance(eq(INSTANCE_ID), any()); + verify(myJobPersistence, times(1)).updateInstance(eq(INSTANCE_ID), any()); + verify(myJobPersistence, times(1)).advanceJobStepAndUpdateChunkStatus(eq(INSTANCE_ID), eq(STEP_2), eq(false)); + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(INSTANCE_ID)); verifyNoMoreInteractions(myJobPersistence); JobWorkNotification payload0 = myMessageCaptor.getAllValues().get(0).getPayload(); assertEquals(STEP_2, payload0.getTargetStepId()); @@ -266,10 +301,13 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { instance.setEndTime(parseTime("2001-01-01T12:12:12Z")); when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); when(myJobPersistence.fetchInstance(INSTANCE_ID)).thenReturn(Optional.of(instance)); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(instance.getInstanceId()), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenReturn(Page.empty()); mySvc.runMaintenancePass(); verify(myJobPersistence, times(1)).deleteInstanceAndChunks(eq(INSTANCE_ID)); + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(instance.getInstanceId())); verifyNoMoreInteractions(myJobPersistence); } @@ -281,7 +319,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:01-04:00")).setEndTime(parseTime("2022-02-12T14:06:00-04:00")).setRecordsProcessed(25), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:02-04:00")).setEndTime(parseTime("2022-02-12T14:06:00-04:00")).setRecordsProcessed(25), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:03-04:00")).setEndTime(parseTime("2022-02-12T14:06:00-04:00")).setRecordsProcessed(25), - JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25),JobCoordinatorImplTest.createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) + JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25), createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) ); myJobDefinitionRegistry.addJobDefinition(createJobDefinition(t -> t.completionHandler(myCompletionHandler))); @@ -289,6 +327,8 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), anyBoolean())).thenAnswer(t->chunks.iterator()); when(myJobPersistence.fetchInstance(INSTANCE_ID)).thenReturn(Optional.of(instance)); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(INSTANCE_ID), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenReturn(Page.empty()); stubUpdateInstanceCallback(instance); // Execute @@ -307,7 +347,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { verify(myJobPersistence, times(1)).deleteChunksAndMarkInstanceAsChunksPurged(eq(INSTANCE_ID)); verify(myCompletionHandler, times(1)).jobComplete(myJobCompletionCaptor.capture()); - + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(instance.getInstanceId())); verifyNoMoreInteractions(myJobPersistence); assertEquals(INSTANCE_ID, myJobCompletionCaptor.getValue().getInstance().getInstanceId()); @@ -322,7 +362,7 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.FAILED).setStartTime(parseTime("2022-02-12T14:00:02-04:00")).setEndTime(parseTime("2022-02-12T14:06:00-04:00")).setRecordsProcessed(25).setErrorMessage("This is an error message"), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:03-04:00")).setEndTime(parseTime("2022-02-12T14:06:00-04:00")).setRecordsProcessed(25), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:00:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25), - JobCoordinatorImplTest.createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) + createWorkChunkStep3().setStatus(WorkChunkStatusEnum.COMPLETED).setStartTime(parseTime("2022-02-12T14:01:00-04:00")).setEndTime(parseTime("2022-02-12T14:10:00-04:00")).setRecordsProcessed(25) ); myJobDefinitionRegistry.addJobDefinition(createJobDefinition()); @@ -331,11 +371,12 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), anyBoolean())) .thenAnswer(t->chunks.iterator()); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(instance.getInstanceId()), eq(Set.of(WorkChunkStatusEnum.READY)))) + .thenReturn(Page.empty()); stubUpdateInstanceCallback(instance); mySvc.runMaintenancePass(); - assertEquals(0.8333333333333334, instance.getProgress()); assertEquals(StatusEnum.FAILED, instance.getStatus()); assertEquals("This is an error message", instance.getErrorMessage()); @@ -346,10 +387,134 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { // twice - once to move to FAILED, and once to purge the chunks verify(myJobPersistence, times(1)).updateInstance(eq(INSTANCE_ID), any()); verify(myJobPersistence, times(1)).deleteChunksAndMarkInstanceAsChunksPurged(eq(INSTANCE_ID)); - + verify(myJobPersistence).updatePollWaitingChunksForJobIfReady(eq(instance.getInstanceId())); verifyNoMoreInteractions(myJobPersistence); } + private void runEnqueueReadyChunksTest(List theChunks, JobDefinition theJobDefinition) { + myJobDefinitionRegistry.addJobDefinition(theJobDefinition); + JobInstance instance = createInstance(); + // we'll set the instance to the first step id + theChunks.stream().findFirst().ifPresent(c -> { + instance.setCurrentGatedStepId(c.getTargetStepId()); + }); + instance.setJobDefinitionId(theJobDefinition.getJobDefinitionId()); + + // mocks + when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance)); + when(myJobPersistence.fetchInstance(eq(INSTANCE_ID))).thenReturn(Optional.of(instance)); + when(myJobPersistence.fetchAllWorkChunksIterator(eq(INSTANCE_ID), anyBoolean())) + .thenAnswer(t -> theChunks.stream().map(c -> c.setStatus(WorkChunkStatusEnum.READY)).toList().iterator()); + + // test + mySvc.runMaintenancePass(); + } + + @Test + public void testMaintenancePass_withREADYWorkChunksForReductionSteps_notQueuedButProcessed() { + // setup + List chunks = List.of( + createWorkChunkStep3().setStatus(WorkChunkStatusEnum.READY), + createWorkChunkStep3().setStatus(WorkChunkStatusEnum.READY) + ); + List previousChunks = List.of( + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED), + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.COMPLETED) + ); + + String lastStepId = chunks.get(0).getTargetStepId(); + + // when + when(myJobPersistence.getDistinctWorkChunkStatesForJobAndStep(eq(INSTANCE_ID), eq(lastStepId))) + .thenReturn(chunks.stream().map(WorkChunk::getStatus).collect(Collectors.toSet())); + + // test + runEnqueueReadyChunksTest(chunks, createJobDefinitionWithReduction()); + + // verify never updated (should remain in ready state) + verify(myJobPersistence, never()).fetchAllWorkChunkMetadataForJobInStates(any(), anyString(), any()); + verify(myJobPersistence, never()).enqueueWorkChunkForProcessing(anyString(), any()); + verify(myWorkChannelProducer, never()).send(any()); + verify(myReductionStepExecutorService) + .triggerReductionStep(anyString(), any()); + } + + @Test + public void testMaintenancePass_withREADYworkChunksForNonReductionStep_movedToQUEUEDandPublished() { + // setup + List chunks = List.of( + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.READY), + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.READY) + ); + + // when + doAnswer(args -> { + Consumer consumer = args.getArgument(1); + consumer.accept(1); + return 1; + }).when(myJobPersistence).enqueueWorkChunkForProcessing(anyString(), any()); + + Page page = getPageOfData(chunks); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(INSTANCE_ID), any())).thenReturn(page); + + // test + runEnqueueReadyChunksTest(chunks, createJobDefinition()); + + // verify + verify(myJobPersistence, times(2)).enqueueWorkChunkForProcessing(anyString(), any()); + verify(myWorkChannelProducer, times(2)).send(myMessageCaptor.capture()); + List> sentMessages = myMessageCaptor.getAllValues(); + for (Message msg : sentMessages) { + JobWorkNotification payload = msg.getPayload(); + assertEquals(STEP_2, payload.getTargetStepId()); + assertEquals(CHUNK_ID, payload.getChunkId()); + } + } + + @Test + public void testMaintenancePass_whenUpdateFails_skipsWorkChunkAndLogs() { + // setup + List chunks = List.of( + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.READY), + createWorkChunkStep2().setStatus(WorkChunkStatusEnum.READY) + ); + JobInstance instance = createInstance(); + instance.setCurrentGatedStepId(STEP_2); + + myLogCapture.setUp(Level.ERROR); + + // when + doAnswer(args -> { + Consumer consumer = args.getArgument(1); + consumer.accept(0); // nothing processed + return 1; + }).when(myJobPersistence).enqueueWorkChunkForProcessing(anyString(), any()); + doAnswer(args -> { + IJobPersistence.JobInstanceUpdateCallback callback = args.getArgument(1); + + callback.doUpdate(instance); + return true; + }).when(myJobPersistence).updateInstance(any(), any()); + when(myJobPersistence.getDistinctWorkChunkStatesForJobAndStep(eq(instance.getInstanceId()), eq(STEP_2))) + .thenReturn(chunks.stream().map(WorkChunkMetadata::getStatus).collect(Collectors.toSet())); + Page page = getPageOfData(chunks); + when(myJobPersistence.fetchAllWorkChunkMetadataForJobInStates(any(Pageable.class), eq(INSTANCE_ID), any())).thenReturn(page); + + + // test + runEnqueueReadyChunksTest(chunks, createJobDefinitionWithReduction()); + + // verify + verify(myJobPersistence, times(2)).enqueueWorkChunkForProcessing(anyString(), any()); + verify(myWorkChannelProducer, never()).send(any()); + + List events = myLogCapture.getLogEvents(); + assertEquals(2, events.size()); + for (ILoggingEvent evt : events) { + assertTrue(evt.getMessage().contains("skipping work chunk")); + } + } + @Test void triggerMaintenancePass_noneInProgress_runsMaintenance() { when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Collections.emptyList()); @@ -408,9 +573,11 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { assertTrue(result2.get()); } - private static Date parseTime(String theDate) { return new DateTimeType(theDate).getValue(); } + private Page getPageOfData(List theChunks) { + return new PageImpl<>(theChunks.stream().map(c -> (WorkChunkMetadata)c).collect(Collectors.toList())); + } } diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index bcdfc3b4916..a5487ccedb9 100644 --- a/hapi-fhir-storage-cr/pom.xml +++ b/hapi-fhir-storage-cr/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index 23727b3009c..669d31c487a 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index f6a72dbc6ab..1027500637c 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index 1ff49ea3ab7..6cd1fd9b443 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 43a2ba0fab3..059bd1b0451 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 2138b6f052c..4d0b3bdd812 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index c94c9e07e17..586b61d07ac 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index c380b9e13a3..2442012db29 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index ba5db156616..d9472c2b050 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/ConsentInterceptorTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/ConsentInterceptorTest.java index 237e72a218c..a1acb0fcc9e 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/ConsentInterceptorTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/ConsentInterceptorTest.java @@ -262,6 +262,7 @@ public class ConsentInterceptorTest { verify(myConsentSvc, timeout(2000).times(0)).willSeeResource(any(), any(), any()); verify(myConsentSvc, timeout(2000).times(0)).startOperation(any(), any()); verify(myConsentSvc, timeout(2000).times(2)).completeOperationSuccess(any(), any()); + verifyNoMoreInteractions(myConsentSvc); } @@ -887,7 +888,8 @@ public class ConsentInterceptorTest { assertEquals(2, response.getTotal()); } - @Nested class CacheUsage { + @Nested + class CacheUsage { @Mock ICachedSearchDetails myCachedSearchDetails; ServletRequestDetails myRequestDetails = new ServletRequestDetails(); diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index 452563edf9d..7b297c89f32 100644 --- a/hapi-fhir-structures-r4b/pom.xml +++ b/hapi-fhir-structures-r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index 270596ab0cd..d833b3419cf 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index dc5ad4d0fc8..f93fcb3edfe 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/LogbackLevelOverrideExtension.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/LogbackLevelOverrideExtension.java index 3188ffa498b..907f378b86e 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/LogbackLevelOverrideExtension.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/LogbackLevelOverrideExtension.java @@ -38,10 +38,14 @@ public class LogbackLevelOverrideExtension implements AfterEachCallback { public void setLogLevel(Class theClass, Level theLevel) { String name = theClass.getName(); - Logger logger = getClassicLogger(name); - if (!mySavedLevels.containsKey(name)) { + setLogLevel(name, theLevel); + } + + public void setLogLevel(String theName, Level theLevel) { + Logger logger = getClassicLogger(theName); + if (!mySavedLevels.containsKey(theName)) { // level can be null - mySavedLevels.put(name, logger.getLevel()); + mySavedLevels.put(theName, logger.getLevel()); } logger.setLevel(theLevel); } diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 162dc758563..d8607ca6c3b 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 4458b64cc8b..828c0364fc5 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 3d923001ddb..17eeee20920 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index 1dcfb04cbbf..69a3445b187 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index f2e3aa6f5c0..157973beb1c 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4b/pom.xml b/hapi-fhir-validation-resources-r4b/pom.xml index 1af75ea43e2..1d364151cae 100644 --- a/hapi-fhir-validation-resources-r4b/pom.xml +++ b/hapi-fhir-validation-resources-r4b/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 989a90079bf..f7129e424c0 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 347c73a1527..6b0d189e778 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 34cfa205251..133e5be72dd 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index aa0dda090ec..a580dcc60b2 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 9abd2416429..b2bcabda6e9 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index 54410998f56..c7e71349f01 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index b0de40fff10..f0e456b6846 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 14cdca64555..1e5ce59b61c 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.0-SNAPSHOT + 7.3.1-SNAPSHOT ../../pom.xml From c87b5b1d2aa04f65ceb595c89a123f1db846f737 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Wed, 8 May 2024 15:45:56 -0400 Subject: [PATCH 05/15] Ensure "Device" is not considered as a resource type for R5 (#5909) * Preliminary fix. * Refine fix. Refine existing tests. Rename existing test to R4. Disable tests that don't work due to newly discovered bug with R5 POST poll. Reverse logging changes and TODOs. * Reverse more logging changes. * Check for whitelist of FHIR versions that support device in patient compartment. * Refine solution. Add a new test. * Add changelog. * Code review fix. --- ...lk-export-r5-fails-resource-not-found.yaml | 5 + ...java => BulkDataExportProviderR4Test.java} | 7 +- .../bulk/BulkDataExportProviderR5Test.java | 1320 +++++++++++++++++ .../jobs/export/BulkDataExportProvider.java | 25 +- .../export/BulkDataExportProviderTest.java | 47 + 5 files changed, 1398 insertions(+), 6 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5913-bulk-export-r5-fails-resource-not-found.yaml rename hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/{BulkDataExportProviderTest.java => BulkDataExportProviderR4Test.java} (99%) create mode 100644 hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR5Test.java create mode 100644 hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProviderTest.java diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5913-bulk-export-r5-fails-resource-not-found.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5913-bulk-export-r5-fails-resource-not-found.yaml new file mode 100644 index 00000000000..b1c09eb7062 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5913-bulk-export-r5-fails-resource-not-found.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5913 +title: "Bulk export was failing with a HAPI-2222 error with the persistence module configured for R5. + This has been fixed." diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR4Test.java similarity index 99% rename from hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java rename to hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR4Test.java index ad2b6dfc33b..425964a47ad 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR4Test.java @@ -45,7 +45,6 @@ import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.InstantType; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.StringType; -import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -97,10 +96,10 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -public class BulkDataExportProviderTest { +public class BulkDataExportProviderR4Test { private static final String A_JOB_ID = "0000000-AAAAAA"; - private static final Logger ourLog = LoggerFactory.getLogger(BulkDataExportProviderTest.class); + private static final Logger ourLog = LoggerFactory.getLogger(BulkDataExportProviderR4Test.class); private static final String GROUP_ID = "Group/G2401"; private static final String G_JOB_ID = "0000000-GGGGGG"; @Spy @@ -1298,7 +1297,7 @@ public class BulkDataExportProviderTest { private class MyRequestPartitionHelperSvc extends RequestPartitionHelperSvc { @Override - public @NotNull RequestPartitionId determineReadPartitionForRequest(@Nonnull RequestDetails theRequest, @Nonnull ReadPartitionIdRequestDetails theDetails) { + public @Nonnull RequestPartitionId determineReadPartitionForRequest(@Nonnull RequestDetails theRequest, @Nonnull ReadPartitionIdRequestDetails theDetails) { assert theRequest != null; if (myPartitionName.equals(theRequest.getTenantId())) { return myRequestPartitionId; diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR5Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR5Test.java new file mode 100644 index 00000000000..0be721b0bae --- /dev/null +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderR5Test.java @@ -0,0 +1,1320 @@ +package ca.uhn.fhir.jpa.bulk; + +import ca.uhn.fhir.batch2.api.IJobCoordinator; +import ca.uhn.fhir.batch2.api.JobOperationResultJson; +import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; +import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; +import ca.uhn.fhir.batch2.model.StatusEnum; +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.Pointcut; +import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails; +import ca.uhn.fhir.interceptor.model.RequestPartitionId; +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.api.model.BulkExportJobResults; +import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; +import ca.uhn.fhir.jpa.bulk.export.model.BulkExportResponseJson; +import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.jpa.partition.RequestPartitionHelperSvc; +import ca.uhn.fhir.rest.api.Constants; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; +import ca.uhn.fhir.rest.client.apache.ResourceEntity; +import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; +import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.provider.ProviderConstants; +import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy; +import ca.uhn.fhir.test.utilities.HttpClientExtension; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import ca.uhn.fhir.util.JsonUtil; +import ca.uhn.fhir.util.SearchParameterUtil; +import ca.uhn.fhir.util.UrlUtil; +import com.google.common.base.Charsets; +import jakarta.annotation.Nonnull; +import org.apache.commons.io.IOUtils; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.InstantType; +import org.hl7.fhir.r5.model.Parameters; +import org.hl7.fhir.r5.model.StringType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Spy; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.contains; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertAll; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.isNotNull; +import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class BulkDataExportProviderR5Test { + + private static final String A_JOB_ID = "0000000-AAAAAA"; + private static final Logger ourLog = LoggerFactory.getLogger(BulkDataExportProviderR5Test.class); + private static final String GROUP_ID = "Group/G2401"; + private static final String G_JOB_ID = "0000000-GGGGGG"; + @Spy + private final FhirContext myCtx = FhirContext.forR5Cached(); + @RegisterExtension + private final HttpClientExtension myClient = new HttpClientExtension(); + private final RequestPartitionId myRequestPartitionId = RequestPartitionId.fromPartitionIdAndName(123, "Partition-A"); + private final String myPartitionName = "Partition-A"; + private final String myFixedBaseUrl = "http:/myfixedbaseurl.com"; + @Mock + IFhirResourceDao myFhirResourceDao; + @Mock + IJobCoordinator myJobCoordinator; + + @Mock + private IInterceptorBroadcaster myInterceptorBroadcaster; + + @InjectMocks + private BulkDataExportProvider myProvider; + @RegisterExtension + private final RestfulServerExtension myServer = new RestfulServerExtension(myCtx) + .withServer(s -> s.registerProvider(myProvider)); + @Spy + private RequestPartitionHelperSvc myRequestPartitionHelperSvc = new MyRequestPartitionHelperSvc(); + private JpaStorageSettings myStorageSettings; + @Mock + private DaoRegistry myDaoRegistry; + + @BeforeEach + public void injectStorageSettings() { + myStorageSettings = new JpaStorageSettings(); + myProvider.setStorageSettings(myStorageSettings); + lenient().when(myDaoRegistry.getRegisteredDaoTypes()).thenReturn(Set.of("Patient", "Observation", "Encounter", "Group", "Device", "DiagnosticReport")); + + lenient().when(myDaoRegistry.getResourceDao(anyString())).thenReturn(myFhirResourceDao); + myProvider.setDaoRegistry(myDaoRegistry); + + } + + public void startWithFixedBaseUrl() { + HardcodedServerAddressStrategy hardcodedServerAddressStrategy = new HardcodedServerAddressStrategy(myFixedBaseUrl); + myServer.withServer(s -> s.setServerAddressStrategy(hardcodedServerAddressStrategy)); + } + + public void enablePartitioning() { + myServer.getRestfulServer().setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy()); + } + + private JobInstanceStartRequest verifyJobStart() { + ArgumentCaptor startJobCaptor = ArgumentCaptor.forClass(JobInstanceStartRequest.class); + verify(myJobCoordinator).startInstance(isNotNull(), startJobCaptor.capture()); + return startJobCaptor.getValue(); + } + + private BulkExportJobParameters verifyJobStartAndReturnParameters() { + return verifyJobStart().getParameters(BulkExportJobParameters.class); + } + + private Batch2JobStartResponse createJobStartResponse(String theJobId) { + Batch2JobStartResponse response = new Batch2JobStartResponse(); + response.setInstanceId(theJobId); + + return response; + } + + private Batch2JobStartResponse createJobStartResponse() { + return createJobStartResponse(A_JOB_ID); + } + + @ParameterizedTest + @CsvSource({"false, false", "false, true", "true, true", "true, false"}) + public void testSuccessfulInitiateBulkRequest_Post_WithFixedBaseURLAndPartitioning(Boolean baseUrlFixed, Boolean partitioningEnabled) throws IOException { + // setup + if (baseUrlFixed) { + startWithFixedBaseUrl(); + } + + String myBaseUriForExport; + if (partitioningEnabled) { + enablePartitioning(); + myBaseUriForExport = myServer.getBaseUrl() + "/" + myPartitionName; + } else { + myBaseUriForExport = myServer.getBaseUrl(); + } + + String patientResource = "Patient"; + String practitionerResource = "Practitioner"; + String filter = "Patient?identifier=foo"; + String postFetchFilter = "Patient?_tag=foo"; + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse()); + + InstantType now = InstantType.now(); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType(patientResource + ", " + practitionerResource)); + input.addParameter(JpaConstants.PARAM_EXPORT_SINCE, now); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_FILTER, new StringType(filter)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_POST_FETCH_FILTER_URL, new StringType(postFetchFilter)); + + ourLog.debug(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input)); + + // test + HttpPost post = new HttpPost(myBaseUriForExport + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + + String baseUrl; + if (baseUrlFixed) { + // If a fixed Base URL is assigned, then the URLs in the poll response should similarly start with the fixed base URL. + baseUrl = myFixedBaseUrl; + } else { + // Otherwise the URLs in the poll response should start with the default server URL. + baseUrl = myServer.getBaseUrl(); + } + + if (partitioningEnabled) { + baseUrl = baseUrl + "/" + myPartitionName; + } + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(baseUrl + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(2, params.getResourceTypes().size()); + assertTrue(params.getResourceTypes().contains(patientResource)); + assertTrue(params.getResourceTypes().contains(practitionerResource)); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + assertNotNull(params.getSince()); + assertTrue(params.getFilters().contains(filter)); + assertThat(params.getPostFetchFilterUrls(), contains("Patient?_tag=foo")); + } + + @Test + public void testOmittingOutputFormatDefaultsToNdjson() throws IOException { + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + Parameters input = new Parameters(); + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + + try (CloseableHttpResponse response = myClient.execute(post)) { + assertEquals(202, response.getStatusLine().getStatusCode()); + } + + BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + + + } + + @ParameterizedTest + @MethodSource("paramsProvider") + public void testSuccessfulInitiateBulkRequest_GetWithPartitioning(boolean partitioningEnabled) throws IOException { + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse()); + + InstantType now = InstantType.now(); + + String myBaseUrl; + if (partitioningEnabled) { + enablePartitioning(); + myBaseUrl = myServer.getBaseUrl() + "/" + myPartitionName; + } else { + myBaseUrl = myServer.getBaseUrl(); + } + String url = myBaseUrl + "/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Patient, Practitioner") + + "&" + JpaConstants.PARAM_EXPORT_SINCE + "=" + UrlUtil.escapeUrlParam(now.getValueAsString()) + + "&" + JpaConstants.PARAM_EXPORT_TYPE_FILTER + "=" + UrlUtil.escapeUrlParam("Patient?identifier=foo"); + + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + ourLog.info("Request: {}", url); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myBaseUrl + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + assertThat(params.getResourceTypes(), containsInAnyOrder("Patient", "Practitioner")); + assertThat(params.getSince(), notNullValue()); + assertThat(params.getFilters(), containsInAnyOrder("Patient?identifier=foo")); + } + + @Test + public void testSuccessfulInitiateBulkRequest_Get_MultipleTypeFilters() throws IOException { + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Patient,EpisodeOfCare") + + "&" + JpaConstants.PARAM_EXPORT_TYPE_FILTER + "=" + UrlUtil.escapeUrlParam("Patient?_id=P999999990") + + "&" + JpaConstants.PARAM_EXPORT_TYPE_FILTER + "=" + UrlUtil.escapeUrlParam("EpisodeOfCare?patient=P999999990"); + + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + ourLog.info("Request: {}", url); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + assertThat(params.getResourceTypes(), containsInAnyOrder("Patient", "EpisodeOfCare")); + assertThat(params.getSince(), nullValue()); + assertThat(params.getFilters(), containsInAnyOrder("Patient?_id=P999999990", "EpisodeOfCare?patient=P999999990")); + } + + @Test + public void testPollForStatus_QUEUED() throws IOException { + // setup + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.QUEUED); + info.setEndTime(new Date()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // test + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals("120", response.getFirstHeader(Constants.HEADER_RETRY_AFTER).getValue()); + assertThat(response.getFirstHeader(Constants.HEADER_X_PROGRESS).getValue(), + containsString("Build in progress - Status set to " + info.getStatus() + " at 20")); + } + } + + @Test + public void testPollForStatus_Failed() throws IOException { + // setup + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.FAILED); + info.setStartTime(new Date()); + info.setErrorMessage("Some Error Message"); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // call + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(500, response.getStatusLine().getStatusCode()); + assertEquals("Server Error", response.getStatusLine().getReasonPhrase()); + + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + ourLog.info("Response content: {}", responseContent); + assertThat(responseContent, containsString("\"diagnostics\": \"Some Error Message\"")); + } + } + + @ParameterizedTest + @CsvSource({"false, false", "false, true", "true, true", "true, false"}) + public void testPollForStatus_COMPLETED_WithFixedBaseURLAndPartitioning(boolean baseUrlFixed, boolean partitioningEnabled) throws IOException { + + // setup + if (baseUrlFixed) { + startWithFixedBaseUrl(); + } + + String myBaseUriForExport; + if (partitioningEnabled) { + enablePartitioning(); + myBaseUriForExport = myServer.getBaseUrl() + "/" + myPartitionName; + } else { + myBaseUriForExport = myServer.getBaseUrl(); + } + + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.COMPLETED); + info.setEndTime(InstantType.now().getValue()); + ArrayList ids = new ArrayList<>(); + ids.add(new IdType("Binary/111").getValueAsString()); + ids.add(new IdType("Binary/222").getValueAsString()); + ids.add(new IdType("Binary/333").getValueAsString()); + BulkExportJobResults results = new BulkExportJobResults(); + + HashMap> map = new HashMap<>(); + map.put("Patient", ids); + results.setResourceTypeToBinaryIds(map); + info.setReport(JsonUtil.serialize(results)); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + if (partitioningEnabled) { + parameters.setPartitionId(myRequestPartitionId); + } + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // call + String url = myBaseUriForExport + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + String myBaseUriForPoll; + if (baseUrlFixed) { + // If a fixed Base URL is provided, the URLs in the poll response should similarly start with the fixed Base URL. + myBaseUriForPoll = myFixedBaseUrl; + } else { + // Otherwise the URLs in the poll response should instead with the default server URL. + myBaseUriForPoll = myServer.getBaseUrl(); + } + if (partitioningEnabled) { + // If partitioning is enabled, then the URLs in the poll response should also have the partition name. + myBaseUriForPoll = myBaseUriForPoll + "/" + myPartitionName; + } + + assertEquals(200, response.getStatusLine().getStatusCode()); + assertEquals("OK", response.getStatusLine().getReasonPhrase()); + assertEquals(Constants.CT_JSON, response.getEntity().getContentType().getValue()); + + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + ourLog.info("Response content: {}", responseContent); + BulkExportResponseJson responseJson = JsonUtil.deserialize(responseContent, BulkExportResponseJson.class); + assertEquals(3, responseJson.getOutput().size()); + assertEquals("Patient", responseJson.getOutput().get(0).getType()); + assertEquals(myBaseUriForPoll + "/Binary/111", responseJson.getOutput().get(0).getUrl()); + assertEquals("Patient", responseJson.getOutput().get(1).getType()); + assertEquals(myBaseUriForPoll + "/Binary/222", responseJson.getOutput().get(1).getUrl()); + assertEquals("Patient", responseJson.getOutput().get(2).getType()); + assertEquals(myBaseUriForPoll + "/Binary/333", responseJson.getOutput().get(2).getUrl()); + } + } + + @Test + public void testPollForStatus_WithInvalidPartition() throws IOException { + + // setup + enablePartitioning(); + + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.COMPLETED); + info.setEndTime(InstantType.now().getValue()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + parameters.setPartitionId(myRequestPartitionId); + info.setParameters(parameters); + + ArrayList ids = new ArrayList<>(); + ids.add(new IdType("Binary/111").getValueAsString()); + ids.add(new IdType("Binary/222").getValueAsString()); + ids.add(new IdType("Binary/333").getValueAsString()); + BulkExportJobResults results = new BulkExportJobResults(); + + HashMap> map = new HashMap<>(); + map.put("Patient", ids); + results.setResourceTypeToBinaryIds(map); + info.setReport(JsonUtil.serialize(results)); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // call + String myBaseUriForExport = myServer.getBaseUrl() + "/Partition-B"; + String url = myBaseUriForExport + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(403, response.getStatusLine().getStatusCode()); + assertEquals("Forbidden", response.getStatusLine().getReasonPhrase()); + } + } + + @Test + public void testExportWhenNoResourcesReturned() throws IOException { + // setup + String msg = "Some msg"; + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.COMPLETED); + info.setEndTime(InstantType.now().getValue()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + info.setParameters(parameters); + + ArrayList ids = new ArrayList<>(); + BulkExportJobResults results = new BulkExportJobResults(); + HashMap> map = new HashMap<>(); + map.put("Patient", ids); + results.setResourceTypeToBinaryIds(map); + results.setReportMsg(msg); + info.setReport(JsonUtil.serialize(results)); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // test + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(200, response.getStatusLine().getStatusCode()); + assertEquals("OK", response.getStatusLine().getReasonPhrase()); + assertEquals(Constants.CT_JSON, response.getEntity().getContentType().getValue()); + + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + ourLog.info("Response content: {}", responseContent); + BulkExportResponseJson responseJson = JsonUtil.deserialize(responseContent, BulkExportResponseJson.class); + assertEquals(msg, responseJson.getMsg()); + } + } + + @Test + public void testPollForStatus_Gone() throws IOException { + // setup + + // when + when(myJobCoordinator.getInstance(anyString())) + .thenThrow(new ResourceNotFoundException("Unknown job: AAA")); + + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + ourLog.info("Response content: {}", responseContent); + + assertEquals(404, response.getStatusLine().getStatusCode()); + assertEquals(Constants.CT_FHIR_JSON_NEW, response.getEntity().getContentType().getValue().replaceAll(";.*", "").trim()); + assertThat(responseContent, containsString("\"diagnostics\": \"Unknown job: AAA\"")); + } + } + + /** + * Group export tests + * See Bulk Data IG + *

+ * GET [fhir base]/Group/[id]/$export + *

+ * FHIR Operation to obtain data on all patients listed in a single FHIR Group Resource. + */ + + @Test + public void testSuccessfulInitiateGroupBulkRequest_Post() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse(G_JOB_ID)); + + InstantType now = InstantType.now(); + + Parameters input = new Parameters(); + StringType obsTypeFilter = new StringType("Observation?code=OBSCODE,DiagnosticReport?code=DRCODE"); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Observation, DiagnosticReport")); + input.addParameter(JpaConstants.PARAM_EXPORT_SINCE, now); + input.addParameter(JpaConstants.PARAM_EXPORT_MDM, true); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_FILTER, obsTypeFilter); + + ourLog.debug(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input)); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + GROUP_ID + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + G_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + // verify + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes(), containsInAnyOrder("Observation", "DiagnosticReport")); + assertThat(bp.getSince(), notNullValue()); + assertThat(bp.getFilters(), notNullValue()); + assertEquals(GROUP_ID, bp.getGroupId()); + assertThat(bp.isExpandMdm(), is(equalTo(true))); + } + + @Test + public void testSuccessfulInitiateGroupBulkRequest_Get() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse(G_JOB_ID)); + + InstantType now = InstantType.now(); + + String url = myServer.getBaseUrl() + "/" + GROUP_ID + "/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Patient, Practitioner") + + "&" + JpaConstants.PARAM_EXPORT_SINCE + "=" + UrlUtil.escapeUrlParam(now.getValueAsString()) + + "&" + JpaConstants.PARAM_EXPORT_TYPE_FILTER + "=" + UrlUtil.escapeUrlParam("Patient?identifier=foo|bar") + + "&" + JpaConstants.PARAM_EXPORT_MDM + "=true"; + + // call + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + ourLog.info("Request: {}", url); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + G_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes(), containsInAnyOrder("Patient", "Practitioner")); + assertThat(bp.getSince(), notNullValue()); + assertThat(bp.getFilters(), notNullValue()); + assertEquals(GROUP_ID, bp.getGroupId()); + assertThat(bp.isExpandMdm(), is(equalTo(true))); + } + + @Test + public void testSuccessfulInitiateGroupBulkRequest_Get_SomeTypesDisabled() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse(G_JOB_ID)); + + InstantType now = InstantType.now(); + + String url = myServer.getBaseUrl() + "/" + GROUP_ID + "/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_SINCE + "=" + UrlUtil.escapeUrlParam(now.getValueAsString()); + + // call + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + ourLog.info("Request: {}", url); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + G_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes().toString(), bp.getResourceTypes(), containsInAnyOrder( + "DiagnosticReport", "Group", "Observation", "Device", "Patient", "Encounter" + )); + assertThat(bp.getSince(), notNullValue()); + assertThat(bp.getFilters(), notNullValue()); + assertEquals(GROUP_ID, bp.getGroupId()); + assertThat(bp.isExpandMdm(), is(equalTo(false))); + } + + @Test + public void testInitiateWithGetAndMultipleTypeFilters() throws IOException { + // setup + InstantType now = InstantType.now(); + + // manual construct + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Immunization, Observation") + + "&" + JpaConstants.PARAM_EXPORT_SINCE + "=" + UrlUtil.escapeUrlParam(now.getValueAsString()); + + String immunizationTypeFilter1 = "Immunization?patient.identifier=SC378274-MRN|009999997,SC378274-MRN|009999998,SC378274-MRN|009999999&date=2020-01-02"; + String immunizationTypeFilter2 = "Immunization?patient=Patient/123"; + String observationFilter1 = "Observation?subject=Patient/123&created=ge2020-01-01"; + String multiValuedTypeFilterBuilder = "&" + + JpaConstants.PARAM_EXPORT_TYPE_FILTER + + "=" + + UrlUtil.escapeUrlParam(immunizationTypeFilter1) + + "," + + UrlUtil.escapeUrlParam(immunizationTypeFilter2) + + "," + + UrlUtil.escapeUrlParam(observationFilter1); + + url += multiValuedTypeFilterBuilder; + + // call + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse ignored = myClient.execute(get)) { + // verify + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertThat(bp.getFilters(), containsInAnyOrder(immunizationTypeFilter1, immunizationTypeFilter2, observationFilter1)); + } + } + + @Test + public void testInitiateGroupExportWithInvalidResourceTypesFails() throws IOException { + // when + + String url = myServer.getBaseUrl() + "/" + "Group/123/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("StructureDefinition,Observation"); + + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse execute = myClient.execute(get)) { + String responseBody = IOUtils.toString(execute.getEntity().getContent(), StandardCharsets.UTF_8); + + // verify + assertThat(execute.getStatusLine().getStatusCode(), is(equalTo(400))); + assertThat(responseBody, is(containsString("Resource types [StructureDefinition] are invalid for this type of export, as they do not contain search parameters that refer to patients."))); + } + } + + @Test + public void testInitiateGroupExportWithNoResourceTypes() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse()); + + // test + String url = myServer.getBaseUrl() + "/" + "Group/123/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON); + + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse execute = myClient.execute(get)) { + + // verify + assertThat(execute.getStatusLine().getStatusCode(), is(equalTo(202))); + final BulkExportJobParameters BulkExportJobParameters = verifyJobStartAndReturnParameters(); + + assertAll( + () -> assertTrue(BulkExportJobParameters.getResourceTypes().contains("Patient")), + () -> assertTrue(BulkExportJobParameters.getResourceTypes().contains("Group")), + () -> assertTrue(BulkExportJobParameters.getResourceTypes().contains("Device")) + ); + } + } + + @Test + public void testInitiateWithPostAndMultipleTypeFilters() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())).thenReturn(createJobStartResponse()); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Patient")); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_FILTER, new StringType("Patient?gender=male,Patient?gender=female")); + + ourLog.debug(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input)); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + // verify + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes(), containsInAnyOrder("Patient")); + assertThat(bp.getFilters(), containsInAnyOrder("Patient?gender=male", "Patient?gender=female")); + } + + @ParameterizedTest + @ValueSource(strings = {"/Patient/" + ProviderConstants.OPERATION_EXPORT, "/Patient/p1/" + ProviderConstants.OPERATION_EXPORT}) + public void testInitiateBulkExportOnPatient_noTypeParam_addsTypeBeforeBulkExport(String mode) throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + mode); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + // verify + Set expectedResourceTypes = new HashSet<>(SearchParameterUtil.getAllResourceTypesThatAreInPatientCompartment(myCtx)); + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes(), containsInAnyOrder(expectedResourceTypes.toArray())); + } + + @Test + public void testInitiatePatientExportRequest() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + InstantType now = InstantType.now(); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Immunization, Observation")); + input.addParameter(JpaConstants.PARAM_EXPORT_SINCE, now); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE_FILTER, new StringType("Immunization?vaccine-code=foo")); + + ourLog.debug(myCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(input)); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/Patient/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + BulkExportJobParameters bp = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, bp.getOutputFormat()); + assertThat(bp.getResourceTypes(), containsInAnyOrder("Immunization", "Observation")); + assertThat(bp.getSince(), notNullValue()); + assertThat(bp.getFilters(), containsInAnyOrder("Immunization?vaccine-code=foo")); + assertThat(bp.getResourceTypes(), contains("Immunization", "Observation")); + } + + @Test + public void testProviderProcessesNoCacheHeader() throws IOException { + // setup + Batch2JobStartResponse startResponse = createJobStartResponse(); + startResponse.setUsesCachedResult(true); + + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(startResponse); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Patient, Practitioner")); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.addHeader(Constants.HEADER_CACHE_CONTROL, Constants.CACHE_CONTROL_NO_CACHE); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + // verify + JobInstanceStartRequest parameters = verifyJobStart(); + assertFalse(parameters.isUseCache()); + } + + @Test + public void testProvider_whenEnableBatchJobReuseIsFalse_startsNewJob() throws IOException { + // setup + Batch2JobStartResponse startResponse = createJobStartResponse(); + startResponse.setUsesCachedResult(true); + + myStorageSettings.setEnableBulkExportJobReuse(false); + + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(startResponse); + + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Patient, Practitioner")); + + // call + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + A_JOB_ID, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + + // verify + JobInstanceStartRequest parameters = verifyJobStart(); + assertFalse(parameters.isUseCache()); + } + + @Test + public void testProviderReturnsSameIdForSameJob() throws IOException { + // given + Batch2JobStartResponse startResponse = createJobStartResponse(); + startResponse.setUsesCachedResult(true); + startResponse.setInstanceId(A_JOB_ID); + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(startResponse); + + // when + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_TYPE, new StringType("Patient, Practitioner")); + + // then + callExportAndAssertJobId(input, A_JOB_ID); + callExportAndAssertJobId(input, A_JOB_ID); + + } + + @ParameterizedTest + @MethodSource("paramsProvider") + public void testDeleteForOperationPollStatus_SUBMITTED_ShouldCancelJobSuccessfully(boolean partitioningEnabled) throws IOException { + // setup + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + if (partitioningEnabled) { + parameters.setPartitionId(myRequestPartitionId); + } + + JobInstance info = new JobInstance(); + info.setParameters(parameters); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.QUEUED); + info.setEndTime(InstantType.now().getValue()); + JobOperationResultJson result = new JobOperationResultJson(); + result.setOperation("Cancel job instance " + A_JOB_ID); + result.setMessage("Job instance <" + A_JOB_ID + "> successfully cancelled."); + result.setSuccess(true); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + when(myJobCoordinator.cancelInstance(eq(A_JOB_ID))) + .thenReturn(result); + + // call + String baseUrl; + if (partitioningEnabled) { + enablePartitioning(); + baseUrl = myServer.getBaseUrl() + "/" + myPartitionName; + } else { + baseUrl = myServer.getBaseUrl(); + } + + String url = baseUrl + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpDelete delete = new HttpDelete(url); + try (CloseableHttpResponse response = myClient.execute(delete)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + + verify(myJobCoordinator, times(1)).cancelInstance(A_JOB_ID); + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + ourLog.info("Response content: {}", responseContent); + assertThat(responseContent, containsString("successfully cancelled.")); + } + } + + @Test + public void testDeleteForOperationPollStatus_COMPLETE_ShouldReturnError() throws IOException { + // setup + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.COMPLETED); + info.setEndTime(InstantType.now().getValue()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // call + String url = myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpDelete delete = new HttpDelete(url); + try (CloseableHttpResponse response = myClient.execute(delete)) { + ourLog.info("Response: {}", response.toString()); + + assertEquals(404, response.getStatusLine().getStatusCode()); + assertEquals("Not Found", response.getStatusLine().getReasonPhrase()); + + verify(myJobCoordinator, times(1)).cancelInstance(A_JOB_ID); + String responseContent = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8); + // content would be blank, since the job is cancelled, so no + ourLog.info("Response content: {}", responseContent); + assertThat(responseContent, containsString("was already cancelled or has completed.")); + } + } + + + + @ParameterizedTest + @ValueSource(strings = { + "$export", + "Patient/$export", + "Patient//$export", + "Group//$export" + }) + public void testBulkDataExport_hookOrder_isMaintained(String theUrl) throws IOException { + // setup + String url = String.format( + "http://localhost:%s/%s", + myServer.getPort(), + theUrl.replaceAll("", "1")); + AtomicBoolean preInitiateCalled = new AtomicBoolean(false); + AtomicBoolean initiateCalled = new AtomicBoolean(false); + + // when + when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT), any(HookParams.class))) + .thenAnswer((args) -> { + assertFalse(initiateCalled.get()); + assertFalse(preInitiateCalled.getAndSet(true)); + return true; + }); + when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT), any(HookParams.class))) + .thenAnswer((args) -> { + assertTrue(preInitiateCalled.get()); + assertFalse(initiateCalled.getAndSet(true)); + return true; + }); + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + // test + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + } + + // verify + assertTrue(preInitiateCalled.get()); + assertTrue(initiateCalled.get()); + } + + @Test + public void testGetBulkExport_outputFormat_FhirNdJson_inHeader() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + // call + final HttpGet httpGet = new HttpGet(String.format("http://localhost:%s/%s", myServer.getPort(), ProviderConstants.OPERATION_EXPORT)); + httpGet.addHeader("_outputFormat", Constants.CT_FHIR_NDJSON); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + + try (CloseableHttpResponse response = myClient.execute(httpGet)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(String.format("http://localhost:%s/$export-poll-status?_jobId=%s", myServer.getPort(), A_JOB_ID), response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + assertTrue(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8).isEmpty()); + } + + final BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + } + + @Test + public void testGetBulkExport_outputFormat_FhirNdJson_inUrl() throws IOException { + // when + when(myJobCoordinator.startInstance(isNotNull(), any())) + .thenReturn(createJobStartResponse()); + + // call + final HttpGet httpGet = new HttpGet(String.format("http://localhost:%s/%s?_outputFormat=%s", myServer.getPort(), ProviderConstants.OPERATION_EXPORT, Constants.CT_FHIR_NDJSON)); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + + try (CloseableHttpResponse response = myClient.execute(httpGet)) { + assertAll( + () -> assertEquals(202, response.getStatusLine().getStatusCode()), + () -> assertEquals("Accepted", response.getStatusLine().getReasonPhrase()), + () -> assertEquals(String.format("http://localhost:%s/$export-poll-status?_jobId=%s", myServer.getPort(), A_JOB_ID), response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()), + () -> assertTrue(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8).isEmpty()) + ); + } + + final BulkExportJobParameters params = verifyJobStartAndReturnParameters(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + } + + @Test + @Disabled("bug with POST poll and R5") + public void testOperationExportPollStatus_POST_NonExistingId_NotFound() throws IOException { + String jobId = "NonExisting-JobId"; + + when(myJobCoordinator.getInstance(any())).thenThrow(new ResourceNotFoundException("Unknown")); + + // Create the initial launch Parameters containing the request + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID, new StringType(jobId)); + + // Initiate Export Poll Status + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + + + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(Constants.STATUS_HTTP_404_NOT_FOUND, response.getStatusLine().getStatusCode()); + } + } + + @ParameterizedTest + @MethodSource("paramsProvider") + @Disabled("bug with POST poll and R5") + public void testOperationExportPollStatus_POST_ExistingId_Accepted(boolean partititioningEnabled) throws IOException { + // setup + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.QUEUED); + info.setEndTime(InstantType.now().getValue()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + if (partititioningEnabled) { + parameters.setPartitionId(myRequestPartitionId); + } + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // Create the initial launch Parameters containing the request + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + input.addParameter(JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID, new StringType(A_JOB_ID)); + + String baseUrl; + if (partititioningEnabled) { + enablePartitioning(); + baseUrl = myServer.getBaseUrl() + "/" + myPartitionName; + } else { + baseUrl = myServer.getBaseUrl(); + } + + // Initiate Export Poll Status + HttpPost post = new HttpPost(baseUrl + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(Constants.STATUS_HTTP_202_ACCEPTED, response.getStatusLine().getStatusCode()); + } + } + + @Test + @Disabled("bug with POST poll and R5") + public void testOperationExportPollStatus_POST_MissingInputParameterJobId_BadRequest() throws IOException { + + // Create the initial launch Parameters containing the request + Parameters input = new Parameters(); + input.addParameter(JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT, new StringType(Constants.CT_FHIR_NDJSON)); + + // Initiate Export Poll Status + HttpPost post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.setEntity(new ResourceEntity(myCtx, input)); + + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(Constants.STATUS_HTTP_400_BAD_REQUEST, response.getStatusLine().getStatusCode()); + } + } + + private void callExportAndAssertJobId(Parameters input, String theExpectedJobId) throws IOException { + HttpPost post; + post = new HttpPost(myServer.getBaseUrl() + "/" + ProviderConstants.OPERATION_EXPORT); + post.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + post.addHeader(Constants.HEADER_CACHE_CONTROL, Constants.CACHE_CONTROL_NO_CACHE); + post.setEntity(new ResourceEntity(myCtx, input)); + ourLog.info("Request: {}", post); + try (CloseableHttpResponse response = myClient.execute(post)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(myServer.getBaseUrl() + "/$export-poll-status?_jobId=" + theExpectedJobId, response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + } + } + + @Test + public void testFailBulkExportRequest_PartitionedWithoutPermissions() throws IOException { + + // setup + enablePartitioning(); + + // test + String url = myServer.getBaseUrl() + "/Partition-B/" + ProviderConstants.OPERATION_EXPORT + + "?" + JpaConstants.PARAM_EXPORT_OUTPUT_FORMAT + "=" + UrlUtil.escapeUrlParam(Constants.CT_FHIR_NDJSON) + + "&" + JpaConstants.PARAM_EXPORT_TYPE + "=" + UrlUtil.escapeUrlParam("Patient, Practitioner"); + + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + ourLog.info("Request: {}", url); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(403, response.getStatusLine().getStatusCode()); + assertEquals("Forbidden", response.getStatusLine().getReasonPhrase()); + } + + } + + @Test + public void testFailPollRequest_PartitionedWithoutPermissions() throws IOException { + // setup + enablePartitioning(); + + JobInstance info = new JobInstance(); + info.setInstanceId(A_JOB_ID); + info.setStatus(StatusEnum.IN_PROGRESS); + info.setEndTime(new Date()); + + BulkExportJobParameters parameters = new BulkExportJobParameters(); + parameters.setPartitionId(myRequestPartitionId); + info.setParameters(parameters); + + // when + when(myJobCoordinator.getInstance(eq(A_JOB_ID))) + .thenReturn(info); + + // test + String url = myServer.getBaseUrl() + "/Partition-B/" + ProviderConstants.OPERATION_EXPORT_POLL_STATUS + "?" + + JpaConstants.PARAM_EXPORT_POLL_STATUS_JOB_ID + "=" + A_JOB_ID; + HttpGet get = new HttpGet(url); + get.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + try (CloseableHttpResponse response = myClient.execute(get)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(403, response.getStatusLine().getStatusCode()); + assertEquals("Forbidden", response.getStatusLine().getReasonPhrase()); + } + } + + static Stream paramsProvider() { + return Stream.of( + Arguments.arguments(true), + Arguments.arguments(false) + ); + } + + private class MyRequestPartitionHelperSvc extends RequestPartitionHelperSvc { + @Override + public @Nonnull RequestPartitionId determineReadPartitionForRequest(@Nonnull RequestDetails theRequest, @Nonnull ReadPartitionIdRequestDetails theDetails) { + assert theRequest != null; + if (myPartitionName.equals(theRequest.getTenantId())) { + return myRequestPartitionId; + } else { + return RequestPartitionId.fromPartitionName(theRequest.getTenantId()); + } + } + + @Override + public void validateHasPartitionPermissions(@Nonnull RequestDetails theRequest, String theResourceType, RequestPartitionId theRequestPartitionId) { + if (!myPartitionName.equals(theRequest.getTenantId()) && theRequest.getTenantId() != null) { + throw new ForbiddenOperationException("User does not have access to resources on the requested partition"); + } + } + + } +} diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProvider.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProvider.java index da6cf525033..002e21a0cf9 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProvider.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProvider.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.batch2.model.JobInstance; import ca.uhn.fhir.batch2.model.JobInstanceStartRequest; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; @@ -99,6 +100,13 @@ public class BulkDataExportProvider { public static final String UNSUPPORTED_BINARY_TYPE = "Binary"; private static final Logger ourLog = getLogger(BulkDataExportProvider.class); + private static final Set PATIENT_COMPARTMENT_FHIR_VERSIONS_SUPPORT_DEVICE = Set.of( + FhirVersionEnum.DSTU2, + FhirVersionEnum.DSTU2_1, + FhirVersionEnum.DSTU2_HL7ORG, + FhirVersionEnum.DSTU3, + FhirVersionEnum.R4, + FhirVersionEnum.R4B); @Autowired private IInterceptorBroadcaster myInterceptorBroadcaster; @@ -344,10 +352,18 @@ public class BulkDataExportProvider { } private Set getPatientCompartmentResources() { + return getPatientCompartmentResources(myFhirContext); + } + + @VisibleForTesting + Set getPatientCompartmentResources(FhirContext theFhirContext) { if (myCompartmentResources == null) { myCompartmentResources = - new HashSet<>(SearchParameterUtil.getAllResourceTypesThatAreInPatientCompartment(myFhirContext)); - myCompartmentResources.add("Device"); + new HashSet<>(SearchParameterUtil.getAllResourceTypesThatAreInPatientCompartment(theFhirContext)); + if (isDeviceResourceSupportedForPatientCompartmentForFhirVersion( + theFhirContext.getVersion().getVersion())) { + myCompartmentResources.add("Device"); + } } return myCompartmentResources; } @@ -803,4 +819,9 @@ public class BulkDataExportProvider { throw new InvalidRequestException(Msg.code(513) + "Must request async processing for " + theOperationName); } } + + private static boolean isDeviceResourceSupportedForPatientCompartmentForFhirVersion( + FhirVersionEnum theFhirVersionEnum) { + return PATIENT_COMPARTMENT_FHIR_VERSIONS_SUPPORT_DEVICE.contains(theFhirVersionEnum); + } } diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProviderTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProviderTest.java new file mode 100644 index 00000000000..8a1a5e3848b --- /dev/null +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkDataExportProviderTest.java @@ -0,0 +1,47 @@ +package ca.uhn.fhir.batch2.jobs.export; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.util.Set; +import java.util.stream.Stream; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.hasItem; +import static org.hamcrest.Matchers.not; + +@ExtendWith(MockitoExtension.class) +class BulkDataExportProviderTest { + private static final Set PATIENT_COMPARTMENT_FHIR_VERSIONS_SUPPORT_DEVICE = Set.of(FhirVersionEnum.DSTU2, FhirVersionEnum.DSTU2_1, FhirVersionEnum.DSTU2_HL7ORG, FhirVersionEnum.DSTU3, FhirVersionEnum.R4, FhirVersionEnum.R4B); + + private static Stream fhirContexts() { + return Stream.of( + Arguments.arguments(FhirContext.forDstu2()), + Arguments.arguments(FhirContext.forDstu2Cached()), + Arguments.arguments(FhirContext.forDstu2Hl7Org()), + Arguments.arguments(FhirContext.forDstu2Hl7OrgCached()), + Arguments.arguments(FhirContext.forDstu3()), + Arguments.arguments(FhirContext.forDstu3Cached()), + Arguments.arguments(FhirContext.forR4()), + Arguments.arguments(FhirContext.forR4Cached()), + Arguments.arguments(FhirContext.forR4B()), + Arguments.arguments(FhirContext.forR4BCached()), + Arguments.arguments(FhirContext.forR5()), + Arguments.arguments(FhirContext.forR5Cached()) + ); + } + + @ParameterizedTest + @MethodSource("fhirContexts") + void checkDeviceIsSupportedInPatientCompartment(FhirContext theFhirContext) { + assertThat(new BulkDataExportProvider().getPatientCompartmentResources(theFhirContext), + PATIENT_COMPARTMENT_FHIR_VERSIONS_SUPPORT_DEVICE.contains(theFhirContext.getVersion().getVersion()) + ? hasItem("Device") + : not(hasItem("Device"))); + } +} From 125513a10009041289b0d0570c30aa4fd637ab0a Mon Sep 17 00:00:00 2001 From: longma1 <32119004+longma1@users.noreply.github.com> Date: Fri, 10 May 2024 15:52:43 -0600 Subject: [PATCH 06/15] 7_2 branch mergeback (#5922) * Enhance RuleBuilder code to support multiple instances (#5852) * Overhaul bulk export permissions. * Overhaul bulk export permissions. * Small tweak to rule builder. * Cleanup validation. * Cleanup validation. * Code review feedback. * Postgres terminology service hard coded column names migration (#5866) * updating parent pids column name * updating name of the fullTestField Search * updating name of the fullTestField Search * fixing typo. * failing test. * - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity; - reverting the name of the FullTextField entity to its previous name of 'myParentPids'; - reverting the name of the lucene index to search on in the terminology service. - updating the changelog; * making spotless happy --------- Co-authored-by: peartree * 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881) * initial failing test. * solution * adding changelog * spotless * moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder. --------- Co-authored-by: peartree * Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811) * Expose BaseRequestPartitionHelperSvc validate and normalize methods * Compilation errors * change mock test to jpa test * change mock test to jpa test * validateAndNormalizePartitionIds * validateAndNormalizePartitionNames * validateAndNormalizePartitionIds validation + bug fix * validateAndNormalizePartitionNames validation * fix test * version bump * Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883) * Add failing test as well as commented out potential solution. * Fix for NumberFormatException. * Add conditional test for survivorship rules. * Spotless. * Add changelog. * Code review feedback. * updating documentation (#5889) * Ensure temp file ends with "." and then suffix. (#5894) * bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892) Co-authored-by: Jens Kristian Villadsen * Enhance mdm interceptor (#5899) * Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened. * Added javadoc * Cahngelog * spotless --------- Co-authored-by: Jens Kristian Villadsen * Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896) * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug. * Add changelog. * Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml Commit code reviewer suggestion. Co-authored-by: Tadgh --------- Co-authored-by: Tadgh * Fix query chained on sort bug where we over-filter results (#5903) * Failing test. * Ensure test cleanup doesn't fail by deleting Patients before Practitioners. * Implement fix. * Spotless. * Clean up unit test and add changelog. Fix unit test. * Fix changelog file. * Apply suggestions from code review Apply code review suggestions. Co-authored-by: Michael Buckley * Spotless --------- Co-authored-by: Michael Buckley * cve fix (#5906) Co-authored-by: Long Ma * Fixing issues with postgres LOB migration. (#5895) * Fixing issues with postgres LOB migration. * addressing code review comments for audit/transaction logs. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for TermConcept migration post code review. * applying spotless * test and implementation for TermConceptProperty migration post code review. * test and implementation for TermValueSetConcept migration post code review. * fixing migration version * fixing migration task * changelog * fixing changelog * Minor renames * addressing comments and suggestions from second code review. * passing tests * fixing more tests --------- Co-authored-by: peartree Co-authored-by: Tadgh * 6051 bulk export security errors (#5915) * Enhance RuleBuilder code to support multiple instances (#5852) * Overhaul bulk export permissions. * Overhaul bulk export permissions. * Small tweak to rule builder. * Cleanup validation. * Cleanup validation. * Code review feedback. * Postgres terminology service hard coded column names migration (#5866) * updating parent pids column name * updating name of the fullTestField Search * updating name of the fullTestField Search * fixing typo. * failing test. * - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity; - reverting the name of the FullTextField entity to its previous name of 'myParentPids'; - reverting the name of the lucene index to search on in the terminology service. - updating the changelog; * making spotless happy --------- Co-authored-by: peartree * 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881) * initial failing test. * solution * adding changelog * spotless * moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder. --------- Co-authored-by: peartree * Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811) * Expose BaseRequestPartitionHelperSvc validate and normalize methods * Compilation errors * change mock test to jpa test * change mock test to jpa test * validateAndNormalizePartitionIds * validateAndNormalizePartitionNames * validateAndNormalizePartitionIds validation + bug fix * validateAndNormalizePartitionNames validation * fix test * version bump * Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883) * Add failing test as well as commented out potential solution. * Fix for NumberFormatException. * Add conditional test for survivorship rules. * Spotless. * Add changelog. * Code review feedback. * updating documentation (#5889) * Ensure temp file ends with "." and then suffix. (#5894) * bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892) Co-authored-by: Jens Kristian Villadsen * Enhance mdm interceptor (#5899) * Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened. * Added javadoc * Cahngelog * spotless --------- Co-authored-by: Jens Kristian Villadsen * Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896) * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug. * Add changelog. * Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml Commit code reviewer suggestion. Co-authored-by: Tadgh --------- Co-authored-by: Tadgh * Fix query chained on sort bug where we over-filter results (#5903) * Failing test. * Ensure test cleanup doesn't fail by deleting Patients before Practitioners. * Implement fix. * Spotless. * Clean up unit test and add changelog. Fix unit test. * Fix changelog file. * Apply suggestions from code review Apply code review suggestions. Co-authored-by: Michael Buckley * Spotless --------- Co-authored-by: Michael Buckley * cve fix (#5906) Co-authored-by: Long Ma * Fixing issues with postgres LOB migration. (#5895) * Fixing issues with postgres LOB migration. * addressing code review comments for audit/transaction logs. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for TermConcept migration post code review. * applying spotless * test and implementation for TermConceptProperty migration post code review. * test and implementation for TermValueSetConcept migration post code review. * fixing migration version * fixing migration task * changelog * fixing changelog * Minor renames * addressing comments and suggestions from second code review. * passing tests * fixing more tests --------- Co-authored-by: peartree Co-authored-by: Tadgh * refactor bulk export rule, add concept of appliestoallpatients, fix tests * spotless * Cahgnelog, tests * more tests * refactor style checks --------- Co-authored-by: Luke deGruchy Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com> Co-authored-by: peartree Co-authored-by: Nathan Doef Co-authored-by: TipzCM Co-authored-by: dotasek Co-authored-by: Jens Kristian Villadsen Co-authored-by: Michael Buckley Co-authored-by: longma1 <32119004+longma1@users.noreply.github.com> Co-authored-by: Long Ma * Convert a few nulls to aggressive denies * Change chain sort syntax for MS SQL (#5917) * Change sort type on chains * Change sort type on chains * Test for MS SQL * Comments --------- Co-authored-by: Luke deGruchy Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com> Co-authored-by: peartree Co-authored-by: Nathan Doef Co-authored-by: TipzCM Co-authored-by: dotasek Co-authored-by: Jens Kristian Villadsen Co-authored-by: Tadgh Co-authored-by: Michael Buckley Co-authored-by: Long Ma --- .../ca/uhn/fhir/interceptor/api/Pointcut.java | 8 +- .../fhir/cli/UploadTerminologyCommand.java | 11 +- .../cli/UploadTerminologyCommandTest.java | 87 ++++ ...ule-builder-code-support-multiple-ids.yaml | 4 + ...dating-name-of-full-text-field-search.yaml | 5 + ...updating-token-param-with-large-value.yaml | 5 + ...-survivorship-number-format-exception.yaml | 6 + ...ry-security-interceptor-documentation.yaml | 7 + ...bility-to-persist-data-to-lob-columns.yaml | 5 + ...-cli-upload-terminology-zip-hapi-0862.yaml | 6 + ...ascale-meta-operation-fails-hapi-0389.yaml | 5 + .../7_2_0/5899-enhance-mdm-interceptor.yaml | 4 + ...ery-chained-sort-returns-less-results.yaml | 4 + .../7_2_0/5915-bulk-export-security-woes.yaml | 4 + .../7_2_0/5917-chain-sort-mssql.yaml | 4 + .../security/binary_security_interceptor.md | 7 +- .../DatabaseBinaryContentStorageSvcImpl.java | 21 +- .../ca/uhn/fhir/jpa/config/JpaConfig.java | 14 + .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 21 +- .../ca/uhn/fhir/jpa/entity/TermConcept.java | 36 +- .../fhir/jpa/entity/TermConceptProperty.java | 15 +- .../fhir/jpa/entity/TermValueSetConcept.java | 11 + .../jpa/entity/TermValueSetConceptView.java | 41 +- .../tasks/HapiFhirJpaMigrationTasks.java | 42 +- .../partition/RequestPartitionHelperSvc.java | 16 +- .../fhir/jpa/search/builder/QueryStack.java | 47 ++- .../term/TermCodeSystemStorageSvcImpl.java | 21 - .../uhn/fhir/jpa/term/TermConceptDaoSvc.java | 10 + .../ca/uhn/fhir/jpa/term/TermReadSvcImpl.java | 11 +- .../jpa/term/ValueSetConceptAccumulator.java | 11 + .../ValueSetConceptAccumulatorFactory.java | 51 +++ .../jpa/term/config/TermCodeSystemConfig.java | 5 +- .../jpa/entity/TermConceptPropertyTest.java | 22 +- .../mdm/svc/GoldenResourceMergerSvcImpl.java | 1 + .../jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java | 22 + .../mdm/svc/MdmSurvivorshipSvcImplTest.java | 19 +- .../jpa/model/entity/BinaryStorageEntity.java | 11 +- .../partition/IRequestPartitionHelperSvc.java | 26 ++ .../config/SubscriptionConfig.java | 35 ++ .../config/SubscriptionSubmitterConfig.java | 12 +- .../jpa/topic/SubscriptionTopicConfig.java | 11 +- ...tabaseBinaryContentStorageSvcImplTest.java | 40 +- .../dao/r4/FhirResourceDaoR4QuerySandbox.java | 27 ++ .../RequestPartitionHelperSvcTest.java | 199 +++++++-- .../stresstest/GiantTransactionPerfTest.java | 10 + ...iftedRefchainsAndChainedSortingR5Test.java | 50 ++- .../database/BaseDatabaseVerificationIT.java | 47 ++- .../fhir/jpa/term/TermConceptDaoSvcTest.java | 57 +++ .../term/ValueSetConceptAccumulatorTest.java | 23 ++ .../fhir/mdm/svc/MdmSurvivorshipSvcImpl.java | 29 +- .../auth/IAuthRuleBuilderOperationNamed.java | 4 + .../auth/IAuthRuleBuilderRuleBulkExport.java | 13 + .../server/interceptor/auth/RuleBuilder.java | 65 ++- .../interceptor/auth/RuleBulkExportImpl.java | 186 ++++----- .../interceptor/auth/RuleBuilderTest.java | 76 +++- .../auth/RuleBulkExportImplTest.java | 384 ++++++++++++++---- .../fhir/jpa/migrate/taskdef/BaseTask.java | 8 + .../jpa/migrate/taskdef/RenameTableTask.java | 44 -- .../fhir/jpa/migrate/tasks/api/Builder.java | 21 +- .../migrate/taskdef/RenameTableTaskTest.java | 22 - .../imprt/BulkDataImportProviderTest.java | 10 + .../cr/r4/ICollectDataServiceFactory.java | 19 + .../r4/IDataRequirementsServiceFactory.java | 19 + .../measure/CollectDataOperationProvider.java | 19 + .../DataRequirementsOperationProvider.java | 19 + .../fhir/storage/test/DaoTestDataBuilder.java | 4 +- .../jpa/api/config/JpaStorageSettings.java | 43 +- .../BaseRequestPartitionHelperSvc.java | 4 - 68 files changed, 1669 insertions(+), 477 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java create mode 100644 hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java create mode 100644 hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java index d2c995a435e..016512e537d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java @@ -2387,13 +2387,19 @@ public enum Pointcut implements IPointcut { *

  • * ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent - Contains information about the from and to resources. *
  • + *
  • + * ca.uhn.fhir.mdm.model.mdmevents.MdmTransactionContext - Contains information about the Transaction context, e.g. merge or link. + *
  • * *

    * Hooks should return void. *

    */ MDM_POST_MERGE_GOLDEN_RESOURCES( - void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent"), + void.class, + "ca.uhn.fhir.rest.api.server.RequestDetails", + "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent", + "ca.uhn.fhir.mdm.model.MdmTransactionContext"), /** * MDM Link History Hook: diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java index e073c2e2c60..6085508f4c2 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.cli; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; @@ -31,6 +32,7 @@ import ca.uhn.fhir.system.HapiSystemProperties; import ca.uhn.fhir.util.AttachmentUtil; import ca.uhn.fhir.util.FileUtil; import ca.uhn.fhir.util.ParametersUtil; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; @@ -265,7 +267,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { "Response:\n{}", myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response)); } - private void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { + protected void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { byte[] bytes = theBytes; String fileName = theFileName; @@ -277,7 +279,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { FileUtil.formatFileSize(ourTransferSizeLimit)); try { - File tempFile = File.createTempFile("hapi-fhir-cli", suffix); + File tempFile = File.createTempFile("hapi-fhir-cli", "." + suffix); tempFile.deleteOnExit(); try (OutputStream fileOutputStream = new FileOutputStream(tempFile, false)) { fileOutputStream.write(bytes); @@ -363,4 +365,9 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { } return retVal; } + + @VisibleForTesting + void setFhirContext(FhirContext theFhirContext) { + myFhirCtx = theFhirContext; + } } diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java index f0e08800425..2511ef9db91 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java @@ -22,6 +22,10 @@ import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyS import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; +import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.r4.model.Attachment; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Type; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,6 +47,7 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -54,6 +59,8 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -479,6 +486,86 @@ public class UploadTerminologyCommandTest { uploadICD10UsingCompressedFile(theFhirVersion, theIncludeTls); } + @ParameterizedTest + @MethodSource("paramsProvider") + @SuppressWarnings("unused") // Both params for @BeforeEach + void testZipFileInParameters(String theFhirVersion, boolean theIncludeTls) { + final IBaseParameters inputParameters = switch (myCtx.getVersion().getVersion()) { + case DSTU2, DSTU2_HL7ORG, DSTU2_1 -> new org.hl7.fhir.dstu2.model.Parameters(); + case DSTU3 -> new org.hl7.fhir.dstu3.model.Parameters(); + case R4 -> new Parameters(); + case R4B -> new org.hl7.fhir.r4b.model.Parameters(); + case R5 -> new org.hl7.fhir.r5.model.Parameters(); + }; + + final UploadTerminologyCommand uploadTerminologyCommand = new UploadTerminologyCommand(); + uploadTerminologyCommand.setFhirContext(myCtx); + uploadTerminologyCommand.setTransferSizeBytes(1); + + uploadTerminologyCommand.addFileToRequestBundle(inputParameters, "something.zip", new byte[] {1,2}); + + final String actualAttachmentUrl = getAttachmentUrl(inputParameters, myCtx); + assertTrue(actualAttachmentUrl.endsWith(".zip")); + } + + private static String getAttachmentUrl(IBaseParameters theInputParameters, FhirContext theCtx) { + switch (theCtx.getVersion().getVersion()) { + case DSTU2: + case DSTU2_HL7ORG: + case DSTU2_1: { + assertInstanceOf(org.hl7.fhir.dstu2.model.Parameters.class, theInputParameters); + final org.hl7.fhir.dstu2.model.Parameters dstu2Parameters = (org.hl7.fhir.dstu2.model.Parameters) theInputParameters; + final List dstu2ParametersList = dstu2Parameters.getParameter(); + final Optional optDstu2FileParam = dstu2ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); + assertTrue(optDstu2FileParam.isPresent()); + final org.hl7.fhir.dstu2.model.Type dstu2Value = optDstu2FileParam.get().getValue(); + assertInstanceOf(org.hl7.fhir.dstu2.model.Attachment.class, dstu2Value); + final org.hl7.fhir.dstu2.model.Attachment dstu2Attachment = (org.hl7.fhir.dstu2.model.Attachment) dstu2Value; + return dstu2Attachment.getUrl(); + } + case DSTU3: { + assertInstanceOf(org.hl7.fhir.dstu3.model.Parameters.class, theInputParameters); + final org.hl7.fhir.dstu3.model.Parameters dstu3Parameters = (org.hl7.fhir.dstu3.model.Parameters) theInputParameters; + final List dstu3ParametersList = dstu3Parameters.getParameter(); + final Optional optDstu3FileParam = dstu3ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); + assertTrue(optDstu3FileParam.isPresent()); + final org.hl7.fhir.dstu3.model.Type dstu3Value = optDstu3FileParam.get().getValue(); + assertInstanceOf(org.hl7.fhir.dstu3.model.Attachment.class, dstu3Value); + final org.hl7.fhir.dstu3.model.Attachment dstu3Attachment = (org.hl7.fhir.dstu3.model.Attachment) dstu3Value; + return dstu3Attachment.getUrl(); + } + case R4: { + assertInstanceOf(Parameters.class, theInputParameters); + final Parameters r4Parameters = (Parameters) theInputParameters; + final Parameters.ParametersParameterComponent r4Parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final Type r4Value = r4Parameter.getValue(); + assertInstanceOf(Attachment.class, r4Value); + final Attachment r4Attachment = (Attachment) r4Value; + return r4Attachment.getUrl(); + } + case R4B: { + assertInstanceOf(org.hl7.fhir.r4b.model.Parameters.class, theInputParameters); + final org.hl7.fhir.r4b.model.Parameters r4bParameters = (org.hl7.fhir.r4b.model.Parameters) theInputParameters; + final org.hl7.fhir.r4b.model.Parameters.ParametersParameterComponent r4bParameter = r4bParameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final org.hl7.fhir.r4b.model.DataType value = r4bParameter.getValue(); + assertInstanceOf(org.hl7.fhir.r4b.model.Attachment.class, value); + final org.hl7.fhir.r4b.model.Attachment r4bAttachment = (org.hl7.fhir.r4b.model.Attachment) value; + return r4bAttachment.getUrl(); + } + case R5: { + assertInstanceOf(org.hl7.fhir.r5.model.Parameters.class, theInputParameters); + final org.hl7.fhir.r5.model.Parameters r4Parameters = (org.hl7.fhir.r5.model.Parameters) theInputParameters; + final org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final org.hl7.fhir.r5.model.DataType value = parameter.getValue(); + assertInstanceOf(org.hl7.fhir.r5.model.Attachment.class, value); + final org.hl7.fhir.r5.model.Attachment attachment = (org.hl7.fhir.r5.model.Attachment) value; + return attachment.getUrl(); + } + default: + throw new IllegalStateException("Unknown FHIR version: " + theCtx.getVersion().getVersion()); + } + } + private void uploadICD10UsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException { if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) { when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101"))); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml new file mode 100644 index 00000000000..c44aca386c9 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 5861 +title: "Enhance RuleBuilder code to support multiple instance IDs." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml new file mode 100644 index 00000000000..358a0e4276a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5865 +title: "Moving the Hibernate.Search annotation for text indexing from the lob column to the column added as part of the + PostgreSql LOB migration." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml new file mode 100644 index 00000000000..ad6bbd02d1f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5877 +title: "Previously, updating a tokenParam with a value greater than 200 characters would raise a SQLException. +This issue has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml new file mode 100644 index 00000000000..9dae5a3b34a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5886 +title: "Previously, either updating links on, or deleting one of two patients with non-numeric IDs linked to a golden + patient would result in a HAPI-0389 if there were survivorship rules. + This issue has been fixed for both the update links and delete cases." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml new file mode 100644 index 00000000000..966fbe3d9c8 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml @@ -0,0 +1,7 @@ +--- +type: fix +issue: 5888 +title: "Updated documentation on binary_security_interceptor to specify using + `STORAGE_PRE_INITIATE_BULK_EXPORT` not `STORAGE_INITIATE_BULK_EXPORT` pointcut + to change bulk export parameters. +" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml new file mode 100644 index 00000000000..bdca0eeba3c --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 5890 +title: "As part of the migration from LOB, provided the capability to force persisting data to LOB columns. The default +behavior is to not persist in lob columns." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml new file mode 100644 index 00000000000..12d853e5842 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5893 +title: "Previously, hapi-fhir-cli: upload-terminology failed with a HAPI-0862 error when uploading LOINC. + This has been fixed." + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml new file mode 100644 index 00000000000..dfe2f459515 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5898 +title: "Previously, triggering a `$meta` via GET on a new patient with Megascale configured resulted in error HAPI-0389. This has been corrected + This has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml new file mode 100644 index 00000000000..8746c27e136 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 5899 +title: "The `MDM_POST_MERGE_GOLDEN_RESOURCES` now supports an additional parameter, of type `ca.uhn.fhir.mdm.model.MdmTransactionContext`. Thanks to Jens Villadsen for the contribution." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml new file mode 100644 index 00000000000..9c8c9873f6d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5904 +title: "Chained sort would exclude results that did not have resources matching the sort chain. These are now included, and sorted at the end." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml new file mode 100644 index 00000000000..8bd43c7a5c0 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5915 +title: "Previously, in some edge case scenarios the Bulk Export Rule Applier could accidentally permit a Patient type level bulk export request, even if the calling user only had permissions to a subset of patients. This has been corrected." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml new file mode 100644 index 00000000000..1e94d65c58d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5917 +title: "Fix chained sorts on strings when using MS Sql" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md index 2fea34f786b..412efaf27a8 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md @@ -14,4 +14,9 @@ This interceptor is intended to be subclassed. A simple example is shown below: ## Combining with Bulk Export -The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. An interceptor on the `STORAGE_INITIATE_BULK_EXPORT` pointcut is the easiest way to set these properties when a new Bulk Export job is being kicked off. +The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. +An interceptor on the `STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is the recommended way to set these properties when a new Bulk Export job is being kicked off. + +NB: Previous versions recommended using the `STORAGE_INITIATE_BULK_EXPORT` pointcut, but this is no longer the recommended way. +`STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is called before `STORAGE_INITIATE_BULK_EXPORT` and is thus guaranteed to be called before +any AuthorizationInterceptors. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java index 8f79e37ecb9..94eddb83955 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java @@ -26,6 +26,7 @@ import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao; import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import com.google.common.annotations.VisibleForTesting; import com.google.common.hash.HashingInputStream; import com.google.common.io.ByteStreams; import jakarta.annotation.Nonnull; @@ -59,6 +60,8 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp @Autowired private IBinaryStorageEntityDao myBinaryStorageEntityDao; + private boolean mySupportLegacyLobServer = false; + @Nonnull @Override @Transactional(propagation = Propagation.REQUIRED) @@ -96,9 +99,10 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp entity.setContentId(id); entity.setStorageContentBin(loadedStream); - // TODO: remove writing Blob in a future release - Blob dataBlob = lobHelper.createBlob(loadedStream); - entity.setBlob(dataBlob); + if (mySupportLegacyLobServer) { + Blob dataBlob = lobHelper.createBlob(loadedStream); + entity.setBlob(dataBlob); + } // Update the entity with the final byte count and hash long bytes = countingInputStream.getByteCount(); @@ -169,6 +173,11 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return copyBinaryContentToByteArray(entityOpt); } + public DatabaseBinaryContentStorageSvcImpl setSupportLegacyLobServer(boolean theSupportLegacyLobServer) { + mySupportLegacyLobServer = theSupportLegacyLobServer; + return this; + } + void copyBinaryContentToOutputStream(OutputStream theOutputStream, BinaryStorageEntity theEntity) throws IOException { @@ -212,4 +221,10 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return retVal; } + + @VisibleForTesting + public DatabaseBinaryContentStorageSvcImpl setEntityManagerForTesting(EntityManager theEntityManager) { + myEntityManager = theEntityManager; + return this; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java index e60974ae642..67a7f55d28e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java @@ -73,6 +73,7 @@ import ca.uhn.fhir.jpa.delete.DeleteConflictFinderService; import ca.uhn.fhir.jpa.delete.DeleteConflictService; import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc; import ca.uhn.fhir.jpa.entity.Search; +import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceServiceRegistry; import ca.uhn.fhir.jpa.graphql.DaoRegistryGraphQLStorageServices; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; @@ -154,6 +155,8 @@ import ca.uhn.fhir.jpa.term.TermCodeSystemStorageSvcImpl; import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermReadSvcImpl; import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl; +import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulator; +import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulatorFactory; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; @@ -822,6 +825,17 @@ public class JpaConfig { return new TermReadSvcImpl(); } + @Bean + public ValueSetConceptAccumulatorFactory valueSetConceptAccumulatorFactory() { + return new ValueSetConceptAccumulatorFactory(); + } + + @Bean + @Scope("prototype") + public ValueSetConceptAccumulator valueSetConceptAccumulator(TermValueSet theTermValueSet) { + return valueSetConceptAccumulatorFactory().create(theTermValueSet); + } + @Bean public ITermCodeSystemStorageSvc termCodeSystemStorageSvc() { return new TermCodeSystemStorageSvcImpl(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 686667b2813..1e786ad5070 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -1410,19 +1410,20 @@ public abstract class BaseHapiFhirResourceDao extends B } @Override - @Transactional public MT metaGetOperation(Class theType, IIdType theId, RequestDetails theRequest) { - Set tagDefs = new HashSet<>(); - BaseHasResource entity = readEntity(theId, theRequest); - for (BaseTag next : entity.getTags()) { - tagDefs.add(next.getTag()); - } - MT retVal = toMetaDt(theType, tagDefs); + return myTransactionService.withRequest(theRequest).execute(() -> { + Set tagDefs = new HashSet<>(); + BaseHasResource entity = readEntity(theId, theRequest); + for (BaseTag next : entity.getTags()) { + tagDefs.add(next.getTag()); + } + MT retVal = toMetaDt(theType, tagDefs); - retVal.setLastUpdated(entity.getUpdatedDate()); - retVal.setVersionId(Long.toString(entity.getVersion())); + retVal.setLastUpdated(entity.getUpdatedDate()); + retVal.setVersionId(Long.toString(entity.getVersion())); - return retVal; + return retVal; + }); } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java index 57674d4cfc7..d238278bcfe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.search.DeferConceptIndexingRoutingBinder; import ca.uhn.fhir.util.ValidateUtil; +import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -58,10 +59,7 @@ import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.RoutingBinderR import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectPath; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyBinding; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue; import org.hl7.fhir.r4.model.Coding; import java.io.Serializable; @@ -177,6 +175,11 @@ public class TermConcept implements Serializable { @Column(name = "PARENT_PIDS", nullable = true) private String myParentPids; + @FullTextField( + name = "myParentPids", + searchable = Searchable.YES, + projectable = Projectable.YES, + analyzer = "conceptParentPidsAnalyzer") @Column(name = "PARENT_PIDS_VC", nullable = true, length = Length.LONG32) private String myParentPidsVc; @@ -189,6 +192,9 @@ public class TermConcept implements Serializable { @Column(name = "CODE_SEQUENCE", nullable = true) private Integer mySequence; + @Transient + private boolean mySupportLegacyLob = false; + public TermConcept() { super(); } @@ -362,13 +368,6 @@ public class TermConcept implements Serializable { return this; } - @Transient - @FullTextField( - name = "myParentPids", - searchable = Searchable.YES, - projectable = Projectable.YES, - analyzer = "conceptParentPidsAnalyzer") - @IndexingDependency(derivedFrom = @ObjectPath({@PropertyValue(propertyName = "myParentPidsVc")})) public String getParentPidsAsString() { return nonNull(myParentPidsVc) ? myParentPidsVc : myParentPids; } @@ -458,6 +457,10 @@ public class TermConcept implements Serializable { ourLog.trace("Code {}/{} has parents {}", entity.getId(), entity.getCode(), entity.getParentPidsAsString()); } + + if (!mySupportLegacyLob) { + clearParentPidsLob(); + } } private void setParentPids(Set theParentPids) { @@ -519,4 +522,17 @@ public class TermConcept implements Serializable { public List getChildCodes() { return getChildren().stream().map(TermConceptParentChildLink::getChild).collect(Collectors.toList()); } + + public void flagForLegacyLobSupport(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + } + + private void clearParentPidsLob() { + myParentPids = null; + } + + @VisibleForTesting + public boolean hasParentPidsLobForTesting() { + return nonNull(myParentPids); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java index 6bbc3b178a4..790dc9048c7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java @@ -54,6 +54,7 @@ import org.hibernate.validator.constraints.NotBlank; import java.io.Serializable; import java.nio.charset.StandardCharsets; +import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -307,9 +308,15 @@ public class TermConceptProperty implements Serializable { return myId; } + public void performLegacyLobSupport(boolean theSupportLegacyLob) { + if (!theSupportLegacyLob) { + myValueLob = null; + } + } + @VisibleForTesting - public byte[] getValueBlobForTesting() { - return myValueLob; + public boolean hasValueBlobForTesting() { + return nonNull(myValueLob); } @VisibleForTesting @@ -318,8 +325,8 @@ public class TermConceptProperty implements Serializable { } @VisibleForTesting - public byte[] getValueBinForTesting() { - return myValueBin; + public boolean hasValueBinForTesting() { + return nonNull(myValueBin); } @VisibleForTesting diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java index 2e17bc6ae9c..c822c56046c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity; import ca.uhn.fhir.util.ValidateUtil; +import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -46,6 +47,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -296,4 +298,13 @@ public class TermValueSetConcept implements Serializable { ? mySourceConceptDirectParentPidsVc : mySourceConceptDirectParentPids; } + + public void clearSourceConceptDirectParentPidsLob() { + mySourceConceptDirectParentPids = null; + } + + @VisibleForTesting + public boolean hasSourceConceptDirectParentPidsLob() { + return nonNull(mySourceConceptDirectParentPids); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java index c66c41a9b7e..28f80e15c62 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java @@ -43,20 +43,21 @@ import java.sql.SQLException; * because hibernate won't allow the view the function without it, but */ "SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " + " vsc.PID AS CONCEPT_PID, " - + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " - + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " - + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " - + " vsc.CODEVAL AS CONCEPT_CODEVAL, " - + " vsc.DISPLAY AS CONCEPT_DISPLAY, " - + " vsc.SYSTEM_VER AS SYSTEM_VER, " - + " vsc.SOURCE_PID AS SOURCE_PID, " - + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " - + " vscd.PID AS DESIGNATION_PID, " - + " vscd.LANG AS DESIGNATION_LANG, " - + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " - + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " - + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " - + " vscd.VAL AS DESIGNATION_VAL " + + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + + " vsc.CODEVAL AS CONCEPT_CODEVAL, " + + " vsc.DISPLAY AS CONCEPT_DISPLAY, " + + " vsc.SYSTEM_VER AS SYSTEM_VER, " + + " vsc.SOURCE_PID AS SOURCE_PID, " + + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " + + " vsc.SOURCE_DIRECT_PARENT_PIDS_VC AS SOURCE_DIRECT_PARENT_PIDS_VC, " + + " vscd.PID AS DESIGNATION_PID, " + + " vscd.LANG AS DESIGNATION_LANG, " + + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " + + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + + " vscd.VAL AS DESIGNATION_VAL " + "FROM TRM_VALUESET_CONCEPT vsc " + "LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID") public class TermValueSetConceptView implements Serializable, ITermValueSetConceptView { @@ -112,6 +113,9 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true) private Clob mySourceConceptDirectParentPids; + @Column(name = "SOURCE_DIRECT_PARENT_PIDS_VC", nullable = true) + private String mySourceConceptDirectParentPidsVc; + @Override public Long getSourceConceptPid() { return mySourceConceptPid; @@ -119,14 +123,19 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Override public String getSourceConceptDirectParentPids() { + String retVal = null; + if (mySourceConceptDirectParentPids != null) { try (Reader characterStream = mySourceConceptDirectParentPids.getCharacterStream()) { - return IOUtils.toString(characterStream); + retVal = IOUtils.toString(characterStream); } catch (IOException | SQLException e) { throw new InternalErrorException(Msg.code(828) + e); } + } else if (mySourceConceptDirectParentPidsVc != null) { + retVal = mySourceConceptDirectParentPidsVc; } - return null; + + return retVal; } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 3c421278e10..03a34c96468 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.entity.BulkImportJobEntity; import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask; +import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateHashesTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateOrdinalDatesTask; import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeEnum; @@ -146,8 +147,16 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { binaryStorageBlobTable .renameColumn("20240404.1", "BLOB_ID", "CONTENT_ID") + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); + binaryStorageBlobTable .renameColumn("20240404.2", "BLOB_SIZE", "CONTENT_SIZE") - .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH"); + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); + binaryStorageBlobTable + .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH") + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); binaryStorageBlobTable .modifyColumn("20240404.4", "BLOB_DATA") @@ -159,9 +168,23 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - binaryStorageBlobTable.migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN"); + binaryStorageBlobTable + .migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN") + .doNothing(); - binaryStorageBlobTable.renameTable("20240404.7", "HFJ_BINARY_STORAGE"); + binaryStorageBlobTable + .renameTable("20240404.7", "HFJ_BINARY_STORAGE") + .doNothing(); + + Builder.BuilderWithTableName binaryStorageTableFix = version.onTable("HFJ_BINARY_STORAGE"); + + binaryStorageTableFix.renameColumn("20240404.10", "CONTENT_ID", "BLOB_ID", true, true); + binaryStorageTableFix.renameColumn("20240404.20", "CONTENT_SIZE", "BLOB_SIZE", true, true); + binaryStorageTableFix.renameColumn("20240404.30", "CONTENT_HASH", "BLOB_HASH", true, true); + + binaryStorageTableFix + .renameTable("20240404.40", "HFJ_BINARY_STORAGE_BLOB") + .failureAllowed(); } { @@ -172,7 +195,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - termConceptPropertyTable.migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN"); + termConceptPropertyTable + .migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN") + .doNothing(); } { @@ -182,8 +207,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termValueSetConceptTable.migrateClobToText( - "20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC"); + termValueSetConceptTable + .migrateClobToText("20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC") + .doNothing(); } { @@ -193,7 +219,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termConceptTable.migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC"); + termConceptTable + .migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC") + .doNothing(); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java index bbc74d27dd5..6202049515d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java @@ -37,7 +37,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { IPartitionLookupSvc myPartitionConfigSvc; @Override - protected RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { List names = null; for (int i = 0; i < theRequestPartitionId.getPartitionIds().size(); i++) { @@ -59,7 +59,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } } - if (theRequestPartitionId.getPartitionNames() != null) { + if (theRequestPartitionId.hasPartitionNames()) { if (partition == null) { Validate.isTrue( theRequestPartitionId.getPartitionIds().get(i) == null, @@ -68,8 +68,8 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } else { Validate.isTrue( Objects.equals( - theRequestPartitionId.getPartitionIds().get(i), partition.getId()), - "Partition name %s does not match ID %n", + theRequestPartitionId.getPartitionNames().get(i), partition.getName()), + "Partition name %s does not match ID %s", theRequestPartitionId.getPartitionNames().get(i), theRequestPartitionId.getPartitionIds().get(i)); } @@ -94,7 +94,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } @Override - protected RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { List ids = null; for (int i = 0; i < theRequestPartitionId.getPartitionNames().size(); i++) { @@ -122,9 +122,9 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { Validate.isTrue( Objects.equals( theRequestPartitionId.getPartitionIds().get(i), partition.getId()), - "Partition name %s does not match ID %n", - theRequestPartitionId.getPartitionNames().get(i), - theRequestPartitionId.getPartitionIds().get(i)); + "Partition ID %s does not match name %s", + theRequestPartitionId.getPartitionIds().get(i), + theRequestPartitionId.getPartitionNames().get(i)); } } else { if (ids == 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 4f0b3e60778..685f96c16f8 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 @@ -353,26 +353,39 @@ public class QueryStack { throw new InvalidRequestException(Msg.code(2289) + msg); } - BaseSearchParamPredicateBuilder chainedPredicateBuilder; - DbColumn[] sortColumn; + // add a left-outer join to a predicate for the target type, then sort on value columns(s). switch (targetSearchParameter.getParamType()) { case STRING: StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder(); - sortColumn = new DbColumn[] {stringPredicateBuilder.getColumnValueNormalized()}; - chainedPredicateBuilder = stringPredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + stringPredicateBuilder, + stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortString( + stringPredicateBuilder.getColumnValueNormalized(), theAscending, myUseAggregate); + return; + case TOKEN: TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder(); - sortColumn = - new DbColumn[] {tokenPredicateBuilder.getColumnSystem(), tokenPredicateBuilder.getColumnValue() - }; - chainedPredicateBuilder = tokenPredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + tokenPredicateBuilder, + tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnSystem(), theAscending, myUseAggregate); + mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnValue(), theAscending, myUseAggregate); + return; + case DATE: DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder(); - sortColumn = new DbColumn[] {datePredicateBuilder.getColumnValueLow()}; - chainedPredicateBuilder = datePredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + datePredicateBuilder, + datePredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortDate(datePredicateBuilder.getColumnValueLow(), theAscending, myUseAggregate); + return; /* * Note that many of the options below aren't implemented because they @@ -417,14 +430,6 @@ public class QueryStack { + theParamName + "." + theChain + " as this parameter. Can not sort on chains of target type: " + targetSearchParameter.getParamType().name()); } - - addSortCustomJoin(resourceLinkPredicateBuilder.getColumnTargetResourceId(), chainedPredicateBuilder, null); - Condition predicate = chainedPredicateBuilder.createHashIdentityPredicate(targetType, theChain); - mySqlBuilder.addPredicate(predicate); - - for (DbColumn next : sortColumn) { - mySqlBuilder.addSortNumeric(next, theAscending, myUseAggregate); - } } public void addSortOnString(String theResourceName, String theParamName, boolean theAscending) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java index 61fbea5830e..15998b0e8e6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java @@ -73,7 +73,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; @@ -685,26 +684,6 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { } } - private int ensureParentsSaved(Collection theParents) { - ourLog.trace("Checking {} parents", theParents.size()); - int retVal = 0; - - for (TermConceptParentChildLink nextLink : theParents) { - if (nextLink.getRelationshipType() == TermConceptParentChildLink.RelationshipTypeEnum.ISA) { - TermConcept nextParent = nextLink.getParent(); - retVal += ensureParentsSaved(nextParent.getParents()); - if (nextParent.getId() == null) { - nextParent.setUpdated(new Date()); - myConceptDao.saveAndFlush(nextParent); - retVal++; - ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); - } - } - } - - return retVal; - } - @Nonnull private TermCodeSystem getOrCreateDistinctTermCodeSystem( IResourcePersistentId theCodeSystemResourcePid, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java index 9bcf47aebb0..1927de43500 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java @@ -46,6 +46,8 @@ public class TermConceptDaoSvc { @Autowired protected ITermConceptDesignationDao myConceptDesignationDao; + private boolean mySupportLegacyLob = false; + public int saveConcept(TermConcept theConcept) { int retVal = 0; @@ -70,9 +72,11 @@ public class TermConceptDaoSvc { retVal++; theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED); theConcept.setUpdated(new Date()); + theConcept.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.save(theConcept); for (TermConceptProperty next : theConcept.getProperties()) { + next.performLegacyLobSupport(mySupportLegacyLob); myConceptPropertyDao.save(next); } @@ -85,6 +89,11 @@ public class TermConceptDaoSvc { return retVal; } + public TermConceptDaoSvc setSupportLegacyLob(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + return this; + } + private int ensureParentsSaved(Collection theParents) { ourLog.trace("Checking {} parents", theParents.size()); int retVal = 0; @@ -95,6 +104,7 @@ public class TermConceptDaoSvc { retVal += ensureParentsSaved(nextParent.getParents()); if (nextParent.getId() == null) { nextParent.setUpdated(new Date()); + nextParent.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.saveAndFlush(nextParent); retVal++; ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); 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 86235e0403b..2705ed40fe5 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 @@ -293,6 +293,9 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { @Autowired private InMemoryTerminologyServerValidationSupport myInMemoryTerminologyServerValidationSupport; + @Autowired + private ValueSetConceptAccumulatorFactory myValueSetConceptAccumulatorFactory; + @Override public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { TermCodeSystemVersionDetails cs = getCurrentCodeSystemVersion(theSystem); @@ -2393,11 +2396,11 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { }); assert valueSet != null; - ValueSetConceptAccumulator accumulator = new ValueSetConceptAccumulator( - valueSetToExpand, myTermValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); + ValueSetConceptAccumulator valueSetConceptAccumulator = + myValueSetConceptAccumulatorFactory.create(valueSetToExpand); ValueSetExpansionOptions options = new ValueSetExpansionOptions(); options.setIncludeHierarchy(true); - expandValueSet(options, valueSet, accumulator); + expandValueSet(options, valueSet, valueSetConceptAccumulator); // We are done with this ValueSet. txTemplate.executeWithoutResult(t -> { @@ -2412,7 +2415,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { "Pre-expanded ValueSet[{}] with URL[{}] - Saved {} concepts in {}", valueSet.getId(), valueSet.getUrl(), - accumulator.getConceptsSaved(), + valueSetConceptAccumulator.getConceptsSaved(), sw); } catch (Exception e) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java index 6561495ad45..9aa38413bb7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java @@ -48,6 +48,8 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { private int myDesignationsSaved; private int myConceptsExcluded; + private boolean mySupportLegacyLob = false; + public ValueSetConceptAccumulator( @Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetDao theValueSetDao, @@ -184,6 +186,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { concept.setSourceConceptPid(theSourceConceptPid); concept.setSourceConceptDirectParentPids(theSourceConceptDirectParentPids); + if (!mySupportLegacyLob) { + concept.clearSourceConceptDirectParentPidsLob(); + } + myValueSetConceptDao.save(concept); myValueSetDao.save(myTermValueSet.incrementTotalConcepts()); @@ -253,4 +259,9 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { // TODO: DM 2019-07-16 - If so, we should also populate TermValueSetConceptProperty entities here. // TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they may be needed to facilitate // filters and parameterized expansions. + + public ValueSetConceptAccumulator setSupportLegacyLob(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + return this; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java new file mode 100644 index 00000000000..e61da193b8a --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java @@ -0,0 +1,51 @@ +/*- + * #%L + * HAPI FHIR JPA Server + * %% + * 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.jpa.term; + +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetDao; +import ca.uhn.fhir.jpa.entity.TermValueSet; +import org.springframework.beans.factory.annotation.Autowired; + +public class ValueSetConceptAccumulatorFactory { + + @Autowired + private ITermValueSetDao myValueSetDao; + + @Autowired + private ITermValueSetConceptDao myValueSetConceptDao; + + @Autowired + private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao; + + @Autowired + private JpaStorageSettings myStorageSettings; + + public ValueSetConceptAccumulator create(TermValueSet theTermValueSet) { + ValueSetConceptAccumulator valueSetConceptAccumulator = new ValueSetConceptAccumulator( + theTermValueSet, myValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); + + valueSetConceptAccumulator.setSupportLegacyLob(myStorageSettings.isWriteToLegacyLobColumns()); + + return valueSetConceptAccumulator; + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java index 297d0726ce3..44132dbdbd6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.jpa.term.config; +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.term.TermConceptDaoSvc; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemDeleteJobSvc; @@ -41,7 +42,7 @@ public class TermCodeSystemConfig { } @Bean - public TermConceptDaoSvc termConceptDaoSvc() { - return new TermConceptDaoSvc(); + public TermConceptDaoSvc termConceptDaoSvc(JpaStorageSettings theJpaStorageSettings) { + return new TermConceptDaoSvc().setSupportLegacyLob(theJpaStorageSettings.isWriteToLegacyLobColumns()); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java index 44a01649cfd..cda9c4554a9 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java @@ -2,8 +2,11 @@ package ca.uhn.fhir.jpa.entity; import com.google.common.base.Strings; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; @@ -21,8 +24,8 @@ public class TermConceptPropertyTest { termConceptProperty.setValue(ourVeryLongString); // then - assertThat(termConceptProperty.getValueBlobForTesting(), notNullValue()); - assertThat(termConceptProperty.getValueBinForTesting(), notNullValue()); + assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(true)); + assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); } @Test @@ -78,4 +81,19 @@ public class TermConceptPropertyTest { assertThat(value, startsWith("a")); } + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testSetValue_withSupportLegacyLob(boolean theSupportLegacyLob){ + // given + TermConceptProperty termConceptProperty = new TermConceptProperty(); + + // when + termConceptProperty.setValue(ourVeryLongString); + termConceptProperty.performLegacyLobSupport(theSupportLegacyLob); + + // then + assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); + assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(theSupportLegacyLob)); + } + } diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java index 5165581e3ef..690d2cc061d 100644 --- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java +++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java @@ -166,6 +166,7 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc { HookParams params = new HookParams(); params.add(MdmMergeEvent.class, event); params.add(RequestDetails.class, theParams.getRequestDetails()); + params.add(MdmTransactionContext.class, theParams.getMdmTransactionContext()); myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES, params); } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java index febcaf4c6e9..5e3aaad9f42 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java @@ -2,11 +2,16 @@ package ca.uhn.fhir.jpa.mdm.svc; import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test; import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService; +import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum; +import ca.uhn.fhir.mdm.api.MdmMatchOutcome; import ca.uhn.fhir.mdm.model.MdmTransactionContext; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -55,4 +60,21 @@ class MdmSurvivorshipSvcImplIT extends BaseMdmR4Test { assertEquals(p1.getTelecom().size(), p1.getTelecom().size()); assertTrue(p2.getTelecomFirstRep().equalsDeep(p1.getTelecomFirstRep())); } + + @Test + public void matchingPatientsWith_NON_Numeric_Ids_matches_doesNotThrow_NumberFormatException() { + final Patient frankPatient1 = buildFrankPatient(); + frankPatient1.setId("patA"); + myPatientDao.update(frankPatient1, new SystemRequestDetails()); + final Patient frankPatient2 = buildFrankPatient(); + frankPatient2.setId("patB"); + myPatientDao.update(frankPatient2, new SystemRequestDetails()); + final Patient goldenPatient = buildFrankPatient(); + myPatientDao.create(goldenPatient, new SystemRequestDetails()); + + myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); + myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient2, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); + + myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK)); + } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java index a6502687415..65cc7bde0c4 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java @@ -25,8 +25,9 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -96,8 +97,9 @@ public class MdmSurvivorshipSvcImplTest { } @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder() { + @ParameterizedTest + @ValueSource(booleans = {true,false}) + public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder(boolean theIsUseNonNumericId) { // setup // create resources Patient goldenPatient = new Patient(); @@ -126,7 +128,7 @@ public class MdmSurvivorshipSvcImplTest { patient.addIdentifier() .setSystem("http://example.com") .setValue("Value" + i); - patient.setId("Patient/" + i); + patient.setId("Patient/" + (theIsUseNonNumericId ? "pat"+i : Integer.toString(i))); resources.add(patient); MdmLinkJson link = createLinkJson( @@ -149,8 +151,13 @@ public class MdmSurvivorshipSvcImplTest { when(myDaoRegistry.getResourceDao(eq("Patient"))) .thenReturn(resourceDao); AtomicInteger counter = new AtomicInteger(); - when(resourceDao.readByPid(any())) - .thenAnswer(params -> resources.get(counter.getAndIncrement())); + if (theIsUseNonNumericId) { + when(resourceDao.read(any(), any())) + .thenAnswer(params -> resources.get(counter.getAndIncrement())); + } else { + when(resourceDao.readByPid(any())) + .thenAnswer(params -> resources.get(counter.getAndIncrement())); + } Page linkPage = mock(Page.class); when(myMdmLinkQuerySvc.queryLinks(any(), any())) .thenReturn(linkPage); diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java index c71b8e29fda..c6b046e0bff 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java @@ -34,23 +34,26 @@ import java.util.Date; import static java.util.Objects.nonNull; @Entity -@Table(name = "HFJ_BINARY_STORAGE") +@Table(name = "HFJ_BINARY_STORAGE_BLOB") public class BinaryStorageEntity { @Id - @Column(name = "CONTENT_ID", length = 200, nullable = false) + @Column(name = "BLOB_ID", length = 200, nullable = false) // N.B GGG: Note that the `content id` is the same as the `externalized binary id`. private String myContentId; @Column(name = "RESOURCE_ID", length = 100, nullable = false) private String myResourceId; - @Column(name = "CONTENT_SIZE", nullable = true) + @Column(name = "BLOB_SIZE", nullable = true) private long mySize; @Column(name = "CONTENT_TYPE", nullable = false, length = 100) private String myContentType; + /** + * @deprecated + */ @Deprecated(since = "7.2.0") @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "BLOB_DATA", nullable = true, insertable = true, updatable = false) @@ -63,7 +66,7 @@ public class BinaryStorageEntity { @Column(name = "PUBLISHED_DATE", nullable = false) private Date myPublished; - @Column(name = "CONTENT_HASH", length = 128, nullable = true) + @Column(name = "BLOB_HASH", length = 128, nullable = true) private String myHash; public Date getPublished() { diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java index cf17cf5af41..ede4b39e7ca 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java @@ -156,4 +156,30 @@ public interface IRequestPartitionHelperSvc { Set toReadPartitions(@Nonnull RequestPartitionId theRequestPartitionId); boolean isResourcePartitionable(String theResourceType); + + /** + * No interceptors should be invoked by this method. It should ONLY be used when partition ids are + * known, but partition names are not. + *

    + * Ensures the list of partition ids inside the given {@link RequestPartitionId} correctly map to the + * list of partition names. If the list of partition names is empty, this method will map the correct + * partition names and return a normalized {@link RequestPartitionId}. + *

    + * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. + * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. + */ + RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); + + /** + * No interceptors should be invoked by this method. It should ONLY be used when partition names are + * known, but partition ids are not. + *

    + * Ensures the list of partition names inside the given {@link RequestPartitionId} correctly map to the + * list of partition ids. If the list of partition ids is empty, this method will map the correct + * partition ids and return a normalized {@link RequestPartitionId}. + *

    + * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. + * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. + */ + RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); } diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java new file mode 100644 index 00000000000..4d95a057c54 --- /dev/null +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java @@ -0,0 +1,35 @@ +/*- + * #%L + * HAPI FHIR Subscription Server + * %% + * 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.jpa.subscription.config; + +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SubscriptionConfig { + @Bean + public SubscriptionQueryValidator subscriptionQueryValidator( + DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { + return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); + } +} diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java index 65e0d2010a7..ff056ad9207 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java @@ -19,15 +19,13 @@ */ package ca.uhn.fhir.jpa.subscription.submit.config; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedProcessingSchedulerSvc; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedSubmitterSvc; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory; -import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; import ca.uhn.fhir.jpa.subscription.model.config.SubscriptionModelConfig; -import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionValidatingInterceptor; import ca.uhn.fhir.jpa.subscription.submit.svc.ResourceModifiedSubmitterSvc; @@ -45,7 +43,7 @@ import org.springframework.context.annotation.Lazy; * matching queue for processing */ @Configuration -@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class}) +@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class, SubscriptionConfig.class}) public class SubscriptionSubmitterConfig { @Bean @@ -53,12 +51,6 @@ public class SubscriptionSubmitterConfig { return new SubscriptionValidatingInterceptor(); } - @Bean - public SubscriptionQueryValidator subscriptionQueryValidator( - DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { - return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); - } - @Bean public SubscriptionSubmitInterceptorLoader subscriptionMatcherInterceptorLoader() { return new SubscriptionSubmitInterceptorLoader(); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java index 4b571c7bd33..802f43a47e5 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java @@ -22,13 +22,15 @@ package ca.uhn.fhir.jpa.topic; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher; -import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; @Configuration +@Import(SubscriptionConfig.class) public class SubscriptionTopicConfig { @Bean SubscriptionTopicMatchingSubscriber subscriptionTopicMatchingSubscriber(FhirContext theFhirContext) { @@ -76,13 +78,6 @@ public class SubscriptionTopicConfig { } } - @Bean - @Lazy - public SubscriptionQueryValidator subscriptionQueryValidator( - DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { - return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); - } - @Bean SubscriptionTopicValidatingInterceptor subscriptionTopicValidatingInterceptor( FhirContext theFhirContext, SubscriptionQueryValidator theSubscriptionQueryValidator) { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java index a0c6b7c4279..ecca07f2b98 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java @@ -7,8 +7,12 @@ import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import jakarta.persistence.EntityManager; +import org.hibernate.LobHelper; +import org.hibernate.Session; import org.hl7.fhir.r4.model.IdType; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -24,6 +28,7 @@ import java.sql.SQLException; import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; @@ -34,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -281,7 +287,7 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { } @Test - public void testStoreBinaryContent_writesBlobAndByteArray() throws IOException { + public void testStoreBinaryContent_byDefault_writesByteArrayOnly() throws IOException { // given ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); String contentType = "image/png"; @@ -296,11 +302,41 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { // then assertThat(binaryStorageEntity.hasStorageContent(), is(true)); - assertThat(binaryStorageEntity.hasBlob(), is(true)); + assertThat(binaryStorageEntity.hasBlob(), is(false)); }); } + @Test + public void testStoreBinaryContent_whenSupportingLegacyBlobServer_willStoreToBlobAndBinaryArray() throws IOException { + ArgumentCaptor captor = ArgumentCaptor.forClass(BinaryStorageEntity.class); + EntityManager mockedEntityManager = mock(EntityManager.class); + Session mockedSession = mock(Session.class); + LobHelper mockedLobHelper = mock(LobHelper.class); + when(mockedEntityManager.getDelegate()).thenReturn(mockedSession); + when(mockedSession.getLobHelper()).thenReturn(mockedLobHelper); + when(mockedLobHelper.createBlob(any())).thenReturn(mock(Blob.class)); + + // given + DatabaseBinaryContentStorageSvcImpl svc = new DatabaseBinaryContentStorageSvcImpl() + .setSupportLegacyLobServer(true) + .setEntityManagerForTesting(mockedEntityManager); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); + String contentType = "image/png"; + IdType resourceId = new IdType("Binary/123"); + + // when + svc.storeBinaryContent(resourceId, null, contentType, inputStream, new ServletRequestDetails()); + + // then + verify(mockedEntityManager, times(1)).persist(captor.capture()); + BinaryStorageEntity capturedBinaryStorageEntity = captor.getValue(); + + assertThat(capturedBinaryStorageEntity.hasBlob(), equalTo(true)); + assertThat(capturedBinaryStorageEntity.hasStorageContent(), equalTo(true)); + } + @Configuration public static class MyConfig { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java index 7efc920ccaf..95ab54ddb19 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java @@ -9,8 +9,11 @@ import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.jpa.util.SqlQuery; import ca.uhn.fhir.jpa.util.SqlQueryList; +import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.storage.test.DaoTestDataBuilder; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -33,6 +36,8 @@ import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Sandbox for implementing queries. @@ -137,6 +142,28 @@ public class FhirResourceDaoR4QuerySandbox extends BaseJpaTest { myTestDaoSearch.assertSearchFindsInOrder("reverse sort by server assigned id", "Patient?family=smith&_sort=-_pid", id3,id2,id1); } + @Test + void testChainedSort() { + final IIdType practitionerId = myDataBuilder.createPractitioner(myDataBuilder.withFamily("Jones")); + + final String id1 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithy")).getIdPart(); + final String id2 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithwick")).getIdPart(); + final String id3 = myDataBuilder.createPatient( + myDataBuilder.withFamily("Smith"), + myDataBuilder.withReference("generalPractitioner", practitionerId)).getIdPart(); + + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); + assertEquals(3, iBundleProvider.size()); + + final List allResources = iBundleProvider.getAllResources(); + assertEquals(3, iBundleProvider.size()); + assertEquals(3, allResources.size()); + + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); + } + public static final class TestDirtiesContextTestExecutionListener extends DirtiesContextTestExecutionListener { @Override diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java index 4f90f46bc41..53ff09b50c6 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java @@ -1,74 +1,189 @@ package ca.uhn.fhir.jpa.partition; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.model.RequestPartitionId; +import ca.uhn.fhir.jpa.dao.data.IPartitionDao; import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.model.config.PartitionSettings; +import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; @ExtendWith(MockitoExtension.class) -class RequestPartitionHelperSvcTest { - static final Integer PARTITION_ID = 2401; - static final String PARTITION_NAME = "JIMMY"; - static final PartitionEntity ourPartitionEntity = new PartitionEntity().setName(PARTITION_NAME); +class RequestPartitionHelperSvcTest extends BaseJpaR4Test { - @Mock + static final int PARTITION_ID_1 = 1; + static final String PARTITION_NAME_1 = "SOME-PARTITION-1"; + + static final int PARTITION_ID_2 = 2; + static final String PARTITION_NAME_2 = "SOME-PARTITION-2"; + + static final int UNKNOWN_PARTITION_ID = 1_000_000; + static final String UNKNOWN_PARTITION_NAME = "UNKNOWN"; + + @Autowired + IPartitionDao myPartitionDao; + @Autowired PartitionSettings myPartitionSettings; - @Mock - IPartitionLookupSvc myPartitionLookupSvc; - @Mock - FhirContext myFhirContext; - @Mock - IInterceptorBroadcaster myInterceptorBroadcaster; + @Autowired + RequestPartitionHelperSvc mySvc; - @InjectMocks - RequestPartitionHelperSvc mySvc = new RequestPartitionHelperSvc(); + Patient myPatient; - @Test - public void determineReadPartitionForSystemRequest() { - // setup - SystemRequestDetails srd = new SystemRequestDetails(); - RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); - srd.setRequestPartitionId(requestPartitionId); - when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); - when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); + @BeforeEach + public void before(){ + myPartitionDao.deleteAll(); + myPartitionSettings.setPartitioningEnabled(true); - // execute - RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, "Patient", new IdType("Patient/123")); - - // verify - assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); + myPatient = new Patient(); + myPatient.setId(new IdType("Patient", "123", "1")); } @Test - public void determineCreatePartitionForSystemRequest() { + public void testDetermineReadPartitionForSystemRequest_withPartitionIdOnly_returnsCorrectPartition() { // setup + PartitionEntity partitionEntity = createPartition1(); SystemRequestDetails srd = new SystemRequestDetails(); - RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); - srd.setRequestPartitionId(requestPartitionId); - when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); - when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); - Patient resource = new Patient(); - when(myFhirContext.getResourceType(resource)).thenReturn("Patient"); + srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); // execute - RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, resource, "Patient"); + RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, myPatient.fhirType(), myPatient.getIdElement()); // verify - assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); } + @Test + public void testDetermineCreatePartitionForRequest_withPartitionIdOnly_returnsCorrectPartition() { + // setup + PartitionEntity partitionEntity = createPartition1(); + SystemRequestDetails srd = new SystemRequestDetails(); + srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); + + // execute + Patient patient = new Patient(); + RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, patient, patient.fhirType()); + + // verify + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionIds_withPartitionIdOnly_populatesPartitionName(){ + PartitionEntity partitionEntity = createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(partitionEntity.getId()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); + + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionIds_withUnknownId_throwsException(){ + RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(UNKNOWN_PARTITION_ID); + + try{ + mySvc.validateAndNormalizePartitionIds(partitionId); + fail(); + } catch (ResourceNotFoundException e){ + assertTrue(e.getMessage().contains("No partition exists with ID 1,000,000")); + } + } + + @Test + public void testValidateAndNormalizePartitionIds_withIdAndInvalidName_throwsException(){ + createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(PARTITION_ID_1, UNKNOWN_PARTITION_NAME); + + try{ + mySvc.validateAndNormalizePartitionIds(partitionId); + fail(); + } catch (IllegalArgumentException e){ + assertTrue(e.getMessage().contains("Partition name UNKNOWN does not match ID 1")); + } + } + + @Test + public void testValidateAndNormalizePartitionIds_withMultiplePartitionIdOnly_populatesPartitionNames(){ + PartitionEntity partitionEntity1 = createPartition1(); + PartitionEntity partitionEntity2 = createPartition2(); + + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIds(partitionEntity1.getId(), partitionEntity2.getId()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); + + assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); + assertNotNull(result.getPartitionNames()); + assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); + } + + @Test + public void testValidateAndNormalizePartitionNames_withPartitionNameOnly_populatesPartitionId(){ + PartitionEntity partitionEntity = createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(partitionEntity.getName()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); + + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionNames_withMultiplePartitionNamesOnly_populatesPartitionIds(){ + PartitionEntity partitionEntity1 = createPartition1(); + PartitionEntity partitionEntity2 = createPartition2(); + + RequestPartitionId partitionId = RequestPartitionId.fromPartitionNames(partitionEntity1.getName(), partitionEntity2.getName()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); + + assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); + assertNotNull(result.getPartitionNames()); + assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); + } + + @Test + public void testValidateAndNormalizePartitionNames_withUnknownName_throwsException(){ + RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(UNKNOWN_PARTITION_NAME); + + try{ + mySvc.validateAndNormalizePartitionNames(partitionId); + fail(); + } catch (ResourceNotFoundException e){ + assertTrue(e.getMessage().contains("Partition name \"UNKNOWN\" is not valid")); + } + } + + @Test + public void testValidateAndNormalizePartitionNames_withNameAndInvalidId_throwsException(){ + createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(UNKNOWN_PARTITION_ID, PARTITION_NAME_1); + + try{ + mySvc.validateAndNormalizePartitionNames(partitionId); + fail(); + } catch (IllegalArgumentException e){ + assertTrue(e.getMessage().contains("Partition ID 1000000 does not match name SOME-PARTITION-1")); + } + } + + private PartitionEntity createPartition1() { + return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_1).setName(PARTITION_NAME_1)); + } + + private PartitionEntity createPartition2() { + return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_2).setName(PARTITION_NAME_2)); + } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java index dcce168fa09..c237dddcd6a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java @@ -884,6 +884,16 @@ public class GiantTransactionPerfTest { return true; } + @Override + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + return RequestPartitionId.defaultPartition(); + } + + @Override + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + return RequestPartitionId.defaultPartition(); + } + } diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java index 5cf0e2a4127..50e2c2787c0 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r5; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; +import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; @@ -12,6 +13,8 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.BundleBuilder; import ca.uhn.fhir.util.HapiExtensions; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Composition; import org.hl7.fhir.r5.model.IdType; import org.hl7.fhir.r5.model.Bundle; @@ -29,6 +32,7 @@ import org.hl7.fhir.r5.model.SearchParameter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import jakarta.annotation.Nonnull; @@ -41,9 +45,10 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -@ContextConfiguration(classes = TestHSearchAddInConfig.NoFT.class) +@ContextConfiguration(classes = { TestHSearchAddInConfig.NoFT.class, TestDaoSearch.Config.class }) @SuppressWarnings({"Duplicates"}) public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String PRACTITIONER_PR1 = "Practitioner/PR1"; @@ -54,6 +59,8 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String ENCOUNTER_E2 = "Encounter/E2"; public static final String ENCOUNTER_E3 = "Encounter/E3"; public static final String ORGANIZATION_O1 = "Organization/O1"; + @Autowired + protected TestDaoSearch myTestDaoSearch; @Override @BeforeEach @@ -867,6 +874,47 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { assertEquals(1, countMatches(querySql, "HFJ_RES_LINK"), querySql); } + + @Test + void testChainedSortWithNulls() { + final IIdType practitionerId1 = createPractitioner(withFamily("Chan")); + final IIdType practitionerId2 = createPractitioner(withFamily("Jones")); + + final String id1 = createPatient(withFamily("Smithy")).getIdPart(); + final String id2 = createPatient(withFamily("Smithwick"), + withReference("generalPractitioner", practitionerId2)).getIdPart(); + final String id3 = createPatient( + withFamily("Smith"), + withReference("generalPractitioner", practitionerId1)).getIdPart(); + + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); + final List allResources = iBundleProvider.getAllResources(); + assertEquals(3, iBundleProvider.size()); + assertEquals(3, allResources.size()); + + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); + } + + @Test + void testChainedReverseStringSort() { + final IIdType practitionerId = createPractitioner(withFamily("Jones")); + + final String id1 = createPatient(withFamily("Smithy")).getIdPart(); + final String id2 = createPatient(withFamily("Smithwick")).getIdPart(); + final String id3 = createPatient( + withFamily("Smith"), + withReference("generalPractitioner", practitionerId)).getIdPart(); + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=-Practitioner:general-practitioner.family"); + assertEquals(3, iBundleProvider.size()); + + final List allResources = iBundleProvider.getAllResources(); + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id3, id2, id1))); + } + /** * Observation:focus is a Reference(Any) so it can't be used in a sort chain because * this would be horribly, horribly inefficient. diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java index e010f25669a..beeef22ff91 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java @@ -1,38 +1,24 @@ package ca.uhn.fhir.jpa.dao.r5.database; -import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; -import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeProvider; -import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient; -import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters; +import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.embedded.JpaEmbeddedDatabase; -import ca.uhn.fhir.jpa.fql.provider.HfqlRestProvider; -import ca.uhn.fhir.jpa.graphql.GraphQLProvider; import ca.uhn.fhir.jpa.migrate.HapiMigrationStorageSvc; import ca.uhn.fhir.jpa.migrate.MigrationTaskList; import ca.uhn.fhir.jpa.migrate.SchemaMigrator; import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks; -import ca.uhn.fhir.jpa.provider.DiffProvider; -import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider; -import ca.uhn.fhir.jpa.provider.ProcessMessageProvider; -import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; -import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.config.TestR5Config; -import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; -import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.server.RestfulServerConfigurerExtension; @@ -44,7 +30,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Patient; import org.junit.jupiter.api.Test; @@ -55,7 +40,6 @@ import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; @@ -63,10 +47,8 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.web.cors.CorsConfiguration; import javax.sql.DataSource; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -80,7 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(SpringExtension.class) @EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) -@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class}) +@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class, TestDaoSearch.Config.class}) public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements ITestDataBuilder { private static final Logger ourLog = LoggerFactory.getLogger(BaseDatabaseVerificationIT.class); private static final String MIGRATION_TABLENAME = "MIGRATIONS"; @@ -109,6 +91,9 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements @Autowired private DatabaseBackedPagingProvider myPagingProvider; + @Autowired + TestDaoSearch myTestDaoSearch; + @RegisterExtension protected RestfulServerExtension myServer = new RestfulServerExtension(FhirContext.forR5Cached()); @@ -175,6 +160,20 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0]))); } + @Test + void testChainedSort() { + // given + + // when + SearchParameterMap map = SearchParameterMap + .newSynchronous() + .setSort(new SortSpec("Practitioner:general-practitioner.family")); + myCaptureQueriesListener.clear(); + myPatientDao.search(map, mySrd); + + } + + @Configuration @@ -222,8 +221,8 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements } public static class JpaDatabaseContextConfigParamObject { - private JpaEmbeddedDatabase myJpaEmbeddedDatabase; - private String myDialect; + final JpaEmbeddedDatabase myJpaEmbeddedDatabase; + final String myDialect; public JpaDatabaseContextConfigParamObject(JpaEmbeddedDatabase theJpaEmbeddedDatabase, String theDialect) { myJpaEmbeddedDatabase = theJpaEmbeddedDatabase; diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java new file mode 100644 index 00000000000..ea05bc1ea9f --- /dev/null +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java @@ -0,0 +1,57 @@ +package ca.uhn.fhir.jpa.term; + +import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; +import ca.uhn.fhir.jpa.entity.TermConcept; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class TermConceptDaoSvcTest { + + @Mock + private ITermConceptDao myConceptDao; + + @InjectMocks + private TermConceptDaoSvc myTermConceptDaoSvc; + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testSaveConcept_withSupportLegacyLob(boolean theSupportLegacyLob){ + final String parentPids = "1 2 3 4 5 6 7 8 9"; + when(myConceptDao.save(any())).thenAnswer(t ->{ + TermConcept codeSystem = (TermConcept) t.getArguments()[0]; + codeSystem.prePersist(); + + return codeSystem; + }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(TermConcept.class); + + // given + TermConcept termConcept = new TermConcept().setParentPids(parentPids); + + // when + myTermConceptDaoSvc.setSupportLegacyLob(theSupportLegacyLob); + myTermConceptDaoSvc.saveConcept(termConcept); + + // then + verify(myConceptDao, times(1)).save(captor.capture()); + TermConcept capturedTermConcept = captor.getValue(); + + assertThat(capturedTermConcept.hasParentPidsLobForTesting(), equalTo(theSupportLegacyLob)); + assertThat(capturedTermConcept.getParentPidsAsString(), equalTo(parentPids)); + } + +} diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java index 972a533ef2e..dbb455d6e87 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java @@ -9,11 +9,16 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; @@ -74,4 +79,22 @@ public class ValueSetConceptAccumulatorTest { } + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testPersistValueSetConcept_whenSupportLegacyLob(boolean theSupportLegacyLob){ + final String sourceConceptDirectParentPids = "1 2 3 4 5 6 7"; + ArgumentCaptor captor = ArgumentCaptor.forClass(TermValueSetConcept.class); + + myAccumulator.setSupportLegacyLob(theSupportLegacyLob); + myAccumulator.includeConcept("sys", "code", "display", null, sourceConceptDirectParentPids, null); + + verify(myValueSetConceptDao, times(1)).save(captor.capture()); + + TermValueSetConcept capturedTermValueSetConcept = captor.getValue(); + + assertThat(capturedTermValueSetConcept.hasSourceConceptDirectParentPidsLob(), equalTo(theSupportLegacyLob)); + assertThat(capturedTermValueSetConcept.getSourceConceptDirectParentPids(), equalTo(sourceConceptDirectParentPids)); + + } + } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java index 27d89757a9c..403db4605b6 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java @@ -31,17 +31,22 @@ import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters; import ca.uhn.fhir.mdm.model.MdmTransactionContext; import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson; import ca.uhn.fhir.mdm.util.GoldenResourceHelper; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import ca.uhn.fhir.util.TerserUtil; +import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; import org.springframework.data.domain.Page; +import java.util.regex.Pattern; import java.util.stream.Stream; public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { + private static final Pattern IS_UUID = + Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); protected final FhirContext myFhirContext; @@ -133,16 +138,30 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { String sourceId = link.getSourceId(); // +1 because of "/" in id: "ResourceType/Id" - IResourcePersistentId pid = getResourcePID(sourceId.substring(resourceType.length() + 1), resourceType); + final String sourceIdUnqualified = sourceId.substring(resourceType.length() + 1); - // this might be a bit unperformant - // but it depends how many links there are - // per golden resource (unlikely to be thousands) - return dao.readByPid(pid); + // myMdmLinkQuerySvc.queryLinks populates sourceId with the FHIR_ID, not the RES_ID, so if we don't + // add this conditional logic, on JPA, myIIdHelperService.newPidFromStringIdAndResourceName will fail with + // NumberFormatException + if (isNumericOrUuid(sourceIdUnqualified)) { + IResourcePersistentId pid = getResourcePID(sourceIdUnqualified, resourceType); + + // this might be a bit unperformant + // but it depends how many links there are + // per golden resource (unlikely to be thousands) + return dao.readByPid(pid); + } else { + return dao.read(new IdDt(sourceId), new SystemRequestDetails()); + } }); } private IResourcePersistentId getResourcePID(String theId, String theResourceType) { return myIIdHelperService.newPidFromStringIdAndResourceName(theId, theResourceType); } + + private boolean isNumericOrUuid(String theLongCandidate) { + return StringUtils.isNumeric(theLongCandidate) + || IS_UUID.matcher(theLongCandidate).matches(); + } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java index 04b897e8a08..ffb08829bfe 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java @@ -22,6 +22,8 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import java.util.Collection; + public interface IAuthRuleBuilderOperationNamed { /** @@ -44,6 +46,8 @@ public interface IAuthRuleBuilderOperationNamed { */ IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId); + IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds); + /** * Rule applies to invocations of this operation at the instance level on any instance of the given type */ diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java index 8eb40512001..f45ab580540 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java @@ -22,6 +22,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import jakarta.annotation.Nonnull; import org.hl7.fhir.instance.model.api.IIdType; +import java.util.Collection; +import java.util.stream.Collectors; + /** * @since 5.5.0 */ @@ -54,10 +57,20 @@ public interface IAuthRuleBuilderRuleBulkExport { IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId); + IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients(); + default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull IIdType theFocusResourceId) { return patientExportOnPatient(theFocusResourceId.getValue()); } + default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatients( + @Nonnull Collection theFocusResourceIds) { + return patientExportOnPatientStrings( + theFocusResourceIds.stream().map(IIdType::getValue).collect(Collectors.toList())); + } + + IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings(Collection theFocusResourceIds); + /** * Allow/deny patient-level export rule applies to the Group with the given resource ID, e.g. Group/123 * diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java index 9316cd89d35..a98e2f1e32a 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java @@ -736,6 +736,20 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderOperationNamedAndScoped(rule); } + @Override + public IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds) { + Validate.notNull(theInstanceIds, "theInstanceIds must not be null"); + theInstanceIds.forEach(instanceId -> Validate.notBlank( + instanceId.getResourceType(), + "at least one of theInstanceIds does not have a resource type")); + theInstanceIds.forEach(instanceId -> Validate.notBlank( + instanceId.getIdPart(), "at least one of theInstanceIds does not have an ID part")); + + final OperationRule rule = createRule(); + rule.appliesToInstances(new ArrayList<>(theInstanceIds)); + return new RuleBuilderOperationNamedAndScoped(rule); + } + @Override public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType( Class theType) { @@ -869,7 +883,7 @@ public class RuleBuilder implements IAuthRuleBuilder { } private class RuleBuilderBulkExport implements IAuthRuleBuilderRuleBulkExport { - private RuleBulkExportImpl ruleBulkExport; + private RuleBulkExportImpl myRuleBulkExport; @Override public IAuthRuleBuilderRuleBulkExportWithTarget groupExportOnGroup(@Nonnull String theFocusResourceId) { @@ -881,23 +895,60 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderBulkExportWithTarget(rule); } + @Override + public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients() { + if (myRuleBulkExport == null) { + RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); + rule.setMode(myRuleMode); + myRuleBulkExport = rule; + } + myRuleBulkExport.setAppliesToPatientExportAllPatients(); + + // prevent duplicate rules being added + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); + } + + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); + } + @Override public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId) { - if (ruleBulkExport == null) { + if (myRuleBulkExport == null) { RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); rule.setAppliesToPatientExport(theFocusResourceId); rule.setMode(myRuleMode); - ruleBulkExport = rule; + myRuleBulkExport = rule; } else { - ruleBulkExport.setAppliesToPatientExport(theFocusResourceId); + myRuleBulkExport.setAppliesToPatientExport(theFocusResourceId); } // prevent duplicate rules being added - if (!myRules.contains(ruleBulkExport)) { - myRules.add(ruleBulkExport); + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); } - return new RuleBuilderBulkExportWithTarget(ruleBulkExport); + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); + } + + @Override + public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings( + @Nonnull Collection theFocusResourceIds) { + if (myRuleBulkExport == null) { + RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); + rule.setAppliesToPatientExport(theFocusResourceIds); + rule.setMode(myRuleMode); + myRuleBulkExport = rule; + } else { + myRuleBulkExport.setAppliesToPatientExport(theFocusResourceIds); + } + + // prevent duplicate rules being added + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); + } + + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); } @Override diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java index 1686c157032..eadb0ee4c99 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java @@ -24,12 +24,12 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; +import com.google.common.annotations.VisibleForTesting; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -42,6 +42,7 @@ public class RuleBulkExportImpl extends BaseRule { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuleBulkExportImpl.class); private String myGroupId; private final Collection myPatientIds; + private boolean myAppliesToAllPatients; private BulkExportJobParameters.ExportStyle myWantExportStyle; private Collection myResourceTypes; private boolean myWantAnyStyle; @@ -69,115 +70,86 @@ public class RuleBulkExportImpl extends BaseRule { return null; } - BulkExportJobParameters options = (BulkExportJobParameters) + BulkExportJobParameters inboundBulkExportRequestOptions = (BulkExportJobParameters) theRequestDetails.getAttribute(AuthorizationInterceptor.REQUEST_ATTRIBUTE_BULK_DATA_EXPORT_OPTIONS); - - if (!myWantAnyStyle && options.getExportStyle() != myWantExportStyle) { + // if style doesn't match - abstain + if (!myWantAnyStyle && inboundBulkExportRequestOptions.getExportStyle() != myWantExportStyle) { return null; } + // Do we only authorize some types? If so, make sure requested types are a subset if (isNotEmpty(myResourceTypes)) { - if (isEmpty(options.getResourceTypes())) { - return null; + if (isEmpty(inboundBulkExportRequestOptions.getResourceTypes())) { + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); } - for (String next : options.getResourceTypes()) { - if (!myResourceTypes.contains(next)) { + if (!myResourceTypes.containsAll(inboundBulkExportRequestOptions.getResourceTypes())) { + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); + } + } + + // system only supports filtering by resource type. So if we are system, or any(), then allow, since we have + // done resource type checking + // above + AuthorizationInterceptor.Verdict allowVerdict = newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + + if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { + return allowVerdict; + } + + // assume myGroupId not empty->myStyle is group. If target group matches, then allow. + if (isNotBlank(myGroupId) && inboundBulkExportRequestOptions.getGroupId() != null) { + String expectedGroupId = + new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); + String actualGroupId = new IdDt(inboundBulkExportRequestOptions.getGroupId()) + .toUnqualifiedVersionless() + .getValue(); + if (Objects.equals(expectedGroupId, actualGroupId)) { + return allowVerdict; + } + } + // patient export mode - instance or type. type can have 0..n patient ids. + // myPatientIds == the rules built by the auth interceptor rule builder + // options.getPatientIds() == the requested IDs in the export job. + + // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve + // 2. If any requested ID is not present in the users permissions, Deny. + if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT) + // Unfiltered Type Level + if (myAppliesToAllPatients) { + return allowVerdict; + } + + // Instance level, or filtered type level + if (isNotEmpty(myPatientIds)) { + // If bulk export options defines no patient IDs, return null. + if (inboundBulkExportRequestOptions.getPatientIds().isEmpty()) { + return null; + } else { + ourLog.debug("options.getPatientIds() != null"); + Set requestedPatientIds = sanitizeIds(inboundBulkExportRequestOptions.getPatientIds()); + Set permittedPatientIds = sanitizeIds(myPatientIds); + if (permittedPatientIds.containsAll(requestedPatientIds)) { + return allowVerdict; + } else { return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); } } } - - if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - if (isNotBlank(myGroupId) && options.getGroupId() != null) { - String expectedGroupId = - new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); - String actualGroupId = - new IdDt(options.getGroupId()).toUnqualifiedVersionless().getValue(); - if (Objects.equals(expectedGroupId, actualGroupId)) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - } - - // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve - // 2. If any requested ID is not present in the users permissions, Deny. - if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT && isNotEmpty(myPatientIds)) { - List permittedPatientIds = myPatientIds.stream() - .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) - .collect(Collectors.toList()); - if (!options.getPatientIds().isEmpty()) { - ourLog.debug("options.getPatientIds() != null"); - List requestedPatientIds = options.getPatientIds().stream() - .map(t -> new IdDt(t).toUnqualifiedVersionless().getValue()) - .collect(Collectors.toList()); - boolean requestedPatientsPermitted = true; - for (String requestedPatientId : requestedPatientIds) { - if (!permittedPatientIds.contains(requestedPatientId)) { - requestedPatientsPermitted = false; - break; - } - } - if (requestedPatientsPermitted) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - - final List filters = options.getFilters(); - - if (!filters.isEmpty()) { - ourLog.debug("filters not empty"); - final Set patientIdsInFilters = filters.stream() - .filter(filter -> filter.startsWith("Patient?_id=")) - .map(filter -> filter.replace("?_id=", "/")) - .collect(Collectors.toUnmodifiableSet()); - - boolean filteredPatientIdsPermitted = true; - for (String patientIdInFilters : patientIdsInFilters) { - if (!permittedPatientIds.contains(patientIdInFilters)) { - filteredPatientIdsPermitted = false; - break; - } - } - - if (filteredPatientIdsPermitted) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - ourLog.debug("patientIds and filters both empty"); - } return null; } + private Set sanitizeIds(Collection myPatientIds) { + return myPatientIds.stream() + .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) + .collect(Collectors.toSet()); + } + public void setAppliesToGroupExportOnGroup(String theGroupId) { myWantExportStyle = BulkExportJobParameters.ExportStyle.GROUP; myGroupId = theGroupId; @@ -193,6 +165,16 @@ public class RuleBulkExportImpl extends BaseRule { myPatientIds.add(thePatientId); } + public void setAppliesToPatientExport(Collection thePatientIds) { + myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; + myPatientIds.addAll(thePatientIds); + } + + public void setAppliesToPatientExportAllPatients() { + myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; + myAppliesToAllPatients = true; + } + public void setAppliesToSystem() { myWantExportStyle = BulkExportJobParameters.ExportStyle.SYSTEM; } @@ -212,4 +194,14 @@ public class RuleBulkExportImpl extends BaseRule { BulkExportJobParameters.ExportStyle getWantExportStyle() { return myWantExportStyle; } + + @VisibleForTesting + Collection getPatientIds() { + return myPatientIds; + } + + @VisibleForTesting + Collection getResourceTypes() { + return myResourceTypes; + } } diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java index b942fcc8023..7dd962d6630 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java @@ -1,16 +1,23 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.server.provider.ProviderConstants; import com.google.common.collect.Lists; +import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.stream.Stream; import static org.hamcrest.Matchers.contains; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.mockito.Mockito.mock; public class RuleBuilderTest { @@ -98,7 +105,72 @@ public class RuleBuilderTest { builder.allow().bulkExport().patientExportOnPatient("Patient/pat2").withResourceTypes(resourceTypes); List rules = builder.build(); assertEquals(rules.size(),1); - assertTrue(rules.get(0) instanceof RuleBulkExportImpl); + assertInstanceOf(RuleBulkExportImpl.class, rules.get(0)); + } + + public static Stream multipleInstancesParams() { + return Stream.of( + Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.DENY), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.DENY), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.DENY) + ); + } + + @ParameterizedTest + @MethodSource("multipleInstancesParams") + public void testBulkExport_PatientExportOnPatients_MultiplePatientsSingleRule(Collection theExpectedPatientIds, Collection theExpectedResourceTypes, PolicyEnum thePolicyEnum) { + final RuleBuilder builder = new RuleBuilder(); + final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { + case ALLOW -> builder.allow(); + case DENY -> builder.deny(); + }; + rule.bulkExport().patientExportOnPatientStrings(theExpectedPatientIds).withResourceTypes(theExpectedResourceTypes); + final List rules = builder.build(); + assertEquals(rules.size(),1); + final IAuthRule authRule = rules.get(0); + assertInstanceOf(RuleBulkExportImpl.class, authRule); + final RuleBulkExportImpl ruleBulkExport = (RuleBulkExportImpl) authRule; + assertEquals(theExpectedPatientIds, ruleBulkExport.getPatientIds()); + assertEquals(theExpectedResourceTypes, ruleBulkExport.getResourceTypes()); + assertEquals(thePolicyEnum, ruleBulkExport.getMode()); + } + + public static Stream owners() { + return Stream.of( + Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.ALLOW), + Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.DENY), + Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.ALLOW), + Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.DENY) + ); + } + + @ParameterizedTest + @MethodSource("owners") + public void testBulkExport_PatientExportOnPatients_onInstances(List theExpectedOwners, PolicyEnum thePolicyEnum) { + final RuleBuilder builder = new RuleBuilder(); + final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { + case ALLOW -> builder.allow(); + case DENY -> builder.deny(); + }; + + final List rules = rule + .operation() + .named(ProviderConstants.OPERATION_EXPORT) + .onInstances(theExpectedOwners) + .andAllowAllResponses() + .andThen() + .build(); + + assertEquals(rules.size(),1); + final IAuthRule authRule = rules.get(0); + assertInstanceOf(OperationRule.class, authRule); + final OperationRule operationRule = (OperationRule) authRule; + assertEquals(theExpectedOwners, operationRule.getAppliesToIds()); + assertEquals(ProviderConstants.OPERATION_EXPORT, operationRule.getOperationName()); + assertEquals(thePolicyEnum, operationRule.getMode()); } @Test diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java index dc71422f128..1dc8eb5b8e8 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java @@ -4,6 +4,9 @@ import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -13,7 +16,6 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -28,10 +30,11 @@ public class RuleBulkExportImplTest { @Mock private Set myFlags; + @Test public void testDenyBulkRequestWithInvalidResourcesTypes() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - + myRule.setMode(PolicyEnum.ALLOW); Set myTypes = new HashSet<>(); myTypes.add("Patient"); myTypes.add("Practitioner"); @@ -42,33 +45,210 @@ public class RuleBulkExportImplTest { BulkExportJobParameters options = new BulkExportJobParameters(); options.setResourceTypes(myWantTypes); - + when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + assertDeny(verdict); + } + + + @Test + public void test_RuleSpecifiesResourceTypes_RequestDoesNot_Abstains() { + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + Set myTypes = new HashSet<>(); + myTypes.add("Patient"); + myRule.setResourceTypes(myTypes); + + + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + assertDeny(verdict); } @Test - public void testBulkRequestWithValidResourcesTypes() { + public void testBulkExportSystem_ruleHasTypes_RequestWithTypes_allow() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - - Set myTypes = new HashSet<>(); - myTypes.add("Patient"); - myTypes.add("Practitioner"); - myRule.setResourceTypes(myTypes); - - Set myWantTypes = new HashSet<>(); - myWantTypes.add("Patient"); - myWantTypes.add("Practitioner"); + myRule.setMode(PolicyEnum.ALLOW); + myRule.setAppliesToSystem(); + myRule.setResourceTypes(Set.of("Patient", "Practitioner")); BulkExportJobParameters options = new BulkExportJobParameters(); - options.setResourceTypes(myWantTypes); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setResourceTypes(Set.of("Patient", "Practitioner")); when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertNull(verdict); + + assertAllow(verdict); + } + + + @Test + public void testBulkExportSystem_ruleHasTypes_RequestWithTooManyTypes_abstain() { + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + myRule.setMode(PolicyEnum.ALLOW); + myRule.setAppliesToSystem(); + myRule.setResourceTypes(Set.of("Patient", "Practitioner")); + + + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setResourceTypes(Set.of("Patient", "Practitioner", "Encounter")); + + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertDeny(verdict); + } + @Nested + class StyleChecks { + BulkExportJobParameters myOptions = new BulkExportJobParameters(); + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + @BeforeEach + void setUp() { + myRule.setMode(PolicyEnum.ALLOW); + when(myRequestDetails.getAttribute(any())).thenReturn(myOptions); + } + @Nested class RuleAnyStyle { + @BeforeEach + void setUp(){ + myRule.setAppliesToAny(); + } + + @Test + public void testRuleAnyStyle_Matches_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + @Test + public void testRuleAnyStyle_Matches_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + + } + @Test + public void testRuleAnyStyle_Matches_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + + } + + } + + @Nested + class RuleSystemStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToSystem(); + } + + @Test + public void test_Matches_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test + public void test_DoesntMatch_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + } + + @Nested + class RuleGroupStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToGroupExportOnGroup("Group/123"); + } + + @Test + public void test_DoesntMatch_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_Matches_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + myOptions.setGroupId("Group/123"); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + } + + @Nested + class RulePatientStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToPatientExport("Patient/123"); + } + + @Test + public void test_DoesntMatch_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + myOptions.setGroupId("Group/123"); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + myOptions.setPatientIds(Set.of("Patient/123")); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + } } @Test @@ -84,7 +264,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(null, verdict); + assertAbstain(verdict); } @Test @@ -100,7 +280,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAllow(verdict); } @Test @@ -118,7 +298,7 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We permit the request, as a patient ID that was requested is honoured by this rule. - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAllow(verdict); } @Test @@ -135,8 +315,8 @@ public class RuleBulkExportImplTest { //When AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: we should deny the request, as the requested export does not contain the patient permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: abstain + assertDeny(verdict); } @Test @@ -153,28 +333,45 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We make no claims about type-level export on Patient. - assertEquals(null, verdict); + assertAbstain(verdict); } @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatient() { + public void testPatientExportRulesWithId_withRequestNoIds_abstains() { //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=123")); - options.setResourceTypes(Set.of("Patient")); when(myRequestDetails.getAttribute(any())).thenReturn(options); //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + //Then: We make no claims about type-level export on Patient. + assertAbstain(verdict); } + @Test + public void testPatientExportRuleWithNoIds_withRequestNoIds_allows() { + //Given + RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + BulkExportJobParameters options = new BulkExportJobParameters(); + + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatientAndFilterHasResources() { //Given @@ -191,27 +388,9 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAbstain(verdict); } - @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypeObservation() { - //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExport("Patient/123"); - myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=123")); - options.setResourceTypes(Set.of("Observation")); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); - } @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterNoResourceType() { @@ -227,27 +406,8 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); - } - - @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterMismatch() { - //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExport("Patient/123"); - myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=456")); - options.setResourceTypes(Set.of("Patient")); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then: The patient IDs do NOT match so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: Filters are ignored for auth purposes. The rule has an ID, indicating it is for instance level, but the job requested type level. Abstain + assertAbstain(verdict); } @Test @@ -265,12 +425,12 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: We do not have permissions on the requested patient so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: We do not have permissions on the requested patient so we abstain + assertDeny(verdict); } @Test - public void testPatientExportRulesOnTypeLevelExportPermittedPatient() { + public void testPatientExport_ruleAllowsId_requestsId_allow() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -289,7 +449,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExportRulesOnTypeLevelExportPermittedPatients() { + public void testPatientExport_ruleAllowsIds_requestsIds_allow() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -309,7 +469,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatients() { + public void testPatientExport_ruleAllowsId_requestsTooManyIds_abstain() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -324,8 +484,61 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: There are unpermitted patients in the request so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + assertDeny(verdict); + } // + + @Test + public void testPatientExport_RuleAllowsAll_RequestId_allows() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + options.setPatientIds(Set.of("Patient/123")); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAllow(verdict); } + + @Test + public void testPatientExport_RuleAllowsAll_RequestAll_allows() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAllow(verdict); + } + + @Test + public void testPatientExport_RuleAllowsExplicitPatient_RequestAll_abstain() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExport("Patient/123"); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAbstain(verdict); + } + @Test public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatientFilters() { //Given @@ -341,7 +554,22 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: There are unpermitted patients in the request so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: There are unpermitted patients in the request so this is not permitted. abstain. + assertAbstain(verdict); + + } + + private static void assertAbstain(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertEquals(null, verdict, "Expect abstain"); + } + + private static void assertAllow(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertNotNull(verdict, "Expect ALLOW, got abstain"); + Assertions.assertEquals(PolicyEnum.ALLOW, verdict.getDecision(), "Expect ALLOW"); + } + + private static void assertDeny(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertNotNull(verdict, "Expect DENY, got abstain"); + Assertions.assertEquals(PolicyEnum.DENY, verdict.getDecision(), "Expect DENY"); } } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java index 168e474ece7..50b7859a0a9 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java @@ -308,6 +308,14 @@ public abstract class BaseTask { } } + public void doNothing() { + setDoNothing(true); + } + + public void failureAllowed() { + setFailureAllowed(true); + } + public boolean isDoNothing() { return myDoNothing; } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java index 49615e73c1a..4b90ea91ac3 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java @@ -22,11 +22,8 @@ package ca.uhn.fhir.jpa.migrate.taskdef; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.migrate.JdbcUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.intellij.lang.annotations.Language; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.jdbc.core.ColumnMapRowMapper; -import org.springframework.jdbc.core.JdbcTemplate; import java.sql.SQLException; import java.util.Set; @@ -51,53 +48,12 @@ public class RenameTableTask extends BaseTableTask { setDescription("Rename table " + getOldTableName()); } - private void handleTableWithNewTableName() throws SQLException { - - if (!myDeleteTargetColumnFirstIfExist) { - throw new SQLException(Msg.code(2517) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because a table with name " + getNewTableName() + " already exists"); - } - - // a table with the new tableName already exists and we can delete it. we will only do so if it is empty. - Integer rowsWithData = getConnectionProperties().getTxTemplate().execute(t -> { - String sql = "SELECT * FROM " + getNewTableName(); - JdbcTemplate jdbcTemplate = getConnectionProperties().newJdbcTemplate(); - jdbcTemplate.setMaxRows(1); - return jdbcTemplate.query(sql, new ColumnMapRowMapper()).size(); - }); - - if (rowsWithData != null && rowsWithData > 0) { - throw new SQLException(Msg.code(2518) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because a table with name " + getNewTableName() + " already exists and is populated."); - } - - logInfo( - ourLog, - "Table {} already exists - Going to drop it before renaming table {} to {}", - getNewTableName(), - getOldTableName(), - getNewTableName()); - - @Language("SQL") - String sql = "DROP TABLE " + getNewTableName(); - executeSql(getNewTableName(), sql); - } - @Override public void doExecute() throws SQLException { Set tableNames = JdbcUtils.getTableNames(getConnectionProperties()); boolean hasTableWithNewTableName = tableNames.contains(getNewTableName()); - if (!tableNames.contains(getOldTableName())) { - throw new SQLException(Msg.code(2516) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because the original table does not exists"); - } - - if (hasTableWithNewTableName) { - handleTableWithNewTableName(); - } - String sql = buildRenameTableSqlStatement(); logInfo(ourLog, "Renaming table: {}", getOldTableName()); 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 ffc800f9a9f..53741f65e5a 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 @@ -57,6 +57,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -185,6 +186,7 @@ public class Builder { private final String myRelease; private final BaseMigrationTasks.IAcceptsTasks mySink; private final String myTableName; + private BaseTask myLastAddedTask; public BuilderWithTableName(String theRelease, BaseMigrationTasks.IAcceptsTasks theSink, String theTableName) { myRelease = theRelease; @@ -274,6 +276,7 @@ public class Builder { @Override public void addTask(BaseTask theTask) { ((BaseTableTask) theTask).setTableName(myTableName); + myLastAddedTask = theTask; mySink.addTask(theTask); } @@ -311,6 +314,10 @@ public class Builder { return this; } + public Optional getLastAddedTask() { + return Optional.ofNullable(myLastAddedTask); + } + /** * @param theFkName the name of the foreign key * @param theParentTableName the name of the table that exports the foreign key @@ -323,31 +330,37 @@ public class Builder { addTask(task); } - public void renameTable(String theVersion, String theNewTableName) { + public BuilderCompleteTask renameTable(String theVersion, String theNewTableName) { RenameTableTask task = new RenameTableTask(myRelease, theVersion, getTableName(), theNewTableName); addTask(task); + return new BuilderCompleteTask(task); } - public void migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { + public BuilderCompleteTask migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { MigratePostgresTextClobToBinaryClobTask task = new MigratePostgresTextClobToBinaryClobTask(myRelease, theVersion); task.setTableName(getTableName()); task.setColumnName(theColumnName); addTask(task); + return new BuilderCompleteTask(task); } - public void migrateBlobToBinary(String theVersion, String theFromColumName, String theToColumName) { + public BuilderCompleteTask migrateBlobToBinary( + String theVersion, String theFromColumName, String theToColumName) { MigrateColumBlobTypeToBinaryTypeTask task = new MigrateColumBlobTypeToBinaryTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); + return new BuilderCompleteTask(task); } - public void migrateClobToText(String theVersion, String theFromColumName, String theToColumName) { + public BuilderCompleteTask migrateClobToText( + String theVersion, String theFromColumName, String theToColumName) { MigrateColumnClobTypeToTextTypeTask task = new MigrateColumnClobTypeToTextTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); + return new BuilderCompleteTask(task); } public class BuilderAddIndexWithName { diff --git a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java index a1c6aad40ba..14cf7896ec6 100644 --- a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java +++ b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java @@ -41,26 +41,4 @@ public class RenameTableTaskTest extends BaseTest { assertThat(tableNames, not(hasItem(oldTableName))); } - @ParameterizedTest(name = "{index}: {0}") - @MethodSource("data") - public void testRenameTableTask_whenTableDoesNotExists_willRaiseException(Supplier theTestDatabaseDetails) throws SQLException { - // given - before(theTestDatabaseDetails); - final String newTableName = "NEWTABLE"; - final String oldTableName = "SOMETABLE"; - - RenameTableTask task = new RenameTableTask("1", "1", oldTableName, newTableName); - getMigrator().addTask(task); - - // when - try { - getMigrator().migrate(); - fail(); - } catch (Exception e){ - // then - assertThat(e.getMessage(), containsString("2516")); - } - - } - } diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java index ddc1fde19f5..9da0e377ce5 100644 --- a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java @@ -436,6 +436,16 @@ public class BulkDataImportProviderTest { public boolean isResourcePartitionable(String theResourceType) { return false; } + + @Override + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + return null; + } + + @Override + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + return null; + } } private Date parseDate(String theString) { diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java index fcd883576bf..e94facf199f 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java index f5de302cd97..483945ba1b5 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java index bdaec6cc8ac..09313ca21ff 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.ICollectDataServiceFactory; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java index 9c801d91d39..da7ff850647 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.IDataRequirementsServiceFactory; diff --git a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java index 299475af681..483736324b2 100644 --- a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java +++ b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java @@ -102,7 +102,9 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa public void cleanup() { ourLog.info("cleanup {}", myIds); - myIds.keySet().forEach(nextType->{ + myIds.keySet().stream() + .sorted() // Hack to ensure Patients are deleted before Practitioners. This may need to be refined. + .forEach(nextType->{ // todo do this in a bundle for perf. IFhirResourceDao dao = myDaoRegistry.getResourceDao(nextType); myIds.get(nextType).forEach(dao::delete); diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java index aafb69b8e2d..78ec78d7c79 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java @@ -360,6 +360,14 @@ public class JpaStorageSettings extends StorageSettings { */ private long myRestDeleteByUrlResourceIdThreshold = DEFAULT_REST_DELETE_BY_URL_RESOURCE_ID_THRESHOLD; + /** + * If enabled, this setting causes persisting data to legacy LOB columns as well as columns introduced + * to migrate away from LOB columns which effectively duplicates stored information. + * + * @since 7.2.0 + */ + private boolean myWriteToLegacyLobColumns = false; + /** * Constructor */ @@ -2423,8 +2431,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} + * {@link IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2439,8 +2447,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} + * {@link IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2454,6 +2462,33 @@ public class JpaStorageSettings extends StorageSettings { myIssueSeverityForCodeDisplayMismatch = theIssueSeverityForCodeDisplayMismatch; } + /** + * This method returns whether data will be stored in LOB columns as well as the columns + * introduced to migrate away from LOB. Writing to LOB columns is set to false by + * default. Enabling the setting will effectively double the persisted information. + * If enabled, a careful monitoring of LOB table (if applicable) is required to avoid + * exceeding the table maximum capacity. + * + * @since 7.2.0 + */ + public boolean isWriteToLegacyLobColumns() { + return myWriteToLegacyLobColumns; + } + + /** + * This setting controls whether data will be stored in LOB columns as well as the columns + * introduced to migrate away from LOB. Writing to LOB columns is set to false by + * default. Enabling the setting will effectively double the persisted information. + * When enabled, a careful monitoring of LOB table (if applicable) is required to avoid + * exceeding the table maximum capacity. + * + * @param theWriteToLegacyLobColumns + * @since 7.2.0 + */ + public void setWriteToLegacyLobColumns(boolean theWriteToLegacyLobColumns) { + myWriteToLegacyLobColumns = theWriteToLegacyLobColumns; + } + /** * This setting controls whether MdmLink and other non-resource DB history is enabled. *

    diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java index a98fb571d1a..be151786428 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java @@ -333,10 +333,6 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition return !myNonPartitionableResourceNames.contains(theResourceType); } - protected abstract RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); - - protected abstract RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); - private void validateSinglePartitionForCreate( RequestPartitionId theRequestPartitionId, @Nonnull String theResourceName, Pointcut thePointcut) { validateRequestPartitionNotNull(theRequestPartitionId, thePointcut); From 3572d593c10ab57b4e0d81b812935e6f5f5b497b Mon Sep 17 00:00:00 2001 From: Tadgh Date: Sun, 12 May 2024 16:04:43 -0700 Subject: [PATCH 07/15] Revert "7_2 branch mergeback (#5922)" (#5927) This reverts commit 125513a10009041289b0d0570c30aa4fd637ab0a. --- .../ca/uhn/fhir/interceptor/api/Pointcut.java | 8 +- .../fhir/cli/UploadTerminologyCommand.java | 11 +- .../cli/UploadTerminologyCommandTest.java | 87 ---- ...ule-builder-code-support-multiple-ids.yaml | 4 - ...dating-name-of-full-text-field-search.yaml | 5 - ...updating-token-param-with-large-value.yaml | 5 - ...-survivorship-number-format-exception.yaml | 6 - ...ry-security-interceptor-documentation.yaml | 7 - ...bility-to-persist-data-to-lob-columns.yaml | 5 - ...-cli-upload-terminology-zip-hapi-0862.yaml | 6 - ...ascale-meta-operation-fails-hapi-0389.yaml | 5 - .../7_2_0/5899-enhance-mdm-interceptor.yaml | 4 - ...ery-chained-sort-returns-less-results.yaml | 4 - .../7_2_0/5915-bulk-export-security-woes.yaml | 4 - .../7_2_0/5917-chain-sort-mssql.yaml | 4 - .../security/binary_security_interceptor.md | 7 +- .../DatabaseBinaryContentStorageSvcImpl.java | 21 +- .../ca/uhn/fhir/jpa/config/JpaConfig.java | 14 - .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 21 +- .../ca/uhn/fhir/jpa/entity/TermConcept.java | 36 +- .../fhir/jpa/entity/TermConceptProperty.java | 15 +- .../fhir/jpa/entity/TermValueSetConcept.java | 11 - .../jpa/entity/TermValueSetConceptView.java | 41 +- .../tasks/HapiFhirJpaMigrationTasks.java | 42 +- .../partition/RequestPartitionHelperSvc.java | 16 +- .../fhir/jpa/search/builder/QueryStack.java | 47 +-- .../term/TermCodeSystemStorageSvcImpl.java | 21 + .../uhn/fhir/jpa/term/TermConceptDaoSvc.java | 10 - .../ca/uhn/fhir/jpa/term/TermReadSvcImpl.java | 11 +- .../jpa/term/ValueSetConceptAccumulator.java | 11 - .../ValueSetConceptAccumulatorFactory.java | 51 --- .../jpa/term/config/TermCodeSystemConfig.java | 5 +- .../jpa/entity/TermConceptPropertyTest.java | 22 +- .../mdm/svc/GoldenResourceMergerSvcImpl.java | 1 - .../jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java | 22 - .../mdm/svc/MdmSurvivorshipSvcImplTest.java | 19 +- .../jpa/model/entity/BinaryStorageEntity.java | 11 +- .../partition/IRequestPartitionHelperSvc.java | 26 -- .../config/SubscriptionConfig.java | 35 -- .../config/SubscriptionSubmitterConfig.java | 12 +- .../jpa/topic/SubscriptionTopicConfig.java | 11 +- ...tabaseBinaryContentStorageSvcImplTest.java | 40 +- .../dao/r4/FhirResourceDaoR4QuerySandbox.java | 27 -- .../RequestPartitionHelperSvcTest.java | 187 ++------- .../stresstest/GiantTransactionPerfTest.java | 10 - ...iftedRefchainsAndChainedSortingR5Test.java | 50 +-- .../database/BaseDatabaseVerificationIT.java | 47 +-- .../fhir/jpa/term/TermConceptDaoSvcTest.java | 57 --- .../term/ValueSetConceptAccumulatorTest.java | 23 -- .../fhir/mdm/svc/MdmSurvivorshipSvcImpl.java | 29 +- .../auth/IAuthRuleBuilderOperationNamed.java | 4 - .../auth/IAuthRuleBuilderRuleBulkExport.java | 13 - .../server/interceptor/auth/RuleBuilder.java | 65 +-- .../interceptor/auth/RuleBulkExportImpl.java | 186 +++++---- .../interceptor/auth/RuleBuilderTest.java | 76 +--- .../auth/RuleBulkExportImplTest.java | 382 ++++-------------- .../fhir/jpa/migrate/taskdef/BaseTask.java | 8 - .../jpa/migrate/taskdef/RenameTableTask.java | 44 ++ .../fhir/jpa/migrate/tasks/api/Builder.java | 21 +- .../migrate/taskdef/RenameTableTaskTest.java | 22 + .../imprt/BulkDataImportProviderTest.java | 10 - .../cr/r4/ICollectDataServiceFactory.java | 19 - .../r4/IDataRequirementsServiceFactory.java | 19 - .../measure/CollectDataOperationProvider.java | 19 - .../DataRequirementsOperationProvider.java | 19 - .../fhir/storage/test/DaoTestDataBuilder.java | 4 +- .../jpa/api/config/JpaStorageSettings.java | 43 +- .../BaseRequestPartitionHelperSvc.java | 4 + 68 files changed, 470 insertions(+), 1662 deletions(-) delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml delete mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml delete mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java delete mode 100644 hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java delete mode 100644 hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java index 016512e537d..d2c995a435e 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java @@ -2387,19 +2387,13 @@ public enum Pointcut implements IPointcut { *

  • * ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent - Contains information about the from and to resources. *
  • - *
  • - * ca.uhn.fhir.mdm.model.mdmevents.MdmTransactionContext - Contains information about the Transaction context, e.g. merge or link. - *
  • * *

    * Hooks should return void. *

    */ MDM_POST_MERGE_GOLDEN_RESOURCES( - void.class, - "ca.uhn.fhir.rest.api.server.RequestDetails", - "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent", - "ca.uhn.fhir.mdm.model.MdmTransactionContext"), + void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent"), /** * MDM Link History Hook: diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java index 6085508f4c2..e073c2e2c60 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java @@ -19,7 +19,6 @@ */ package ca.uhn.fhir.cli; -import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; @@ -32,7 +31,6 @@ import ca.uhn.fhir.system.HapiSystemProperties; import ca.uhn.fhir.util.AttachmentUtil; import ca.uhn.fhir.util.FileUtil; import ca.uhn.fhir.util.ParametersUtil; -import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; @@ -267,7 +265,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { "Response:\n{}", myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response)); } - protected void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { + private void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { byte[] bytes = theBytes; String fileName = theFileName; @@ -279,7 +277,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { FileUtil.formatFileSize(ourTransferSizeLimit)); try { - File tempFile = File.createTempFile("hapi-fhir-cli", "." + suffix); + File tempFile = File.createTempFile("hapi-fhir-cli", suffix); tempFile.deleteOnExit(); try (OutputStream fileOutputStream = new FileOutputStream(tempFile, false)) { fileOutputStream.write(bytes); @@ -365,9 +363,4 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { } return retVal; } - - @VisibleForTesting - void setFhirContext(FhirContext theFhirContext) { - myFhirCtx = theFhirContext; - } } diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java index 2511ef9db91..f0e08800425 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java @@ -22,10 +22,6 @@ import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyS import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; -import org.hl7.fhir.instance.model.api.IBaseParameters; -import org.hl7.fhir.r4.model.Attachment; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.Type; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -47,7 +43,6 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.List; -import java.util.Optional; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -59,8 +54,6 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -486,86 +479,6 @@ public class UploadTerminologyCommandTest { uploadICD10UsingCompressedFile(theFhirVersion, theIncludeTls); } - @ParameterizedTest - @MethodSource("paramsProvider") - @SuppressWarnings("unused") // Both params for @BeforeEach - void testZipFileInParameters(String theFhirVersion, boolean theIncludeTls) { - final IBaseParameters inputParameters = switch (myCtx.getVersion().getVersion()) { - case DSTU2, DSTU2_HL7ORG, DSTU2_1 -> new org.hl7.fhir.dstu2.model.Parameters(); - case DSTU3 -> new org.hl7.fhir.dstu3.model.Parameters(); - case R4 -> new Parameters(); - case R4B -> new org.hl7.fhir.r4b.model.Parameters(); - case R5 -> new org.hl7.fhir.r5.model.Parameters(); - }; - - final UploadTerminologyCommand uploadTerminologyCommand = new UploadTerminologyCommand(); - uploadTerminologyCommand.setFhirContext(myCtx); - uploadTerminologyCommand.setTransferSizeBytes(1); - - uploadTerminologyCommand.addFileToRequestBundle(inputParameters, "something.zip", new byte[] {1,2}); - - final String actualAttachmentUrl = getAttachmentUrl(inputParameters, myCtx); - assertTrue(actualAttachmentUrl.endsWith(".zip")); - } - - private static String getAttachmentUrl(IBaseParameters theInputParameters, FhirContext theCtx) { - switch (theCtx.getVersion().getVersion()) { - case DSTU2: - case DSTU2_HL7ORG: - case DSTU2_1: { - assertInstanceOf(org.hl7.fhir.dstu2.model.Parameters.class, theInputParameters); - final org.hl7.fhir.dstu2.model.Parameters dstu2Parameters = (org.hl7.fhir.dstu2.model.Parameters) theInputParameters; - final List dstu2ParametersList = dstu2Parameters.getParameter(); - final Optional optDstu2FileParam = dstu2ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); - assertTrue(optDstu2FileParam.isPresent()); - final org.hl7.fhir.dstu2.model.Type dstu2Value = optDstu2FileParam.get().getValue(); - assertInstanceOf(org.hl7.fhir.dstu2.model.Attachment.class, dstu2Value); - final org.hl7.fhir.dstu2.model.Attachment dstu2Attachment = (org.hl7.fhir.dstu2.model.Attachment) dstu2Value; - return dstu2Attachment.getUrl(); - } - case DSTU3: { - assertInstanceOf(org.hl7.fhir.dstu3.model.Parameters.class, theInputParameters); - final org.hl7.fhir.dstu3.model.Parameters dstu3Parameters = (org.hl7.fhir.dstu3.model.Parameters) theInputParameters; - final List dstu3ParametersList = dstu3Parameters.getParameter(); - final Optional optDstu3FileParam = dstu3ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); - assertTrue(optDstu3FileParam.isPresent()); - final org.hl7.fhir.dstu3.model.Type dstu3Value = optDstu3FileParam.get().getValue(); - assertInstanceOf(org.hl7.fhir.dstu3.model.Attachment.class, dstu3Value); - final org.hl7.fhir.dstu3.model.Attachment dstu3Attachment = (org.hl7.fhir.dstu3.model.Attachment) dstu3Value; - return dstu3Attachment.getUrl(); - } - case R4: { - assertInstanceOf(Parameters.class, theInputParameters); - final Parameters r4Parameters = (Parameters) theInputParameters; - final Parameters.ParametersParameterComponent r4Parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); - final Type r4Value = r4Parameter.getValue(); - assertInstanceOf(Attachment.class, r4Value); - final Attachment r4Attachment = (Attachment) r4Value; - return r4Attachment.getUrl(); - } - case R4B: { - assertInstanceOf(org.hl7.fhir.r4b.model.Parameters.class, theInputParameters); - final org.hl7.fhir.r4b.model.Parameters r4bParameters = (org.hl7.fhir.r4b.model.Parameters) theInputParameters; - final org.hl7.fhir.r4b.model.Parameters.ParametersParameterComponent r4bParameter = r4bParameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); - final org.hl7.fhir.r4b.model.DataType value = r4bParameter.getValue(); - assertInstanceOf(org.hl7.fhir.r4b.model.Attachment.class, value); - final org.hl7.fhir.r4b.model.Attachment r4bAttachment = (org.hl7.fhir.r4b.model.Attachment) value; - return r4bAttachment.getUrl(); - } - case R5: { - assertInstanceOf(org.hl7.fhir.r5.model.Parameters.class, theInputParameters); - final org.hl7.fhir.r5.model.Parameters r4Parameters = (org.hl7.fhir.r5.model.Parameters) theInputParameters; - final org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); - final org.hl7.fhir.r5.model.DataType value = parameter.getValue(); - assertInstanceOf(org.hl7.fhir.r5.model.Attachment.class, value); - final org.hl7.fhir.r5.model.Attachment attachment = (org.hl7.fhir.r5.model.Attachment) value; - return attachment.getUrl(); - } - default: - throw new IllegalStateException("Unknown FHIR version: " + theCtx.getVersion().getVersion()); - } - } - private void uploadICD10UsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException { if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) { when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101"))); diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml deleted file mode 100644 index c44aca386c9..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: add -issue: 5861 -title: "Enhance RuleBuilder code to support multiple instance IDs." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml deleted file mode 100644 index 358a0e4276a..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: fix -issue: 5865 -title: "Moving the Hibernate.Search annotation for text indexing from the lob column to the column added as part of the - PostgreSql LOB migration." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml deleted file mode 100644 index ad6bbd02d1f..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: fix -issue: 5877 -title: "Previously, updating a tokenParam with a value greater than 200 characters would raise a SQLException. -This issue has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml deleted file mode 100644 index 9dae5a3b34a..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: fix -issue: 5886 -title: "Previously, either updating links on, or deleting one of two patients with non-numeric IDs linked to a golden - patient would result in a HAPI-0389 if there were survivorship rules. - This issue has been fixed for both the update links and delete cases." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml deleted file mode 100644 index 966fbe3d9c8..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -type: fix -issue: 5888 -title: "Updated documentation on binary_security_interceptor to specify using - `STORAGE_PRE_INITIATE_BULK_EXPORT` not `STORAGE_INITIATE_BULK_EXPORT` pointcut - to change bulk export parameters. -" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml deleted file mode 100644 index bdca0eeba3c..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: add -issue: 5890 -title: "As part of the migration from LOB, provided the capability to force persisting data to LOB columns. The default -behavior is to not persist in lob columns." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml deleted file mode 100644 index 12d853e5842..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml +++ /dev/null @@ -1,6 +0,0 @@ ---- -type: fix -issue: 5893 -title: "Previously, hapi-fhir-cli: upload-terminology failed with a HAPI-0862 error when uploading LOINC. - This has been fixed." - diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml deleted file mode 100644 index dfe2f459515..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -type: fix -issue: 5898 -title: "Previously, triggering a `$meta` via GET on a new patient with Megascale configured resulted in error HAPI-0389. This has been corrected - This has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml deleted file mode 100644 index 8746c27e136..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: add -issue: 5899 -title: "The `MDM_POST_MERGE_GOLDEN_RESOURCES` now supports an additional parameter, of type `ca.uhn.fhir.mdm.model.MdmTransactionContext`. Thanks to Jens Villadsen for the contribution." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml deleted file mode 100644 index 9c8c9873f6d..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: fix -issue: 5904 -title: "Chained sort would exclude results that did not have resources matching the sort chain. These are now included, and sorted at the end." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml deleted file mode 100644 index 8bd43c7a5c0..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: fix -issue: 5915 -title: "Previously, in some edge case scenarios the Bulk Export Rule Applier could accidentally permit a Patient type level bulk export request, even if the calling user only had permissions to a subset of patients. This has been corrected." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml deleted file mode 100644 index 1e94d65c58d..00000000000 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml +++ /dev/null @@ -1,4 +0,0 @@ ---- -type: fix -issue: 5917 -title: "Fix chained sorts on strings when using MS Sql" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md index 412efaf27a8..2fea34f786b 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md @@ -14,9 +14,4 @@ This interceptor is intended to be subclassed. A simple example is shown below: ## Combining with Bulk Export -The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. -An interceptor on the `STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is the recommended way to set these properties when a new Bulk Export job is being kicked off. - -NB: Previous versions recommended using the `STORAGE_INITIATE_BULK_EXPORT` pointcut, but this is no longer the recommended way. -`STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is called before `STORAGE_INITIATE_BULK_EXPORT` and is thus guaranteed to be called before -any AuthorizationInterceptors. +The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. An interceptor on the `STORAGE_INITIATE_BULK_EXPORT` pointcut is the easiest way to set these properties when a new Bulk Export job is being kicked off. diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java index 94eddb83955..8f79e37ecb9 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java @@ -26,7 +26,6 @@ import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao; import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -import com.google.common.annotations.VisibleForTesting; import com.google.common.hash.HashingInputStream; import com.google.common.io.ByteStreams; import jakarta.annotation.Nonnull; @@ -60,8 +59,6 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp @Autowired private IBinaryStorageEntityDao myBinaryStorageEntityDao; - private boolean mySupportLegacyLobServer = false; - @Nonnull @Override @Transactional(propagation = Propagation.REQUIRED) @@ -99,10 +96,9 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp entity.setContentId(id); entity.setStorageContentBin(loadedStream); - if (mySupportLegacyLobServer) { - Blob dataBlob = lobHelper.createBlob(loadedStream); - entity.setBlob(dataBlob); - } + // TODO: remove writing Blob in a future release + Blob dataBlob = lobHelper.createBlob(loadedStream); + entity.setBlob(dataBlob); // Update the entity with the final byte count and hash long bytes = countingInputStream.getByteCount(); @@ -173,11 +169,6 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return copyBinaryContentToByteArray(entityOpt); } - public DatabaseBinaryContentStorageSvcImpl setSupportLegacyLobServer(boolean theSupportLegacyLobServer) { - mySupportLegacyLobServer = theSupportLegacyLobServer; - return this; - } - void copyBinaryContentToOutputStream(OutputStream theOutputStream, BinaryStorageEntity theEntity) throws IOException { @@ -221,10 +212,4 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return retVal; } - - @VisibleForTesting - public DatabaseBinaryContentStorageSvcImpl setEntityManagerForTesting(EntityManager theEntityManager) { - myEntityManager = theEntityManager; - return this; - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java index 67a7f55d28e..e60974ae642 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java @@ -73,7 +73,6 @@ import ca.uhn.fhir.jpa.delete.DeleteConflictFinderService; import ca.uhn.fhir.jpa.delete.DeleteConflictService; import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc; import ca.uhn.fhir.jpa.entity.Search; -import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceServiceRegistry; import ca.uhn.fhir.jpa.graphql.DaoRegistryGraphQLStorageServices; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; @@ -155,8 +154,6 @@ import ca.uhn.fhir.jpa.term.TermCodeSystemStorageSvcImpl; import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermReadSvcImpl; import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl; -import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulator; -import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulatorFactory; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; @@ -825,17 +822,6 @@ public class JpaConfig { return new TermReadSvcImpl(); } - @Bean - public ValueSetConceptAccumulatorFactory valueSetConceptAccumulatorFactory() { - return new ValueSetConceptAccumulatorFactory(); - } - - @Bean - @Scope("prototype") - public ValueSetConceptAccumulator valueSetConceptAccumulator(TermValueSet theTermValueSet) { - return valueSetConceptAccumulatorFactory().create(theTermValueSet); - } - @Bean public ITermCodeSystemStorageSvc termCodeSystemStorageSvc() { return new TermCodeSystemStorageSvcImpl(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 1e786ad5070..686667b2813 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -1410,20 +1410,19 @@ public abstract class BaseHapiFhirResourceDao extends B } @Override + @Transactional public MT metaGetOperation(Class theType, IIdType theId, RequestDetails theRequest) { - return myTransactionService.withRequest(theRequest).execute(() -> { - Set tagDefs = new HashSet<>(); - BaseHasResource entity = readEntity(theId, theRequest); - for (BaseTag next : entity.getTags()) { - tagDefs.add(next.getTag()); - } - MT retVal = toMetaDt(theType, tagDefs); + Set tagDefs = new HashSet<>(); + BaseHasResource entity = readEntity(theId, theRequest); + for (BaseTag next : entity.getTags()) { + tagDefs.add(next.getTag()); + } + MT retVal = toMetaDt(theType, tagDefs); - retVal.setLastUpdated(entity.getUpdatedDate()); - retVal.setVersionId(Long.toString(entity.getVersion())); + retVal.setLastUpdated(entity.getUpdatedDate()); + retVal.setVersionId(Long.toString(entity.getVersion())); - return retVal; - }); + return retVal; } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java index d238278bcfe..57674d4cfc7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java @@ -24,7 +24,6 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.search.DeferConceptIndexingRoutingBinder; import ca.uhn.fhir.util.ValidateUtil; -import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -59,7 +58,10 @@ import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.RoutingBinderR import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectPath; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyBinding; +import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue; import org.hl7.fhir.r4.model.Coding; import java.io.Serializable; @@ -175,11 +177,6 @@ public class TermConcept implements Serializable { @Column(name = "PARENT_PIDS", nullable = true) private String myParentPids; - @FullTextField( - name = "myParentPids", - searchable = Searchable.YES, - projectable = Projectable.YES, - analyzer = "conceptParentPidsAnalyzer") @Column(name = "PARENT_PIDS_VC", nullable = true, length = Length.LONG32) private String myParentPidsVc; @@ -192,9 +189,6 @@ public class TermConcept implements Serializable { @Column(name = "CODE_SEQUENCE", nullable = true) private Integer mySequence; - @Transient - private boolean mySupportLegacyLob = false; - public TermConcept() { super(); } @@ -368,6 +362,13 @@ public class TermConcept implements Serializable { return this; } + @Transient + @FullTextField( + name = "myParentPids", + searchable = Searchable.YES, + projectable = Projectable.YES, + analyzer = "conceptParentPidsAnalyzer") + @IndexingDependency(derivedFrom = @ObjectPath({@PropertyValue(propertyName = "myParentPidsVc")})) public String getParentPidsAsString() { return nonNull(myParentPidsVc) ? myParentPidsVc : myParentPids; } @@ -457,10 +458,6 @@ public class TermConcept implements Serializable { ourLog.trace("Code {}/{} has parents {}", entity.getId(), entity.getCode(), entity.getParentPidsAsString()); } - - if (!mySupportLegacyLob) { - clearParentPidsLob(); - } } private void setParentPids(Set theParentPids) { @@ -522,17 +519,4 @@ public class TermConcept implements Serializable { public List getChildCodes() { return getChildren().stream().map(TermConceptParentChildLink::getChild).collect(Collectors.toList()); } - - public void flagForLegacyLobSupport(boolean theSupportLegacyLob) { - mySupportLegacyLob = theSupportLegacyLob; - } - - private void clearParentPidsLob() { - myParentPids = null; - } - - @VisibleForTesting - public boolean hasParentPidsLobForTesting() { - return nonNull(myParentPids); - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java index 790dc9048c7..6bbc3b178a4 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java @@ -54,7 +54,6 @@ import org.hibernate.validator.constraints.NotBlank; import java.io.Serializable; import java.nio.charset.StandardCharsets; -import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -308,15 +307,9 @@ public class TermConceptProperty implements Serializable { return myId; } - public void performLegacyLobSupport(boolean theSupportLegacyLob) { - if (!theSupportLegacyLob) { - myValueLob = null; - } - } - @VisibleForTesting - public boolean hasValueBlobForTesting() { - return nonNull(myValueLob); + public byte[] getValueBlobForTesting() { + return myValueLob; } @VisibleForTesting @@ -325,8 +318,8 @@ public class TermConceptProperty implements Serializable { } @VisibleForTesting - public boolean hasValueBinForTesting() { - return nonNull(myValueBin); + public byte[] getValueBinForTesting() { + return myValueBin; } @VisibleForTesting diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java index c822c56046c..2e17bc6ae9c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java @@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.entity; import ca.uhn.fhir.util.ValidateUtil; -import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -47,7 +46,6 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; -import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -298,13 +296,4 @@ public class TermValueSetConcept implements Serializable { ? mySourceConceptDirectParentPidsVc : mySourceConceptDirectParentPids; } - - public void clearSourceConceptDirectParentPidsLob() { - mySourceConceptDirectParentPids = null; - } - - @VisibleForTesting - public boolean hasSourceConceptDirectParentPidsLob() { - return nonNull(mySourceConceptDirectParentPids); - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java index 28f80e15c62..c66c41a9b7e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java @@ -43,21 +43,20 @@ import java.sql.SQLException; * because hibernate won't allow the view the function without it, but */ "SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " + " vsc.PID AS CONCEPT_PID, " - + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " - + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " - + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " - + " vsc.CODEVAL AS CONCEPT_CODEVAL, " - + " vsc.DISPLAY AS CONCEPT_DISPLAY, " - + " vsc.SYSTEM_VER AS SYSTEM_VER, " - + " vsc.SOURCE_PID AS SOURCE_PID, " - + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " - + " vsc.SOURCE_DIRECT_PARENT_PIDS_VC AS SOURCE_DIRECT_PARENT_PIDS_VC, " - + " vscd.PID AS DESIGNATION_PID, " - + " vscd.LANG AS DESIGNATION_LANG, " - + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " - + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " - + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " - + " vscd.VAL AS DESIGNATION_VAL " + + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + + " vsc.CODEVAL AS CONCEPT_CODEVAL, " + + " vsc.DISPLAY AS CONCEPT_DISPLAY, " + + " vsc.SYSTEM_VER AS SYSTEM_VER, " + + " vsc.SOURCE_PID AS SOURCE_PID, " + + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " + + " vscd.PID AS DESIGNATION_PID, " + + " vscd.LANG AS DESIGNATION_LANG, " + + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " + + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + + " vscd.VAL AS DESIGNATION_VAL " + "FROM TRM_VALUESET_CONCEPT vsc " + "LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID") public class TermValueSetConceptView implements Serializable, ITermValueSetConceptView { @@ -113,9 +112,6 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true) private Clob mySourceConceptDirectParentPids; - @Column(name = "SOURCE_DIRECT_PARENT_PIDS_VC", nullable = true) - private String mySourceConceptDirectParentPidsVc; - @Override public Long getSourceConceptPid() { return mySourceConceptPid; @@ -123,19 +119,14 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Override public String getSourceConceptDirectParentPids() { - String retVal = null; - if (mySourceConceptDirectParentPids != null) { try (Reader characterStream = mySourceConceptDirectParentPids.getCharacterStream()) { - retVal = IOUtils.toString(characterStream); + return IOUtils.toString(characterStream); } catch (IOException | SQLException e) { throw new InternalErrorException(Msg.code(828) + e); } - } else if (mySourceConceptDirectParentPidsVc != null) { - retVal = mySourceConceptDirectParentPidsVc; } - - return retVal; + return null; } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 03a34c96468..3c421278e10 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.entity.BulkImportJobEntity; import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask; -import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateHashesTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateOrdinalDatesTask; import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeEnum; @@ -147,16 +146,8 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { binaryStorageBlobTable .renameColumn("20240404.1", "BLOB_ID", "CONTENT_ID") - .getLastAddedTask() - .ifPresent(BaseTask::doNothing); - binaryStorageBlobTable .renameColumn("20240404.2", "BLOB_SIZE", "CONTENT_SIZE") - .getLastAddedTask() - .ifPresent(BaseTask::doNothing); - binaryStorageBlobTable - .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH") - .getLastAddedTask() - .ifPresent(BaseTask::doNothing); + .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH"); binaryStorageBlobTable .modifyColumn("20240404.4", "BLOB_DATA") @@ -168,23 +159,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - binaryStorageBlobTable - .migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN") - .doNothing(); + binaryStorageBlobTable.migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN"); - binaryStorageBlobTable - .renameTable("20240404.7", "HFJ_BINARY_STORAGE") - .doNothing(); - - Builder.BuilderWithTableName binaryStorageTableFix = version.onTable("HFJ_BINARY_STORAGE"); - - binaryStorageTableFix.renameColumn("20240404.10", "CONTENT_ID", "BLOB_ID", true, true); - binaryStorageTableFix.renameColumn("20240404.20", "CONTENT_SIZE", "BLOB_SIZE", true, true); - binaryStorageTableFix.renameColumn("20240404.30", "CONTENT_HASH", "BLOB_HASH", true, true); - - binaryStorageTableFix - .renameTable("20240404.40", "HFJ_BINARY_STORAGE_BLOB") - .failureAllowed(); + binaryStorageBlobTable.renameTable("20240404.7", "HFJ_BINARY_STORAGE"); } { @@ -195,9 +172,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - termConceptPropertyTable - .migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN") - .doNothing(); + termConceptPropertyTable.migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN"); } { @@ -207,9 +182,8 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termValueSetConceptTable - .migrateClobToText("20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC") - .doNothing(); + termValueSetConceptTable.migrateClobToText( + "20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC"); } { @@ -219,9 +193,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termConceptTable - .migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC") - .doNothing(); + termConceptTable.migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC"); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java index 6202049515d..bbc74d27dd5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java @@ -37,7 +37,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { IPartitionLookupSvc myPartitionConfigSvc; @Override - public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + protected RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { List names = null; for (int i = 0; i < theRequestPartitionId.getPartitionIds().size(); i++) { @@ -59,7 +59,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } } - if (theRequestPartitionId.hasPartitionNames()) { + if (theRequestPartitionId.getPartitionNames() != null) { if (partition == null) { Validate.isTrue( theRequestPartitionId.getPartitionIds().get(i) == null, @@ -68,8 +68,8 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } else { Validate.isTrue( Objects.equals( - theRequestPartitionId.getPartitionNames().get(i), partition.getName()), - "Partition name %s does not match ID %s", + theRequestPartitionId.getPartitionIds().get(i), partition.getId()), + "Partition name %s does not match ID %n", theRequestPartitionId.getPartitionNames().get(i), theRequestPartitionId.getPartitionIds().get(i)); } @@ -94,7 +94,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } @Override - public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + protected RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { List ids = null; for (int i = 0; i < theRequestPartitionId.getPartitionNames().size(); i++) { @@ -122,9 +122,9 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { Validate.isTrue( Objects.equals( theRequestPartitionId.getPartitionIds().get(i), partition.getId()), - "Partition ID %s does not match name %s", - theRequestPartitionId.getPartitionIds().get(i), - theRequestPartitionId.getPartitionNames().get(i)); + "Partition name %s does not match ID %n", + theRequestPartitionId.getPartitionNames().get(i), + theRequestPartitionId.getPartitionIds().get(i)); } } else { if (ids == 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 685f96c16f8..4f0b3e60778 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 @@ -353,39 +353,26 @@ public class QueryStack { throw new InvalidRequestException(Msg.code(2289) + msg); } - // add a left-outer join to a predicate for the target type, then sort on value columns(s). + BaseSearchParamPredicateBuilder chainedPredicateBuilder; + DbColumn[] sortColumn; switch (targetSearchParameter.getParamType()) { case STRING: StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder(); - addSortCustomJoin( - resourceLinkPredicateBuilder.getColumnTargetResourceId(), - stringPredicateBuilder, - stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); - - mySqlBuilder.addSortString( - stringPredicateBuilder.getColumnValueNormalized(), theAscending, myUseAggregate); - return; - + sortColumn = new DbColumn[] {stringPredicateBuilder.getColumnValueNormalized()}; + chainedPredicateBuilder = stringPredicateBuilder; + break; case TOKEN: TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder(); - addSortCustomJoin( - resourceLinkPredicateBuilder.getColumnTargetResourceId(), - tokenPredicateBuilder, - tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); - - mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnSystem(), theAscending, myUseAggregate); - mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnValue(), theAscending, myUseAggregate); - return; - + sortColumn = + new DbColumn[] {tokenPredicateBuilder.getColumnSystem(), tokenPredicateBuilder.getColumnValue() + }; + chainedPredicateBuilder = tokenPredicateBuilder; + break; case DATE: DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder(); - addSortCustomJoin( - resourceLinkPredicateBuilder.getColumnTargetResourceId(), - datePredicateBuilder, - datePredicateBuilder.createHashIdentityPredicate(targetType, theChain)); - - mySqlBuilder.addSortDate(datePredicateBuilder.getColumnValueLow(), theAscending, myUseAggregate); - return; + sortColumn = new DbColumn[] {datePredicateBuilder.getColumnValueLow()}; + chainedPredicateBuilder = datePredicateBuilder; + break; /* * Note that many of the options below aren't implemented because they @@ -430,6 +417,14 @@ public class QueryStack { + theParamName + "." + theChain + " as this parameter. Can not sort on chains of target type: " + targetSearchParameter.getParamType().name()); } + + addSortCustomJoin(resourceLinkPredicateBuilder.getColumnTargetResourceId(), chainedPredicateBuilder, null); + Condition predicate = chainedPredicateBuilder.createHashIdentityPredicate(targetType, theChain); + mySqlBuilder.addPredicate(predicate); + + for (DbColumn next : sortColumn) { + mySqlBuilder.addSortNumeric(next, theAscending, myUseAggregate); + } } public void addSortOnString(String theResourceName, String theParamName, boolean theAscending) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java index 15998b0e8e6..61fbea5830e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java @@ -73,6 +73,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; @@ -684,6 +685,26 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { } } + private int ensureParentsSaved(Collection theParents) { + ourLog.trace("Checking {} parents", theParents.size()); + int retVal = 0; + + for (TermConceptParentChildLink nextLink : theParents) { + if (nextLink.getRelationshipType() == TermConceptParentChildLink.RelationshipTypeEnum.ISA) { + TermConcept nextParent = nextLink.getParent(); + retVal += ensureParentsSaved(nextParent.getParents()); + if (nextParent.getId() == null) { + nextParent.setUpdated(new Date()); + myConceptDao.saveAndFlush(nextParent); + retVal++; + ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); + } + } + } + + return retVal; + } + @Nonnull private TermCodeSystem getOrCreateDistinctTermCodeSystem( IResourcePersistentId theCodeSystemResourcePid, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java index 1927de43500..9bcf47aebb0 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java @@ -46,8 +46,6 @@ public class TermConceptDaoSvc { @Autowired protected ITermConceptDesignationDao myConceptDesignationDao; - private boolean mySupportLegacyLob = false; - public int saveConcept(TermConcept theConcept) { int retVal = 0; @@ -72,11 +70,9 @@ public class TermConceptDaoSvc { retVal++; theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED); theConcept.setUpdated(new Date()); - theConcept.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.save(theConcept); for (TermConceptProperty next : theConcept.getProperties()) { - next.performLegacyLobSupport(mySupportLegacyLob); myConceptPropertyDao.save(next); } @@ -89,11 +85,6 @@ public class TermConceptDaoSvc { return retVal; } - public TermConceptDaoSvc setSupportLegacyLob(boolean theSupportLegacyLob) { - mySupportLegacyLob = theSupportLegacyLob; - return this; - } - private int ensureParentsSaved(Collection theParents) { ourLog.trace("Checking {} parents", theParents.size()); int retVal = 0; @@ -104,7 +95,6 @@ public class TermConceptDaoSvc { retVal += ensureParentsSaved(nextParent.getParents()); if (nextParent.getId() == null) { nextParent.setUpdated(new Date()); - nextParent.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.saveAndFlush(nextParent); retVal++; ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); 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 2705ed40fe5..86235e0403b 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 @@ -293,9 +293,6 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { @Autowired private InMemoryTerminologyServerValidationSupport myInMemoryTerminologyServerValidationSupport; - @Autowired - private ValueSetConceptAccumulatorFactory myValueSetConceptAccumulatorFactory; - @Override public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { TermCodeSystemVersionDetails cs = getCurrentCodeSystemVersion(theSystem); @@ -2396,11 +2393,11 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { }); assert valueSet != null; - ValueSetConceptAccumulator valueSetConceptAccumulator = - myValueSetConceptAccumulatorFactory.create(valueSetToExpand); + ValueSetConceptAccumulator accumulator = new ValueSetConceptAccumulator( + valueSetToExpand, myTermValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); ValueSetExpansionOptions options = new ValueSetExpansionOptions(); options.setIncludeHierarchy(true); - expandValueSet(options, valueSet, valueSetConceptAccumulator); + expandValueSet(options, valueSet, accumulator); // We are done with this ValueSet. txTemplate.executeWithoutResult(t -> { @@ -2415,7 +2412,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { "Pre-expanded ValueSet[{}] with URL[{}] - Saved {} concepts in {}", valueSet.getId(), valueSet.getUrl(), - valueSetConceptAccumulator.getConceptsSaved(), + accumulator.getConceptsSaved(), sw); } catch (Exception e) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java index 9aa38413bb7..6561495ad45 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java @@ -48,8 +48,6 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { private int myDesignationsSaved; private int myConceptsExcluded; - private boolean mySupportLegacyLob = false; - public ValueSetConceptAccumulator( @Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetDao theValueSetDao, @@ -186,10 +184,6 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { concept.setSourceConceptPid(theSourceConceptPid); concept.setSourceConceptDirectParentPids(theSourceConceptDirectParentPids); - if (!mySupportLegacyLob) { - concept.clearSourceConceptDirectParentPidsLob(); - } - myValueSetConceptDao.save(concept); myValueSetDao.save(myTermValueSet.incrementTotalConcepts()); @@ -259,9 +253,4 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { // TODO: DM 2019-07-16 - If so, we should also populate TermValueSetConceptProperty entities here. // TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they may be needed to facilitate // filters and parameterized expansions. - - public ValueSetConceptAccumulator setSupportLegacyLob(boolean theSupportLegacyLob) { - mySupportLegacyLob = theSupportLegacyLob; - return this; - } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java deleted file mode 100644 index e61da193b8a..00000000000 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java +++ /dev/null @@ -1,51 +0,0 @@ -/*- - * #%L - * HAPI FHIR JPA Server - * %% - * 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.jpa.term; - -import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; -import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao; -import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao; -import ca.uhn.fhir.jpa.dao.data.ITermValueSetDao; -import ca.uhn.fhir.jpa.entity.TermValueSet; -import org.springframework.beans.factory.annotation.Autowired; - -public class ValueSetConceptAccumulatorFactory { - - @Autowired - private ITermValueSetDao myValueSetDao; - - @Autowired - private ITermValueSetConceptDao myValueSetConceptDao; - - @Autowired - private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao; - - @Autowired - private JpaStorageSettings myStorageSettings; - - public ValueSetConceptAccumulator create(TermValueSet theTermValueSet) { - ValueSetConceptAccumulator valueSetConceptAccumulator = new ValueSetConceptAccumulator( - theTermValueSet, myValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); - - valueSetConceptAccumulator.setSupportLegacyLob(myStorageSettings.isWriteToLegacyLobColumns()); - - return valueSetConceptAccumulator; - } -} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java index 44132dbdbd6..297d0726ce3 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java @@ -19,7 +19,6 @@ */ package ca.uhn.fhir.jpa.term.config; -import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.term.TermConceptDaoSvc; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemDeleteJobSvc; @@ -42,7 +41,7 @@ public class TermCodeSystemConfig { } @Bean - public TermConceptDaoSvc termConceptDaoSvc(JpaStorageSettings theJpaStorageSettings) { - return new TermConceptDaoSvc().setSupportLegacyLob(theJpaStorageSettings.isWriteToLegacyLobColumns()); + public TermConceptDaoSvc termConceptDaoSvc() { + return new TermConceptDaoSvc(); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java index cda9c4554a9..44a01649cfd 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java @@ -2,11 +2,8 @@ package ca.uhn.fhir.jpa.entity; import com.google.common.base.Strings; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; @@ -24,8 +21,8 @@ public class TermConceptPropertyTest { termConceptProperty.setValue(ourVeryLongString); // then - assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(true)); - assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); + assertThat(termConceptProperty.getValueBlobForTesting(), notNullValue()); + assertThat(termConceptProperty.getValueBinForTesting(), notNullValue()); } @Test @@ -81,19 +78,4 @@ public class TermConceptPropertyTest { assertThat(value, startsWith("a")); } - @ParameterizedTest - @ValueSource(booleans = {false, true}) - public void testSetValue_withSupportLegacyLob(boolean theSupportLegacyLob){ - // given - TermConceptProperty termConceptProperty = new TermConceptProperty(); - - // when - termConceptProperty.setValue(ourVeryLongString); - termConceptProperty.performLegacyLobSupport(theSupportLegacyLob); - - // then - assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); - assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(theSupportLegacyLob)); - } - } diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java index 690d2cc061d..5165581e3ef 100644 --- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java +++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java @@ -166,7 +166,6 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc { HookParams params = new HookParams(); params.add(MdmMergeEvent.class, event); params.add(RequestDetails.class, theParams.getRequestDetails()); - params.add(MdmTransactionContext.class, theParams.getMdmTransactionContext()); myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES, params); } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java index 5e3aaad9f42..febcaf4c6e9 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java @@ -2,16 +2,11 @@ package ca.uhn.fhir.jpa.mdm.svc; import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test; import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService; -import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum; -import ca.uhn.fhir.mdm.api.MdmMatchOutcome; import ca.uhn.fhir.mdm.model.MdmTransactionContext; -import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.util.List; - import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -60,21 +55,4 @@ class MdmSurvivorshipSvcImplIT extends BaseMdmR4Test { assertEquals(p1.getTelecom().size(), p1.getTelecom().size()); assertTrue(p2.getTelecomFirstRep().equalsDeep(p1.getTelecomFirstRep())); } - - @Test - public void matchingPatientsWith_NON_Numeric_Ids_matches_doesNotThrow_NumberFormatException() { - final Patient frankPatient1 = buildFrankPatient(); - frankPatient1.setId("patA"); - myPatientDao.update(frankPatient1, new SystemRequestDetails()); - final Patient frankPatient2 = buildFrankPatient(); - frankPatient2.setId("patB"); - myPatientDao.update(frankPatient2, new SystemRequestDetails()); - final Patient goldenPatient = buildFrankPatient(); - myPatientDao.create(goldenPatient, new SystemRequestDetails()); - - myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); - myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient2, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); - - myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK)); - } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java index 65cc7bde0c4..a6502687415 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java @@ -25,9 +25,8 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -97,9 +96,8 @@ public class MdmSurvivorshipSvcImplTest { } @SuppressWarnings({"rawtypes", "unchecked"}) - @ParameterizedTest - @ValueSource(booleans = {true,false}) - public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder(boolean theIsUseNonNumericId) { + @Test + public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder() { // setup // create resources Patient goldenPatient = new Patient(); @@ -128,7 +126,7 @@ public class MdmSurvivorshipSvcImplTest { patient.addIdentifier() .setSystem("http://example.com") .setValue("Value" + i); - patient.setId("Patient/" + (theIsUseNonNumericId ? "pat"+i : Integer.toString(i))); + patient.setId("Patient/" + i); resources.add(patient); MdmLinkJson link = createLinkJson( @@ -151,13 +149,8 @@ public class MdmSurvivorshipSvcImplTest { when(myDaoRegistry.getResourceDao(eq("Patient"))) .thenReturn(resourceDao); AtomicInteger counter = new AtomicInteger(); - if (theIsUseNonNumericId) { - when(resourceDao.read(any(), any())) - .thenAnswer(params -> resources.get(counter.getAndIncrement())); - } else { - when(resourceDao.readByPid(any())) - .thenAnswer(params -> resources.get(counter.getAndIncrement())); - } + when(resourceDao.readByPid(any())) + .thenAnswer(params -> resources.get(counter.getAndIncrement())); Page linkPage = mock(Page.class); when(myMdmLinkQuerySvc.queryLinks(any(), any())) .thenReturn(linkPage); diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java index c6b046e0bff..c71b8e29fda 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java @@ -34,26 +34,23 @@ import java.util.Date; import static java.util.Objects.nonNull; @Entity -@Table(name = "HFJ_BINARY_STORAGE_BLOB") +@Table(name = "HFJ_BINARY_STORAGE") public class BinaryStorageEntity { @Id - @Column(name = "BLOB_ID", length = 200, nullable = false) + @Column(name = "CONTENT_ID", length = 200, nullable = false) // N.B GGG: Note that the `content id` is the same as the `externalized binary id`. private String myContentId; @Column(name = "RESOURCE_ID", length = 100, nullable = false) private String myResourceId; - @Column(name = "BLOB_SIZE", nullable = true) + @Column(name = "CONTENT_SIZE", nullable = true) private long mySize; @Column(name = "CONTENT_TYPE", nullable = false, length = 100) private String myContentType; - /** - * @deprecated - */ @Deprecated(since = "7.2.0") @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "BLOB_DATA", nullable = true, insertable = true, updatable = false) @@ -66,7 +63,7 @@ public class BinaryStorageEntity { @Column(name = "PUBLISHED_DATE", nullable = false) private Date myPublished; - @Column(name = "BLOB_HASH", length = 128, nullable = true) + @Column(name = "CONTENT_HASH", length = 128, nullable = true) private String myHash; public Date getPublished() { diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java index ede4b39e7ca..cf17cf5af41 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java @@ -156,30 +156,4 @@ public interface IRequestPartitionHelperSvc { Set toReadPartitions(@Nonnull RequestPartitionId theRequestPartitionId); boolean isResourcePartitionable(String theResourceType); - - /** - * No interceptors should be invoked by this method. It should ONLY be used when partition ids are - * known, but partition names are not. - *

    - * Ensures the list of partition ids inside the given {@link RequestPartitionId} correctly map to the - * list of partition names. If the list of partition names is empty, this method will map the correct - * partition names and return a normalized {@link RequestPartitionId}. - *

    - * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. - * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. - */ - RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); - - /** - * No interceptors should be invoked by this method. It should ONLY be used when partition names are - * known, but partition ids are not. - *

    - * Ensures the list of partition names inside the given {@link RequestPartitionId} correctly map to the - * list of partition ids. If the list of partition ids is empty, this method will map the correct - * partition ids and return a normalized {@link RequestPartitionId}. - *

    - * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. - * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. - */ - RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); } diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java deleted file mode 100644 index 4d95a057c54..00000000000 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java +++ /dev/null @@ -1,35 +0,0 @@ -/*- - * #%L - * HAPI FHIR Subscription Server - * %% - * 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.jpa.subscription.config; - -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; -import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class SubscriptionConfig { - @Bean - public SubscriptionQueryValidator subscriptionQueryValidator( - DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { - return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); - } -} diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java index ff056ad9207..65e0d2010a7 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java @@ -19,13 +19,15 @@ */ package ca.uhn.fhir.jpa.subscription.submit.config; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedProcessingSchedulerSvc; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedSubmitterSvc; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory; -import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; +import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; import ca.uhn.fhir.jpa.subscription.model.config.SubscriptionModelConfig; +import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionValidatingInterceptor; import ca.uhn.fhir.jpa.subscription.submit.svc.ResourceModifiedSubmitterSvc; @@ -43,7 +45,7 @@ import org.springframework.context.annotation.Lazy; * matching queue for processing */ @Configuration -@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class, SubscriptionConfig.class}) +@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class}) public class SubscriptionSubmitterConfig { @Bean @@ -51,6 +53,12 @@ public class SubscriptionSubmitterConfig { return new SubscriptionValidatingInterceptor(); } + @Bean + public SubscriptionQueryValidator subscriptionQueryValidator( + DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { + return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); + } + @Bean public SubscriptionSubmitInterceptorLoader subscriptionMatcherInterceptorLoader() { return new SubscriptionSubmitInterceptorLoader(); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java index 802f43a47e5..4b571c7bd33 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java @@ -22,15 +22,13 @@ package ca.uhn.fhir.jpa.topic; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher; -import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; +import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; @Configuration -@Import(SubscriptionConfig.class) public class SubscriptionTopicConfig { @Bean SubscriptionTopicMatchingSubscriber subscriptionTopicMatchingSubscriber(FhirContext theFhirContext) { @@ -78,6 +76,13 @@ public class SubscriptionTopicConfig { } } + @Bean + @Lazy + public SubscriptionQueryValidator subscriptionQueryValidator( + DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { + return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); + } + @Bean SubscriptionTopicValidatingInterceptor subscriptionTopicValidatingInterceptor( FhirContext theFhirContext, SubscriptionQueryValidator theSubscriptionQueryValidator) { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java index ecca07f2b98..a0c6b7c4279 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java @@ -7,12 +7,8 @@ import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; -import jakarta.persistence.EntityManager; -import org.hibernate.LobHelper; -import org.hibernate.Session; import org.hl7.fhir.r4.model.IdType; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -28,7 +24,6 @@ import java.sql.SQLException; import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; -import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; @@ -39,7 +34,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -287,7 +281,7 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { } @Test - public void testStoreBinaryContent_byDefault_writesByteArrayOnly() throws IOException { + public void testStoreBinaryContent_writesBlobAndByteArray() throws IOException { // given ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); String contentType = "image/png"; @@ -302,41 +296,11 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { // then assertThat(binaryStorageEntity.hasStorageContent(), is(true)); - assertThat(binaryStorageEntity.hasBlob(), is(false)); + assertThat(binaryStorageEntity.hasBlob(), is(true)); }); } - @Test - public void testStoreBinaryContent_whenSupportingLegacyBlobServer_willStoreToBlobAndBinaryArray() throws IOException { - ArgumentCaptor captor = ArgumentCaptor.forClass(BinaryStorageEntity.class); - EntityManager mockedEntityManager = mock(EntityManager.class); - Session mockedSession = mock(Session.class); - LobHelper mockedLobHelper = mock(LobHelper.class); - when(mockedEntityManager.getDelegate()).thenReturn(mockedSession); - when(mockedSession.getLobHelper()).thenReturn(mockedLobHelper); - when(mockedLobHelper.createBlob(any())).thenReturn(mock(Blob.class)); - - // given - DatabaseBinaryContentStorageSvcImpl svc = new DatabaseBinaryContentStorageSvcImpl() - .setSupportLegacyLobServer(true) - .setEntityManagerForTesting(mockedEntityManager); - - ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); - String contentType = "image/png"; - IdType resourceId = new IdType("Binary/123"); - - // when - svc.storeBinaryContent(resourceId, null, contentType, inputStream, new ServletRequestDetails()); - - // then - verify(mockedEntityManager, times(1)).persist(captor.capture()); - BinaryStorageEntity capturedBinaryStorageEntity = captor.getValue(); - - assertThat(capturedBinaryStorageEntity.hasBlob(), equalTo(true)); - assertThat(capturedBinaryStorageEntity.hasStorageContent(), equalTo(true)); - } - @Configuration public static class MyConfig { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java index 95ab54ddb19..7efc920ccaf 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java @@ -9,11 +9,8 @@ import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.jpa.util.SqlQuery; import ca.uhn.fhir.jpa.util.SqlQueryList; -import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.storage.test.DaoTestDataBuilder; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -36,8 +33,6 @@ import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; /** * Sandbox for implementing queries. @@ -142,28 +137,6 @@ public class FhirResourceDaoR4QuerySandbox extends BaseJpaTest { myTestDaoSearch.assertSearchFindsInOrder("reverse sort by server assigned id", "Patient?family=smith&_sort=-_pid", id3,id2,id1); } - @Test - void testChainedSort() { - final IIdType practitionerId = myDataBuilder.createPractitioner(myDataBuilder.withFamily("Jones")); - - final String id1 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithy")).getIdPart(); - final String id2 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithwick")).getIdPart(); - final String id3 = myDataBuilder.createPatient( - myDataBuilder.withFamily("Smith"), - myDataBuilder.withReference("generalPractitioner", practitionerId)).getIdPart(); - - - final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); - assertEquals(3, iBundleProvider.size()); - - final List allResources = iBundleProvider.getAllResources(); - assertEquals(3, iBundleProvider.size()); - assertEquals(3, allResources.size()); - - final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); - assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); - } - public static final class TestDirtiesContextTestExecutionListener extends DirtiesContextTestExecutionListener { @Override diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java index 53ff09b50c6..4f90f46bc41 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java @@ -1,189 +1,74 @@ package ca.uhn.fhir.jpa.partition; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.model.RequestPartitionId; -import ca.uhn.fhir.jpa.dao.data.IPartitionDao; import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.model.config.PartitionSettings; -import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; -import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Patient; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.beans.factory.annotation.Autowired; - -import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) -class RequestPartitionHelperSvcTest extends BaseJpaR4Test { +class RequestPartitionHelperSvcTest { + static final Integer PARTITION_ID = 2401; + static final String PARTITION_NAME = "JIMMY"; + static final PartitionEntity ourPartitionEntity = new PartitionEntity().setName(PARTITION_NAME); - static final int PARTITION_ID_1 = 1; - static final String PARTITION_NAME_1 = "SOME-PARTITION-1"; - - static final int PARTITION_ID_2 = 2; - static final String PARTITION_NAME_2 = "SOME-PARTITION-2"; - - static final int UNKNOWN_PARTITION_ID = 1_000_000; - static final String UNKNOWN_PARTITION_NAME = "UNKNOWN"; - - @Autowired - IPartitionDao myPartitionDao; - @Autowired + @Mock PartitionSettings myPartitionSettings; - @Autowired - RequestPartitionHelperSvc mySvc; + @Mock + IPartitionLookupSvc myPartitionLookupSvc; + @Mock + FhirContext myFhirContext; + @Mock + IInterceptorBroadcaster myInterceptorBroadcaster; - Patient myPatient; - - @BeforeEach - public void before(){ - myPartitionDao.deleteAll(); - myPartitionSettings.setPartitioningEnabled(true); - - myPatient = new Patient(); - myPatient.setId(new IdType("Patient", "123", "1")); - } + @InjectMocks + RequestPartitionHelperSvc mySvc = new RequestPartitionHelperSvc(); @Test - public void testDetermineReadPartitionForSystemRequest_withPartitionIdOnly_returnsCorrectPartition() { + public void determineReadPartitionForSystemRequest() { // setup - PartitionEntity partitionEntity = createPartition1(); SystemRequestDetails srd = new SystemRequestDetails(); - srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); + RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); + srd.setRequestPartitionId(requestPartitionId); + when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); + when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); // execute - RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, myPatient.fhirType(), myPatient.getIdElement()); + RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, "Patient", new IdType("Patient/123")); // verify - assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); } @Test - public void testDetermineCreatePartitionForRequest_withPartitionIdOnly_returnsCorrectPartition() { + public void determineCreatePartitionForSystemRequest() { // setup - PartitionEntity partitionEntity = createPartition1(); SystemRequestDetails srd = new SystemRequestDetails(); - srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); + RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); + srd.setRequestPartitionId(requestPartitionId); + when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); + when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); + Patient resource = new Patient(); + when(myFhirContext.getResourceType(resource)).thenReturn("Patient"); // execute - Patient patient = new Patient(); - RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, patient, patient.fhirType()); + RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, resource, "Patient"); // verify - assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); } - @Test - public void testValidateAndNormalizePartitionIds_withPartitionIdOnly_populatesPartitionName(){ - PartitionEntity partitionEntity = createPartition1(); - RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(partitionEntity.getId()); - RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); - - assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); - } - - @Test - public void testValidateAndNormalizePartitionIds_withUnknownId_throwsException(){ - RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(UNKNOWN_PARTITION_ID); - - try{ - mySvc.validateAndNormalizePartitionIds(partitionId); - fail(); - } catch (ResourceNotFoundException e){ - assertTrue(e.getMessage().contains("No partition exists with ID 1,000,000")); - } - } - - @Test - public void testValidateAndNormalizePartitionIds_withIdAndInvalidName_throwsException(){ - createPartition1(); - RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(PARTITION_ID_1, UNKNOWN_PARTITION_NAME); - - try{ - mySvc.validateAndNormalizePartitionIds(partitionId); - fail(); - } catch (IllegalArgumentException e){ - assertTrue(e.getMessage().contains("Partition name UNKNOWN does not match ID 1")); - } - } - - @Test - public void testValidateAndNormalizePartitionIds_withMultiplePartitionIdOnly_populatesPartitionNames(){ - PartitionEntity partitionEntity1 = createPartition1(); - PartitionEntity partitionEntity2 = createPartition2(); - - RequestPartitionId partitionId = RequestPartitionId.fromPartitionIds(partitionEntity1.getId(), partitionEntity2.getId()); - RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); - - assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); - assertNotNull(result.getPartitionNames()); - assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); - } - - @Test - public void testValidateAndNormalizePartitionNames_withPartitionNameOnly_populatesPartitionId(){ - PartitionEntity partitionEntity = createPartition1(); - RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(partitionEntity.getName()); - RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); - - assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); - } - - @Test - public void testValidateAndNormalizePartitionNames_withMultiplePartitionNamesOnly_populatesPartitionIds(){ - PartitionEntity partitionEntity1 = createPartition1(); - PartitionEntity partitionEntity2 = createPartition2(); - - RequestPartitionId partitionId = RequestPartitionId.fromPartitionNames(partitionEntity1.getName(), partitionEntity2.getName()); - RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); - - assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); - assertNotNull(result.getPartitionNames()); - assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); - } - - @Test - public void testValidateAndNormalizePartitionNames_withUnknownName_throwsException(){ - RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(UNKNOWN_PARTITION_NAME); - - try{ - mySvc.validateAndNormalizePartitionNames(partitionId); - fail(); - } catch (ResourceNotFoundException e){ - assertTrue(e.getMessage().contains("Partition name \"UNKNOWN\" is not valid")); - } - } - - @Test - public void testValidateAndNormalizePartitionNames_withNameAndInvalidId_throwsException(){ - createPartition1(); - RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(UNKNOWN_PARTITION_ID, PARTITION_NAME_1); - - try{ - mySvc.validateAndNormalizePartitionNames(partitionId); - fail(); - } catch (IllegalArgumentException e){ - assertTrue(e.getMessage().contains("Partition ID 1000000 does not match name SOME-PARTITION-1")); - } - } - - private PartitionEntity createPartition1() { - return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_1).setName(PARTITION_NAME_1)); - } - - private PartitionEntity createPartition2() { - return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_2).setName(PARTITION_NAME_2)); - } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java index c237dddcd6a..dcce168fa09 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java @@ -884,16 +884,6 @@ public class GiantTransactionPerfTest { return true; } - @Override - public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { - return RequestPartitionId.defaultPartition(); - } - - @Override - public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { - return RequestPartitionId.defaultPartition(); - } - } diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java index 50e2c2787c0..5cf0e2a4127 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java @@ -2,7 +2,6 @@ package ca.uhn.fhir.jpa.dao.r5; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; -import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; @@ -13,8 +12,6 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.BundleBuilder; import ca.uhn.fhir.util.HapiExtensions; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Composition; import org.hl7.fhir.r5.model.IdType; import org.hl7.fhir.r5.model.Bundle; @@ -32,7 +29,6 @@ import org.hl7.fhir.r5.model.SearchParameter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import jakarta.annotation.Nonnull; @@ -45,10 +41,9 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -@ContextConfiguration(classes = { TestHSearchAddInConfig.NoFT.class, TestDaoSearch.Config.class }) +@ContextConfiguration(classes = TestHSearchAddInConfig.NoFT.class) @SuppressWarnings({"Duplicates"}) public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String PRACTITIONER_PR1 = "Practitioner/PR1"; @@ -59,8 +54,6 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String ENCOUNTER_E2 = "Encounter/E2"; public static final String ENCOUNTER_E3 = "Encounter/E3"; public static final String ORGANIZATION_O1 = "Organization/O1"; - @Autowired - protected TestDaoSearch myTestDaoSearch; @Override @BeforeEach @@ -874,47 +867,6 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { assertEquals(1, countMatches(querySql, "HFJ_RES_LINK"), querySql); } - - @Test - void testChainedSortWithNulls() { - final IIdType practitionerId1 = createPractitioner(withFamily("Chan")); - final IIdType practitionerId2 = createPractitioner(withFamily("Jones")); - - final String id1 = createPatient(withFamily("Smithy")).getIdPart(); - final String id2 = createPatient(withFamily("Smithwick"), - withReference("generalPractitioner", practitionerId2)).getIdPart(); - final String id3 = createPatient( - withFamily("Smith"), - withReference("generalPractitioner", practitionerId1)).getIdPart(); - - - final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); - final List allResources = iBundleProvider.getAllResources(); - assertEquals(3, iBundleProvider.size()); - assertEquals(3, allResources.size()); - - final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); - assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); - } - - @Test - void testChainedReverseStringSort() { - final IIdType practitionerId = createPractitioner(withFamily("Jones")); - - final String id1 = createPatient(withFamily("Smithy")).getIdPart(); - final String id2 = createPatient(withFamily("Smithwick")).getIdPart(); - final String id3 = createPatient( - withFamily("Smith"), - withReference("generalPractitioner", practitionerId)).getIdPart(); - - final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=-Practitioner:general-practitioner.family"); - assertEquals(3, iBundleProvider.size()); - - final List allResources = iBundleProvider.getAllResources(); - final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); - assertTrue(actualIds.containsAll(List.of(id3, id2, id1))); - } - /** * Observation:focus is a Reference(Any) so it can't be used in a sort chain because * this would be horribly, horribly inefficient. diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java index beeef22ff91..e010f25669a 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java @@ -1,24 +1,38 @@ package ca.uhn.fhir.jpa.dao.r5.database; +import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; +import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeProvider; +import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient; -import ca.uhn.fhir.jpa.dao.TestDaoSearch; +import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters; import ca.uhn.fhir.jpa.embedded.JpaEmbeddedDatabase; +import ca.uhn.fhir.jpa.fql.provider.HfqlRestProvider; +import ca.uhn.fhir.jpa.graphql.GraphQLProvider; import ca.uhn.fhir.jpa.migrate.HapiMigrationStorageSvc; import ca.uhn.fhir.jpa.migrate.MigrationTaskList; import ca.uhn.fhir.jpa.migrate.SchemaMigrator; import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks; +import ca.uhn.fhir.jpa.provider.DiffProvider; +import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider; +import ca.uhn.fhir.jpa.provider.ProcessMessageProvider; +import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider; +import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; +import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.config.TestR5Config; +import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.SortSpec; +import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; +import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.server.RestfulServerConfigurerExtension; @@ -30,6 +44,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.IdType; +import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Patient; import org.junit.jupiter.api.Test; @@ -40,6 +55,7 @@ import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; @@ -47,8 +63,10 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.PlatformTransactionManager; +import org.springframework.web.cors.CorsConfiguration; import javax.sql.DataSource; +import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -62,7 +80,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(SpringExtension.class) @EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) -@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class, TestDaoSearch.Config.class}) +@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class}) public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements ITestDataBuilder { private static final Logger ourLog = LoggerFactory.getLogger(BaseDatabaseVerificationIT.class); private static final String MIGRATION_TABLENAME = "MIGRATIONS"; @@ -91,9 +109,6 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements @Autowired private DatabaseBackedPagingProvider myPagingProvider; - @Autowired - TestDaoSearch myTestDaoSearch; - @RegisterExtension protected RestfulServerExtension myServer = new RestfulServerExtension(FhirContext.forR5Cached()); @@ -160,20 +175,6 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0]))); } - @Test - void testChainedSort() { - // given - - // when - SearchParameterMap map = SearchParameterMap - .newSynchronous() - .setSort(new SortSpec("Practitioner:general-practitioner.family")); - myCaptureQueriesListener.clear(); - myPatientDao.search(map, mySrd); - - } - - @Configuration @@ -221,8 +222,8 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements } public static class JpaDatabaseContextConfigParamObject { - final JpaEmbeddedDatabase myJpaEmbeddedDatabase; - final String myDialect; + private JpaEmbeddedDatabase myJpaEmbeddedDatabase; + private String myDialect; public JpaDatabaseContextConfigParamObject(JpaEmbeddedDatabase theJpaEmbeddedDatabase, String theDialect) { myJpaEmbeddedDatabase = theJpaEmbeddedDatabase; diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java deleted file mode 100644 index ea05bc1ea9f..00000000000 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java +++ /dev/null @@ -1,57 +0,0 @@ -package ca.uhn.fhir.jpa.term; - -import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; -import ca.uhn.fhir.jpa.entity.TermConcept; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; -import org.mockito.InjectMocks; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.times; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -@ExtendWith(MockitoExtension.class) -public class TermConceptDaoSvcTest { - - @Mock - private ITermConceptDao myConceptDao; - - @InjectMocks - private TermConceptDaoSvc myTermConceptDaoSvc; - - @ParameterizedTest - @ValueSource(booleans = {false, true}) - public void testSaveConcept_withSupportLegacyLob(boolean theSupportLegacyLob){ - final String parentPids = "1 2 3 4 5 6 7 8 9"; - when(myConceptDao.save(any())).thenAnswer(t ->{ - TermConcept codeSystem = (TermConcept) t.getArguments()[0]; - codeSystem.prePersist(); - - return codeSystem; - }); - - ArgumentCaptor captor = ArgumentCaptor.forClass(TermConcept.class); - - // given - TermConcept termConcept = new TermConcept().setParentPids(parentPids); - - // when - myTermConceptDaoSvc.setSupportLegacyLob(theSupportLegacyLob); - myTermConceptDaoSvc.saveConcept(termConcept); - - // then - verify(myConceptDao, times(1)).save(captor.capture()); - TermConcept capturedTermConcept = captor.getValue(); - - assertThat(capturedTermConcept.hasParentPidsLobForTesting(), equalTo(theSupportLegacyLob)); - assertThat(capturedTermConcept.getParentPidsAsString(), equalTo(parentPids)); - } - -} diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java index dbb455d6e87..972a533ef2e 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java @@ -9,16 +9,11 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; @@ -79,22 +74,4 @@ public class ValueSetConceptAccumulatorTest { } - @ParameterizedTest - @ValueSource(booleans = {false, true}) - public void testPersistValueSetConcept_whenSupportLegacyLob(boolean theSupportLegacyLob){ - final String sourceConceptDirectParentPids = "1 2 3 4 5 6 7"; - ArgumentCaptor captor = ArgumentCaptor.forClass(TermValueSetConcept.class); - - myAccumulator.setSupportLegacyLob(theSupportLegacyLob); - myAccumulator.includeConcept("sys", "code", "display", null, sourceConceptDirectParentPids, null); - - verify(myValueSetConceptDao, times(1)).save(captor.capture()); - - TermValueSetConcept capturedTermValueSetConcept = captor.getValue(); - - assertThat(capturedTermValueSetConcept.hasSourceConceptDirectParentPidsLob(), equalTo(theSupportLegacyLob)); - assertThat(capturedTermValueSetConcept.getSourceConceptDirectParentPids(), equalTo(sourceConceptDirectParentPids)); - - } - } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java index 403db4605b6..27d89757a9c 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java @@ -31,22 +31,17 @@ import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters; import ca.uhn.fhir.mdm.model.MdmTransactionContext; import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson; import ca.uhn.fhir.mdm.util.GoldenResourceHelper; -import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import ca.uhn.fhir.util.TerserUtil; -import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; import org.springframework.data.domain.Page; -import java.util.regex.Pattern; import java.util.stream.Stream; public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { - private static final Pattern IS_UUID = - Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); protected final FhirContext myFhirContext; @@ -138,30 +133,16 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { String sourceId = link.getSourceId(); // +1 because of "/" in id: "ResourceType/Id" - final String sourceIdUnqualified = sourceId.substring(resourceType.length() + 1); + IResourcePersistentId pid = getResourcePID(sourceId.substring(resourceType.length() + 1), resourceType); - // myMdmLinkQuerySvc.queryLinks populates sourceId with the FHIR_ID, not the RES_ID, so if we don't - // add this conditional logic, on JPA, myIIdHelperService.newPidFromStringIdAndResourceName will fail with - // NumberFormatException - if (isNumericOrUuid(sourceIdUnqualified)) { - IResourcePersistentId pid = getResourcePID(sourceIdUnqualified, resourceType); - - // this might be a bit unperformant - // but it depends how many links there are - // per golden resource (unlikely to be thousands) - return dao.readByPid(pid); - } else { - return dao.read(new IdDt(sourceId), new SystemRequestDetails()); - } + // this might be a bit unperformant + // but it depends how many links there are + // per golden resource (unlikely to be thousands) + return dao.readByPid(pid); }); } private IResourcePersistentId getResourcePID(String theId, String theResourceType) { return myIIdHelperService.newPidFromStringIdAndResourceName(theId, theResourceType); } - - private boolean isNumericOrUuid(String theLongCandidate) { - return StringUtils.isNumeric(theLongCandidate) - || IS_UUID.matcher(theLongCandidate).matches(); - } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java index ffb08829bfe..04b897e8a08 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java @@ -22,8 +22,6 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; -import java.util.Collection; - public interface IAuthRuleBuilderOperationNamed { /** @@ -46,8 +44,6 @@ public interface IAuthRuleBuilderOperationNamed { */ IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId); - IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds); - /** * Rule applies to invocations of this operation at the instance level on any instance of the given type */ diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java index f45ab580540..8eb40512001 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java @@ -22,9 +22,6 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import jakarta.annotation.Nonnull; import org.hl7.fhir.instance.model.api.IIdType; -import java.util.Collection; -import java.util.stream.Collectors; - /** * @since 5.5.0 */ @@ -57,20 +54,10 @@ public interface IAuthRuleBuilderRuleBulkExport { IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId); - IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients(); - default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull IIdType theFocusResourceId) { return patientExportOnPatient(theFocusResourceId.getValue()); } - default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatients( - @Nonnull Collection theFocusResourceIds) { - return patientExportOnPatientStrings( - theFocusResourceIds.stream().map(IIdType::getValue).collect(Collectors.toList())); - } - - IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings(Collection theFocusResourceIds); - /** * Allow/deny patient-level export rule applies to the Group with the given resource ID, e.g. Group/123 * diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java index a98e2f1e32a..9316cd89d35 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java @@ -736,20 +736,6 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderOperationNamedAndScoped(rule); } - @Override - public IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds) { - Validate.notNull(theInstanceIds, "theInstanceIds must not be null"); - theInstanceIds.forEach(instanceId -> Validate.notBlank( - instanceId.getResourceType(), - "at least one of theInstanceIds does not have a resource type")); - theInstanceIds.forEach(instanceId -> Validate.notBlank( - instanceId.getIdPart(), "at least one of theInstanceIds does not have an ID part")); - - final OperationRule rule = createRule(); - rule.appliesToInstances(new ArrayList<>(theInstanceIds)); - return new RuleBuilderOperationNamedAndScoped(rule); - } - @Override public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType( Class theType) { @@ -883,7 +869,7 @@ public class RuleBuilder implements IAuthRuleBuilder { } private class RuleBuilderBulkExport implements IAuthRuleBuilderRuleBulkExport { - private RuleBulkExportImpl myRuleBulkExport; + private RuleBulkExportImpl ruleBulkExport; @Override public IAuthRuleBuilderRuleBulkExportWithTarget groupExportOnGroup(@Nonnull String theFocusResourceId) { @@ -895,60 +881,23 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderBulkExportWithTarget(rule); } - @Override - public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients() { - if (myRuleBulkExport == null) { - RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); - rule.setMode(myRuleMode); - myRuleBulkExport = rule; - } - myRuleBulkExport.setAppliesToPatientExportAllPatients(); - - // prevent duplicate rules being added - if (!myRules.contains(myRuleBulkExport)) { - myRules.add(myRuleBulkExport); - } - - return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); - } - @Override public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId) { - if (myRuleBulkExport == null) { + if (ruleBulkExport == null) { RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); rule.setAppliesToPatientExport(theFocusResourceId); rule.setMode(myRuleMode); - myRuleBulkExport = rule; + ruleBulkExport = rule; } else { - myRuleBulkExport.setAppliesToPatientExport(theFocusResourceId); + ruleBulkExport.setAppliesToPatientExport(theFocusResourceId); } // prevent duplicate rules being added - if (!myRules.contains(myRuleBulkExport)) { - myRules.add(myRuleBulkExport); + if (!myRules.contains(ruleBulkExport)) { + myRules.add(ruleBulkExport); } - return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); - } - - @Override - public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings( - @Nonnull Collection theFocusResourceIds) { - if (myRuleBulkExport == null) { - RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); - rule.setAppliesToPatientExport(theFocusResourceIds); - rule.setMode(myRuleMode); - myRuleBulkExport = rule; - } else { - myRuleBulkExport.setAppliesToPatientExport(theFocusResourceIds); - } - - // prevent duplicate rules being added - if (!myRules.contains(myRuleBulkExport)) { - myRules.add(myRuleBulkExport); - } - - return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); + return new RuleBuilderBulkExportWithTarget(ruleBulkExport); } @Override diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java index eadb0ee4c99..1686c157032 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java @@ -24,12 +24,12 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; -import com.google.common.annotations.VisibleForTesting; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import java.util.ArrayList; import java.util.Collection; +import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -42,7 +42,6 @@ public class RuleBulkExportImpl extends BaseRule { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuleBulkExportImpl.class); private String myGroupId; private final Collection myPatientIds; - private boolean myAppliesToAllPatients; private BulkExportJobParameters.ExportStyle myWantExportStyle; private Collection myResourceTypes; private boolean myWantAnyStyle; @@ -70,84 +69,113 @@ public class RuleBulkExportImpl extends BaseRule { return null; } - BulkExportJobParameters inboundBulkExportRequestOptions = (BulkExportJobParameters) + BulkExportJobParameters options = (BulkExportJobParameters) theRequestDetails.getAttribute(AuthorizationInterceptor.REQUEST_ATTRIBUTE_BULK_DATA_EXPORT_OPTIONS); - // if style doesn't match - abstain - if (!myWantAnyStyle && inboundBulkExportRequestOptions.getExportStyle() != myWantExportStyle) { + + if (!myWantAnyStyle && options.getExportStyle() != myWantExportStyle) { return null; } - // Do we only authorize some types? If so, make sure requested types are a subset if (isNotEmpty(myResourceTypes)) { - if (isEmpty(inboundBulkExportRequestOptions.getResourceTypes())) { - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - if (!myResourceTypes.containsAll(inboundBulkExportRequestOptions.getResourceTypes())) { - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - } - - // system only supports filtering by resource type. So if we are system, or any(), then allow, since we have - // done resource type checking - // above - AuthorizationInterceptor.Verdict allowVerdict = newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - - if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { - return allowVerdict; - } - - // assume myGroupId not empty->myStyle is group. If target group matches, then allow. - if (isNotBlank(myGroupId) && inboundBulkExportRequestOptions.getGroupId() != null) { - String expectedGroupId = - new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); - String actualGroupId = new IdDt(inboundBulkExportRequestOptions.getGroupId()) - .toUnqualifiedVersionless() - .getValue(); - if (Objects.equals(expectedGroupId, actualGroupId)) { - return allowVerdict; - } - } - // patient export mode - instance or type. type can have 0..n patient ids. - // myPatientIds == the rules built by the auth interceptor rule builder - // options.getPatientIds() == the requested IDs in the export job. - - // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve - // 2. If any requested ID is not present in the users permissions, Deny. - if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT) - // Unfiltered Type Level - if (myAppliesToAllPatients) { - return allowVerdict; - } - - // Instance level, or filtered type level - if (isNotEmpty(myPatientIds)) { - // If bulk export options defines no patient IDs, return null. - if (inboundBulkExportRequestOptions.getPatientIds().isEmpty()) { + if (isEmpty(options.getResourceTypes())) { return null; - } else { - ourLog.debug("options.getPatientIds() != null"); - Set requestedPatientIds = sanitizeIds(inboundBulkExportRequestOptions.getPatientIds()); - Set permittedPatientIds = sanitizeIds(myPatientIds); - if (permittedPatientIds.containsAll(requestedPatientIds)) { - return allowVerdict; - } else { + } + for (String next : options.getResourceTypes()) { + if (!myResourceTypes.contains(next)) { return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); } } } - return null; - } - private Set sanitizeIds(Collection myPatientIds) { - return myPatientIds.stream() - .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) - .collect(Collectors.toSet()); + if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { + return newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + } + + if (isNotBlank(myGroupId) && options.getGroupId() != null) { + String expectedGroupId = + new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); + String actualGroupId = + new IdDt(options.getGroupId()).toUnqualifiedVersionless().getValue(); + if (Objects.equals(expectedGroupId, actualGroupId)) { + return newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + } + } + + // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve + // 2. If any requested ID is not present in the users permissions, Deny. + if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT && isNotEmpty(myPatientIds)) { + List permittedPatientIds = myPatientIds.stream() + .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) + .collect(Collectors.toList()); + if (!options.getPatientIds().isEmpty()) { + ourLog.debug("options.getPatientIds() != null"); + List requestedPatientIds = options.getPatientIds().stream() + .map(t -> new IdDt(t).toUnqualifiedVersionless().getValue()) + .collect(Collectors.toList()); + boolean requestedPatientsPermitted = true; + for (String requestedPatientId : requestedPatientIds) { + if (!permittedPatientIds.contains(requestedPatientId)) { + requestedPatientsPermitted = false; + break; + } + } + if (requestedPatientsPermitted) { + return newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + } + + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); + } + + final List filters = options.getFilters(); + + if (!filters.isEmpty()) { + ourLog.debug("filters not empty"); + final Set patientIdsInFilters = filters.stream() + .filter(filter -> filter.startsWith("Patient?_id=")) + .map(filter -> filter.replace("?_id=", "/")) + .collect(Collectors.toUnmodifiableSet()); + + boolean filteredPatientIdsPermitted = true; + for (String patientIdInFilters : patientIdsInFilters) { + if (!permittedPatientIds.contains(patientIdInFilters)) { + filteredPatientIdsPermitted = false; + break; + } + } + + if (filteredPatientIdsPermitted) { + return newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + } + + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); + } + ourLog.debug("patientIds and filters both empty"); + } + return null; } public void setAppliesToGroupExportOnGroup(String theGroupId) { @@ -165,16 +193,6 @@ public class RuleBulkExportImpl extends BaseRule { myPatientIds.add(thePatientId); } - public void setAppliesToPatientExport(Collection thePatientIds) { - myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; - myPatientIds.addAll(thePatientIds); - } - - public void setAppliesToPatientExportAllPatients() { - myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; - myAppliesToAllPatients = true; - } - public void setAppliesToSystem() { myWantExportStyle = BulkExportJobParameters.ExportStyle.SYSTEM; } @@ -194,14 +212,4 @@ public class RuleBulkExportImpl extends BaseRule { BulkExportJobParameters.ExportStyle getWantExportStyle() { return myWantExportStyle; } - - @VisibleForTesting - Collection getPatientIds() { - return myPatientIds; - } - - @VisibleForTesting - Collection getResourceTypes() { - return myResourceTypes; - } } diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java index 7dd962d6630..b942fcc8023 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java @@ -1,23 +1,16 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import ca.uhn.fhir.model.primitive.IdDt; -import ca.uhn.fhir.rest.server.provider.ProviderConstants; import com.google.common.collect.Lists; -import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; import java.util.ArrayList; -import java.util.Collection; import java.util.List; -import java.util.stream.Stream; import static org.hamcrest.Matchers.contains; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; public class RuleBuilderTest { @@ -105,72 +98,7 @@ public class RuleBuilderTest { builder.allow().bulkExport().patientExportOnPatient("Patient/pat2").withResourceTypes(resourceTypes); List rules = builder.build(); assertEquals(rules.size(),1); - assertInstanceOf(RuleBulkExportImpl.class, rules.get(0)); - } - - public static Stream multipleInstancesParams() { - return Stream.of( - Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.ALLOW), - Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.ALLOW), - Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.ALLOW), - Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.DENY), - Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.DENY), - Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.DENY) - ); - } - - @ParameterizedTest - @MethodSource("multipleInstancesParams") - public void testBulkExport_PatientExportOnPatients_MultiplePatientsSingleRule(Collection theExpectedPatientIds, Collection theExpectedResourceTypes, PolicyEnum thePolicyEnum) { - final RuleBuilder builder = new RuleBuilder(); - final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { - case ALLOW -> builder.allow(); - case DENY -> builder.deny(); - }; - rule.bulkExport().patientExportOnPatientStrings(theExpectedPatientIds).withResourceTypes(theExpectedResourceTypes); - final List rules = builder.build(); - assertEquals(rules.size(),1); - final IAuthRule authRule = rules.get(0); - assertInstanceOf(RuleBulkExportImpl.class, authRule); - final RuleBulkExportImpl ruleBulkExport = (RuleBulkExportImpl) authRule; - assertEquals(theExpectedPatientIds, ruleBulkExport.getPatientIds()); - assertEquals(theExpectedResourceTypes, ruleBulkExport.getResourceTypes()); - assertEquals(thePolicyEnum, ruleBulkExport.getMode()); - } - - public static Stream owners() { - return Stream.of( - Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.ALLOW), - Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.DENY), - Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.ALLOW), - Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.DENY) - ); - } - - @ParameterizedTest - @MethodSource("owners") - public void testBulkExport_PatientExportOnPatients_onInstances(List theExpectedOwners, PolicyEnum thePolicyEnum) { - final RuleBuilder builder = new RuleBuilder(); - final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { - case ALLOW -> builder.allow(); - case DENY -> builder.deny(); - }; - - final List rules = rule - .operation() - .named(ProviderConstants.OPERATION_EXPORT) - .onInstances(theExpectedOwners) - .andAllowAllResponses() - .andThen() - .build(); - - assertEquals(rules.size(),1); - final IAuthRule authRule = rules.get(0); - assertInstanceOf(OperationRule.class, authRule); - final OperationRule operationRule = (OperationRule) authRule; - assertEquals(theExpectedOwners, operationRule.getAppliesToIds()); - assertEquals(ProviderConstants.OPERATION_EXPORT, operationRule.getOperationName()); - assertEquals(thePolicyEnum, operationRule.getMode()); + assertTrue(rules.get(0) instanceof RuleBulkExportImpl); } @Test diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java index 1dc8eb5b8e8..dc71422f128 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java @@ -4,9 +4,6 @@ import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -16,6 +13,7 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -30,11 +28,10 @@ public class RuleBulkExportImplTest { @Mock private Set myFlags; - @Test public void testDenyBulkRequestWithInvalidResourcesTypes() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - myRule.setMode(PolicyEnum.ALLOW); + Set myTypes = new HashSet<>(); myTypes.add("Patient"); myTypes.add("Practitioner"); @@ -45,210 +42,33 @@ public class RuleBulkExportImplTest { BulkExportJobParameters options = new BulkExportJobParameters(); options.setResourceTypes(myWantTypes); - - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertDeny(verdict); - } - - - @Test - public void test_RuleSpecifiesResourceTypes_RequestDoesNot_Abstains() { - RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - myRule.setAppliesToPatientExportAllPatients(); - myRule.setMode(PolicyEnum.ALLOW); - Set myTypes = new HashSet<>(); - myTypes.add("Patient"); - myRule.setResourceTypes(myTypes); - - - BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertDeny(verdict); - } - - @Test - public void testBulkExportSystem_ruleHasTypes_RequestWithTypes_allow() { - RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - myRule.setMode(PolicyEnum.ALLOW); - myRule.setAppliesToSystem(); - myRule.setResourceTypes(Set.of("Patient", "Practitioner")); - - BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - options.setResourceTypes(Set.of("Patient", "Practitioner")); when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } - @Test - public void testBulkExportSystem_ruleHasTypes_RequestWithTooManyTypes_abstain() { + public void testBulkRequestWithValidResourcesTypes() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - myRule.setMode(PolicyEnum.ALLOW); - myRule.setAppliesToSystem(); - myRule.setResourceTypes(Set.of("Patient", "Practitioner")); + Set myTypes = new HashSet<>(); + myTypes.add("Patient"); + myTypes.add("Practitioner"); + myRule.setResourceTypes(myTypes); + + Set myWantTypes = new HashSet<>(); + myWantTypes.add("Patient"); + myWantTypes.add("Practitioner"); BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - options.setResourceTypes(Set.of("Patient", "Practitioner", "Encounter")); - + options.setResourceTypes(myWantTypes); + when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertDeny(verdict); - } - @Nested - class StyleChecks { - BulkExportJobParameters myOptions = new BulkExportJobParameters(); - RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - @BeforeEach - void setUp() { - myRule.setMode(PolicyEnum.ALLOW); - when(myRequestDetails.getAttribute(any())).thenReturn(myOptions); - } - @Nested class RuleAnyStyle { - @BeforeEach - void setUp(){ - myRule.setAppliesToAny(); - } - - @Test - public void testRuleAnyStyle_Matches_SystemStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - } - @Test - public void testRuleAnyStyle_Matches_PatientStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - - } - @Test - public void testRuleAnyStyle_Matches_GroupStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - - } - - } - - @Nested - class RuleSystemStyle { - @BeforeEach - void setUp() { - myRule.setAppliesToSystem(); - } - - @Test - public void test_Matches_SystemStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - } - - @Test - public void test_DoesntMatch_GroupStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - - @Test - public void test_DoesntMatch_PatientStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - } - - @Nested - class RuleGroupStyle { - @BeforeEach - void setUp() { - myRule.setAppliesToGroupExportOnGroup("Group/123"); - } - - @Test - public void test_DoesntMatch_SystemStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - - @Test - public void test_Matches_GroupStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); - myOptions.setGroupId("Group/123"); - - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - } - - @Test - public void test_DoesntMatch_PatientStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - } - - @Nested - class RulePatientStyle { - @BeforeEach - void setUp() { - myRule.setAppliesToPatientExport("Patient/123"); - } - - @Test - public void test_DoesntMatch_SystemStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - - @Test - public void test_DoesntMatch_GroupStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); - myOptions.setGroupId("Group/123"); - - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAbstain(verdict); - } - - @Test - public void test_DoesntMatch_PatientStyle() { - myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - myOptions.setPatientIds(Set.of("Patient/123")); - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - } - } + assertNull(verdict); } @Test @@ -264,7 +84,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertAbstain(verdict); + assertEquals(null, verdict); } @Test @@ -280,7 +100,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertAllow(verdict); + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); } @Test @@ -298,7 +118,7 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We permit the request, as a patient ID that was requested is honoured by this rule. - assertAllow(verdict); + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); } @Test @@ -315,8 +135,8 @@ public class RuleBulkExportImplTest { //When AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: abstain - assertDeny(verdict); + //Then: we should deny the request, as the requested export does not contain the patient permitted. + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } @Test @@ -333,45 +153,28 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We make no claims about type-level export on Patient. - assertAbstain(verdict); + assertEquals(null, verdict); } @Test - public void testPatientExportRulesWithId_withRequestNoIds_abstains() { + public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatient() { //Given - RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); myRule.setMode(PolicyEnum.ALLOW); - BulkExportJobParameters options = new BulkExportJobParameters(); - + final BulkExportJobParameters options = new BulkExportJobParameters(); options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + options.setFilters(Set.of("Patient?_id=123")); + options.setResourceTypes(Set.of("Patient")); when(myRequestDetails.getAttribute(any())).thenReturn(options); //When - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: We make no claims about type-level export on Patient. - assertAbstain(verdict); + //Then: The patient IDs match so this is permitted + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); } - @Test - public void testPatientExportRuleWithNoIds_withRequestNoIds_allows() { - //Given - RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExportAllPatients(); - myRule.setMode(PolicyEnum.ALLOW); - BulkExportJobParameters options = new BulkExportJobParameters(); - - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - assertAllow(verdict); - } - - @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatientAndFilterHasResources() { //Given @@ -388,9 +191,27 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: The patient IDs match so this is permitted - assertAbstain(verdict); + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); } + @Test + public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypeObservation() { + //Given + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExport("Patient/123"); + myRule.setMode(PolicyEnum.ALLOW); + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + options.setFilters(Set.of("Patient?_id=123")); + options.setResourceTypes(Set.of("Observation")); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then: The patient IDs match so this is permitted + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + } @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterNoResourceType() { @@ -406,8 +227,27 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: Filters are ignored for auth purposes. The rule has an ID, indicating it is for instance level, but the job requested type level. Abstain - assertAbstain(verdict); + //Then: The patient IDs match so this is permitted + assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + } + + @Test + public void testPatientExportRulesOnTypeLevelExportWithTypeFilterMismatch() { + //Given + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExport("Patient/123"); + myRule.setMode(PolicyEnum.ALLOW); + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + options.setFilters(Set.of("Patient?_id=456")); + options.setResourceTypes(Set.of("Patient")); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then: The patient IDs do NOT match so this is not permitted. + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } @Test @@ -425,12 +265,12 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: We do not have permissions on the requested patient so we abstain - assertDeny(verdict); + //Then: We do not have permissions on the requested patient so this is not permitted. + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } @Test - public void testPatientExport_ruleAllowsId_requestsId_allow() { + public void testPatientExportRulesOnTypeLevelExportPermittedPatient() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -449,7 +289,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExport_ruleAllowsIds_requestsIds_allow() { + public void testPatientExportRulesOnTypeLevelExportPermittedPatients() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -469,7 +309,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExport_ruleAllowsId_requestsTooManyIds_abstain() { + public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatients() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -484,61 +324,8 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: There are unpermitted patients in the request so this is not permitted. - assertDeny(verdict); - } // - - @Test - public void testPatientExport_RuleAllowsAll_RequestId_allows() { - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExportAllPatients(); - myRule.setMode(PolicyEnum.ALLOW); - - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setPatientIds(Set.of("Patient/123")); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then - assertAllow(verdict); + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } - - @Test - public void testPatientExport_RuleAllowsAll_RequestAll_allows() { - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExportAllPatients(); - myRule.setMode(PolicyEnum.ALLOW); - - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then - assertAllow(verdict); - } - - @Test - public void testPatientExport_RuleAllowsExplicitPatient_RequestAll_abstain() { - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExport("Patient/123"); - myRule.setMode(PolicyEnum.ALLOW); - - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then - assertAbstain(verdict); - } - @Test public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatientFilters() { //Given @@ -554,22 +341,7 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: There are unpermitted patients in the request so this is not permitted. abstain. - assertAbstain(verdict); - - } - - private static void assertAbstain(AuthorizationInterceptor.Verdict verdict) { - Assertions.assertEquals(null, verdict, "Expect abstain"); - } - - private static void assertAllow(AuthorizationInterceptor.Verdict verdict) { - Assertions.assertNotNull(verdict, "Expect ALLOW, got abstain"); - Assertions.assertEquals(PolicyEnum.ALLOW, verdict.getDecision(), "Expect ALLOW"); - } - - private static void assertDeny(AuthorizationInterceptor.Verdict verdict) { - Assertions.assertNotNull(verdict, "Expect DENY, got abstain"); - Assertions.assertEquals(PolicyEnum.DENY, verdict.getDecision(), "Expect DENY"); + //Then: There are unpermitted patients in the request so this is not permitted. + assertEquals(PolicyEnum.DENY, verdict.getDecision()); } } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java index 50b7859a0a9..168e474ece7 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java @@ -308,14 +308,6 @@ public abstract class BaseTask { } } - public void doNothing() { - setDoNothing(true); - } - - public void failureAllowed() { - setFailureAllowed(true); - } - public boolean isDoNothing() { return myDoNothing; } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java index 4b90ea91ac3..49615e73c1a 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java @@ -22,8 +22,11 @@ package ca.uhn.fhir.jpa.migrate.taskdef; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.migrate.JdbcUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; +import org.intellij.lang.annotations.Language; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ColumnMapRowMapper; +import org.springframework.jdbc.core.JdbcTemplate; import java.sql.SQLException; import java.util.Set; @@ -48,12 +51,53 @@ public class RenameTableTask extends BaseTableTask { setDescription("Rename table " + getOldTableName()); } + private void handleTableWithNewTableName() throws SQLException { + + if (!myDeleteTargetColumnFirstIfExist) { + throw new SQLException(Msg.code(2517) + "Can not rename " + getOldTableName() + " to " + getNewTableName() + + " because a table with name " + getNewTableName() + " already exists"); + } + + // a table with the new tableName already exists and we can delete it. we will only do so if it is empty. + Integer rowsWithData = getConnectionProperties().getTxTemplate().execute(t -> { + String sql = "SELECT * FROM " + getNewTableName(); + JdbcTemplate jdbcTemplate = getConnectionProperties().newJdbcTemplate(); + jdbcTemplate.setMaxRows(1); + return jdbcTemplate.query(sql, new ColumnMapRowMapper()).size(); + }); + + if (rowsWithData != null && rowsWithData > 0) { + throw new SQLException(Msg.code(2518) + "Can not rename " + getOldTableName() + " to " + getNewTableName() + + " because a table with name " + getNewTableName() + " already exists and is populated."); + } + + logInfo( + ourLog, + "Table {} already exists - Going to drop it before renaming table {} to {}", + getNewTableName(), + getOldTableName(), + getNewTableName()); + + @Language("SQL") + String sql = "DROP TABLE " + getNewTableName(); + executeSql(getNewTableName(), sql); + } + @Override public void doExecute() throws SQLException { Set tableNames = JdbcUtils.getTableNames(getConnectionProperties()); boolean hasTableWithNewTableName = tableNames.contains(getNewTableName()); + if (!tableNames.contains(getOldTableName())) { + throw new SQLException(Msg.code(2516) + "Can not rename " + getOldTableName() + " to " + getNewTableName() + + " because the original table does not exists"); + } + + if (hasTableWithNewTableName) { + handleTableWithNewTableName(); + } + String sql = buildRenameTableSqlStatement(); logInfo(ourLog, "Renaming table: {}", getOldTableName()); 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 53741f65e5a..ffc800f9a9f 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 @@ -57,7 +57,6 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -186,7 +185,6 @@ public class Builder { private final String myRelease; private final BaseMigrationTasks.IAcceptsTasks mySink; private final String myTableName; - private BaseTask myLastAddedTask; public BuilderWithTableName(String theRelease, BaseMigrationTasks.IAcceptsTasks theSink, String theTableName) { myRelease = theRelease; @@ -276,7 +274,6 @@ public class Builder { @Override public void addTask(BaseTask theTask) { ((BaseTableTask) theTask).setTableName(myTableName); - myLastAddedTask = theTask; mySink.addTask(theTask); } @@ -314,10 +311,6 @@ public class Builder { return this; } - public Optional getLastAddedTask() { - return Optional.ofNullable(myLastAddedTask); - } - /** * @param theFkName the name of the foreign key * @param theParentTableName the name of the table that exports the foreign key @@ -330,37 +323,31 @@ public class Builder { addTask(task); } - public BuilderCompleteTask renameTable(String theVersion, String theNewTableName) { + public void renameTable(String theVersion, String theNewTableName) { RenameTableTask task = new RenameTableTask(myRelease, theVersion, getTableName(), theNewTableName); addTask(task); - return new BuilderCompleteTask(task); } - public BuilderCompleteTask migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { + public void migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { MigratePostgresTextClobToBinaryClobTask task = new MigratePostgresTextClobToBinaryClobTask(myRelease, theVersion); task.setTableName(getTableName()); task.setColumnName(theColumnName); addTask(task); - return new BuilderCompleteTask(task); } - public BuilderCompleteTask migrateBlobToBinary( - String theVersion, String theFromColumName, String theToColumName) { + public void migrateBlobToBinary(String theVersion, String theFromColumName, String theToColumName) { MigrateColumBlobTypeToBinaryTypeTask task = new MigrateColumBlobTypeToBinaryTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); - return new BuilderCompleteTask(task); } - public BuilderCompleteTask migrateClobToText( - String theVersion, String theFromColumName, String theToColumName) { + public void migrateClobToText(String theVersion, String theFromColumName, String theToColumName) { MigrateColumnClobTypeToTextTypeTask task = new MigrateColumnClobTypeToTextTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); - return new BuilderCompleteTask(task); } public class BuilderAddIndexWithName { diff --git a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java index 14cf7896ec6..a1c6aad40ba 100644 --- a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java +++ b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java @@ -41,4 +41,26 @@ public class RenameTableTaskTest extends BaseTest { assertThat(tableNames, not(hasItem(oldTableName))); } + @ParameterizedTest(name = "{index}: {0}") + @MethodSource("data") + public void testRenameTableTask_whenTableDoesNotExists_willRaiseException(Supplier theTestDatabaseDetails) throws SQLException { + // given + before(theTestDatabaseDetails); + final String newTableName = "NEWTABLE"; + final String oldTableName = "SOMETABLE"; + + RenameTableTask task = new RenameTableTask("1", "1", oldTableName, newTableName); + getMigrator().addTask(task); + + // when + try { + getMigrator().migrate(); + fail(); + } catch (Exception e){ + // then + assertThat(e.getMessage(), containsString("2516")); + } + + } + } diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java index 9da0e377ce5..ddc1fde19f5 100644 --- a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java @@ -436,16 +436,6 @@ public class BulkDataImportProviderTest { public boolean isResourcePartitionable(String theResourceType) { return false; } - - @Override - public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { - return null; - } - - @Override - public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { - return null; - } } private Date parseDate(String theString) { diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java index e94facf199f..fcd883576bf 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java @@ -1,22 +1,3 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java index 483945ba1b5..f5de302cd97 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java @@ -1,22 +1,3 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java index 09313ca21ff..bdaec6cc8ac 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java @@ -1,22 +1,3 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.ICollectDataServiceFactory; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java index da7ff850647..9c801d91d39 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java @@ -1,22 +1,3 @@ -/*- - * #%L - * HAPI FHIR - Clinical Reasoning - * %% - * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.IDataRequirementsServiceFactory; diff --git a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java index 483736324b2..299475af681 100644 --- a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java +++ b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java @@ -102,9 +102,7 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa public void cleanup() { ourLog.info("cleanup {}", myIds); - myIds.keySet().stream() - .sorted() // Hack to ensure Patients are deleted before Practitioners. This may need to be refined. - .forEach(nextType->{ + myIds.keySet().forEach(nextType->{ // todo do this in a bundle for perf. IFhirResourceDao dao = myDaoRegistry.getResourceDao(nextType); myIds.get(nextType).forEach(dao::delete); diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java index 78ec78d7c79..aafb69b8e2d 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java @@ -360,14 +360,6 @@ public class JpaStorageSettings extends StorageSettings { */ private long myRestDeleteByUrlResourceIdThreshold = DEFAULT_REST_DELETE_BY_URL_RESOURCE_ID_THRESHOLD; - /** - * If enabled, this setting causes persisting data to legacy LOB columns as well as columns introduced - * to migrate away from LOB columns which effectively duplicates stored information. - * - * @since 7.2.0 - */ - private boolean myWriteToLegacyLobColumns = false; - /** * Constructor */ @@ -2431,8 +2423,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link IValidationSupport.IssueSeverity#INFORMATION} + * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2447,8 +2439,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link IValidationSupport.IssueSeverity#INFORMATION} + * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2462,33 +2454,6 @@ public class JpaStorageSettings extends StorageSettings { myIssueSeverityForCodeDisplayMismatch = theIssueSeverityForCodeDisplayMismatch; } - /** - * This method returns whether data will be stored in LOB columns as well as the columns - * introduced to migrate away from LOB. Writing to LOB columns is set to false by - * default. Enabling the setting will effectively double the persisted information. - * If enabled, a careful monitoring of LOB table (if applicable) is required to avoid - * exceeding the table maximum capacity. - * - * @since 7.2.0 - */ - public boolean isWriteToLegacyLobColumns() { - return myWriteToLegacyLobColumns; - } - - /** - * This setting controls whether data will be stored in LOB columns as well as the columns - * introduced to migrate away from LOB. Writing to LOB columns is set to false by - * default. Enabling the setting will effectively double the persisted information. - * When enabled, a careful monitoring of LOB table (if applicable) is required to avoid - * exceeding the table maximum capacity. - * - * @param theWriteToLegacyLobColumns - * @since 7.2.0 - */ - public void setWriteToLegacyLobColumns(boolean theWriteToLegacyLobColumns) { - myWriteToLegacyLobColumns = theWriteToLegacyLobColumns; - } - /** * This setting controls whether MdmLink and other non-resource DB history is enabled. *

    diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java index be151786428..a98fb571d1a 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java @@ -333,6 +333,10 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition return !myNonPartitionableResourceNames.contains(theResourceType); } + protected abstract RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); + + protected abstract RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); + private void validateSinglePartitionForCreate( RequestPartitionId theRequestPartitionId, @Nonnull String theResourceName, Pointcut thePointcut) { validateRequestPartitionNotNull(theRequestPartitionId, thePointcut); From 078e87a4aaa1749d270248ca43c90e203a6ae30d Mon Sep 17 00:00:00 2001 From: longma1 <32119004+longma1@users.noreply.github.com> Date: Mon, 13 May 2024 16:51:03 -0600 Subject: [PATCH 08/15] 7 2 mergeback may 10 v2 (#5928) * Enhance RuleBuilder code to support multiple instances (#5852) * Overhaul bulk export permissions. * Overhaul bulk export permissions. * Small tweak to rule builder. * Cleanup validation. * Cleanup validation. * Code review feedback. * Postgres terminology service hard coded column names migration (#5866) * updating parent pids column name * updating name of the fullTestField Search * updating name of the fullTestField Search * fixing typo. * failing test. * - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity; - reverting the name of the FullTextField entity to its previous name of 'myParentPids'; - reverting the name of the lucene index to search on in the terminology service. - updating the changelog; * making spotless happy --------- Co-authored-by: peartree * 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881) * initial failing test. * solution * adding changelog * spotless * moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder. --------- Co-authored-by: peartree * Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811) * Expose BaseRequestPartitionHelperSvc validate and normalize methods * Compilation errors * change mock test to jpa test * change mock test to jpa test * validateAndNormalizePartitionIds * validateAndNormalizePartitionNames * validateAndNormalizePartitionIds validation + bug fix * validateAndNormalizePartitionNames validation * fix test * version bump * Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883) * Add failing test as well as commented out potential solution. * Fix for NumberFormatException. * Add conditional test for survivorship rules. * Spotless. * Add changelog. * Code review feedback. * updating documentation (#5889) * Ensure temp file ends with "." and then suffix. (#5894) * bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892) Co-authored-by: Jens Kristian Villadsen * Enhance mdm interceptor (#5899) * Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened. * Added javadoc * Cahngelog * spotless --------- Co-authored-by: Jens Kristian Villadsen * Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896) * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug. * Add changelog. * Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml Commit code reviewer suggestion. Co-authored-by: Tadgh --------- Co-authored-by: Tadgh * Fix query chained on sort bug where we over-filter results (#5903) * Failing test. * Ensure test cleanup doesn't fail by deleting Patients before Practitioners. * Implement fix. * Spotless. * Clean up unit test and add changelog. Fix unit test. * Fix changelog file. * Apply suggestions from code review Apply code review suggestions. Co-authored-by: Michael Buckley * Spotless --------- Co-authored-by: Michael Buckley * cve fix (#5906) Co-authored-by: Long Ma * Fixing issues with postgres LOB migration. (#5895) * Fixing issues with postgres LOB migration. * addressing code review comments for audit/transaction logs. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for TermConcept migration post code review. * applying spotless * test and implementation for TermConceptProperty migration post code review. * test and implementation for TermValueSetConcept migration post code review. * fixing migration version * fixing migration task * changelog * fixing changelog * Minor renames * addressing comments and suggestions from second code review. * passing tests * fixing more tests --------- Co-authored-by: peartree Co-authored-by: Tadgh * 6051 bulk export security errors (#5915) * Enhance RuleBuilder code to support multiple instances (#5852) * Overhaul bulk export permissions. * Overhaul bulk export permissions. * Small tweak to rule builder. * Cleanup validation. * Cleanup validation. * Code review feedback. * Postgres terminology service hard coded column names migration (#5866) * updating parent pids column name * updating name of the fullTestField Search * updating name of the fullTestField Search * fixing typo. * failing test. * - Moving FullTextField annotation from getter method and adding it to the newly added VC property of the entity; - reverting the name of the FullTextField entity to its previous name of 'myParentPids'; - reverting the name of the lucene index to search on in the terminology service. - updating the changelog; * making spotless happy --------- Co-authored-by: peartree * 5879 back porting fix for issue 5877 (attempting to update a tokenparam with a value greater than 200 characters raises an sqlexception) to release rel_7_2 (#5881) * initial failing test. * solution * adding changelog * spotless * moving changelog from 7_4_0 to 7_2_0 and deleting 7_4_0 folder. --------- Co-authored-by: peartree * Expose BaseRequestPartitionHelperSvc validateAndNormalize methods (#5811) * Expose BaseRequestPartitionHelperSvc validate and normalize methods * Compilation errors * change mock test to jpa test * change mock test to jpa test * validateAndNormalizePartitionIds * validateAndNormalizePartitionNames * validateAndNormalizePartitionIds validation + bug fix * validateAndNormalizePartitionNames validation * fix test * version bump * Ensure a non-numeric FHIR ID doesn't result in a NumberFormatException when processing survivorship rules (#5883) * Add failing test as well as commented out potential solution. * Fix for NumberFormatException. * Add conditional test for survivorship rules. * Spotless. * Add changelog. * Code review feedback. * updating documentation (#5889) * Ensure temp file ends with "." and then suffix. (#5894) * bugfix to https://github.com/hapifhir/hapi-fhir-jpaserver-starter/issues/675 (#5892) Co-authored-by: Jens Kristian Villadsen * Enhance mdm interceptor (#5899) * Add MDM Transaction Context for further downstream processing giving interceptors a better chance of figuring out what happened. * Added javadoc * Cahngelog * spotless --------- Co-authored-by: Jens Kristian Villadsen * Fix BaseHapiFhirResourceDao $meta method to use HapiTransactionService instead of @Transaction (#5896) * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Try making ResourceTable.myTags EAGER instead of LAZY and see if it breaks anything. * Ensure BaseHapiFhirResourceDao#metaGetOperation uses HapiTransactionService instead of @Transactional in order to resolve megascale $meta bug. * Add changelog. * Update hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml Commit code reviewer suggestion. Co-authored-by: Tadgh --------- Co-authored-by: Tadgh * Fix query chained on sort bug where we over-filter results (#5903) * Failing test. * Ensure test cleanup doesn't fail by deleting Patients before Practitioners. * Implement fix. * Spotless. * Clean up unit test and add changelog. Fix unit test. * Fix changelog file. * Apply suggestions from code review Apply code review suggestions. Co-authored-by: Michael Buckley * Spotless --------- Co-authored-by: Michael Buckley * cve fix (#5906) Co-authored-by: Long Ma * Fixing issues with postgres LOB migration. (#5895) * Fixing issues with postgres LOB migration. * addressing code review comments for audit/transaction logs. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for BinaryStorageEntity migration post code review. * test and implementation for TermConcept migration post code review. * applying spotless * test and implementation for TermConceptProperty migration post code review. * test and implementation for TermValueSetConcept migration post code review. * fixing migration version * fixing migration task * changelog * fixing changelog * Minor renames * addressing comments and suggestions from second code review. * passing tests * fixing more tests --------- Co-authored-by: peartree Co-authored-by: Tadgh * refactor bulk export rule, add concept of appliestoallpatients, fix tests * spotless * Cahgnelog, tests * more tests * refactor style checks --------- Co-authored-by: Luke deGruchy Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com> Co-authored-by: peartree Co-authored-by: Nathan Doef Co-authored-by: TipzCM Co-authored-by: dotasek Co-authored-by: Jens Kristian Villadsen Co-authored-by: Michael Buckley Co-authored-by: longma1 <32119004+longma1@users.noreply.github.com> Co-authored-by: Long Ma * Convert a few nulls to aggressive denies * Change chain sort syntax for MS SQL (#5917) * Change sort type on chains * Change sort type on chains * Test for MS SQL * Comments * Version bump * version bump to 7.3.1-SNAPSHOT --------- Co-authored-by: Luke deGruchy Co-authored-by: Etienne Poirier <33007955+epeartree@users.noreply.github.com> Co-authored-by: peartree Co-authored-by: Nathan Doef Co-authored-by: TipzCM Co-authored-by: dotasek Co-authored-by: Jens Kristian Villadsen Co-authored-by: Tadgh Co-authored-by: Michael Buckley Co-authored-by: Long Ma --- hapi-deployable-pom/pom.xml | 2 +- hapi-fhir-android/pom.xml | 2 +- hapi-fhir-base/pom.xml | 2 +- .../ca/uhn/fhir/interceptor/api/Pointcut.java | 8 +- hapi-fhir-bom/pom.xml | 4 +- hapi-fhir-checkstyle/pom.xml | 2 +- hapi-fhir-cli/hapi-fhir-cli-api/pom.xml | 2 +- .../fhir/cli/UploadTerminologyCommand.java | 11 +- .../cli/UploadTerminologyCommandTest.java | 87 ++++ hapi-fhir-cli/hapi-fhir-cli-app/pom.xml | 2 +- hapi-fhir-cli/pom.xml | 2 +- hapi-fhir-client-okhttp/pom.xml | 2 +- hapi-fhir-client/pom.xml | 2 +- hapi-fhir-converter/pom.xml | 2 +- hapi-fhir-dist/pom.xml | 2 +- hapi-fhir-docs/pom.xml | 2 +- ...ule-builder-code-support-multiple-ids.yaml | 4 + ...dating-name-of-full-text-field-search.yaml | 5 + ...updating-token-param-with-large-value.yaml | 5 + ...-survivorship-number-format-exception.yaml | 6 + ...ry-security-interceptor-documentation.yaml | 7 + ...bility-to-persist-data-to-lob-columns.yaml | 5 + ...-cli-upload-terminology-zip-hapi-0862.yaml | 6 + ...ascale-meta-operation-fails-hapi-0389.yaml | 5 + .../7_2_0/5899-enhance-mdm-interceptor.yaml | 4 + ...ery-chained-sort-returns-less-results.yaml | 4 + .../7_2_0/5915-bulk-export-security-woes.yaml | 4 + .../7_2_0/5917-chain-sort-mssql.yaml | 4 + .../security/binary_security_interceptor.md | 7 +- hapi-fhir-jacoco/pom.xml | 2 +- hapi-fhir-jaxrsserver-base/pom.xml | 2 +- hapi-fhir-jpa/pom.xml | 2 +- hapi-fhir-jpaserver-base/pom.xml | 2 +- .../DatabaseBinaryContentStorageSvcImpl.java | 21 +- .../ca/uhn/fhir/jpa/config/JpaConfig.java | 14 + .../fhir/jpa/dao/BaseHapiFhirResourceDao.java | 21 +- .../ca/uhn/fhir/jpa/entity/TermConcept.java | 36 +- .../fhir/jpa/entity/TermConceptProperty.java | 15 +- .../fhir/jpa/entity/TermValueSetConcept.java | 11 + .../jpa/entity/TermValueSetConceptView.java | 41 +- .../tasks/HapiFhirJpaMigrationTasks.java | 42 +- .../partition/RequestPartitionHelperSvc.java | 16 +- .../fhir/jpa/search/builder/QueryStack.java | 47 ++- .../term/TermCodeSystemStorageSvcImpl.java | 21 - .../uhn/fhir/jpa/term/TermConceptDaoSvc.java | 10 + .../ca/uhn/fhir/jpa/term/TermReadSvcImpl.java | 11 +- .../jpa/term/ValueSetConceptAccumulator.java | 11 + .../ValueSetConceptAccumulatorFactory.java | 51 +++ .../jpa/term/config/TermCodeSystemConfig.java | 5 +- .../jpa/entity/TermConceptPropertyTest.java | 22 +- .../pom.xml | 2 +- hapi-fhir-jpaserver-hfql/pom.xml | 2 +- hapi-fhir-jpaserver-ips/pom.xml | 2 +- hapi-fhir-jpaserver-mdm/pom.xml | 2 +- .../mdm/svc/GoldenResourceMergerSvcImpl.java | 1 + .../jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java | 22 + .../mdm/svc/MdmSurvivorshipSvcImplTest.java | 19 +- hapi-fhir-jpaserver-model/pom.xml | 2 +- .../jpa/model/entity/BinaryStorageEntity.java | 11 +- hapi-fhir-jpaserver-searchparam/pom.xml | 2 +- .../partition/IRequestPartitionHelperSvc.java | 26 ++ hapi-fhir-jpaserver-subscription/pom.xml | 2 +- .../config/SubscriptionConfig.java | 35 ++ .../config/SubscriptionSubmitterConfig.java | 12 +- .../jpa/topic/SubscriptionTopicConfig.java | 11 +- hapi-fhir-jpaserver-test-dstu2/pom.xml | 2 +- hapi-fhir-jpaserver-test-dstu3/pom.xml | 2 +- hapi-fhir-jpaserver-test-r4/pom.xml | 2 +- ...tabaseBinaryContentStorageSvcImplTest.java | 40 +- .../dao/r4/FhirResourceDaoR4QuerySandbox.java | 27 ++ .../RequestPartitionHelperSvcTest.java | 199 +++++++-- .../stresstest/GiantTransactionPerfTest.java | 10 + hapi-fhir-jpaserver-test-r4b/pom.xml | 2 +- hapi-fhir-jpaserver-test-r5/pom.xml | 2 +- ...iftedRefchainsAndChainedSortingR5Test.java | 50 ++- .../database/BaseDatabaseVerificationIT.java | 47 ++- hapi-fhir-jpaserver-test-utilities/pom.xml | 2 +- .../fhir/jpa/term/TermConceptDaoSvcTest.java | 57 +++ .../term/ValueSetConceptAccumulatorTest.java | 23 ++ hapi-fhir-jpaserver-uhnfhirtest/pom.xml | 2 +- hapi-fhir-server-cds-hooks/pom.xml | 2 +- hapi-fhir-server-mdm/pom.xml | 2 +- .../fhir/mdm/svc/MdmSurvivorshipSvcImpl.java | 29 +- hapi-fhir-server-openapi/pom.xml | 2 +- hapi-fhir-server/pom.xml | 2 +- .../auth/IAuthRuleBuilderOperationNamed.java | 4 + .../auth/IAuthRuleBuilderRuleBulkExport.java | 13 + .../server/interceptor/auth/RuleBuilder.java | 65 ++- .../interceptor/auth/RuleBulkExportImpl.java | 186 ++++----- .../interceptor/auth/RuleBuilderTest.java | 76 +++- .../auth/RuleBulkExportImplTest.java | 384 ++++++++++++++---- .../hapi-fhir-caching-api/pom.xml | 2 +- .../hapi-fhir-caching-caffeine/pom.xml | 4 +- .../hapi-fhir-caching-guava/pom.xml | 2 +- .../hapi-fhir-caching-testing/pom.xml | 2 +- hapi-fhir-serviceloaders/pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../hapi-fhir-spring-boot-samples/pom.xml | 2 +- .../hapi-fhir-spring-boot-starter/pom.xml | 2 +- hapi-fhir-spring-boot/pom.xml | 2 +- hapi-fhir-sql-migrate/pom.xml | 2 +- .../fhir/jpa/migrate/taskdef/BaseTask.java | 8 + .../jpa/migrate/taskdef/RenameTableTask.java | 44 -- .../fhir/jpa/migrate/tasks/api/Builder.java | 21 +- .../migrate/taskdef/RenameTableTaskTest.java | 22 - hapi-fhir-storage-batch2-jobs/pom.xml | 2 +- .../imprt/BulkDataImportProviderTest.java | 10 + .../pom.xml | 2 +- hapi-fhir-storage-batch2/pom.xml | 2 +- hapi-fhir-storage-cr/pom.xml | 2 +- .../cr/r4/ICollectDataServiceFactory.java | 19 + .../r4/IDataRequirementsServiceFactory.java | 19 + .../measure/CollectDataOperationProvider.java | 19 + .../DataRequirementsOperationProvider.java | 19 + hapi-fhir-storage-mdm/pom.xml | 2 +- hapi-fhir-storage-test-utilities/pom.xml | 2 +- .../fhir/storage/test/DaoTestDataBuilder.java | 4 +- hapi-fhir-storage/pom.xml | 2 +- .../jpa/api/config/JpaStorageSettings.java | 43 +- .../BaseRequestPartitionHelperSvc.java | 4 - hapi-fhir-structures-dstu2.1/pom.xml | 2 +- hapi-fhir-structures-dstu2/pom.xml | 2 +- hapi-fhir-structures-dstu3/pom.xml | 2 +- hapi-fhir-structures-hl7org-dstu2/pom.xml | 2 +- hapi-fhir-structures-r4/pom.xml | 2 +- hapi-fhir-structures-r4b/pom.xml | 2 +- hapi-fhir-structures-r5/pom.xml | 2 +- hapi-fhir-test-utilities/pom.xml | 2 +- hapi-fhir-testpage-overlay/pom.xml | 2 +- .../pom.xml | 2 +- hapi-fhir-validation-resources-dstu2/pom.xml | 2 +- hapi-fhir-validation-resources-dstu3/pom.xml | 2 +- hapi-fhir-validation-resources-r4/pom.xml | 2 +- hapi-fhir-validation-resources-r4b/pom.xml | 2 +- hapi-fhir-validation-resources-r5/pom.xml | 2 +- hapi-fhir-validation/pom.xml | 2 +- hapi-tinder-plugin/pom.xml | 2 +- hapi-tinder-test/pom.xml | 2 +- pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- .../pom.xml | 2 +- 145 files changed, 1748 insertions(+), 556 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml create mode 100644 hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java create mode 100644 hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java create mode 100644 hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index f3f866d46a1..e7e60c90cf7 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 2dd9942ba2a..d2004aa485b 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 188e9bcbe27..49d05ccdc80 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java index d2c995a435e..016512e537d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/interceptor/api/Pointcut.java @@ -2387,13 +2387,19 @@ public enum Pointcut implements IPointcut { *

  • * ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent - Contains information about the from and to resources. *
  • + *
  • + * ca.uhn.fhir.mdm.model.mdmevents.MdmTransactionContext - Contains information about the Transaction context, e.g. merge or link. + *
  • * *

    * Hooks should return void. *

    */ MDM_POST_MERGE_GOLDEN_RESOURCES( - void.class, "ca.uhn.fhir.rest.api.server.RequestDetails", "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent"), + void.class, + "ca.uhn.fhir.rest.api.server.RequestDetails", + "ca.uhn.fhir.mdm.model.mdmevents.MdmMergeEvent", + "ca.uhn.fhir.mdm.model.MdmTransactionContext"), /** * MDM Link History Hook: diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index 11be6c4e547..745c1cb4d45 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -4,7 +4,7 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT pom HAPI FHIR BOM @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index edeebb36033..5771607ca08 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index a6301421773..2a62129d23a 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java index e073c2e2c60..6085508f4c2 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/UploadTerminologyCommand.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.cli; +import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; @@ -31,6 +32,7 @@ import ca.uhn.fhir.system.HapiSystemProperties; import ca.uhn.fhir.util.AttachmentUtil; import ca.uhn.fhir.util.FileUtil; import ca.uhn.fhir.util.ParametersUtil; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Charsets; import org.apache.commons.cli.CommandLine; import org.apache.commons.cli.Options; @@ -265,7 +267,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { "Response:\n{}", myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(response)); } - private void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { + protected void addFileToRequestBundle(IBaseParameters theInputParameters, String theFileName, byte[] theBytes) { byte[] bytes = theBytes; String fileName = theFileName; @@ -277,7 +279,7 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { FileUtil.formatFileSize(ourTransferSizeLimit)); try { - File tempFile = File.createTempFile("hapi-fhir-cli", suffix); + File tempFile = File.createTempFile("hapi-fhir-cli", "." + suffix); tempFile.deleteOnExit(); try (OutputStream fileOutputStream = new FileOutputStream(tempFile, false)) { fileOutputStream.write(bytes); @@ -363,4 +365,9 @@ public class UploadTerminologyCommand extends BaseRequestGeneratingCommand { } return retVal; } + + @VisibleForTesting + void setFhirContext(FhirContext theFhirContext) { + myFhirCtx = theFhirContext; + } } diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java index f0e08800425..2511ef9db91 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/test/java/ca/uhn/fhir/cli/UploadTerminologyCommandTest.java @@ -22,6 +22,10 @@ import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyS import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; +import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.r4.model.Attachment; +import org.hl7.fhir.r4.model.Parameters; +import org.hl7.fhir.r4.model.Type; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -43,6 +47,7 @@ import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.util.List; +import java.util.Optional; import java.util.stream.Stream; import java.util.zip.ZipEntry; import java.util.zip.ZipOutputStream; @@ -54,6 +59,8 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyList; @@ -479,6 +486,86 @@ public class UploadTerminologyCommandTest { uploadICD10UsingCompressedFile(theFhirVersion, theIncludeTls); } + @ParameterizedTest + @MethodSource("paramsProvider") + @SuppressWarnings("unused") // Both params for @BeforeEach + void testZipFileInParameters(String theFhirVersion, boolean theIncludeTls) { + final IBaseParameters inputParameters = switch (myCtx.getVersion().getVersion()) { + case DSTU2, DSTU2_HL7ORG, DSTU2_1 -> new org.hl7.fhir.dstu2.model.Parameters(); + case DSTU3 -> new org.hl7.fhir.dstu3.model.Parameters(); + case R4 -> new Parameters(); + case R4B -> new org.hl7.fhir.r4b.model.Parameters(); + case R5 -> new org.hl7.fhir.r5.model.Parameters(); + }; + + final UploadTerminologyCommand uploadTerminologyCommand = new UploadTerminologyCommand(); + uploadTerminologyCommand.setFhirContext(myCtx); + uploadTerminologyCommand.setTransferSizeBytes(1); + + uploadTerminologyCommand.addFileToRequestBundle(inputParameters, "something.zip", new byte[] {1,2}); + + final String actualAttachmentUrl = getAttachmentUrl(inputParameters, myCtx); + assertTrue(actualAttachmentUrl.endsWith(".zip")); + } + + private static String getAttachmentUrl(IBaseParameters theInputParameters, FhirContext theCtx) { + switch (theCtx.getVersion().getVersion()) { + case DSTU2: + case DSTU2_HL7ORG: + case DSTU2_1: { + assertInstanceOf(org.hl7.fhir.dstu2.model.Parameters.class, theInputParameters); + final org.hl7.fhir.dstu2.model.Parameters dstu2Parameters = (org.hl7.fhir.dstu2.model.Parameters) theInputParameters; + final List dstu2ParametersList = dstu2Parameters.getParameter(); + final Optional optDstu2FileParam = dstu2ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); + assertTrue(optDstu2FileParam.isPresent()); + final org.hl7.fhir.dstu2.model.Type dstu2Value = optDstu2FileParam.get().getValue(); + assertInstanceOf(org.hl7.fhir.dstu2.model.Attachment.class, dstu2Value); + final org.hl7.fhir.dstu2.model.Attachment dstu2Attachment = (org.hl7.fhir.dstu2.model.Attachment) dstu2Value; + return dstu2Attachment.getUrl(); + } + case DSTU3: { + assertInstanceOf(org.hl7.fhir.dstu3.model.Parameters.class, theInputParameters); + final org.hl7.fhir.dstu3.model.Parameters dstu3Parameters = (org.hl7.fhir.dstu3.model.Parameters) theInputParameters; + final List dstu3ParametersList = dstu3Parameters.getParameter(); + final Optional optDstu3FileParam = dstu3ParametersList.stream().filter(param -> TerminologyUploaderProvider.PARAM_FILE.equals(param.getName())).findFirst(); + assertTrue(optDstu3FileParam.isPresent()); + final org.hl7.fhir.dstu3.model.Type dstu3Value = optDstu3FileParam.get().getValue(); + assertInstanceOf(org.hl7.fhir.dstu3.model.Attachment.class, dstu3Value); + final org.hl7.fhir.dstu3.model.Attachment dstu3Attachment = (org.hl7.fhir.dstu3.model.Attachment) dstu3Value; + return dstu3Attachment.getUrl(); + } + case R4: { + assertInstanceOf(Parameters.class, theInputParameters); + final Parameters r4Parameters = (Parameters) theInputParameters; + final Parameters.ParametersParameterComponent r4Parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final Type r4Value = r4Parameter.getValue(); + assertInstanceOf(Attachment.class, r4Value); + final Attachment r4Attachment = (Attachment) r4Value; + return r4Attachment.getUrl(); + } + case R4B: { + assertInstanceOf(org.hl7.fhir.r4b.model.Parameters.class, theInputParameters); + final org.hl7.fhir.r4b.model.Parameters r4bParameters = (org.hl7.fhir.r4b.model.Parameters) theInputParameters; + final org.hl7.fhir.r4b.model.Parameters.ParametersParameterComponent r4bParameter = r4bParameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final org.hl7.fhir.r4b.model.DataType value = r4bParameter.getValue(); + assertInstanceOf(org.hl7.fhir.r4b.model.Attachment.class, value); + final org.hl7.fhir.r4b.model.Attachment r4bAttachment = (org.hl7.fhir.r4b.model.Attachment) value; + return r4bAttachment.getUrl(); + } + case R5: { + assertInstanceOf(org.hl7.fhir.r5.model.Parameters.class, theInputParameters); + final org.hl7.fhir.r5.model.Parameters r4Parameters = (org.hl7.fhir.r5.model.Parameters) theInputParameters; + final org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent parameter = r4Parameters.getParameter(TerminologyUploaderProvider.PARAM_FILE); + final org.hl7.fhir.r5.model.DataType value = parameter.getValue(); + assertInstanceOf(org.hl7.fhir.r5.model.Attachment.class, value); + final org.hl7.fhir.r5.model.Attachment attachment = (org.hl7.fhir.r5.model.Attachment) value; + return attachment.getUrl(); + } + default: + throw new IllegalStateException("Unknown FHIR version: " + theCtx.getVersion().getVersion()); + } + } + private void uploadICD10UsingCompressedFile(String theFhirVersion, boolean theIncludeTls) throws IOException { if (FHIR_VERSION_DSTU3.equals(theFhirVersion)) { when(myTermLoaderSvc.loadIcd10cm(anyList(), any())).thenReturn(new UploadStatistics(100, new org.hl7.fhir.dstu3.model.IdType("CodeSystem/101"))); diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 5a80f6e818b..ee553db9b80 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index f3ad5743264..f1833db3541 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 4038b5c527e..152e6a9b4da 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index a13e2b42330..a7a422ff02a 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 62951f59897..620c32c7964 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index 2e78389b1ec..d73bfb0550d 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index b60a2d29aa1..14ff85036be 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml new file mode 100644 index 00000000000..c44aca386c9 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5861-enhance-rule-builder-code-support-multiple-ids.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 5861 +title: "Enhance RuleBuilder code to support multiple instance IDs." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml new file mode 100644 index 00000000000..358a0e4276a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5865-updating-name-of-full-text-field-search.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5865 +title: "Moving the Hibernate.Search annotation for text indexing from the lob column to the column added as part of the + PostgreSql LOB migration." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml new file mode 100644 index 00000000000..ad6bbd02d1f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5877-exception-when-updating-token-param-with-large-value.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5877 +title: "Previously, updating a tokenParam with a value greater than 200 characters would raise a SQLException. +This issue has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml new file mode 100644 index 00000000000..9dae5a3b34a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5886-mdm-apply-survivorship-number-format-exception.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5886 +title: "Previously, either updating links on, or deleting one of two patients with non-numeric IDs linked to a golden + patient would result in a HAPI-0389 if there were survivorship rules. + This issue has been fixed for both the update links and delete cases." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml new file mode 100644 index 00000000000..966fbe3d9c8 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5888-update-binary-security-interceptor-documentation.yaml @@ -0,0 +1,7 @@ +--- +type: fix +issue: 5888 +title: "Updated documentation on binary_security_interceptor to specify using + `STORAGE_PRE_INITIATE_BULK_EXPORT` not `STORAGE_INITIATE_BULK_EXPORT` pointcut + to change bulk export parameters. +" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml new file mode 100644 index 00000000000..bdca0eeba3c --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5890-add-possibility-to-persist-data-to-lob-columns.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 5890 +title: "As part of the migration from LOB, provided the capability to force persisting data to LOB columns. The default +behavior is to not persist in lob columns." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml new file mode 100644 index 00000000000..12d853e5842 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5893-hapi-fhir-cli-upload-terminology-zip-hapi-0862.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 5893 +title: "Previously, hapi-fhir-cli: upload-terminology failed with a HAPI-0862 error when uploading LOINC. + This has been fixed." + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml new file mode 100644 index 00000000000..dfe2f459515 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5898-ld-megascale-meta-operation-fails-hapi-0389.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5898 +title: "Previously, triggering a `$meta` via GET on a new patient with Megascale configured resulted in error HAPI-0389. This has been corrected + This has been fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml new file mode 100644 index 00000000000..8746c27e136 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5899-enhance-mdm-interceptor.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 5899 +title: "The `MDM_POST_MERGE_GOLDEN_RESOURCES` now supports an additional parameter, of type `ca.uhn.fhir.mdm.model.MdmTransactionContext`. Thanks to Jens Villadsen for the contribution." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml new file mode 100644 index 00000000000..9c8c9873f6d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5904-query-chained-sort-returns-less-results.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5904 +title: "Chained sort would exclude results that did not have resources matching the sort chain. These are now included, and sorted at the end." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml new file mode 100644 index 00000000000..8bd43c7a5c0 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5915-bulk-export-security-woes.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5915 +title: "Previously, in some edge case scenarios the Bulk Export Rule Applier could accidentally permit a Patient type level bulk export request, even if the calling user only had permissions to a subset of patients. This has been corrected." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml new file mode 100644 index 00000000000..1e94d65c58d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_2_0/5917-chain-sort-mssql.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 5917 +title: "Fix chained sorts on strings when using MS Sql" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md index 2fea34f786b..412efaf27a8 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/binary_security_interceptor.md @@ -14,4 +14,9 @@ This interceptor is intended to be subclassed. A simple example is shown below: ## Combining with Bulk Export -The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. An interceptor on the `STORAGE_INITIATE_BULK_EXPORT` pointcut is the easiest way to set these properties when a new Bulk Export job is being kicked off. +The `setBinarySecurityContextIdentifierSystem(..)` and `setBinarySecurityContextIdentifierValue(..)` properties on the `BulkExportJobParameters` object can be used to automatically populate the security context on Binary resources created by Bulk Export jobs with values that can be verified by this interceptor. +An interceptor on the `STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is the recommended way to set these properties when a new Bulk Export job is being kicked off. + +NB: Previous versions recommended using the `STORAGE_INITIATE_BULK_EXPORT` pointcut, but this is no longer the recommended way. +`STORAGE_PRE_INITIATE_BULK_EXPORT` pointcut is called before `STORAGE_INITIATE_BULK_EXPORT` and is thus guaranteed to be called before +any AuthorizationInterceptors. diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 3ba709907e0..a1e8a5b7719 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index a36f270f1ca..3015345ac60 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index fd28ff49ed0..cbe8992f6af 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index d4995828336..9b3f1e03072 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java index 8f79e37ecb9..94eddb83955 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImpl.java @@ -26,6 +26,7 @@ import ca.uhn.fhir.jpa.dao.data.IBinaryStorageEntityDao; import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import com.google.common.annotations.VisibleForTesting; import com.google.common.hash.HashingInputStream; import com.google.common.io.ByteStreams; import jakarta.annotation.Nonnull; @@ -59,6 +60,8 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp @Autowired private IBinaryStorageEntityDao myBinaryStorageEntityDao; + private boolean mySupportLegacyLobServer = false; + @Nonnull @Override @Transactional(propagation = Propagation.REQUIRED) @@ -96,9 +99,10 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp entity.setContentId(id); entity.setStorageContentBin(loadedStream); - // TODO: remove writing Blob in a future release - Blob dataBlob = lobHelper.createBlob(loadedStream); - entity.setBlob(dataBlob); + if (mySupportLegacyLobServer) { + Blob dataBlob = lobHelper.createBlob(loadedStream); + entity.setBlob(dataBlob); + } // Update the entity with the final byte count and hash long bytes = countingInputStream.getByteCount(); @@ -169,6 +173,11 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return copyBinaryContentToByteArray(entityOpt); } + public DatabaseBinaryContentStorageSvcImpl setSupportLegacyLobServer(boolean theSupportLegacyLobServer) { + mySupportLegacyLobServer = theSupportLegacyLobServer; + return this; + } + void copyBinaryContentToOutputStream(OutputStream theOutputStream, BinaryStorageEntity theEntity) throws IOException { @@ -212,4 +221,10 @@ public class DatabaseBinaryContentStorageSvcImpl extends BaseBinaryStorageSvcImp return retVal; } + + @VisibleForTesting + public DatabaseBinaryContentStorageSvcImpl setEntityManagerForTesting(EntityManager theEntityManager) { + myEntityManager = theEntityManager; + return this; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java index e60974ae642..67a7f55d28e 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java @@ -73,6 +73,7 @@ import ca.uhn.fhir.jpa.delete.DeleteConflictFinderService; import ca.uhn.fhir.jpa.delete.DeleteConflictService; import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc; import ca.uhn.fhir.jpa.entity.Search; +import ca.uhn.fhir.jpa.entity.TermValueSet; import ca.uhn.fhir.jpa.esr.ExternallyStoredResourceServiceRegistry; import ca.uhn.fhir.jpa.graphql.DaoRegistryGraphQLStorageServices; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; @@ -154,6 +155,8 @@ import ca.uhn.fhir.jpa.term.TermCodeSystemStorageSvcImpl; import ca.uhn.fhir.jpa.term.TermConceptMappingSvcImpl; import ca.uhn.fhir.jpa.term.TermReadSvcImpl; import ca.uhn.fhir.jpa.term.TermReindexingSvcImpl; +import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulator; +import ca.uhn.fhir.jpa.term.ValueSetConceptAccumulatorFactory; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc; import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; @@ -822,6 +825,17 @@ public class JpaConfig { return new TermReadSvcImpl(); } + @Bean + public ValueSetConceptAccumulatorFactory valueSetConceptAccumulatorFactory() { + return new ValueSetConceptAccumulatorFactory(); + } + + @Bean + @Scope("prototype") + public ValueSetConceptAccumulator valueSetConceptAccumulator(TermValueSet theTermValueSet) { + return valueSetConceptAccumulatorFactory().create(theTermValueSet); + } + @Bean public ITermCodeSystemStorageSvc termCodeSystemStorageSvc() { return new TermCodeSystemStorageSvcImpl(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index 686667b2813..1e786ad5070 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -1410,19 +1410,20 @@ public abstract class BaseHapiFhirResourceDao extends B } @Override - @Transactional public MT metaGetOperation(Class theType, IIdType theId, RequestDetails theRequest) { - Set tagDefs = new HashSet<>(); - BaseHasResource entity = readEntity(theId, theRequest); - for (BaseTag next : entity.getTags()) { - tagDefs.add(next.getTag()); - } - MT retVal = toMetaDt(theType, tagDefs); + return myTransactionService.withRequest(theRequest).execute(() -> { + Set tagDefs = new HashSet<>(); + BaseHasResource entity = readEntity(theId, theRequest); + for (BaseTag next : entity.getTags()) { + tagDefs.add(next.getTag()); + } + MT retVal = toMetaDt(theType, tagDefs); - retVal.setLastUpdated(entity.getUpdatedDate()); - retVal.setVersionId(Long.toString(entity.getVersion())); + retVal.setLastUpdated(entity.getUpdatedDate()); + retVal.setVersionId(Long.toString(entity.getVersion())); - return retVal; + return retVal; + }); } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java index 57674d4cfc7..d238278bcfe 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConcept.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum; import ca.uhn.fhir.jpa.search.DeferConceptIndexingRoutingBinder; import ca.uhn.fhir.util.ValidateUtil; +import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -58,10 +59,7 @@ import org.hibernate.search.mapper.pojo.bridge.mapping.annotation.RoutingBinderR import org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.Indexed; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.IndexingDependency; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.ObjectPath; import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyBinding; -import org.hibernate.search.mapper.pojo.mapping.definition.annotation.PropertyValue; import org.hl7.fhir.r4.model.Coding; import java.io.Serializable; @@ -177,6 +175,11 @@ public class TermConcept implements Serializable { @Column(name = "PARENT_PIDS", nullable = true) private String myParentPids; + @FullTextField( + name = "myParentPids", + searchable = Searchable.YES, + projectable = Projectable.YES, + analyzer = "conceptParentPidsAnalyzer") @Column(name = "PARENT_PIDS_VC", nullable = true, length = Length.LONG32) private String myParentPidsVc; @@ -189,6 +192,9 @@ public class TermConcept implements Serializable { @Column(name = "CODE_SEQUENCE", nullable = true) private Integer mySequence; + @Transient + private boolean mySupportLegacyLob = false; + public TermConcept() { super(); } @@ -362,13 +368,6 @@ public class TermConcept implements Serializable { return this; } - @Transient - @FullTextField( - name = "myParentPids", - searchable = Searchable.YES, - projectable = Projectable.YES, - analyzer = "conceptParentPidsAnalyzer") - @IndexingDependency(derivedFrom = @ObjectPath({@PropertyValue(propertyName = "myParentPidsVc")})) public String getParentPidsAsString() { return nonNull(myParentPidsVc) ? myParentPidsVc : myParentPids; } @@ -458,6 +457,10 @@ public class TermConcept implements Serializable { ourLog.trace("Code {}/{} has parents {}", entity.getId(), entity.getCode(), entity.getParentPidsAsString()); } + + if (!mySupportLegacyLob) { + clearParentPidsLob(); + } } private void setParentPids(Set theParentPids) { @@ -519,4 +522,17 @@ public class TermConcept implements Serializable { public List getChildCodes() { return getChildren().stream().map(TermConceptParentChildLink::getChild).collect(Collectors.toList()); } + + public void flagForLegacyLobSupport(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + } + + private void clearParentPidsLob() { + myParentPids = null; + } + + @VisibleForTesting + public boolean hasParentPidsLobForTesting() { + return nonNull(myParentPids); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java index 6bbc3b178a4..790dc9048c7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermConceptProperty.java @@ -54,6 +54,7 @@ import org.hibernate.validator.constraints.NotBlank; import java.io.Serializable; import java.nio.charset.StandardCharsets; +import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -307,9 +308,15 @@ public class TermConceptProperty implements Serializable { return myId; } + public void performLegacyLobSupport(boolean theSupportLegacyLob) { + if (!theSupportLegacyLob) { + myValueLob = null; + } + } + @VisibleForTesting - public byte[] getValueBlobForTesting() { - return myValueLob; + public boolean hasValueBlobForTesting() { + return nonNull(myValueLob); } @VisibleForTesting @@ -318,8 +325,8 @@ public class TermConceptProperty implements Serializable { } @VisibleForTesting - public byte[] getValueBinForTesting() { - return myValueBin; + public boolean hasValueBinForTesting() { + return nonNull(myValueBin); } @VisibleForTesting diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java index 2e17bc6ae9c..c822c56046c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConcept.java @@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity; import ca.uhn.fhir.util.ValidateUtil; +import com.google.common.annotations.VisibleForTesting; import jakarta.annotation.Nonnull; import jakarta.persistence.Column; import jakarta.persistence.Entity; @@ -46,6 +47,7 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import static java.util.Objects.nonNull; import static org.apache.commons.lang3.StringUtils.isNotEmpty; import static org.apache.commons.lang3.StringUtils.left; import static org.apache.commons.lang3.StringUtils.length; @@ -296,4 +298,13 @@ public class TermValueSetConcept implements Serializable { ? mySourceConceptDirectParentPidsVc : mySourceConceptDirectParentPids; } + + public void clearSourceConceptDirectParentPidsLob() { + mySourceConceptDirectParentPids = null; + } + + @VisibleForTesting + public boolean hasSourceConceptDirectParentPidsLob() { + return nonNull(mySourceConceptDirectParentPids); + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java index c66c41a9b7e..28f80e15c62 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java @@ -43,20 +43,21 @@ import java.sql.SQLException; * because hibernate won't allow the view the function without it, but */ "SELECT CONCAT_WS(' ', vsc.PID, vscd.PID) AS PID, " + " vsc.PID AS CONCEPT_PID, " - + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " - + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " - + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " - + " vsc.CODEVAL AS CONCEPT_CODEVAL, " - + " vsc.DISPLAY AS CONCEPT_DISPLAY, " - + " vsc.SYSTEM_VER AS SYSTEM_VER, " - + " vsc.SOURCE_PID AS SOURCE_PID, " - + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " - + " vscd.PID AS DESIGNATION_PID, " - + " vscd.LANG AS DESIGNATION_LANG, " - + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " - + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " - + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " - + " vscd.VAL AS DESIGNATION_VAL " + + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + + " vsc.CODEVAL AS CONCEPT_CODEVAL, " + + " vsc.DISPLAY AS CONCEPT_DISPLAY, " + + " vsc.SYSTEM_VER AS SYSTEM_VER, " + + " vsc.SOURCE_PID AS SOURCE_PID, " + + " vsc.SOURCE_DIRECT_PARENT_PIDS AS SOURCE_DIRECT_PARENT_PIDS, " + + " vsc.SOURCE_DIRECT_PARENT_PIDS_VC AS SOURCE_DIRECT_PARENT_PIDS_VC, " + + " vscd.PID AS DESIGNATION_PID, " + + " vscd.LANG AS DESIGNATION_LANG, " + + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " + + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + + " vscd.VAL AS DESIGNATION_VAL " + "FROM TRM_VALUESET_CONCEPT vsc " + "LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID") public class TermValueSetConceptView implements Serializable, ITermValueSetConceptView { @@ -112,6 +113,9 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Column(name = "SOURCE_DIRECT_PARENT_PIDS", nullable = true) private Clob mySourceConceptDirectParentPids; + @Column(name = "SOURCE_DIRECT_PARENT_PIDS_VC", nullable = true) + private String mySourceConceptDirectParentPidsVc; + @Override public Long getSourceConceptPid() { return mySourceConceptPid; @@ -119,14 +123,19 @@ public class TermValueSetConceptView implements Serializable, ITermValueSetConce @Override public String getSourceConceptDirectParentPids() { + String retVal = null; + if (mySourceConceptDirectParentPids != null) { try (Reader characterStream = mySourceConceptDirectParentPids.getCharacterStream()) { - return IOUtils.toString(characterStream); + retVal = IOUtils.toString(characterStream); } catch (IOException | SQLException e) { throw new InternalErrorException(Msg.code(828) + e); } + } else if (mySourceConceptDirectParentPidsVc != null) { + retVal = mySourceConceptDirectParentPidsVc; } - return null; + + return retVal; } @Override diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 3c421278e10..03a34c96468 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.entity.BulkImportJobEntity; import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; import ca.uhn.fhir.jpa.migrate.taskdef.ArbitrarySqlTask; +import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateHashesTask; import ca.uhn.fhir.jpa.migrate.taskdef.CalculateOrdinalDatesTask; import ca.uhn.fhir.jpa.migrate.taskdef.ColumnTypeEnum; @@ -146,8 +147,16 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { binaryStorageBlobTable .renameColumn("20240404.1", "BLOB_ID", "CONTENT_ID") + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); + binaryStorageBlobTable .renameColumn("20240404.2", "BLOB_SIZE", "CONTENT_SIZE") - .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH"); + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); + binaryStorageBlobTable + .renameColumn("20240404.3", "BLOB_HASH", "CONTENT_HASH") + .getLastAddedTask() + .ifPresent(BaseTask::doNothing); binaryStorageBlobTable .modifyColumn("20240404.4", "BLOB_DATA") @@ -159,9 +168,23 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - binaryStorageBlobTable.migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN"); + binaryStorageBlobTable + .migrateBlobToBinary("20240404.6", "BLOB_DATA", "STORAGE_CONTENT_BIN") + .doNothing(); - binaryStorageBlobTable.renameTable("20240404.7", "HFJ_BINARY_STORAGE"); + binaryStorageBlobTable + .renameTable("20240404.7", "HFJ_BINARY_STORAGE") + .doNothing(); + + Builder.BuilderWithTableName binaryStorageTableFix = version.onTable("HFJ_BINARY_STORAGE"); + + binaryStorageTableFix.renameColumn("20240404.10", "CONTENT_ID", "BLOB_ID", true, true); + binaryStorageTableFix.renameColumn("20240404.20", "CONTENT_SIZE", "BLOB_SIZE", true, true); + binaryStorageTableFix.renameColumn("20240404.30", "CONTENT_HASH", "BLOB_HASH", true, true); + + binaryStorageTableFix + .renameTable("20240404.40", "HFJ_BINARY_STORAGE_BLOB") + .failureAllowed(); } { @@ -172,7 +195,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.BINARY); - termConceptPropertyTable.migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN"); + termConceptPropertyTable + .migrateBlobToBinary("20240409.2", "PROP_VAL_LOB", "PROP_VAL_BIN") + .doNothing(); } { @@ -182,8 +207,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termValueSetConceptTable.migrateClobToText( - "20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC"); + termValueSetConceptTable + .migrateClobToText("20240409.4", "SOURCE_DIRECT_PARENT_PIDS", "SOURCE_DIRECT_PARENT_PIDS_VC") + .doNothing(); } { @@ -193,7 +219,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .nullable() .type(ColumnTypeEnum.TEXT); - termConceptTable.migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC"); + termConceptTable + .migrateClobToText("20240410.2", "PARENT_PIDS", "PARENT_PIDS_VC") + .doNothing(); } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java index bbc74d27dd5..6202049515d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java @@ -37,7 +37,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { IPartitionLookupSvc myPartitionConfigSvc; @Override - protected RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { List names = null; for (int i = 0; i < theRequestPartitionId.getPartitionIds().size(); i++) { @@ -59,7 +59,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } } - if (theRequestPartitionId.getPartitionNames() != null) { + if (theRequestPartitionId.hasPartitionNames()) { if (partition == null) { Validate.isTrue( theRequestPartitionId.getPartitionIds().get(i) == null, @@ -68,8 +68,8 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } else { Validate.isTrue( Objects.equals( - theRequestPartitionId.getPartitionIds().get(i), partition.getId()), - "Partition name %s does not match ID %n", + theRequestPartitionId.getPartitionNames().get(i), partition.getName()), + "Partition name %s does not match ID %s", theRequestPartitionId.getPartitionNames().get(i), theRequestPartitionId.getPartitionIds().get(i)); } @@ -94,7 +94,7 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { } @Override - protected RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { List ids = null; for (int i = 0; i < theRequestPartitionId.getPartitionNames().size(); i++) { @@ -122,9 +122,9 @@ public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc { Validate.isTrue( Objects.equals( theRequestPartitionId.getPartitionIds().get(i), partition.getId()), - "Partition name %s does not match ID %n", - theRequestPartitionId.getPartitionNames().get(i), - theRequestPartitionId.getPartitionIds().get(i)); + "Partition ID %s does not match name %s", + theRequestPartitionId.getPartitionIds().get(i), + theRequestPartitionId.getPartitionNames().get(i)); } } else { if (ids == 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 4f0b3e60778..685f96c16f8 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 @@ -353,26 +353,39 @@ public class QueryStack { throw new InvalidRequestException(Msg.code(2289) + msg); } - BaseSearchParamPredicateBuilder chainedPredicateBuilder; - DbColumn[] sortColumn; + // add a left-outer join to a predicate for the target type, then sort on value columns(s). switch (targetSearchParameter.getParamType()) { case STRING: StringPredicateBuilder stringPredicateBuilder = mySqlBuilder.createStringPredicateBuilder(); - sortColumn = new DbColumn[] {stringPredicateBuilder.getColumnValueNormalized()}; - chainedPredicateBuilder = stringPredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + stringPredicateBuilder, + stringPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortString( + stringPredicateBuilder.getColumnValueNormalized(), theAscending, myUseAggregate); + return; + case TOKEN: TokenPredicateBuilder tokenPredicateBuilder = mySqlBuilder.createTokenPredicateBuilder(); - sortColumn = - new DbColumn[] {tokenPredicateBuilder.getColumnSystem(), tokenPredicateBuilder.getColumnValue() - }; - chainedPredicateBuilder = tokenPredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + tokenPredicateBuilder, + tokenPredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnSystem(), theAscending, myUseAggregate); + mySqlBuilder.addSortString(tokenPredicateBuilder.getColumnValue(), theAscending, myUseAggregate); + return; + case DATE: DatePredicateBuilder datePredicateBuilder = mySqlBuilder.createDatePredicateBuilder(); - sortColumn = new DbColumn[] {datePredicateBuilder.getColumnValueLow()}; - chainedPredicateBuilder = datePredicateBuilder; - break; + addSortCustomJoin( + resourceLinkPredicateBuilder.getColumnTargetResourceId(), + datePredicateBuilder, + datePredicateBuilder.createHashIdentityPredicate(targetType, theChain)); + + mySqlBuilder.addSortDate(datePredicateBuilder.getColumnValueLow(), theAscending, myUseAggregate); + return; /* * Note that many of the options below aren't implemented because they @@ -417,14 +430,6 @@ public class QueryStack { + theParamName + "." + theChain + " as this parameter. Can not sort on chains of target type: " + targetSearchParameter.getParamType().name()); } - - addSortCustomJoin(resourceLinkPredicateBuilder.getColumnTargetResourceId(), chainedPredicateBuilder, null); - Condition predicate = chainedPredicateBuilder.createHashIdentityPredicate(targetType, theChain); - mySqlBuilder.addPredicate(predicate); - - for (DbColumn next : sortColumn) { - mySqlBuilder.addSortNumeric(next, theAscending, myUseAggregate); - } } public void addSortOnString(String theResourceName, String theParamName, boolean theAscending) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java index 61fbea5830e..15998b0e8e6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermCodeSystemStorageSvcImpl.java @@ -73,7 +73,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; @@ -685,26 +684,6 @@ public class TermCodeSystemStorageSvcImpl implements ITermCodeSystemStorageSvc { } } - private int ensureParentsSaved(Collection theParents) { - ourLog.trace("Checking {} parents", theParents.size()); - int retVal = 0; - - for (TermConceptParentChildLink nextLink : theParents) { - if (nextLink.getRelationshipType() == TermConceptParentChildLink.RelationshipTypeEnum.ISA) { - TermConcept nextParent = nextLink.getParent(); - retVal += ensureParentsSaved(nextParent.getParents()); - if (nextParent.getId() == null) { - nextParent.setUpdated(new Date()); - myConceptDao.saveAndFlush(nextParent); - retVal++; - ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); - } - } - } - - return retVal; - } - @Nonnull private TermCodeSystem getOrCreateDistinctTermCodeSystem( IResourcePersistentId theCodeSystemResourcePid, diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java index 9bcf47aebb0..1927de43500 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvc.java @@ -46,6 +46,8 @@ public class TermConceptDaoSvc { @Autowired protected ITermConceptDesignationDao myConceptDesignationDao; + private boolean mySupportLegacyLob = false; + public int saveConcept(TermConcept theConcept) { int retVal = 0; @@ -70,9 +72,11 @@ public class TermConceptDaoSvc { retVal++; theConcept.setIndexStatus(BaseHapiFhirDao.INDEX_STATUS_INDEXED); theConcept.setUpdated(new Date()); + theConcept.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.save(theConcept); for (TermConceptProperty next : theConcept.getProperties()) { + next.performLegacyLobSupport(mySupportLegacyLob); myConceptPropertyDao.save(next); } @@ -85,6 +89,11 @@ public class TermConceptDaoSvc { return retVal; } + public TermConceptDaoSvc setSupportLegacyLob(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + return this; + } + private int ensureParentsSaved(Collection theParents) { ourLog.trace("Checking {} parents", theParents.size()); int retVal = 0; @@ -95,6 +104,7 @@ public class TermConceptDaoSvc { retVal += ensureParentsSaved(nextParent.getParents()); if (nextParent.getId() == null) { nextParent.setUpdated(new Date()); + nextParent.flagForLegacyLobSupport(mySupportLegacyLob); myConceptDao.saveAndFlush(nextParent); retVal++; ourLog.debug("Saved parent code {} and got id {}", nextParent.getCode(), nextParent.getId()); 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 86235e0403b..2705ed40fe5 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 @@ -293,6 +293,9 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { @Autowired private InMemoryTerminologyServerValidationSupport myInMemoryTerminologyServerValidationSupport; + @Autowired + private ValueSetConceptAccumulatorFactory myValueSetConceptAccumulatorFactory; + @Override public boolean isCodeSystemSupported(ValidationSupportContext theValidationSupportContext, String theSystem) { TermCodeSystemVersionDetails cs = getCurrentCodeSystemVersion(theSystem); @@ -2393,11 +2396,11 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { }); assert valueSet != null; - ValueSetConceptAccumulator accumulator = new ValueSetConceptAccumulator( - valueSetToExpand, myTermValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); + ValueSetConceptAccumulator valueSetConceptAccumulator = + myValueSetConceptAccumulatorFactory.create(valueSetToExpand); ValueSetExpansionOptions options = new ValueSetExpansionOptions(); options.setIncludeHierarchy(true); - expandValueSet(options, valueSet, accumulator); + expandValueSet(options, valueSet, valueSetConceptAccumulator); // We are done with this ValueSet. txTemplate.executeWithoutResult(t -> { @@ -2412,7 +2415,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs { "Pre-expanded ValueSet[{}] with URL[{}] - Saved {} concepts in {}", valueSet.getId(), valueSet.getUrl(), - accumulator.getConceptsSaved(), + valueSetConceptAccumulator.getConceptsSaved(), sw); } catch (Exception e) { diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java index 6561495ad45..9aa38413bb7 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulator.java @@ -48,6 +48,8 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { private int myDesignationsSaved; private int myConceptsExcluded; + private boolean mySupportLegacyLob = false; + public ValueSetConceptAccumulator( @Nonnull TermValueSet theTermValueSet, @Nonnull ITermValueSetDao theValueSetDao, @@ -184,6 +186,10 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { concept.setSourceConceptPid(theSourceConceptPid); concept.setSourceConceptDirectParentPids(theSourceConceptDirectParentPids); + if (!mySupportLegacyLob) { + concept.clearSourceConceptDirectParentPidsLob(); + } + myValueSetConceptDao.save(concept); myValueSetDao.save(myTermValueSet.incrementTotalConcepts()); @@ -253,4 +259,9 @@ public class ValueSetConceptAccumulator implements IValueSetConceptAccumulator { // TODO: DM 2019-07-16 - If so, we should also populate TermValueSetConceptProperty entities here. // TODO: DM 2019-07-30 - Expansions don't include the properties themselves; they may be needed to facilitate // filters and parameterized expansions. + + public ValueSetConceptAccumulator setSupportLegacyLob(boolean theSupportLegacyLob) { + mySupportLegacyLob = theSupportLegacyLob; + return this; + } } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java new file mode 100644 index 00000000000..e61da193b8a --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorFactory.java @@ -0,0 +1,51 @@ +/*- + * #%L + * HAPI FHIR JPA Server + * %% + * 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.jpa.term; + +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDao; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetConceptDesignationDao; +import ca.uhn.fhir.jpa.dao.data.ITermValueSetDao; +import ca.uhn.fhir.jpa.entity.TermValueSet; +import org.springframework.beans.factory.annotation.Autowired; + +public class ValueSetConceptAccumulatorFactory { + + @Autowired + private ITermValueSetDao myValueSetDao; + + @Autowired + private ITermValueSetConceptDao myValueSetConceptDao; + + @Autowired + private ITermValueSetConceptDesignationDao myValueSetConceptDesignationDao; + + @Autowired + private JpaStorageSettings myStorageSettings; + + public ValueSetConceptAccumulator create(TermValueSet theTermValueSet) { + ValueSetConceptAccumulator valueSetConceptAccumulator = new ValueSetConceptAccumulator( + theTermValueSet, myValueSetDao, myValueSetConceptDao, myValueSetConceptDesignationDao); + + valueSetConceptAccumulator.setSupportLegacyLob(myStorageSettings.isWriteToLegacyLobColumns()); + + return valueSetConceptAccumulator; + } +} diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java index 297d0726ce3..44132dbdbd6 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/term/config/TermCodeSystemConfig.java @@ -19,6 +19,7 @@ */ package ca.uhn.fhir.jpa.term.config; +import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; import ca.uhn.fhir.jpa.term.TermConceptDaoSvc; import ca.uhn.fhir.jpa.term.TermDeferredStorageSvcImpl; import ca.uhn.fhir.jpa.term.api.ITermCodeSystemDeleteJobSvc; @@ -41,7 +42,7 @@ public class TermCodeSystemConfig { } @Bean - public TermConceptDaoSvc termConceptDaoSvc() { - return new TermConceptDaoSvc(); + public TermConceptDaoSvc termConceptDaoSvc(JpaStorageSettings theJpaStorageSettings) { + return new TermConceptDaoSvc().setSupportLegacyLob(theJpaStorageSettings.isWriteToLegacyLobColumns()); } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java index 44a01649cfd..cda9c4554a9 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/entity/TermConceptPropertyTest.java @@ -2,8 +2,11 @@ package ca.uhn.fhir.jpa.entity; import com.google.common.base.Strings; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; @@ -21,8 +24,8 @@ public class TermConceptPropertyTest { termConceptProperty.setValue(ourVeryLongString); // then - assertThat(termConceptProperty.getValueBlobForTesting(), notNullValue()); - assertThat(termConceptProperty.getValueBinForTesting(), notNullValue()); + assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(true)); + assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); } @Test @@ -78,4 +81,19 @@ public class TermConceptPropertyTest { assertThat(value, startsWith("a")); } + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testSetValue_withSupportLegacyLob(boolean theSupportLegacyLob){ + // given + TermConceptProperty termConceptProperty = new TermConceptProperty(); + + // when + termConceptProperty.setValue(ourVeryLongString); + termConceptProperty.performLegacyLobSupport(theSupportLegacyLob); + + // then + assertThat(termConceptProperty.hasValueBinForTesting(), equalTo(true)); + assertThat(termConceptProperty.hasValueBlobForTesting(), equalTo(theSupportLegacyLob)); + } + } diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index 157c68d5c0c..ceacb98ed4f 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-hfql/pom.xml b/hapi-fhir-jpaserver-hfql/pom.xml index 706d5ca1335..2b3e69a5d91 100644 --- a/hapi-fhir-jpaserver-hfql/pom.xml +++ b/hapi-fhir-jpaserver-hfql/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml index ca914b4b1bd..425e1cad165 100644 --- a/hapi-fhir-jpaserver-ips/pom.xml +++ b/hapi-fhir-jpaserver-ips/pom.xml @@ -3,7 +3,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index 3030cb455b6..e8897259569 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java index 5165581e3ef..690d2cc061d 100644 --- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java +++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java @@ -166,6 +166,7 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc { HookParams params = new HookParams(); params.add(MdmMergeEvent.class, event); params.add(RequestDetails.class, theParams.getRequestDetails()); + params.add(MdmTransactionContext.class, theParams.getMdmTransactionContext()); myInterceptorBroadcaster.callHooks(Pointcut.MDM_POST_MERGE_GOLDEN_RESOURCES, params); } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java index febcaf4c6e9..5e3aaad9f42 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplIT.java @@ -2,11 +2,16 @@ package ca.uhn.fhir.jpa.mdm.svc; import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test; import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService; +import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum; +import ca.uhn.fhir.mdm.api.MdmMatchOutcome; import ca.uhn.fhir.mdm.model.MdmTransactionContext; +import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; @@ -55,4 +60,21 @@ class MdmSurvivorshipSvcImplIT extends BaseMdmR4Test { assertEquals(p1.getTelecom().size(), p1.getTelecom().size()); assertTrue(p2.getTelecomFirstRep().equalsDeep(p1.getTelecomFirstRep())); } + + @Test + public void matchingPatientsWith_NON_Numeric_Ids_matches_doesNotThrow_NumberFormatException() { + final Patient frankPatient1 = buildFrankPatient(); + frankPatient1.setId("patA"); + myPatientDao.update(frankPatient1, new SystemRequestDetails()); + final Patient frankPatient2 = buildFrankPatient(); + frankPatient2.setId("patB"); + myPatientDao.update(frankPatient2, new SystemRequestDetails()); + final Patient goldenPatient = buildFrankPatient(); + myPatientDao.create(goldenPatient, new SystemRequestDetails()); + + myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); + myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, frankPatient2, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient")); + + myMdmSurvivorshipService.rebuildGoldenResourceWithSurvivorshipRules(goldenPatient, new MdmTransactionContext(MdmTransactionContext.OperationType.UPDATE_LINK)); + } } diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java index a6502687415..65cc7bde0c4 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmSurvivorshipSvcImplTest.java @@ -25,8 +25,9 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.mockito.Mock; import org.mockito.Spy; import org.mockito.junit.jupiter.MockitoExtension; @@ -96,8 +97,9 @@ public class MdmSurvivorshipSvcImplTest { } @SuppressWarnings({"rawtypes", "unchecked"}) - @Test - public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder() { + @ParameterizedTest + @ValueSource(booleans = {true,false}) + public void rebuildGoldenResourceCurrentLinksUsingSurvivorshipRules_withManyLinks_rebuildsInUpdateOrder(boolean theIsUseNonNumericId) { // setup // create resources Patient goldenPatient = new Patient(); @@ -126,7 +128,7 @@ public class MdmSurvivorshipSvcImplTest { patient.addIdentifier() .setSystem("http://example.com") .setValue("Value" + i); - patient.setId("Patient/" + i); + patient.setId("Patient/" + (theIsUseNonNumericId ? "pat"+i : Integer.toString(i))); resources.add(patient); MdmLinkJson link = createLinkJson( @@ -149,8 +151,13 @@ public class MdmSurvivorshipSvcImplTest { when(myDaoRegistry.getResourceDao(eq("Patient"))) .thenReturn(resourceDao); AtomicInteger counter = new AtomicInteger(); - when(resourceDao.readByPid(any())) - .thenAnswer(params -> resources.get(counter.getAndIncrement())); + if (theIsUseNonNumericId) { + when(resourceDao.read(any(), any())) + .thenAnswer(params -> resources.get(counter.getAndIncrement())); + } else { + when(resourceDao.readByPid(any())) + .thenAnswer(params -> resources.get(counter.getAndIncrement())); + } Page linkPage = mock(Page.class); when(myMdmLinkQuerySvc.queryLinks(any(), any())) .thenReturn(linkPage); diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index d2028f332ae..ab641072b81 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java index c71b8e29fda..c6b046e0bff 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/BinaryStorageEntity.java @@ -34,23 +34,26 @@ import java.util.Date; import static java.util.Objects.nonNull; @Entity -@Table(name = "HFJ_BINARY_STORAGE") +@Table(name = "HFJ_BINARY_STORAGE_BLOB") public class BinaryStorageEntity { @Id - @Column(name = "CONTENT_ID", length = 200, nullable = false) + @Column(name = "BLOB_ID", length = 200, nullable = false) // N.B GGG: Note that the `content id` is the same as the `externalized binary id`. private String myContentId; @Column(name = "RESOURCE_ID", length = 100, nullable = false) private String myResourceId; - @Column(name = "CONTENT_SIZE", nullable = true) + @Column(name = "BLOB_SIZE", nullable = true) private long mySize; @Column(name = "CONTENT_TYPE", nullable = false, length = 100) private String myContentType; + /** + * @deprecated + */ @Deprecated(since = "7.2.0") @Lob // TODO: VC column added in 7.2.0 - Remove non-VC column later @Column(name = "BLOB_DATA", nullable = true, insertable = true, updatable = false) @@ -63,7 +66,7 @@ public class BinaryStorageEntity { @Column(name = "PUBLISHED_DATE", nullable = false) private Date myPublished; - @Column(name = "CONTENT_HASH", length = 128, nullable = true) + @Column(name = "BLOB_HASH", length = 128, nullable = true) private String myHash; public Date getPublished() { diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index 87f9dd268b2..a389caf223d 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java index cf17cf5af41..ede4b39e7ca 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java @@ -156,4 +156,30 @@ public interface IRequestPartitionHelperSvc { Set toReadPartitions(@Nonnull RequestPartitionId theRequestPartitionId); boolean isResourcePartitionable(String theResourceType); + + /** + * No interceptors should be invoked by this method. It should ONLY be used when partition ids are + * known, but partition names are not. + *

    + * Ensures the list of partition ids inside the given {@link RequestPartitionId} correctly map to the + * list of partition names. If the list of partition names is empty, this method will map the correct + * partition names and return a normalized {@link RequestPartitionId}. + *

    + * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. + * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. + */ + RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); + + /** + * No interceptors should be invoked by this method. It should ONLY be used when partition names are + * known, but partition ids are not. + *

    + * Ensures the list of partition names inside the given {@link RequestPartitionId} correctly map to the + * list of partition ids. If the list of partition ids is empty, this method will map the correct + * partition ids and return a normalized {@link RequestPartitionId}. + *

    + * @param theRequestPartitionId - An unvalidated and unnormalized {@link RequestPartitionId}. + * @return - A {@link RequestPartitionId} with a normalized list of partition ids and partition names. + */ + RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); } diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index e608341ec73..662f5721df9 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java new file mode 100644 index 00000000000..4d95a057c54 --- /dev/null +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/config/SubscriptionConfig.java @@ -0,0 +1,35 @@ +/*- + * #%L + * HAPI FHIR Subscription Server + * %% + * 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.jpa.subscription.config; + +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SubscriptionConfig { + @Bean + public SubscriptionQueryValidator subscriptionQueryValidator( + DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { + return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); + } +} diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java index 65e0d2010a7..ff056ad9207 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/submit/config/SubscriptionSubmitterConfig.java @@ -19,15 +19,13 @@ */ package ca.uhn.fhir.jpa.subscription.submit.config; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedProcessingSchedulerSvc; import ca.uhn.fhir.jpa.subscription.async.AsyncResourceModifiedSubmitterSvc; import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelFactory; -import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; import ca.uhn.fhir.jpa.subscription.model.config.SubscriptionModelConfig; -import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionSubmitInterceptorLoader; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionValidatingInterceptor; import ca.uhn.fhir.jpa.subscription.submit.svc.ResourceModifiedSubmitterSvc; @@ -45,7 +43,7 @@ import org.springframework.context.annotation.Lazy; * matching queue for processing */ @Configuration -@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class}) +@Import({SubscriptionModelConfig.class, SubscriptionMatcherInterceptorConfig.class, SubscriptionConfig.class}) public class SubscriptionSubmitterConfig { @Bean @@ -53,12 +51,6 @@ public class SubscriptionSubmitterConfig { return new SubscriptionValidatingInterceptor(); } - @Bean - public SubscriptionQueryValidator subscriptionQueryValidator( - DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { - return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); - } - @Bean public SubscriptionSubmitInterceptorLoader subscriptionMatcherInterceptorLoader() { return new SubscriptionSubmitInterceptorLoader(); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java index 4b571c7bd33..802f43a47e5 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/topic/SubscriptionTopicConfig.java @@ -22,13 +22,15 @@ package ca.uhn.fhir.jpa.topic; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.matcher.SearchParamMatcher; -import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator; +import ca.uhn.fhir.jpa.subscription.config.SubscriptionConfig; import ca.uhn.fhir.jpa.subscription.submit.interceptor.SubscriptionQueryValidator; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; @Configuration +@Import(SubscriptionConfig.class) public class SubscriptionTopicConfig { @Bean SubscriptionTopicMatchingSubscriber subscriptionTopicMatchingSubscriber(FhirContext theFhirContext) { @@ -76,13 +78,6 @@ public class SubscriptionTopicConfig { } } - @Bean - @Lazy - public SubscriptionQueryValidator subscriptionQueryValidator( - DaoRegistry theDaoRegistry, SubscriptionStrategyEvaluator theSubscriptionStrategyEvaluator) { - return new SubscriptionQueryValidator(theDaoRegistry, theSubscriptionStrategyEvaluator); - } - @Bean SubscriptionTopicValidatingInterceptor subscriptionTopicValidatingInterceptor( FhirContext theFhirContext, SubscriptionQueryValidator theSubscriptionQueryValidator) { diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index ccc242c944d..3085908ca26 100644 --- a/hapi-fhir-jpaserver-test-dstu2/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index bb969873766..04582ab3410 100644 --- a/hapi-fhir-jpaserver-test-dstu3/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index cc21ea5b56e..16932279acd 100644 --- a/hapi-fhir-jpaserver-test-r4/pom.xml +++ b/hapi-fhir-jpaserver-test-r4/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java index a0c6b7c4279..ecca07f2b98 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/binstore/DatabaseBinaryContentStorageSvcImplTest.java @@ -7,8 +7,12 @@ import ca.uhn.fhir.jpa.model.entity.BinaryStorageEntity; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; +import jakarta.persistence.EntityManager; +import org.hibernate.LobHelper; +import org.hibernate.Session; import org.hl7.fhir.r4.model.IdType; import org.junit.jupiter.api.Test; +import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; @@ -24,6 +28,7 @@ import java.sql.SQLException; import java.util.Optional; import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.matchesPattern; @@ -34,6 +39,7 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -281,7 +287,7 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { } @Test - public void testStoreBinaryContent_writesBlobAndByteArray() throws IOException { + public void testStoreBinaryContent_byDefault_writesByteArrayOnly() throws IOException { // given ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); String contentType = "image/png"; @@ -296,11 +302,41 @@ public class DatabaseBinaryContentStorageSvcImplTest extends BaseJpaR4Test { // then assertThat(binaryStorageEntity.hasStorageContent(), is(true)); - assertThat(binaryStorageEntity.hasBlob(), is(true)); + assertThat(binaryStorageEntity.hasBlob(), is(false)); }); } + @Test + public void testStoreBinaryContent_whenSupportingLegacyBlobServer_willStoreToBlobAndBinaryArray() throws IOException { + ArgumentCaptor captor = ArgumentCaptor.forClass(BinaryStorageEntity.class); + EntityManager mockedEntityManager = mock(EntityManager.class); + Session mockedSession = mock(Session.class); + LobHelper mockedLobHelper = mock(LobHelper.class); + when(mockedEntityManager.getDelegate()).thenReturn(mockedSession); + when(mockedSession.getLobHelper()).thenReturn(mockedLobHelper); + when(mockedLobHelper.createBlob(any())).thenReturn(mock(Blob.class)); + + // given + DatabaseBinaryContentStorageSvcImpl svc = new DatabaseBinaryContentStorageSvcImpl() + .setSupportLegacyLobServer(true) + .setEntityManagerForTesting(mockedEntityManager); + + ByteArrayInputStream inputStream = new ByteArrayInputStream(SOME_BYTES); + String contentType = "image/png"; + IdType resourceId = new IdType("Binary/123"); + + // when + svc.storeBinaryContent(resourceId, null, contentType, inputStream, new ServletRequestDetails()); + + // then + verify(mockedEntityManager, times(1)).persist(captor.capture()); + BinaryStorageEntity capturedBinaryStorageEntity = captor.getValue(); + + assertThat(capturedBinaryStorageEntity.hasBlob(), equalTo(true)); + assertThat(capturedBinaryStorageEntity.hasStorageContent(), equalTo(true)); + } + @Configuration public static class MyConfig { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java index 7efc920ccaf..95ab54ddb19 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4QuerySandbox.java @@ -9,8 +9,11 @@ import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.jpa.util.SqlQuery; import ca.uhn.fhir.jpa.util.SqlQueryList; +import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.storage.test.DaoTestDataBuilder; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -33,6 +36,8 @@ import java.util.List; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.not; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Sandbox for implementing queries. @@ -137,6 +142,28 @@ public class FhirResourceDaoR4QuerySandbox extends BaseJpaTest { myTestDaoSearch.assertSearchFindsInOrder("reverse sort by server assigned id", "Patient?family=smith&_sort=-_pid", id3,id2,id1); } + @Test + void testChainedSort() { + final IIdType practitionerId = myDataBuilder.createPractitioner(myDataBuilder.withFamily("Jones")); + + final String id1 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithy")).getIdPart(); + final String id2 = myDataBuilder.createPatient(myDataBuilder.withFamily("Smithwick")).getIdPart(); + final String id3 = myDataBuilder.createPatient( + myDataBuilder.withFamily("Smith"), + myDataBuilder.withReference("generalPractitioner", practitionerId)).getIdPart(); + + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); + assertEquals(3, iBundleProvider.size()); + + final List allResources = iBundleProvider.getAllResources(); + assertEquals(3, iBundleProvider.size()); + assertEquals(3, allResources.size()); + + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); + } + public static final class TestDirtiesContextTestExecutionListener extends DirtiesContextTestExecutionListener { @Override diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java index 4f90f46bc41..53ff09b50c6 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvcTest.java @@ -1,74 +1,189 @@ package ca.uhn.fhir.jpa.partition; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.model.RequestPartitionId; +import ca.uhn.fhir.jpa.dao.data.IPartitionDao; import ca.uhn.fhir.jpa.entity.PartitionEntity; import ca.uhn.fhir.jpa.model.config.PartitionSettings; +import ca.uhn.fhir.jpa.test.BaseJpaR4Test; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.InjectMocks; -import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.Set; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.Mockito.when; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; @ExtendWith(MockitoExtension.class) -class RequestPartitionHelperSvcTest { - static final Integer PARTITION_ID = 2401; - static final String PARTITION_NAME = "JIMMY"; - static final PartitionEntity ourPartitionEntity = new PartitionEntity().setName(PARTITION_NAME); +class RequestPartitionHelperSvcTest extends BaseJpaR4Test { - @Mock + static final int PARTITION_ID_1 = 1; + static final String PARTITION_NAME_1 = "SOME-PARTITION-1"; + + static final int PARTITION_ID_2 = 2; + static final String PARTITION_NAME_2 = "SOME-PARTITION-2"; + + static final int UNKNOWN_PARTITION_ID = 1_000_000; + static final String UNKNOWN_PARTITION_NAME = "UNKNOWN"; + + @Autowired + IPartitionDao myPartitionDao; + @Autowired PartitionSettings myPartitionSettings; - @Mock - IPartitionLookupSvc myPartitionLookupSvc; - @Mock - FhirContext myFhirContext; - @Mock - IInterceptorBroadcaster myInterceptorBroadcaster; + @Autowired + RequestPartitionHelperSvc mySvc; - @InjectMocks - RequestPartitionHelperSvc mySvc = new RequestPartitionHelperSvc(); + Patient myPatient; - @Test - public void determineReadPartitionForSystemRequest() { - // setup - SystemRequestDetails srd = new SystemRequestDetails(); - RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); - srd.setRequestPartitionId(requestPartitionId); - when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); - when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); + @BeforeEach + public void before(){ + myPartitionDao.deleteAll(); + myPartitionSettings.setPartitioningEnabled(true); - // execute - RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, "Patient", new IdType("Patient/123")); - - // verify - assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); + myPatient = new Patient(); + myPatient.setId(new IdType("Patient", "123", "1")); } @Test - public void determineCreatePartitionForSystemRequest() { + public void testDetermineReadPartitionForSystemRequest_withPartitionIdOnly_returnsCorrectPartition() { // setup + PartitionEntity partitionEntity = createPartition1(); SystemRequestDetails srd = new SystemRequestDetails(); - RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(PARTITION_ID); - srd.setRequestPartitionId(requestPartitionId); - when(myPartitionSettings.isPartitioningEnabled()).thenReturn(true); - when(myPartitionLookupSvc.getPartitionById(PARTITION_ID)).thenReturn(ourPartitionEntity); - Patient resource = new Patient(); - when(myFhirContext.getResourceType(resource)).thenReturn("Patient"); + srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); // execute - RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, resource, "Patient"); + RequestPartitionId result = mySvc.determineReadPartitionForRequestForRead(srd, myPatient.fhirType(), myPatient.getIdElement()); // verify - assertEquals(PARTITION_ID, result.getFirstPartitionIdOrNull()); - assertEquals(PARTITION_NAME, result.getFirstPartitionNameOrNull()); + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); } + @Test + public void testDetermineCreatePartitionForRequest_withPartitionIdOnly_returnsCorrectPartition() { + // setup + PartitionEntity partitionEntity = createPartition1(); + SystemRequestDetails srd = new SystemRequestDetails(); + srd.setRequestPartitionId(RequestPartitionId.fromPartitionId(partitionEntity.getId())); + + // execute + Patient patient = new Patient(); + RequestPartitionId result = mySvc.determineCreatePartitionForRequest(srd, patient, patient.fhirType()); + + // verify + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionIds_withPartitionIdOnly_populatesPartitionName(){ + PartitionEntity partitionEntity = createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(partitionEntity.getId()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); + + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionIds_withUnknownId_throwsException(){ + RequestPartitionId partitionId = RequestPartitionId.fromPartitionId(UNKNOWN_PARTITION_ID); + + try{ + mySvc.validateAndNormalizePartitionIds(partitionId); + fail(); + } catch (ResourceNotFoundException e){ + assertTrue(e.getMessage().contains("No partition exists with ID 1,000,000")); + } + } + + @Test + public void testValidateAndNormalizePartitionIds_withIdAndInvalidName_throwsException(){ + createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(PARTITION_ID_1, UNKNOWN_PARTITION_NAME); + + try{ + mySvc.validateAndNormalizePartitionIds(partitionId); + fail(); + } catch (IllegalArgumentException e){ + assertTrue(e.getMessage().contains("Partition name UNKNOWN does not match ID 1")); + } + } + + @Test + public void testValidateAndNormalizePartitionIds_withMultiplePartitionIdOnly_populatesPartitionNames(){ + PartitionEntity partitionEntity1 = createPartition1(); + PartitionEntity partitionEntity2 = createPartition2(); + + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIds(partitionEntity1.getId(), partitionEntity2.getId()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionIds(partitionId); + + assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); + assertNotNull(result.getPartitionNames()); + assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); + } + + @Test + public void testValidateAndNormalizePartitionNames_withPartitionNameOnly_populatesPartitionId(){ + PartitionEntity partitionEntity = createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(partitionEntity.getName()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); + + assertEquals(PARTITION_ID_1, result.getFirstPartitionIdOrNull()); + assertEquals(PARTITION_NAME_1, result.getFirstPartitionNameOrNull()); + } + + @Test + public void testValidateAndNormalizePartitionNames_withMultiplePartitionNamesOnly_populatesPartitionIds(){ + PartitionEntity partitionEntity1 = createPartition1(); + PartitionEntity partitionEntity2 = createPartition2(); + + RequestPartitionId partitionId = RequestPartitionId.fromPartitionNames(partitionEntity1.getName(), partitionEntity2.getName()); + RequestPartitionId result = mySvc.validateAndNormalizePartitionNames(partitionId); + + assertTrue(result.getPartitionIds().containsAll(Set.of(PARTITION_ID_1, PARTITION_ID_2))); + assertNotNull(result.getPartitionNames()); + assertTrue(result.getPartitionNames().containsAll(Set.of(PARTITION_NAME_1, PARTITION_NAME_2))); + } + + @Test + public void testValidateAndNormalizePartitionNames_withUnknownName_throwsException(){ + RequestPartitionId partitionId = RequestPartitionId.fromPartitionName(UNKNOWN_PARTITION_NAME); + + try{ + mySvc.validateAndNormalizePartitionNames(partitionId); + fail(); + } catch (ResourceNotFoundException e){ + assertTrue(e.getMessage().contains("Partition name \"UNKNOWN\" is not valid")); + } + } + + @Test + public void testValidateAndNormalizePartitionNames_withNameAndInvalidId_throwsException(){ + createPartition1(); + RequestPartitionId partitionId = RequestPartitionId.fromPartitionIdAndName(UNKNOWN_PARTITION_ID, PARTITION_NAME_1); + + try{ + mySvc.validateAndNormalizePartitionNames(partitionId); + fail(); + } catch (IllegalArgumentException e){ + assertTrue(e.getMessage().contains("Partition ID 1000000 does not match name SOME-PARTITION-1")); + } + } + + private PartitionEntity createPartition1() { + return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_1).setName(PARTITION_NAME_1)); + } + + private PartitionEntity createPartition2() { + return myPartitionDao.save(new PartitionEntity().setId(PARTITION_ID_2).setName(PARTITION_NAME_2)); + } } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java index dcce168fa09..c237dddcd6a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/stresstest/GiantTransactionPerfTest.java @@ -884,6 +884,16 @@ public class GiantTransactionPerfTest { return true; } + @Override + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + return RequestPartitionId.defaultPartition(); + } + + @Override + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + return RequestPartitionId.defaultPartition(); + } + } diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index 0c26dd83b61..b63529ec844 100644 --- a/hapi-fhir-jpaserver-test-r4b/pom.xml +++ b/hapi-fhir-jpaserver-test-r4b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml index b3dc3455ff3..b3435697f66 100644 --- a/hapi-fhir-jpaserver-test-r5/pom.xml +++ b/hapi-fhir-jpaserver-test-r5/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java index 5cf0e2a4127..50e2c2787c0 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/UpliftedRefchainsAndChainedSortingR5Test.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r5; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; +import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.model.entity.StorageSettings; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.config.TestHSearchAddInConfig; @@ -12,6 +13,8 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; import ca.uhn.fhir.util.BundleBuilder; import ca.uhn.fhir.util.HapiExtensions; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Composition; import org.hl7.fhir.r5.model.IdType; import org.hl7.fhir.r5.model.Bundle; @@ -29,6 +32,7 @@ import org.hl7.fhir.r5.model.SearchParameter; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import jakarta.annotation.Nonnull; @@ -41,9 +45,10 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; -@ContextConfiguration(classes = TestHSearchAddInConfig.NoFT.class) +@ContextConfiguration(classes = { TestHSearchAddInConfig.NoFT.class, TestDaoSearch.Config.class }) @SuppressWarnings({"Duplicates"}) public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String PRACTITIONER_PR1 = "Practitioner/PR1"; @@ -54,6 +59,8 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { public static final String ENCOUNTER_E2 = "Encounter/E2"; public static final String ENCOUNTER_E3 = "Encounter/E3"; public static final String ORGANIZATION_O1 = "Organization/O1"; + @Autowired + protected TestDaoSearch myTestDaoSearch; @Override @BeforeEach @@ -867,6 +874,47 @@ public class UpliftedRefchainsAndChainedSortingR5Test extends BaseJpaR5Test { assertEquals(1, countMatches(querySql, "HFJ_RES_LINK"), querySql); } + + @Test + void testChainedSortWithNulls() { + final IIdType practitionerId1 = createPractitioner(withFamily("Chan")); + final IIdType practitionerId2 = createPractitioner(withFamily("Jones")); + + final String id1 = createPatient(withFamily("Smithy")).getIdPart(); + final String id2 = createPatient(withFamily("Smithwick"), + withReference("generalPractitioner", practitionerId2)).getIdPart(); + final String id3 = createPatient( + withFamily("Smith"), + withReference("generalPractitioner", practitionerId1)).getIdPart(); + + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=Practitioner:general-practitioner.family"); + final List allResources = iBundleProvider.getAllResources(); + assertEquals(3, iBundleProvider.size()); + assertEquals(3, allResources.size()); + + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id1, id2, id3))); + } + + @Test + void testChainedReverseStringSort() { + final IIdType practitionerId = createPractitioner(withFamily("Jones")); + + final String id1 = createPatient(withFamily("Smithy")).getIdPart(); + final String id2 = createPatient(withFamily("Smithwick")).getIdPart(); + final String id3 = createPatient( + withFamily("Smith"), + withReference("generalPractitioner", practitionerId)).getIdPart(); + + final IBundleProvider iBundleProvider = myTestDaoSearch.searchForBundleProvider("Patient?_total=ACCURATE&_sort=-Practitioner:general-practitioner.family"); + assertEquals(3, iBundleProvider.size()); + + final List allResources = iBundleProvider.getAllResources(); + final List actualIds = allResources.stream().map(IBaseResource::getIdElement).map(IIdType::getIdPart).toList(); + assertTrue(actualIds.containsAll(List.of(id3, id2, id1))); + } + /** * Observation:focus is a Reference(Any) so it can't be used in a sort chain because * this would be horribly, horribly inefficient. diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java index e010f25669a..beeef22ff91 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java @@ -1,38 +1,24 @@ package ca.uhn.fhir.jpa.dao.r5.database; -import ca.uhn.fhir.batch2.jobs.export.BulkDataExportProvider; -import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeProvider; -import ca.uhn.fhir.batch2.jobs.reindex.ReindexProvider; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoPatient; -import ca.uhn.fhir.jpa.api.dao.PatientEverythingParameters; +import ca.uhn.fhir.jpa.dao.TestDaoSearch; import ca.uhn.fhir.jpa.embedded.JpaEmbeddedDatabase; -import ca.uhn.fhir.jpa.fql.provider.HfqlRestProvider; -import ca.uhn.fhir.jpa.graphql.GraphQLProvider; import ca.uhn.fhir.jpa.migrate.HapiMigrationStorageSvc; import ca.uhn.fhir.jpa.migrate.MigrationTaskList; import ca.uhn.fhir.jpa.migrate.SchemaMigrator; import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks; -import ca.uhn.fhir.jpa.provider.DiffProvider; -import ca.uhn.fhir.jpa.provider.JpaCapabilityStatementProvider; -import ca.uhn.fhir.jpa.provider.ProcessMessageProvider; -import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider; -import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; -import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.config.TestR5Config; -import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; -import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor; import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory; import ca.uhn.fhir.test.utilities.ITestDataBuilder; import ca.uhn.fhir.test.utilities.server.RestfulServerConfigurerExtension; @@ -44,7 +30,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.IdType; -import org.hl7.fhir.r5.model.IntegerType; import org.hl7.fhir.r5.model.Parameters; import org.hl7.fhir.r5.model.Patient; import org.junit.jupiter.api.Test; @@ -55,7 +40,6 @@ import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.envers.repository.support.EnversRevisionRepositoryFactoryBean; @@ -63,10 +47,8 @@ import org.springframework.data.jpa.repository.config.EnableJpaRepositories; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit.jupiter.SpringExtension; import org.springframework.transaction.PlatformTransactionManager; -import org.springframework.web.cors.CorsConfiguration; import javax.sql.DataSource; -import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Properties; @@ -80,7 +62,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows; @ExtendWith(SpringExtension.class) @EnableJpaRepositories(repositoryFactoryBeanClass = EnversRevisionRepositoryFactoryBean.class) -@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class}) +@ContextConfiguration(classes = {BaseDatabaseVerificationIT.TestConfig.class, TestDaoSearch.Config.class}) public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements ITestDataBuilder { private static final Logger ourLog = LoggerFactory.getLogger(BaseDatabaseVerificationIT.class); private static final String MIGRATION_TABLENAME = "MIGRATIONS"; @@ -109,6 +91,9 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements @Autowired private DatabaseBackedPagingProvider myPagingProvider; + @Autowired + TestDaoSearch myTestDaoSearch; + @RegisterExtension protected RestfulServerExtension myServer = new RestfulServerExtension(FhirContext.forR5Cached()); @@ -175,6 +160,20 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0]))); } + @Test + void testChainedSort() { + // given + + // when + SearchParameterMap map = SearchParameterMap + .newSynchronous() + .setSort(new SortSpec("Practitioner:general-practitioner.family")); + myCaptureQueriesListener.clear(); + myPatientDao.search(map, mySrd); + + } + + @Configuration @@ -222,8 +221,8 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements } public static class JpaDatabaseContextConfigParamObject { - private JpaEmbeddedDatabase myJpaEmbeddedDatabase; - private String myDialect; + final JpaEmbeddedDatabase myJpaEmbeddedDatabase; + final String myDialect; public JpaDatabaseContextConfigParamObject(JpaEmbeddedDatabase theJpaEmbeddedDatabase, String theDialect) { myJpaEmbeddedDatabase = theJpaEmbeddedDatabase; diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index 5aad3443ecb..fe0dc105bd7 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java new file mode 100644 index 00000000000..ea05bc1ea9f --- /dev/null +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/TermConceptDaoSvcTest.java @@ -0,0 +1,57 @@ +package ca.uhn.fhir.jpa.term; + +import ca.uhn.fhir.jpa.dao.data.ITermConceptDao; +import ca.uhn.fhir.jpa.entity.TermConcept; +import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +public class TermConceptDaoSvcTest { + + @Mock + private ITermConceptDao myConceptDao; + + @InjectMocks + private TermConceptDaoSvc myTermConceptDaoSvc; + + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testSaveConcept_withSupportLegacyLob(boolean theSupportLegacyLob){ + final String parentPids = "1 2 3 4 5 6 7 8 9"; + when(myConceptDao.save(any())).thenAnswer(t ->{ + TermConcept codeSystem = (TermConcept) t.getArguments()[0]; + codeSystem.prePersist(); + + return codeSystem; + }); + + ArgumentCaptor captor = ArgumentCaptor.forClass(TermConcept.class); + + // given + TermConcept termConcept = new TermConcept().setParentPids(parentPids); + + // when + myTermConceptDaoSvc.setSupportLegacyLob(theSupportLegacyLob); + myTermConceptDaoSvc.saveConcept(termConcept); + + // then + verify(myConceptDao, times(1)).save(captor.capture()); + TermConcept capturedTermConcept = captor.getValue(); + + assertThat(capturedTermConcept.hasParentPidsLobForTesting(), equalTo(theSupportLegacyLob)); + assertThat(capturedTermConcept.getParentPidsAsString(), equalTo(parentPids)); + } + +} diff --git a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java index 972a533ef2e..dbb455d6e87 100644 --- a/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java +++ b/hapi-fhir-jpaserver-test-utilities/src/test/java/ca/uhn/fhir/jpa/term/ValueSetConceptAccumulatorTest.java @@ -9,11 +9,16 @@ import ca.uhn.fhir.jpa.entity.TermValueSetConceptDesignation; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Optional; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.equalTo; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.times; @@ -74,4 +79,22 @@ public class ValueSetConceptAccumulatorTest { } + @ParameterizedTest + @ValueSource(booleans = {false, true}) + public void testPersistValueSetConcept_whenSupportLegacyLob(boolean theSupportLegacyLob){ + final String sourceConceptDirectParentPids = "1 2 3 4 5 6 7"; + ArgumentCaptor captor = ArgumentCaptor.forClass(TermValueSetConcept.class); + + myAccumulator.setSupportLegacyLob(theSupportLegacyLob); + myAccumulator.includeConcept("sys", "code", "display", null, sourceConceptDirectParentPids, null); + + verify(myValueSetConceptDao, times(1)).save(captor.capture()); + + TermValueSetConcept capturedTermValueSetConcept = captor.getValue(); + + assertThat(capturedTermValueSetConcept.hasSourceConceptDirectParentPidsLob(), equalTo(theSupportLegacyLob)); + assertThat(capturedTermValueSetConcept.getSourceConceptDirectParentPids(), equalTo(sourceConceptDirectParentPids)); + + } + } diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index bd83c065399..f19e6e9ddac 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-cds-hooks/pom.xml b/hapi-fhir-server-cds-hooks/pom.xml index d5de58458b9..4450165821f 100644 --- a/hapi-fhir-server-cds-hooks/pom.xml +++ b/hapi-fhir-server-cds-hooks/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 8be4eeef20e..0ea28b3b88f 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java index 27d89757a9c..403db4605b6 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/svc/MdmSurvivorshipSvcImpl.java @@ -31,17 +31,22 @@ import ca.uhn.fhir.mdm.api.params.MdmQuerySearchParameters; import ca.uhn.fhir.mdm.model.MdmTransactionContext; import ca.uhn.fhir.mdm.model.mdmevents.MdmLinkJson; import ca.uhn.fhir.mdm.util.GoldenResourceHelper; +import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; import ca.uhn.fhir.util.TerserUtil; +import org.apache.commons.lang3.StringUtils; import org.hl7.fhir.instance.model.api.IAnyResource; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; import org.springframework.data.domain.Page; +import java.util.regex.Pattern; import java.util.stream.Stream; public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { + private static final Pattern IS_UUID = + Pattern.compile("[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"); protected final FhirContext myFhirContext; @@ -133,16 +138,30 @@ public class MdmSurvivorshipSvcImpl implements IMdmSurvivorshipService { String sourceId = link.getSourceId(); // +1 because of "/" in id: "ResourceType/Id" - IResourcePersistentId pid = getResourcePID(sourceId.substring(resourceType.length() + 1), resourceType); + final String sourceIdUnqualified = sourceId.substring(resourceType.length() + 1); - // this might be a bit unperformant - // but it depends how many links there are - // per golden resource (unlikely to be thousands) - return dao.readByPid(pid); + // myMdmLinkQuerySvc.queryLinks populates sourceId with the FHIR_ID, not the RES_ID, so if we don't + // add this conditional logic, on JPA, myIIdHelperService.newPidFromStringIdAndResourceName will fail with + // NumberFormatException + if (isNumericOrUuid(sourceIdUnqualified)) { + IResourcePersistentId pid = getResourcePID(sourceIdUnqualified, resourceType); + + // this might be a bit unperformant + // but it depends how many links there are + // per golden resource (unlikely to be thousands) + return dao.readByPid(pid); + } else { + return dao.read(new IdDt(sourceId), new SystemRequestDetails()); + } }); } private IResourcePersistentId getResourcePID(String theId, String theResourceType) { return myIIdHelperService.newPidFromStringIdAndResourceName(theId, theResourceType); } + + private boolean isNumericOrUuid(String theLongCandidate) { + return StringUtils.isNumeric(theLongCandidate) + || IS_UUID.matcher(theLongCandidate).matches(); + } } diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index 91b0ba08703..7eeac31f01d 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index ffce06e1c4a..f54f6f2644c 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java index 04b897e8a08..ffb08829bfe 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderOperationNamed.java @@ -22,6 +22,8 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import java.util.Collection; + public interface IAuthRuleBuilderOperationNamed { /** @@ -44,6 +46,8 @@ public interface IAuthRuleBuilderOperationNamed { */ IAuthRuleBuilderOperationNamedAndScoped onInstance(IIdType theInstanceId); + IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds); + /** * Rule applies to invocations of this operation at the instance level on any instance of the given type */ diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java index 8eb40512001..f45ab580540 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/IAuthRuleBuilderRuleBulkExport.java @@ -22,6 +22,9 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import jakarta.annotation.Nonnull; import org.hl7.fhir.instance.model.api.IIdType; +import java.util.Collection; +import java.util.stream.Collectors; + /** * @since 5.5.0 */ @@ -54,10 +57,20 @@ public interface IAuthRuleBuilderRuleBulkExport { IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId); + IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients(); + default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull IIdType theFocusResourceId) { return patientExportOnPatient(theFocusResourceId.getValue()); } + default IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatients( + @Nonnull Collection theFocusResourceIds) { + return patientExportOnPatientStrings( + theFocusResourceIds.stream().map(IIdType::getValue).collect(Collectors.toList())); + } + + IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings(Collection theFocusResourceIds); + /** * Allow/deny patient-level export rule applies to the Group with the given resource ID, e.g. Group/123 * diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java index 9316cd89d35..a98e2f1e32a 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilder.java @@ -736,6 +736,20 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderOperationNamedAndScoped(rule); } + @Override + public IAuthRuleBuilderOperationNamedAndScoped onInstances(Collection theInstanceIds) { + Validate.notNull(theInstanceIds, "theInstanceIds must not be null"); + theInstanceIds.forEach(instanceId -> Validate.notBlank( + instanceId.getResourceType(), + "at least one of theInstanceIds does not have a resource type")); + theInstanceIds.forEach(instanceId -> Validate.notBlank( + instanceId.getIdPart(), "at least one of theInstanceIds does not have an ID part")); + + final OperationRule rule = createRule(); + rule.appliesToInstances(new ArrayList<>(theInstanceIds)); + return new RuleBuilderOperationNamedAndScoped(rule); + } + @Override public IAuthRuleBuilderOperationNamedAndScoped onInstancesOfType( Class theType) { @@ -869,7 +883,7 @@ public class RuleBuilder implements IAuthRuleBuilder { } private class RuleBuilderBulkExport implements IAuthRuleBuilderRuleBulkExport { - private RuleBulkExportImpl ruleBulkExport; + private RuleBulkExportImpl myRuleBulkExport; @Override public IAuthRuleBuilderRuleBulkExportWithTarget groupExportOnGroup(@Nonnull String theFocusResourceId) { @@ -881,23 +895,60 @@ public class RuleBuilder implements IAuthRuleBuilder { return new RuleBuilderBulkExportWithTarget(rule); } + @Override + public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnAllPatients() { + if (myRuleBulkExport == null) { + RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); + rule.setMode(myRuleMode); + myRuleBulkExport = rule; + } + myRuleBulkExport.setAppliesToPatientExportAllPatients(); + + // prevent duplicate rules being added + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); + } + + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); + } + @Override public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatient(@Nonnull String theFocusResourceId) { - if (ruleBulkExport == null) { + if (myRuleBulkExport == null) { RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); rule.setAppliesToPatientExport(theFocusResourceId); rule.setMode(myRuleMode); - ruleBulkExport = rule; + myRuleBulkExport = rule; } else { - ruleBulkExport.setAppliesToPatientExport(theFocusResourceId); + myRuleBulkExport.setAppliesToPatientExport(theFocusResourceId); } // prevent duplicate rules being added - if (!myRules.contains(ruleBulkExport)) { - myRules.add(ruleBulkExport); + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); } - return new RuleBuilderBulkExportWithTarget(ruleBulkExport); + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); + } + + @Override + public IAuthRuleBuilderRuleBulkExportWithTarget patientExportOnPatientStrings( + @Nonnull Collection theFocusResourceIds) { + if (myRuleBulkExport == null) { + RuleBulkExportImpl rule = new RuleBulkExportImpl(myRuleName); + rule.setAppliesToPatientExport(theFocusResourceIds); + rule.setMode(myRuleMode); + myRuleBulkExport = rule; + } else { + myRuleBulkExport.setAppliesToPatientExport(theFocusResourceIds); + } + + // prevent duplicate rules being added + if (!myRules.contains(myRuleBulkExport)) { + myRules.add(myRuleBulkExport); + } + + return new RuleBuilderBulkExportWithTarget(myRuleBulkExport); } @Override diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java index 1686c157032..eadb0ee4c99 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImpl.java @@ -24,12 +24,12 @@ import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; +import com.google.common.annotations.VisibleForTesting; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Objects; import java.util.Set; import java.util.stream.Collectors; @@ -42,6 +42,7 @@ public class RuleBulkExportImpl extends BaseRule { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuleBulkExportImpl.class); private String myGroupId; private final Collection myPatientIds; + private boolean myAppliesToAllPatients; private BulkExportJobParameters.ExportStyle myWantExportStyle; private Collection myResourceTypes; private boolean myWantAnyStyle; @@ -69,115 +70,86 @@ public class RuleBulkExportImpl extends BaseRule { return null; } - BulkExportJobParameters options = (BulkExportJobParameters) + BulkExportJobParameters inboundBulkExportRequestOptions = (BulkExportJobParameters) theRequestDetails.getAttribute(AuthorizationInterceptor.REQUEST_ATTRIBUTE_BULK_DATA_EXPORT_OPTIONS); - - if (!myWantAnyStyle && options.getExportStyle() != myWantExportStyle) { + // if style doesn't match - abstain + if (!myWantAnyStyle && inboundBulkExportRequestOptions.getExportStyle() != myWantExportStyle) { return null; } + // Do we only authorize some types? If so, make sure requested types are a subset if (isNotEmpty(myResourceTypes)) { - if (isEmpty(options.getResourceTypes())) { - return null; + if (isEmpty(inboundBulkExportRequestOptions.getResourceTypes())) { + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); } - for (String next : options.getResourceTypes()) { - if (!myResourceTypes.contains(next)) { + if (!myResourceTypes.containsAll(inboundBulkExportRequestOptions.getResourceTypes())) { + return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); + } + } + + // system only supports filtering by resource type. So if we are system, or any(), then allow, since we have + // done resource type checking + // above + AuthorizationInterceptor.Verdict allowVerdict = newVerdict( + theOperation, + theRequestDetails, + theInputResource, + theInputResourceId, + theOutputResource, + theRuleApplier); + + if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { + return allowVerdict; + } + + // assume myGroupId not empty->myStyle is group. If target group matches, then allow. + if (isNotBlank(myGroupId) && inboundBulkExportRequestOptions.getGroupId() != null) { + String expectedGroupId = + new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); + String actualGroupId = new IdDt(inboundBulkExportRequestOptions.getGroupId()) + .toUnqualifiedVersionless() + .getValue(); + if (Objects.equals(expectedGroupId, actualGroupId)) { + return allowVerdict; + } + } + // patient export mode - instance or type. type can have 0..n patient ids. + // myPatientIds == the rules built by the auth interceptor rule builder + // options.getPatientIds() == the requested IDs in the export job. + + // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve + // 2. If any requested ID is not present in the users permissions, Deny. + if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT) + // Unfiltered Type Level + if (myAppliesToAllPatients) { + return allowVerdict; + } + + // Instance level, or filtered type level + if (isNotEmpty(myPatientIds)) { + // If bulk export options defines no patient IDs, return null. + if (inboundBulkExportRequestOptions.getPatientIds().isEmpty()) { + return null; + } else { + ourLog.debug("options.getPatientIds() != null"); + Set requestedPatientIds = sanitizeIds(inboundBulkExportRequestOptions.getPatientIds()); + Set permittedPatientIds = sanitizeIds(myPatientIds); + if (permittedPatientIds.containsAll(requestedPatientIds)) { + return allowVerdict; + } else { return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); } } } - - if (myWantAnyStyle || myWantExportStyle == BulkExportJobParameters.ExportStyle.SYSTEM) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - if (isNotBlank(myGroupId) && options.getGroupId() != null) { - String expectedGroupId = - new IdDt(myGroupId).toUnqualifiedVersionless().getValue(); - String actualGroupId = - new IdDt(options.getGroupId()).toUnqualifiedVersionless().getValue(); - if (Objects.equals(expectedGroupId, actualGroupId)) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - } - - // 1. If each of the requested resource IDs in the parameters are present in the users permissions, Approve - // 2. If any requested ID is not present in the users permissions, Deny. - if (myWantExportStyle == BulkExportJobParameters.ExportStyle.PATIENT && isNotEmpty(myPatientIds)) { - List permittedPatientIds = myPatientIds.stream() - .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) - .collect(Collectors.toList()); - if (!options.getPatientIds().isEmpty()) { - ourLog.debug("options.getPatientIds() != null"); - List requestedPatientIds = options.getPatientIds().stream() - .map(t -> new IdDt(t).toUnqualifiedVersionless().getValue()) - .collect(Collectors.toList()); - boolean requestedPatientsPermitted = true; - for (String requestedPatientId : requestedPatientIds) { - if (!permittedPatientIds.contains(requestedPatientId)) { - requestedPatientsPermitted = false; - break; - } - } - if (requestedPatientsPermitted) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - - final List filters = options.getFilters(); - - if (!filters.isEmpty()) { - ourLog.debug("filters not empty"); - final Set patientIdsInFilters = filters.stream() - .filter(filter -> filter.startsWith("Patient?_id=")) - .map(filter -> filter.replace("?_id=", "/")) - .collect(Collectors.toUnmodifiableSet()); - - boolean filteredPatientIdsPermitted = true; - for (String patientIdInFilters : patientIdsInFilters) { - if (!permittedPatientIds.contains(patientIdInFilters)) { - filteredPatientIdsPermitted = false; - break; - } - } - - if (filteredPatientIdsPermitted) { - return newVerdict( - theOperation, - theRequestDetails, - theInputResource, - theInputResourceId, - theOutputResource, - theRuleApplier); - } - - return new AuthorizationInterceptor.Verdict(PolicyEnum.DENY, this); - } - ourLog.debug("patientIds and filters both empty"); - } return null; } + private Set sanitizeIds(Collection myPatientIds) { + return myPatientIds.stream() + .map(id -> new IdDt(id).toUnqualifiedVersionless().getValue()) + .collect(Collectors.toSet()); + } + public void setAppliesToGroupExportOnGroup(String theGroupId) { myWantExportStyle = BulkExportJobParameters.ExportStyle.GROUP; myGroupId = theGroupId; @@ -193,6 +165,16 @@ public class RuleBulkExportImpl extends BaseRule { myPatientIds.add(thePatientId); } + public void setAppliesToPatientExport(Collection thePatientIds) { + myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; + myPatientIds.addAll(thePatientIds); + } + + public void setAppliesToPatientExportAllPatients() { + myWantExportStyle = BulkExportJobParameters.ExportStyle.PATIENT; + myAppliesToAllPatients = true; + } + public void setAppliesToSystem() { myWantExportStyle = BulkExportJobParameters.ExportStyle.SYSTEM; } @@ -212,4 +194,14 @@ public class RuleBulkExportImpl extends BaseRule { BulkExportJobParameters.ExportStyle getWantExportStyle() { return myWantExportStyle; } + + @VisibleForTesting + Collection getPatientIds() { + return myPatientIds; + } + + @VisibleForTesting + Collection getResourceTypes() { + return myResourceTypes; + } } diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java index b942fcc8023..7dd962d6630 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBuilderTest.java @@ -1,16 +1,23 @@ package ca.uhn.fhir.rest.server.interceptor.auth; import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.server.provider.ProviderConstants; import com.google.common.collect.Lists; +import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.util.ArrayList; +import java.util.Collection; import java.util.List; +import java.util.stream.Stream; import static org.hamcrest.Matchers.contains; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; import static org.mockito.Mockito.mock; public class RuleBuilderTest { @@ -98,7 +105,72 @@ public class RuleBuilderTest { builder.allow().bulkExport().patientExportOnPatient("Patient/pat2").withResourceTypes(resourceTypes); List rules = builder.build(); assertEquals(rules.size(),1); - assertTrue(rules.get(0) instanceof RuleBulkExportImpl); + assertInstanceOf(RuleBulkExportImpl.class, rules.get(0)); + } + + public static Stream multipleInstancesParams() { + return Stream.of( + Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.ALLOW), + Arguments.of(List.of("Patient/pat1"), List.of("Patient"), PolicyEnum.DENY), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient"), PolicyEnum.DENY), + Arguments.of(List.of("Patient/pat1", "Patient/pat2"), List.of("Patient", "Observation"), PolicyEnum.DENY) + ); + } + + @ParameterizedTest + @MethodSource("multipleInstancesParams") + public void testBulkExport_PatientExportOnPatients_MultiplePatientsSingleRule(Collection theExpectedPatientIds, Collection theExpectedResourceTypes, PolicyEnum thePolicyEnum) { + final RuleBuilder builder = new RuleBuilder(); + final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { + case ALLOW -> builder.allow(); + case DENY -> builder.deny(); + }; + rule.bulkExport().patientExportOnPatientStrings(theExpectedPatientIds).withResourceTypes(theExpectedResourceTypes); + final List rules = builder.build(); + assertEquals(rules.size(),1); + final IAuthRule authRule = rules.get(0); + assertInstanceOf(RuleBulkExportImpl.class, authRule); + final RuleBulkExportImpl ruleBulkExport = (RuleBulkExportImpl) authRule; + assertEquals(theExpectedPatientIds, ruleBulkExport.getPatientIds()); + assertEquals(theExpectedResourceTypes, ruleBulkExport.getResourceTypes()); + assertEquals(thePolicyEnum, ruleBulkExport.getMode()); + } + + public static Stream owners() { + return Stream.of( + Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.ALLOW), + Arguments.of(List.of(new IdDt("Patient/pat1")), PolicyEnum.DENY), + Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.ALLOW), + Arguments.of(List.of(new IdDt("Patient/pat1"), new IdDt("Patient/pat2")), PolicyEnum.DENY) + ); + } + + @ParameterizedTest + @MethodSource("owners") + public void testBulkExport_PatientExportOnPatients_onInstances(List theExpectedOwners, PolicyEnum thePolicyEnum) { + final RuleBuilder builder = new RuleBuilder(); + final IAuthRuleBuilderRule rule = switch (thePolicyEnum) { + case ALLOW -> builder.allow(); + case DENY -> builder.deny(); + }; + + final List rules = rule + .operation() + .named(ProviderConstants.OPERATION_EXPORT) + .onInstances(theExpectedOwners) + .andAllowAllResponses() + .andThen() + .build(); + + assertEquals(rules.size(),1); + final IAuthRule authRule = rules.get(0); + assertInstanceOf(OperationRule.class, authRule); + final OperationRule operationRule = (OperationRule) authRule; + assertEquals(theExpectedOwners, operationRule.getAppliesToIds()); + assertEquals(ProviderConstants.OPERATION_EXPORT, operationRule.getOperationName()); + assertEquals(thePolicyEnum, operationRule.getMode()); } @Test diff --git a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java index dc71422f128..1dc8eb5b8e8 100644 --- a/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java +++ b/hapi-fhir-server/src/test/java/ca/uhn/fhir/rest/server/interceptor/auth/RuleBulkExportImplTest.java @@ -4,6 +4,9 @@ import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.rest.api.RestOperationTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.bulk.BulkExportJobParameters; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; @@ -13,7 +16,6 @@ import java.util.HashSet; import java.util.Set; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNull; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; @@ -28,10 +30,11 @@ public class RuleBulkExportImplTest { @Mock private Set myFlags; + @Test public void testDenyBulkRequestWithInvalidResourcesTypes() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - + myRule.setMode(PolicyEnum.ALLOW); Set myTypes = new HashSet<>(); myTypes.add("Patient"); myTypes.add("Practitioner"); @@ -42,33 +45,210 @@ public class RuleBulkExportImplTest { BulkExportJobParameters options = new BulkExportJobParameters(); options.setResourceTypes(myWantTypes); - + when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + assertDeny(verdict); + } + + + @Test + public void test_RuleSpecifiesResourceTypes_RequestDoesNot_Abstains() { + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + Set myTypes = new HashSet<>(); + myTypes.add("Patient"); + myRule.setResourceTypes(myTypes); + + + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + assertDeny(verdict); } @Test - public void testBulkRequestWithValidResourcesTypes() { + public void testBulkExportSystem_ruleHasTypes_RequestWithTypes_allow() { RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); - - Set myTypes = new HashSet<>(); - myTypes.add("Patient"); - myTypes.add("Practitioner"); - myRule.setResourceTypes(myTypes); - - Set myWantTypes = new HashSet<>(); - myWantTypes.add("Patient"); - myWantTypes.add("Practitioner"); + myRule.setMode(PolicyEnum.ALLOW); + myRule.setAppliesToSystem(); + myRule.setResourceTypes(Set.of("Patient", "Practitioner")); BulkExportJobParameters options = new BulkExportJobParameters(); - options.setResourceTypes(myWantTypes); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setResourceTypes(Set.of("Patient", "Practitioner")); when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertNull(verdict); + + assertAllow(verdict); + } + + + @Test + public void testBulkExportSystem_ruleHasTypes_RequestWithTooManyTypes_abstain() { + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + myRule.setMode(PolicyEnum.ALLOW); + myRule.setAppliesToSystem(); + myRule.setResourceTypes(Set.of("Patient", "Practitioner")); + + + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + options.setResourceTypes(Set.of("Patient", "Practitioner", "Encounter")); + + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertDeny(verdict); + } + @Nested + class StyleChecks { + BulkExportJobParameters myOptions = new BulkExportJobParameters(); + RuleBulkExportImpl myRule = new RuleBulkExportImpl("a"); + @BeforeEach + void setUp() { + myRule.setMode(PolicyEnum.ALLOW); + when(myRequestDetails.getAttribute(any())).thenReturn(myOptions); + } + @Nested class RuleAnyStyle { + @BeforeEach + void setUp(){ + myRule.setAppliesToAny(); + } + + @Test + public void testRuleAnyStyle_Matches_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + @Test + public void testRuleAnyStyle_Matches_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + + } + @Test + public void testRuleAnyStyle_Matches_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + + } + + } + + @Nested + class RuleSystemStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToSystem(); + } + + @Test + public void test_Matches_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test + public void test_DoesntMatch_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + } + + @Nested + class RuleGroupStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToGroupExportOnGroup("Group/123"); + } + + @Test + public void test_DoesntMatch_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_Matches_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + myOptions.setGroupId("Group/123"); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + } + + @Nested + class RulePatientStyle { + @BeforeEach + void setUp() { + myRule.setAppliesToPatientExport("Patient/123"); + } + + @Test + public void test_DoesntMatch_SystemStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.SYSTEM); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_GroupStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.GROUP); + myOptions.setGroupId("Group/123"); + + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAbstain(verdict); + } + + @Test + public void test_DoesntMatch_PatientStyle() { + myOptions.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + myOptions.setPatientIds(Set.of("Patient/123")); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + } } @Test @@ -84,7 +264,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(null, verdict); + assertAbstain(verdict); } @Test @@ -100,7 +280,7 @@ public class RuleBulkExportImplTest { when(myRequestDetails.getAttribute(any())).thenReturn(options); AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAllow(verdict); } @Test @@ -118,7 +298,7 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We permit the request, as a patient ID that was requested is honoured by this rule. - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAllow(verdict); } @Test @@ -135,8 +315,8 @@ public class RuleBulkExportImplTest { //When AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: we should deny the request, as the requested export does not contain the patient permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: abstain + assertDeny(verdict); } @Test @@ -153,28 +333,45 @@ public class RuleBulkExportImplTest { AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: We make no claims about type-level export on Patient. - assertEquals(null, verdict); + assertAbstain(verdict); } @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatient() { + public void testPatientExportRulesWithId_withRequestNoIds_abstains() { //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); + BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=123")); - options.setResourceTypes(Set.of("Patient")); when(myRequestDetails.getAttribute(any())).thenReturn(options); //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + //Then: We make no claims about type-level export on Patient. + assertAbstain(verdict); } + @Test + public void testPatientExportRuleWithNoIds_withRequestNoIds_allows() { + //Given + RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + BulkExportJobParameters options = new BulkExportJobParameters(); + + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + assertAllow(verdict); + } + + @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypePatientAndFilterHasResources() { //Given @@ -191,27 +388,9 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); + assertAbstain(verdict); } - @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterResourceTypeObservation() { - //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExport("Patient/123"); - myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=123")); - options.setResourceTypes(Set.of("Observation")); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); - } @Test public void testPatientExportRulesOnTypeLevelExportWithTypeFilterNoResourceType() { @@ -227,27 +406,8 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: The patient IDs match so this is permitted - assertEquals(PolicyEnum.ALLOW, verdict.getDecision()); - } - - @Test - public void testPatientExportRulesOnTypeLevelExportWithTypeFilterMismatch() { - //Given - final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); - myRule.setAppliesToPatientExport("Patient/123"); - myRule.setMode(PolicyEnum.ALLOW); - final BulkExportJobParameters options = new BulkExportJobParameters(); - options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); - options.setFilters(Set.of("Patient?_id=456")); - options.setResourceTypes(Set.of("Patient")); - when(myRequestDetails.getAttribute(any())).thenReturn(options); - - //When - final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - - //Then: The patient IDs do NOT match so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: Filters are ignored for auth purposes. The rule has an ID, indicating it is for instance level, but the job requested type level. Abstain + assertAbstain(verdict); } @Test @@ -265,12 +425,12 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: We do not have permissions on the requested patient so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: We do not have permissions on the requested patient so we abstain + assertDeny(verdict); } @Test - public void testPatientExportRulesOnTypeLevelExportPermittedPatient() { + public void testPatientExport_ruleAllowsId_requestsId_allow() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -289,7 +449,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExportRulesOnTypeLevelExportPermittedPatients() { + public void testPatientExport_ruleAllowsIds_requestsIds_allow() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -309,7 +469,7 @@ public class RuleBulkExportImplTest { } @Test - public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatients() { + public void testPatientExport_ruleAllowsId_requestsTooManyIds_abstain() { //Given final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); myRule.setAppliesToPatientExport("Patient/123"); @@ -324,8 +484,61 @@ public class RuleBulkExportImplTest { final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); //Then: There are unpermitted patients in the request so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + assertDeny(verdict); + } // + + @Test + public void testPatientExport_RuleAllowsAll_RequestId_allows() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + options.setPatientIds(Set.of("Patient/123")); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAllow(verdict); } + + @Test + public void testPatientExport_RuleAllowsAll_RequestAll_allows() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExportAllPatients(); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAllow(verdict); + } + + @Test + public void testPatientExport_RuleAllowsExplicitPatient_RequestAll_abstain() { + final RuleBulkExportImpl myRule = new RuleBulkExportImpl("b"); + myRule.setAppliesToPatientExport("Patient/123"); + myRule.setMode(PolicyEnum.ALLOW); + + final BulkExportJobParameters options = new BulkExportJobParameters(); + options.setExportStyle(BulkExportJobParameters.ExportStyle.PATIENT); + when(myRequestDetails.getAttribute(any())).thenReturn(options); + + //When + final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); + + //Then + assertAbstain(verdict); + } + @Test public void testPatientExportRulesOnTypeLevelExportWithPermittedAndUnpermittedPatientFilters() { //Given @@ -341,7 +554,22 @@ public class RuleBulkExportImplTest { //When final AuthorizationInterceptor.Verdict verdict = myRule.applyRule(myOperation, myRequestDetails, null, null, null, myRuleApplier, myFlags, myPointcut); - //Then: There are unpermitted patients in the request so this is not permitted. - assertEquals(PolicyEnum.DENY, verdict.getDecision()); + //Then: There are unpermitted patients in the request so this is not permitted. abstain. + assertAbstain(verdict); + + } + + private static void assertAbstain(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertEquals(null, verdict, "Expect abstain"); + } + + private static void assertAllow(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertNotNull(verdict, "Expect ALLOW, got abstain"); + Assertions.assertEquals(PolicyEnum.ALLOW, verdict.getDecision(), "Expect ALLOW"); + } + + private static void assertDeny(AuthorizationInterceptor.Verdict verdict) { + Assertions.assertNotNull(verdict, "Expect DENY, got abstain"); + Assertions.assertEquals(PolicyEnum.DENY, verdict.getDecision(), "Expect DENY"); } } diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml index 60e63aab6ac..740864e6037 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml index 8b0d686bf00..7a9d57a2ce2 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index f932afeef76..73af9bb7830 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml @@ -7,7 +7,7 @@ hapi-fhir-serviceloaders ca.uhn.hapi.fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml index e589b46af12..8dd166ebe2e 100644 --- a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml +++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml @@ -7,7 +7,7 @@ hapi-fhir ca.uhn.hapi.fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index fb776ba6387..60c50d927e4 100644 --- a/hapi-fhir-serviceloaders/pom.xml +++ b/hapi-fhir-serviceloaders/pom.xml @@ -5,7 +5,7 @@ hapi-deployable-pom ca.uhn.hapi.fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index c78e261e01a..b5f08048eb8 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index 88f887381f2..f75ae34132e 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index 206beef0160..1add14a4dc6 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index 14cf689c7c2..4b7e0b7be3e 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index e37aaba366e..b045486e12b 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index af6174b4f59..1d85730a35d 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index 4b909f3288e..bb235dcba8d 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 88c51675f81..390b14413a0 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java index 168e474ece7..50b7859a0a9 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java @@ -308,6 +308,14 @@ public abstract class BaseTask { } } + public void doNothing() { + setDoNothing(true); + } + + public void failureAllowed() { + setFailureAllowed(true); + } + public boolean isDoNothing() { return myDoNothing; } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java index 49615e73c1a..4b90ea91ac3 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTask.java @@ -22,11 +22,8 @@ package ca.uhn.fhir.jpa.migrate.taskdef; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.migrate.JdbcUtils; import org.apache.commons.lang3.builder.HashCodeBuilder; -import org.intellij.lang.annotations.Language; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.jdbc.core.ColumnMapRowMapper; -import org.springframework.jdbc.core.JdbcTemplate; import java.sql.SQLException; import java.util.Set; @@ -51,53 +48,12 @@ public class RenameTableTask extends BaseTableTask { setDescription("Rename table " + getOldTableName()); } - private void handleTableWithNewTableName() throws SQLException { - - if (!myDeleteTargetColumnFirstIfExist) { - throw new SQLException(Msg.code(2517) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because a table with name " + getNewTableName() + " already exists"); - } - - // a table with the new tableName already exists and we can delete it. we will only do so if it is empty. - Integer rowsWithData = getConnectionProperties().getTxTemplate().execute(t -> { - String sql = "SELECT * FROM " + getNewTableName(); - JdbcTemplate jdbcTemplate = getConnectionProperties().newJdbcTemplate(); - jdbcTemplate.setMaxRows(1); - return jdbcTemplate.query(sql, new ColumnMapRowMapper()).size(); - }); - - if (rowsWithData != null && rowsWithData > 0) { - throw new SQLException(Msg.code(2518) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because a table with name " + getNewTableName() + " already exists and is populated."); - } - - logInfo( - ourLog, - "Table {} already exists - Going to drop it before renaming table {} to {}", - getNewTableName(), - getOldTableName(), - getNewTableName()); - - @Language("SQL") - String sql = "DROP TABLE " + getNewTableName(); - executeSql(getNewTableName(), sql); - } - @Override public void doExecute() throws SQLException { Set tableNames = JdbcUtils.getTableNames(getConnectionProperties()); boolean hasTableWithNewTableName = tableNames.contains(getNewTableName()); - if (!tableNames.contains(getOldTableName())) { - throw new SQLException(Msg.code(2516) + "Can not rename " + getOldTableName() + " to " + getNewTableName() - + " because the original table does not exists"); - } - - if (hasTableWithNewTableName) { - handleTableWithNewTableName(); - } - String sql = buildRenameTableSqlStatement(); logInfo(ourLog, "Renaming table: {}", getOldTableName()); 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 ffc800f9a9f..53741f65e5a 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 @@ -57,6 +57,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.stream.Collectors; @@ -185,6 +186,7 @@ public class Builder { private final String myRelease; private final BaseMigrationTasks.IAcceptsTasks mySink; private final String myTableName; + private BaseTask myLastAddedTask; public BuilderWithTableName(String theRelease, BaseMigrationTasks.IAcceptsTasks theSink, String theTableName) { myRelease = theRelease; @@ -274,6 +276,7 @@ public class Builder { @Override public void addTask(BaseTask theTask) { ((BaseTableTask) theTask).setTableName(myTableName); + myLastAddedTask = theTask; mySink.addTask(theTask); } @@ -311,6 +314,10 @@ public class Builder { return this; } + public Optional getLastAddedTask() { + return Optional.ofNullable(myLastAddedTask); + } + /** * @param theFkName the name of the foreign key * @param theParentTableName the name of the table that exports the foreign key @@ -323,31 +330,37 @@ public class Builder { addTask(task); } - public void renameTable(String theVersion, String theNewTableName) { + public BuilderCompleteTask renameTable(String theVersion, String theNewTableName) { RenameTableTask task = new RenameTableTask(myRelease, theVersion, getTableName(), theNewTableName); addTask(task); + return new BuilderCompleteTask(task); } - public void migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { + public BuilderCompleteTask migratePostgresTextClobToBinaryClob(String theVersion, String theColumnName) { MigratePostgresTextClobToBinaryClobTask task = new MigratePostgresTextClobToBinaryClobTask(myRelease, theVersion); task.setTableName(getTableName()); task.setColumnName(theColumnName); addTask(task); + return new BuilderCompleteTask(task); } - public void migrateBlobToBinary(String theVersion, String theFromColumName, String theToColumName) { + public BuilderCompleteTask migrateBlobToBinary( + String theVersion, String theFromColumName, String theToColumName) { MigrateColumBlobTypeToBinaryTypeTask task = new MigrateColumBlobTypeToBinaryTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); + return new BuilderCompleteTask(task); } - public void migrateClobToText(String theVersion, String theFromColumName, String theToColumName) { + public BuilderCompleteTask migrateClobToText( + String theVersion, String theFromColumName, String theToColumName) { MigrateColumnClobTypeToTextTypeTask task = new MigrateColumnClobTypeToTextTypeTask( myRelease, theVersion, getTableName(), theFromColumName, theToColumName); addTask(task); + return new BuilderCompleteTask(task); } public class BuilderAddIndexWithName { diff --git a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java index a1c6aad40ba..14cf7896ec6 100644 --- a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java +++ b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/RenameTableTaskTest.java @@ -41,26 +41,4 @@ public class RenameTableTaskTest extends BaseTest { assertThat(tableNames, not(hasItem(oldTableName))); } - @ParameterizedTest(name = "{index}: {0}") - @MethodSource("data") - public void testRenameTableTask_whenTableDoesNotExists_willRaiseException(Supplier theTestDatabaseDetails) throws SQLException { - // given - before(theTestDatabaseDetails); - final String newTableName = "NEWTABLE"; - final String oldTableName = "SOMETABLE"; - - RenameTableTask task = new RenameTableTask("1", "1", oldTableName, newTableName); - getMigrator().addTask(task); - - // when - try { - getMigrator().migrate(); - fail(); - } catch (Exception e){ - // then - assertThat(e.getMessage(), containsString("2516")); - } - - } - } diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 863a09e4eb6..17ce5ee847d 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java index ddc1fde19f5..9da0e377ce5 100644 --- a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/imprt/BulkDataImportProviderTest.java @@ -436,6 +436,16 @@ public class BulkDataImportProviderTest { public boolean isResourcePartitionable(String theResourceType) { return false; } + + @Override + public RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) { + return null; + } + + @Override + public RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId) { + return null; + } } private Date parseDate(String theString) { diff --git a/hapi-fhir-storage-batch2-test-utilities/pom.xml b/hapi-fhir-storage-batch2-test-utilities/pom.xml index 4f97d4da2b4..991e665f285 100644 --- a/hapi-fhir-storage-batch2-test-utilities/pom.xml +++ b/hapi-fhir-storage-batch2-test-utilities/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 5d2047f4996..2eb4e947fcd 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index a5487ccedb9..58146efa16b 100644 --- a/hapi-fhir-storage-cr/pom.xml +++ b/hapi-fhir-storage-cr/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java index fcd883576bf..e94facf199f 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/ICollectDataServiceFactory.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java index f5de302cd97..483945ba1b5 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/IDataRequirementsServiceFactory.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java index bdaec6cc8ac..09313ca21ff 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/CollectDataOperationProvider.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.ICollectDataServiceFactory; diff --git a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java index 9c801d91d39..da7ff850647 100644 --- a/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java +++ b/hapi-fhir-storage-cr/src/main/java/ca/uhn/fhir/cr/r4/measure/DataRequirementsOperationProvider.java @@ -1,3 +1,22 @@ +/*- + * #%L + * HAPI FHIR - Clinical Reasoning + * %% + * 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.cr.r4.measure; import ca.uhn.fhir.cr.r4.IDataRequirementsServiceFactory; diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index 669d31c487a..9009c8a0158 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index 1027500637c..016c2d046fc 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java index 299475af681..483736324b2 100644 --- a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java +++ b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java @@ -102,7 +102,9 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa public void cleanup() { ourLog.info("cleanup {}", myIds); - myIds.keySet().forEach(nextType->{ + myIds.keySet().stream() + .sorted() // Hack to ensure Patients are deleted before Practitioners. This may need to be refined. + .forEach(nextType->{ // todo do this in a bundle for perf. IFhirResourceDao dao = myDaoRegistry.getResourceDao(nextType); myIds.get(nextType).forEach(dao::delete); diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index 6cd1fd9b443..24e7f37378a 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java index aafb69b8e2d..78ec78d7c79 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/api/config/JpaStorageSettings.java @@ -360,6 +360,14 @@ public class JpaStorageSettings extends StorageSettings { */ private long myRestDeleteByUrlResourceIdThreshold = DEFAULT_REST_DELETE_BY_URL_RESOURCE_ID_THRESHOLD; + /** + * If enabled, this setting causes persisting data to legacy LOB columns as well as columns introduced + * to migrate away from LOB columns which effectively duplicates stored information. + * + * @since 7.2.0 + */ + private boolean myWriteToLegacyLobColumns = false; + /** * Constructor */ @@ -2423,8 +2431,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} + * {@link IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2439,8 +2447,8 @@ public class JpaStorageSettings extends StorageSettings { * This setting controls the validation issue severity to report when a code validation * finds that the code is present in the given CodeSystem, but the display name being * validated doesn't match the expected value(s). Defaults to - * {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#WARNING}. Set this - * value to {@link ca.uhn.fhir.context.support.IValidationSupport.IssueSeverity#INFORMATION} + * {@link IValidationSupport.IssueSeverity#WARNING}. Set this + * value to {@link IValidationSupport.IssueSeverity#INFORMATION} * if you don't want to see display name validation issues at all in resource validation * outcomes. * @@ -2454,6 +2462,33 @@ public class JpaStorageSettings extends StorageSettings { myIssueSeverityForCodeDisplayMismatch = theIssueSeverityForCodeDisplayMismatch; } + /** + * This method returns whether data will be stored in LOB columns as well as the columns + * introduced to migrate away from LOB. Writing to LOB columns is set to false by + * default. Enabling the setting will effectively double the persisted information. + * If enabled, a careful monitoring of LOB table (if applicable) is required to avoid + * exceeding the table maximum capacity. + * + * @since 7.2.0 + */ + public boolean isWriteToLegacyLobColumns() { + return myWriteToLegacyLobColumns; + } + + /** + * This setting controls whether data will be stored in LOB columns as well as the columns + * introduced to migrate away from LOB. Writing to LOB columns is set to false by + * default. Enabling the setting will effectively double the persisted information. + * When enabled, a careful monitoring of LOB table (if applicable) is required to avoid + * exceeding the table maximum capacity. + * + * @param theWriteToLegacyLobColumns + * @since 7.2.0 + */ + public void setWriteToLegacyLobColumns(boolean theWriteToLegacyLobColumns) { + myWriteToLegacyLobColumns = theWriteToLegacyLobColumns; + } + /** * This setting controls whether MdmLink and other non-resource DB history is enabled. *

    diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java index a98fb571d1a..be151786428 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/BaseRequestPartitionHelperSvc.java @@ -333,10 +333,6 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition return !myNonPartitionableResourceNames.contains(theResourceType); } - protected abstract RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId); - - protected abstract RequestPartitionId validateAndNormalizePartitionNames(RequestPartitionId theRequestPartitionId); - private void validateSinglePartitionForCreate( RequestPartitionId theRequestPartitionId, @Nonnull String theResourceName, Pointcut thePointcut) { validateRequestPartitionNotNull(theRequestPartitionId, thePointcut); diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 059bd1b0451..45643caeb31 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 4d0b3bdd812..9d615df12eb 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index 586b61d07ac..ee2af415b28 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index 2442012db29..5a8fc931e57 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index d9472c2b050..6befea4b575 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index 7b297c89f32..e8bf664af69 100644 --- a/hapi-fhir-structures-r4b/pom.xml +++ b/hapi-fhir-structures-r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index d833b3419cf..03d8fdfb775 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index f93fcb3edfe..ea8b9caf743 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index d8607ca6c3b..899bb3ddf89 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 828c0364fc5..5f4f73a205c 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 17eeee20920..7b78709aea3 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index 69a3445b187..e03063125a6 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index 157973beb1c..8b115b616a9 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4b/pom.xml b/hapi-fhir-validation-resources-r4b/pom.xml index 1d364151cae..8fe4ca83685 100644 --- a/hapi-fhir-validation-resources-r4b/pom.xml +++ b/hapi-fhir-validation-resources-r4b/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index f7129e424c0..e9b8603f992 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 6b0d189e778..4a9b14bc483 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 133e5be72dd..88a5048898c 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index a580dcc60b2..ba399b7c166 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index b2bcabda6e9..3b6244971d5 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index c7e71349f01..755d7930070 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index f0e456b6846..807c663b008 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 1e5ce59b61c..6bf041357aa 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 7.3.1-SNAPSHOT + 7.3.2-SNAPSHOT ../../pom.xml From 9b5673e240f60b97024ef2d137bd71b430d17620 Mon Sep 17 00:00:00 2001 From: Luke deGruchy Date: Tue, 14 May 2024 16:52:30 -0400 Subject: [PATCH 09/15] Bulk export: SearchParameters evaluation for patient compartment. If non-R4 evaluation would have failed, extract using R4 FHIR path (#5931) * Proposed change to make DSTU3 find the same patient path as R4. * Update logic based on conversation. * Update logic based on conversation with R4 gating. * Update logic again. * Tweak logic again with an even narrower code path and add a new unit test. * Add changelog. Tweak javadoc. * Code review feedback. --- .../ca/uhn/fhir/util/SearchParameterUtil.java | 90 ++++++++++++++----- ...s-resource-more-than-one-search-param.yaml | 5 ++ .../fhir/util/SearchParameterUtilTest.java | 55 ++++++++++++ 3 files changed, 130 insertions(+), 20 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5933-bulk-export-dstu3-fails-resource-more-than-one-search-param.yaml create mode 100644 hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/util/SearchParameterUtilTest.java diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/SearchParameterUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/SearchParameterUtil.java index ca6a887f160..f77a59ce746 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/SearchParameterUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/SearchParameterUtil.java @@ -21,16 +21,20 @@ package ca.uhn.fhir.util; import ca.uhn.fhir.context.BaseRuntimeChildDefinition; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeSearchParam; import ca.uhn.fhir.i18n.Msg; +import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IPrimitiveType; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -59,8 +63,12 @@ public class SearchParameterUtil { * 1. Attempt to find one called 'patient' * 2. If that fails, find one called 'subject' * 3. If that fails, find one by Patient Compartment. - * 3.1 If that returns >1 result, throw an error - * 3.2 If that returns 1 result, return it + * 3.1 If that returns exactly 1 result then return it + * 3.2 If that doesn't return exactly 1 result and is R4, fall to 3.3, otherwise, 3.5 + * 3.3 If that returns >1 result, throw an error + * 3.4 If that returns 1 result, return it + * 3.5 Find the search parameters by patient compartment using the R4 FHIR path, and return it if there is 1 result, + * otherwise, fall to 3.3 */ public static Optional getOnlyPatientSearchParamForResourceType( FhirContext theFhirContext, String theResourceType) { @@ -70,10 +78,40 @@ public class SearchParameterUtil { if (myPatientSearchParam == null) { myPatientSearchParam = runtimeResourceDefinition.getSearchParam("subject"); if (myPatientSearchParam == null) { - myPatientSearchParam = getOnlyPatientCompartmentRuntimeSearchParam(runtimeResourceDefinition); + final List searchParamsForCurrentVersion = + runtimeResourceDefinition.getSearchParamsForCompartmentName("Patient"); + final List searchParamsToUse; + // We want to handle a narrow code path in which attempting to process SearchParameters for a non-R4 + // resource would have failed, and instead make another attempt to process them with the R4-equivalent + // FHIR path. + if (FhirVersionEnum.R4 == theFhirContext.getVersion().getVersion() + || searchParamsForCurrentVersion.size() == 1) { + searchParamsToUse = searchParamsForCurrentVersion; + } else { + searchParamsToUse = + checkR4PatientCompartmentForMatchingSearchParam(runtimeResourceDefinition, theResourceType); + } + myPatientSearchParam = + validateSearchParamsAndReturnOnlyOne(runtimeResourceDefinition, searchParamsToUse); } } - return Optional.ofNullable(myPatientSearchParam); + return Optional.of(myPatientSearchParam); + } + + @Nonnull + private static List checkR4PatientCompartmentForMatchingSearchParam( + RuntimeResourceDefinition theRuntimeResourceDefinition, String theResourceType) { + final RuntimeSearchParam patientSearchParamForR4 = + FhirContext.forR4Cached().getResourceDefinition(theResourceType).getSearchParam("patient"); + + return Optional.ofNullable(patientSearchParamForR4) + .map(patientSearchParamForR4NonNull -> + theRuntimeResourceDefinition.getSearchParamsForCompartmentName("Patient").stream() + .filter(searchParam -> searchParam.getPath() != null) + .filter(searchParam -> + searchParam.getPath().equals(patientSearchParamForR4NonNull.getPath())) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); } /** @@ -94,7 +132,7 @@ public class SearchParameterUtil { if (mySubjectSearchParam != null) { searchParams.add(mySubjectSearchParam); } - if (searchParams == null || searchParams.size() == 0) { + if (CollectionUtils.isEmpty(searchParams)) { String errorMessage = String.format( "Resource type [%s] is not eligible for this type of export, as it contains no Patient compartment, and no `patient` or `subject` search parameter", runtimeResourceDefinition.getId()); @@ -115,19 +153,34 @@ public class SearchParameterUtil { public static RuntimeSearchParam getOnlyPatientCompartmentRuntimeSearchParam( RuntimeResourceDefinition runtimeResourceDefinition) { - RuntimeSearchParam patientSearchParam; - List searchParams = runtimeResourceDefinition.getSearchParamsForCompartmentName("Patient"); - if (searchParams == null || searchParams.size() == 0) { + return validateSearchParamsAndReturnOnlyOne( + runtimeResourceDefinition, runtimeResourceDefinition.getSearchParamsForCompartmentName("Patient")); + } + + public static RuntimeSearchParam getOnlyPatientCompartmentRuntimeSearchParam( + RuntimeResourceDefinition runtimeResourceDefinition, List theSearchParams) { + return validateSearchParamsAndReturnOnlyOne(runtimeResourceDefinition, theSearchParams); + } + + @Nonnull + private static RuntimeSearchParam validateSearchParamsAndReturnOnlyOne( + RuntimeResourceDefinition theRuntimeResourceDefinition, List theSearchParams) { + final RuntimeSearchParam patientSearchParam; + if (CollectionUtils.isEmpty(theSearchParams)) { String errorMessage = String.format( - "Resource type [%s] is not eligible for this type of export, as it contains no Patient compartment, and no `patient` or `subject` search parameter", - runtimeResourceDefinition.getId()); + "Resource type [%s] for ID [%s] and version: [%s] is not eligible for this type of export, as it contains no Patient compartment, and no `patient` or `subject` search parameter", + theRuntimeResourceDefinition.getName(), + theRuntimeResourceDefinition.getId(), + theRuntimeResourceDefinition.getStructureVersion()); throw new IllegalArgumentException(Msg.code(1774) + errorMessage); - } else if (searchParams.size() == 1) { - patientSearchParam = searchParams.get(0); + } else if (theSearchParams.size() == 1) { + patientSearchParam = theSearchParams.get(0); } else { String errorMessage = String.format( - "Resource type %s has more than one Search Param which references a patient compartment. We are unable to disambiguate which patient search parameter we should be searching by.", - runtimeResourceDefinition.getId()); + "Resource type [%s] for ID [%s] and version: [%s] has more than one Search Param which references a patient compartment. We are unable to disambiguate which patient search parameter we should be searching by.", + theRuntimeResourceDefinition.getName(), + theRuntimeResourceDefinition.getId(), + theRuntimeResourceDefinition.getStructureVersion()); throw new IllegalArgumentException(Msg.code(1775) + errorMessage); } return patientSearchParam; @@ -148,9 +201,8 @@ public class SearchParameterUtil { public static Set getAllResourceTypesThatAreInPatientCompartment(FhirContext theFhirContext) { return theFhirContext.getResourceTypes().stream() - .filter(type -> getAllPatientCompartmentRuntimeSearchParamsForResourceType(theFhirContext, type) - .size() - > 0) + .filter(type -> CollectionUtils.isNotEmpty( + getAllPatientCompartmentRuntimeSearchParamsForResourceType(theFhirContext, type))) .collect(Collectors.toSet()); } @@ -165,9 +217,7 @@ public class SearchParameterUtil { */ public static boolean isResourceTypeInPatientCompartment(FhirContext theFhirContext, String theResourceType) { RuntimeResourceDefinition runtimeResourceDefinition = theFhirContext.getResourceDefinition(theResourceType); - return getAllPatientCompartmentRuntimeSearchParams(runtimeResourceDefinition) - .size() - > 0; + return CollectionUtils.isNotEmpty(getAllPatientCompartmentRuntimeSearchParams(runtimeResourceDefinition)); } @Nullable diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5933-bulk-export-dstu3-fails-resource-more-than-one-search-param.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5933-bulk-export-dstu3-fails-resource-more-than-one-search-param.yaml new file mode 100644 index 00000000000..d8cf24481a0 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5933-bulk-export-dstu3-fails-resource-more-than-one-search-param.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5933 +title: "Bulk export was failing with a HAPI-1775 error with the persistence module configured for DSTU3. + This has been fixed." diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/util/SearchParameterUtilTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/util/SearchParameterUtilTest.java new file mode 100644 index 00000000000..19b0bb26a95 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/util/SearchParameterUtilTest.java @@ -0,0 +1,55 @@ +package ca.uhn.fhir.util; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.context.RuntimeSearchParam; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Optional; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * We can't test this class from hapi-fhir-base due to the dependency restrictions (see the IMPORTANT NOT in the pom.xml + * That's why we're testing the class from this module. + */ +class SearchParameterUtilTest { + private static final String COVERAGE_BENEFICIARY = "Coverage.beneficiary"; + private static final String PATIENT_LINK_OTHER = "Patient.link.other"; + private static final String RESEARCH_SUBJECT_INDIVIDUAL = "ResearchSubject.individual"; + + private static final String SUPER_LONG_FHIR_PATH = "Account.subject.where(resolve() is Patient) | AdverseEvent.subject.where(resolve() is Patient) | AllergyIntolerance.patient | Appointment.participant.actor.where(resolve() is Patient) | Appointment.subject.where(resolve() is Patient) | AppointmentResponse.actor.where(resolve() is Patient) | AuditEvent.patient | Basic.subject.where(resolve() is Patient) | BodyStructure.patient | CarePlan.subject.where(resolve() is Patient) | CareTeam.subject.where(resolve() is Patient) | ChargeItem.subject.where(resolve() is Patient) | Claim.patient | ClaimResponse.patient | ClinicalImpression.subject.where(resolve() is Patient) | Communication.subject.where(resolve() is Patient) | CommunicationRequest.subject.where(resolve() is Patient) | Composition.subject.where(resolve() is Patient) | Condition.subject.where(resolve() is Patient) | Consent.subject.where(resolve() is Patient) | Contract.subject.where(resolve() is Patient) | Coverage.beneficiary | CoverageEligibilityRequest.patient | CoverageEligibilityResponse.patient | DetectedIssue.subject.where(resolve() is Patient) | DeviceRequest.subject.where(resolve() is Patient) | DeviceUsage.patient | DiagnosticReport.subject.where(resolve() is Patient) | DocumentReference.subject.where(resolve() is Patient) | Encounter.subject.where(resolve() is Patient) | EnrollmentRequest.candidate | EpisodeOfCare.patient | ExplanationOfBenefit.patient | FamilyMemberHistory.patient | Flag.subject.where(resolve() is Patient) | Goal.subject.where(resolve() is Patient) | GuidanceResponse.subject.where(resolve() is Patient) | ImagingSelection.subject.where(resolve() is Patient) | ImagingStudy.subject.where(resolve() is Patient) | Immunization.patient | ImmunizationEvaluation.patient | ImmunizationRecommendation.patient | Invoice.subject.where(resolve() is Patient) | List.subject.where(resolve() is Patient) | MeasureReport.subject.where(resolve() is Patient) | MedicationAdministration.subject.where(resolve() is Patient) | MedicationDispense.subject.where(resolve() is Patient) | MedicationRequest.subject.where(resolve() is Patient) | MedicationStatement.subject.where(resolve() is Patient) | MolecularSequence.subject.where(resolve() is Patient) | NutritionIntake.subject.where(resolve() is Patient) | NutritionOrder.subject.where(resolve() is Patient) | Observation.subject.where(resolve() is Patient) | Person.link.target.where(resolve() is Patient) | Procedure.subject.where(resolve() is Patient) | Provenance.patient | QuestionnaireResponse.subject.where(resolve() is Patient) | RelatedPerson.patient | RequestOrchestration.subject.where(resolve() is Patient) | ResearchSubject.subject.where(resolve() is Patient) | RiskAssessment.subject.where(resolve() is Patient) | ServiceRequest.subject.where(resolve() is Patient) | Specimen.subject.where(resolve() is Patient) | SupplyDelivery.patient | SupplyRequest.deliverFor | Task.for.where(resolve() is Patient) | VisionPrescription.patient"; + + public static Stream fhirVersionAndResourceType() { + return Stream.of( + Arguments.of(FhirVersionEnum.DSTU3, "Coverage", COVERAGE_BENEFICIARY), + Arguments.of(FhirVersionEnum.R4, "Coverage", COVERAGE_BENEFICIARY), + Arguments.of(FhirVersionEnum.R4B, "Coverage", COVERAGE_BENEFICIARY), + Arguments.of(FhirVersionEnum.R5, "Coverage", SUPER_LONG_FHIR_PATH), + Arguments.of(FhirVersionEnum.DSTU3, "Patient", PATIENT_LINK_OTHER), + Arguments.of(FhirVersionEnum.R4, "Patient", PATIENT_LINK_OTHER), + Arguments.of(FhirVersionEnum.R4B, "Patient", PATIENT_LINK_OTHER), + Arguments.of(FhirVersionEnum.R5, "Patient", PATIENT_LINK_OTHER), + Arguments.of(FhirVersionEnum.DSTU3, "ResearchSubject", RESEARCH_SUBJECT_INDIVIDUAL), + Arguments.of(FhirVersionEnum.R4, "ResearchSubject", RESEARCH_SUBJECT_INDIVIDUAL), + Arguments.of(FhirVersionEnum.R4B, "ResearchSubject", RESEARCH_SUBJECT_INDIVIDUAL), + Arguments.of(FhirVersionEnum.R5, "ResearchSubject", SUPER_LONG_FHIR_PATH) + ); + } + + @ParameterizedTest + @MethodSource("fhirVersionAndResourceType") + void getOnlyPatientSearchParamForResourceType(FhirVersionEnum theFhirVersion, String theResourceType, String theExpectedPath) { + final Optional optRuntimeSearchParam = SearchParameterUtil.getOnlyPatientSearchParamForResourceType(FhirContext.forCached(theFhirVersion), theResourceType); + + assertTrue(optRuntimeSearchParam.isPresent()); + final RuntimeSearchParam runtimeSearchParam = optRuntimeSearchParam.get(); + assertEquals(theExpectedPath, runtimeSearchParam.getPath()); + } +} From 729c0c8546243be123e8fa2a35c71c1449497562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pablo=20Pazos=20Guti=C3=A9rrez?= Date: Wed, 15 May 2024 05:24:24 -0300 Subject: [PATCH 10/15] fixed small typo (#5934) --- .../src/main/java/ca/uhn/fhir/to/TesterConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/TesterConfig.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/TesterConfig.java index 95e9334aa6e..05b420b0781 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/TesterConfig.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/TesterConfig.java @@ -152,7 +152,7 @@ public class TesterConfig { if (nextSplit.length < 3) { throw new IllegalArgumentException( - Msg.code(195) + "Invalid serveer line '" + nextRaw + "' - Must be comma separated"); + Msg.code(195) + "Invalid server line '" + nextRaw + "' - Must be comma separated"); } else { Validate.notBlank(nextSplit[0], "theId can not be blank"); Validate.notBlank(nextSplit[1], "theVersion can not be blank"); From 0a009901b392fb9974c8835d0472bbbe592cfc33 Mon Sep 17 00:00:00 2001 From: Michael Buckley Date: Wed, 15 May 2024 18:10:32 -0400 Subject: [PATCH 11/15] Add some more sql syntax tests for Postgres, Oracle, and Sql Server (#5923) Also: - fix total parsing in internal MatchUrl service. - Add more syntax tests for our docker database tests - Change DaoTestDataBuilder to use a bundle with delete entries for teardown. --- .../fhir/jpa/searchparam/MatchUrlService.java | 16 ++++++--- .../jpa/searchparam/MatchUrlServiceTest.java | 21 +++++++++++ .../database/BaseDatabaseVerificationIT.java | 35 ++++++++++--------- .../fhir/storage/test/DaoTestDataBuilder.java | 22 +++++++----- 4 files changed, 65 insertions(+), 29 deletions(-) diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/MatchUrlService.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/MatchUrlService.java index 362d1cbeb1a..49f48f74433 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/MatchUrlService.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/MatchUrlService.java @@ -127,12 +127,18 @@ public class MatchUrlService { && !paramList.isEmpty() && !paramList.get(0).isEmpty()) { String totalModeEnumStr = paramList.get(0).get(0); - try { - paramMap.setSearchTotalMode(SearchTotalModeEnum.valueOf(totalModeEnumStr)); - } catch (IllegalArgumentException e) { - throw new InvalidRequestException(Msg.code(2078) + "Invalid " - + Constants.PARAM_SEARCH_TOTAL_MODE + " value: " + totalModeEnumStr); + SearchTotalModeEnum searchTotalMode = SearchTotalModeEnum.fromCode(totalModeEnumStr); + if (searchTotalMode == null) { + // We had an oops here supporting the UPPER CASE enum instead of the FHIR code for _total. + // Keep supporting it in case someone is using it. + try { + paramMap.setSearchTotalMode(SearchTotalModeEnum.valueOf(totalModeEnumStr)); + } catch (IllegalArgumentException e) { + throw new InvalidRequestException(Msg.code(2078) + "Invalid " + + Constants.PARAM_SEARCH_TOTAL_MODE + " value: " + totalModeEnumStr); + } } + paramMap.setSearchTotalMode(searchTotalMode); } } else if (Constants.PARAM_OFFSET.equals(nextParamName)) { if (paramList != null diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/searchparam/MatchUrlServiceTest.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/searchparam/MatchUrlServiceTest.java index 41f7226825b..9b46664d817 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/searchparam/MatchUrlServiceTest.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/searchparam/MatchUrlServiceTest.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.searchparam.util.Dstu3DistanceHelper; import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.config.TestDstu3Config; +import ca.uhn.fhir.rest.api.SearchTotalModeEnum; import ca.uhn.fhir.rest.param.QuantityParam; import ca.uhn.fhir.rest.param.ReferenceParam; import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; @@ -97,6 +98,26 @@ public class MatchUrlServiceTest extends BaseJpaTest { } } + @Test + void testTotal_fromStandardLowerCase() { + // given + // when + var map = myMatchUrlService.translateMatchUrl("Patient?family=smith&_total=none", ourCtx.getResourceDefinition("Patient")); + + // then + assertEquals(SearchTotalModeEnum.NONE, map.getSearchTotalMode()); + } + + @Test + void testTotal_fromUpperCase() { + // given + // when + var map = myMatchUrlService.translateMatchUrl("Patient?family=smith&_total=none", ourCtx.getResourceDefinition("Patient")); + + // then + assertEquals(SearchTotalModeEnum.NONE, map.getSearchTotalMode()); + } + @Override protected FhirContext getFhirContext() { return ourCtx; diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java index beeef22ff91..2298bf75de7 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/dao/r5/database/BaseDatabaseVerificationIT.java @@ -11,11 +11,9 @@ import ca.uhn.fhir.jpa.migrate.SchemaMigrator; import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.tasks.HapiFhirJpaMigrationTasks; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaTest; import ca.uhn.fhir.jpa.test.config.TestR5Config; import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.SortSpec; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException; @@ -36,6 +34,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.api.extension.RegisterExtension; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import org.junit.jupiter.params.provider.ValueSource; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -57,6 +56,7 @@ import java.util.Set; import static ca.uhn.fhir.jpa.model.util.JpaConstants.OPERATION_EVERYTHING; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -160,22 +160,23 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements assertThat(values.toString(), values, containsInAnyOrder(expectedIds.toArray(new String[0]))); } - @Test - void testChainedSort() { - // given - - // when - SearchParameterMap map = SearchParameterMap - .newSynchronous() - .setSort(new SortSpec("Practitioner:general-practitioner.family")); - myCaptureQueriesListener.clear(); - myPatientDao.search(map, mySrd); - + @ParameterizedTest + @CsvSource(textBlock = """ + query string, Patient?name=smith + query date, Observation?date=2021 + query token, Patient?active=true + sort string, Patient?_sort=name + sort date, Observation?_sort=date + sort token, Patient?_sort=active + sort chained date, Observation?_sort=patient.birthdate + sort chained string, Observation?_sort=patient.name + sort chained qualified, Patient?_sort=Practitioner:general-practitioner.family + sort chained token, Observation?_sort=patient.active + """) + void testSyntaxForVariousQueries(String theMessage, String theQuery) { + assertDoesNotThrow(()->myTestDaoSearch.searchForBundleProvider(theQuery), theMessage); } - - - @Configuration public static class TestConfig extends TestR5Config { @@ -238,11 +239,13 @@ public abstract class BaseDatabaseVerificationIT extends BaseJpaTest implements } } + @SuppressWarnings("unchecked") @Override public IIdType doCreateResource(IBaseResource theResource) { return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).create(theResource, new SystemRequestDetails()).getId(); } + @SuppressWarnings("unchecked") @Override public IIdType doUpdateResource(IBaseResource theResource) { return myDaoRegistry.getResourceDao(myFhirContext.getResourceType(theResource)).update(theResource, new SystemRequestDetails()).getId(); diff --git a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java index 483736324b2..cd7f6019568 100644 --- a/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java +++ b/hapi-fhir-storage-test-utilities/src/main/java/ca/uhn/fhir/storage/test/DaoTestDataBuilder.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.SystemRequestDetails; import ca.uhn.fhir.test.utilities.ITestDataBuilder; +import ca.uhn.fhir.util.BundleBuilder; import com.google.common.collect.HashMultimap; import com.google.common.collect.SetMultimap; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -97,21 +98,26 @@ public class DaoTestDataBuilder implements ITestDataBuilder.WithSupport, ITestDa } /** - * Delete anything created + * Delete anything created by this builder since the last cleanup(). */ public void cleanup() { ourLog.info("cleanup {}", myIds); - myIds.keySet().stream() - .sorted() // Hack to ensure Patients are deleted before Practitioners. This may need to be refined. - .forEach(nextType->{ - // todo do this in a bundle for perf. - IFhirResourceDao dao = myDaoRegistry.getResourceDao(nextType); - myIds.get(nextType).forEach(dao::delete); - }); + var builder = new BundleBuilder(myFhirCtx); + myIds.values() + .forEach(builder::addTransactionDeleteEntry); + var bundle = builder.getBundle(); + + ourLog.trace("Deleting in bundle {}", myFhirCtx.newJsonParser().encodeToString(bundle)); + //noinspection unchecked + myDaoRegistry.getSystemDao().transaction(mySrd, bundle); + myIds.clear(); } + /** + * Tear down and cleanup any Resources created during execution. + */ @Override public void afterEach(ExtensionContext context) throws Exception { cleanup(); From 446869b524b8a34b13a86409d9d1b05b5ed35c35 Mon Sep 17 00:00:00 2001 From: Renaud Subiger Date: Thu, 16 May 2024 08:20:29 +0200 Subject: [PATCH 12/15] Fix UnsupportedOperationException while validating MHD Document Bundle (#5925) * Fix UnsupportedOperationException while validating MHD Document Bundle * Add credit --------- Co-authored-by: James Agnew --- ...rtedoperationexception-validating-mhd.yaml | 5 + .../VersionSpecificWorkerContextWrapper.java | 3 +- .../NpmPackageValidationSupportTest.java | 29 +++ .../test/resources/package/ihe.iti.mhd.tgz | Bin 0 -> 727264 bytes .../mhd_minimal_provide_document_bundle.json | 190 ++++++++++++++++++ pom.xml | 4 + 6 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5925-resole-unsupportedoperationexception-validating-mhd.yaml create mode 100644 hapi-fhir-validation/src/test/resources/package/ihe.iti.mhd.tgz create mode 100644 hapi-fhir-validation/src/test/resources/r4/mhd_minimal_provide_document_bundle.json diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5925-resole-unsupportedoperationexception-validating-mhd.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5925-resole-unsupportedoperationexception-validating-mhd.yaml new file mode 100644 index 00000000000..f19fba74278 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5925-resole-unsupportedoperationexception-validating-mhd.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 5925 +title: "An UnsupportedOperationException occurred when validating R5 MHD bundles using + the HAPI FHIR validator. Thanks to Renaud Subiger for contributing a fix!" 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 340dcfc775c..0dc166c0c8e 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 @@ -322,7 +322,8 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent binding, boolean cacheOk, boolean Hierarchical) { - throw new UnsupportedOperationException(Msg.code(663)); + ValueSet valueSet = fetchResource(ValueSet.class, binding.getValueSet(), src); + return expandVS(valueSet, cacheOk, Hierarchical); } @Override diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/NpmPackageValidationSupportTest.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/NpmPackageValidationSupportTest.java index 9549e2ad2ad..0afad0fee73 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/NpmPackageValidationSupportTest.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/NpmPackageValidationSupportTest.java @@ -24,6 +24,7 @@ import java.util.Map; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; public class NpmPackageValidationSupportTest extends BaseValidationTestWithInlineMocks { @@ -89,4 +90,32 @@ public class NpmPackageValidationSupportTest extends BaseValidationTestWithInlin assertArrayEquals(expectedBytes, actualBytes); } } + + @Test + public void testValidateIheMhdPackage() throws IOException { + ValidationSupportChain validationSupportChain = new ValidationSupportChain(); + validationSupportChain.addValidationSupport(getNpmPackageValidationSupport("classpath:package/ihe.iti.mhd.tgz")); + validationSupportChain.addValidationSupport(new DefaultProfileValidationSupport(myFhirContext)); + validationSupportChain.addValidationSupport(new CommonCodeSystemsTerminologyService(myFhirContext)); + validationSupportChain.addValidationSupport(new InMemoryTerminologyServerValidationSupport(myFhirContext)); + validationSupportChain.addValidationSupport(new SnapshotGeneratingValidationSupport(myFhirContext)); + + CachingValidationSupport validationSupport = new CachingValidationSupport(validationSupportChain); + + FhirValidator validator = myFhirContext.newValidator(); + FhirInstanceValidator instanceValidator = new FhirInstanceValidator(validationSupport); + validator.registerValidatorModule(instanceValidator); + + String bundle = loadResource("/r4/mhd_minimal_provide_document_bundle.json"); + ValidationResult validationResult = validator.validateWithResult(bundle); + + assertEquals(1, validationResult.getMessages().size()); + + String outcomeSerialized = myFhirContext.newJsonParser() + .setPrettyPrint(true) + .encodeResourceToString(validationResult.toOperationOutcome()); + ourLog.info(outcomeSerialized); + + assertThat(outcomeSerialized, containsString("Terminology_TX_ValueSet_NotFound")); + } } diff --git a/hapi-fhir-validation/src/test/resources/package/ihe.iti.mhd.tgz b/hapi-fhir-validation/src/test/resources/package/ihe.iti.mhd.tgz new file mode 100644 index 0000000000000000000000000000000000000000..5e3d6cc6b61eeea526a8b8fadcc4ab75523e0121 GIT binary patch literal 727264 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 z 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 z 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 z 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%0Ag9xcIA9yWAeJ@HLwg`1NiSlA&5zuo_-C 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

    g7wARibsF7#W>>r6+@8I_d5~gG=gc;ok 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

    %kTbD@MpV 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 literal 0 HcmV?d00001 diff --git a/hapi-fhir-validation/src/test/resources/r4/mhd_minimal_provide_document_bundle.json b/hapi-fhir-validation/src/test/resources/r4/mhd_minimal_provide_document_bundle.json new file mode 100644 index 00000000000..0663757c515 --- /dev/null +++ b/hapi-fhir-validation/src/test/resources/r4/mhd_minimal_provide_document_bundle.json @@ -0,0 +1,190 @@ +{ + "resourceType": "Bundle", + "meta": { + "profile": [ + "https://profiles.ihe.net/ITI/MHD/StructureDefinition/IHE.MHD.Minimal.ProvideBundle" + ], + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", + "code": "HTEST" + } + ] + }, + "type": "transaction", + "timestamp": "2024-05-11T14:16:19.224Z", + "entry": [ + { + "fullUrl": "urn:uuid:9649cc3d-eb0b-407b-b1ba-61c4eef4dba3", + "resource": { + "resourceType": "List", + "id": "9649cc3d-eb0b-407b-b1ba-61c4eef4dba3", + "meta": { + "profile": [ + "https://profiles.ihe.net/ITI/MHD/StructureDefinition/IHE.MHD.Minimal.SubmissionSet" + ], + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", + "code": "HTEST" + } + ] + }, + "text": { + "status": "extensions", + "div": "
    SubmissionSet with Patient
    " + }, + "contained": [ + { + "resourceType": "Practitioner", + "id": "622209e6-32ad-4283-b4eb-e2bea2aea856", + "telecom": [ + { + "system": "email", + "value": "john.doe@localhost" + } + ] + } + ], + "extension": [ + { + "url": "https://profiles.ihe.net/ITI/MHD/StructureDefinition/ihe-sourceId", + "valueIdentifier": { + "value": "urn:oid:1.2.3.4" + } + }, + { + "url": "https://profiles.ihe.net/ITI/MHD/StructureDefinition/ihe-intendedRecipient", + "valueReference": { + "reference": "#622209e6-32ad-4283-b4eb-e2bea2aea856" + } + } + ], + "identifier": [ + { + "use": "usual", + "system": "urn:ietf:rfc:3986", + "value": "urn:oid:1.2.840.113556.1.8000.2554.58783.21864.3474.19410.44358.58254.41281.46343" + } + ], + "status": "current", + "mode": "working", + "code": { + "coding": [ + { + "system": "https://profiles.ihe.net/ITI/MHD/CodeSystem/MHDlistTypes", + "code": "submissionset" + } + ] + }, + "subject": { + "reference": "urn:uuid:51eb4fab-9d1a-4314-ad7c-363fc430f52c" + }, + "date": "2004-10-25T23:50:50-05:00", + "entry": [ + { + "item": { + "reference": "urn:uuid:f494ac72-be69-4910-baf4-0cce4a45e7c1" + } + } + ] + }, + "request": { + "method": "POST", + "url": "List" + } + }, + { + "fullUrl": "urn:uuid:f494ac72-be69-4910-baf4-0cce4a45e7c1", + "resource": { + "resourceType": "DocumentReference", + "id": "f494ac72-be69-4910-baf4-0cce4a45e7c1", + "meta": { + "profile": [ + "https://profiles.ihe.net/ITI/MHD/StructureDefinition/IHE.MHD.Minimal.DocumentReference" + ], + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", + "code": "HTEST" + } + ] + }, + "masterIdentifier": { + "system": "urn:ietf:rfc:3986", + "value": "urn:oid:1.2.840.113556.1.8000.2554.53432.348.12973.17740.34205.4355.50220.62012" + }, + "status": "current", + "subject": { + "reference": "urn:uuid:51eb4fab-9d1a-4314-ad7c-363fc430f52c" + }, + "content": [ + { + "attachment": { + "contentType": "text/plain", + "url": "urn:uuid:4d14267b-19ff-4237-a301-4cdcfd67d4f9", + "size": 11, + "hash": "MGE0ZDU1YThkNzc4ZTUwMjJmYWI3MDE5NzdjNWQ4NDBiYmM0ODZkMA==" + }, + "format": { + "system": "http://ihe.net/fhir/ihe.formatcode.fhir/CodeSystem/formatcode", + "code": "urn:ihe:iti:xds-sd:text:2008" + } + } + ] + }, + "request": { + "method": "POST", + "url": "DocumentReference" + } + }, + { + "fullUrl": "urn:uuid:4d14267b-19ff-4237-a301-4cdcfd67d4f9", + "resource": { + "resourceType": "Binary", + "id": "4d14267b-19ff-4237-a301-4cdcfd67d4f9", + "meta": { + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", + "code": "HTEST" + } + ] + }, + "contentType": "text/plain", + "data": "SGVsbG8gV29ybGQ=" + }, + "request": { + "method": "POST", + "url": "Binary" + } + }, + { + "fullUrl": "urn:uuid:51eb4fab-9d1a-4314-ad7c-363fc430f52c", + "resource": { + "resourceType": "Patient", + "id": "51eb4fab-9d1a-4314-ad7c-363fc430f52c", + "meta": { + "security": [ + { + "system": "http://terminology.hl7.org/CodeSystem/v3-ActReason", + "code": "HTEST" + } + ] + }, + "name": [ + { + "family": "Schmidt", + "given": [ + "Dee" + ] + } + ] + }, + "request": { + "method": "POST", + "url": "Patient" + } + } + ] +} diff --git a/pom.xml b/pom.xml index 3b6244971d5..08b3a1c9d6a 100644 --- a/pom.xml +++ b/pom.xml @@ -913,6 +913,10 @@ thetrueoneshots Gijs Groenewegen + + subigre + Renaud Subiger + From 14c364dffdc26be0185415109a5ccf2000d6be5e Mon Sep 17 00:00:00 2001 From: James Agnew Date: Thu, 16 May 2024 05:02:06 -0400 Subject: [PATCH 13/15] Include profile URL in generated IPS (#5938) * Include profile URL in generated IPS * Add changelog * Documentation tweak --- .../java/ca/uhn/fhir/util/BundleBuilder.java | 10 ++++++ .../5938-include-bundle-profile-in-ips.yaml | 4 +++ .../jpa/ips/api/IIpsGenerationStrategy.java | 5 ++- .../ips/generator/IpsGeneratorSvcImpl.java | 1 + .../ips/generator/IpsGenerationR4Test.java | 31 +++++++++++------- .../src/test/resources/ips-package-1.1.0.tgz | Bin 0 -> 1065105 bytes 6 files changed, 39 insertions(+), 12 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5938-include-bundle-profile-in-ips.yaml create mode 100644 hapi-fhir-jpaserver-ips/src/test/resources/ips-package-1.1.0.tgz diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleBuilder.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleBuilder.java index 2b030a8953e..d8b7665be3d 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleBuilder.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleBuilder.java @@ -626,6 +626,16 @@ public class BundleBuilder { terser.setElement(myBundle, "Bundle.timestamp", theTimestamp.getValueAsString()); } + /** + * Adds a profile URL to Bundle.meta.profile + * + * @since 7.4.0 + */ + public void addProfile(String theProfile) { + FhirTerser terser = myContext.newTerser(); + terser.addElement(myBundle, "Bundle.meta.profile", theProfile); + } + public class DeleteBuilder extends BaseOperationBuilder { // nothing yet diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5938-include-bundle-profile-in-ips.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5938-include-bundle-profile-in-ips.yaml new file mode 100644 index 00000000000..c631d878c61 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5938-include-bundle-profile-in-ips.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 5938 +title: "Generated IPS documents will now include a bundle profile declaration." diff --git a/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/api/IIpsGenerationStrategy.java b/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/api/IIpsGenerationStrategy.java index bad1470d646..9be8fe35c2b 100644 --- a/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/api/IIpsGenerationStrategy.java +++ b/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/api/IIpsGenerationStrategy.java @@ -42,7 +42,10 @@ public interface IIpsGenerationStrategy { /** * This method returns the profile associated with the IPS document - * generated by this strategy. + * generated by this strategy. This URL will be added to generated + * IPS Bundles in Bundle.meta.profile, and can also + * be used to support the profile parameter on the + * $summary operation. */ String getBundleProfile(); diff --git a/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImpl.java b/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImpl.java index 7562c5daf93..aa2db895631 100644 --- a/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImpl.java +++ b/hapi-fhir-jpaserver-ips/src/main/java/ca/uhn/fhir/jpa/ips/generator/IpsGeneratorSvcImpl.java @@ -146,6 +146,7 @@ public class IpsGeneratorSvcImpl implements IIpsGeneratorSvc { bundleBuilder.setType(Bundle.BundleType.DOCUMENT.toCode()); bundleBuilder.setIdentifier("urn:ietf:rfc:4122", UUID.randomUUID().toString()); bundleBuilder.setTimestamp(InstantType.now()); + bundleBuilder.addProfile(theStrategy.getBundleProfile()); // Add composition to document bundleBuilder.addDocumentEntry(composition); diff --git a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java index bb9bf90b283..e697ef20b2a 100644 --- a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java +++ b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java @@ -5,7 +5,6 @@ import ca.uhn.fhir.context.support.ConceptValidationOptions; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.jpa.api.config.JpaStorageSettings; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.ips.api.IIpsGenerationStrategy; import ca.uhn.fhir.jpa.ips.jpa.DefaultJpaIpsGenerationStrategy; import ca.uhn.fhir.jpa.ips.provider.IpsOperationProvider; @@ -18,6 +17,7 @@ import ca.uhn.fhir.validation.SingleValidationMessage; import ca.uhn.fhir.validation.ValidationResult; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import org.hl7.fhir.common.hapi.validation.support.NpmPackageValidationSupport; import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -31,6 +31,7 @@ import org.hl7.fhir.r4.model.Immunization; import org.hl7.fhir.r4.model.MedicationStatement; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Patient; +import org.hl7.fhir.r4.model.PrimitiveType; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; import org.junit.jupiter.api.AfterEach; @@ -41,6 +42,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.test.context.ContextConfiguration; +import java.io.IOException; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -48,10 +50,10 @@ import java.util.stream.Collectors; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.hibernate.validator.internal.util.Contracts.assertNotNull; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; /** * This test uses a complete R4 JPA server as a backend and wires the @@ -77,7 +79,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { @Test - public void testGenerateLargePatientSummary() { + public void testGenerateLargePatientSummary() throws IOException { Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything.json.gz"); sourceData.setType(Bundle.BundleType.TRANSACTION); for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) { @@ -97,6 +99,9 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output)); // Verify + assertThat(output.getMeta().getProfile().stream().map(PrimitiveType::getValue).toList(), contains( + "http://hl7.org/fhir/uv/ips/StructureDefinition/Bundle-uv-ips" + )); validateDocument(output); assertEquals(117, output.getEntry().size()); String patientId = findFirstEntryResource(output, Patient.class, 1).getIdElement().toUnqualifiedVersionless().getValue(); @@ -162,7 +167,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { } @Test - public void testGenerateTinyPatientSummary() { + public void testGenerateTinyPatientSummary() throws IOException { myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY); Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/tiny-patient-everything.json.gz"); @@ -251,7 +256,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { @Nonnull - private static Composition findCompositionSectionByDisplay(Bundle output, String theDisplay) { + private static Composition findCompositionSectionByDisplay(Bundle output, @SuppressWarnings("SameParameterValue") String theDisplay) { Composition composition = (Composition) output.getEntry().get(0).getResource(); Composition.SectionComponent section = composition .getSection() @@ -259,6 +264,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { .filter(t -> t.getCode().getCoding().get(0).getDisplay().equals(theDisplay)) .findFirst() .orElseThrow(); + assertNotNull(section); return composition; } @@ -266,23 +272,26 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { @Nonnull private static List extractSectionTitles(Bundle outcome) { Composition composition = (Composition) outcome.getEntry().get(0).getResource(); - List sectionTitles = composition + return composition .getSection() .stream() .map(Composition.SectionComponent::getTitle) .toList(); - return sectionTitles; } - private void validateDocument(Bundle theOutcome) { + private void validateDocument(Bundle theOutcome) throws IOException { FhirValidator validator = myFhirContext.newValidator(); FhirInstanceValidator instanceValidator = new FhirInstanceValidator(myFhirContext); - instanceValidator.setValidationSupport(new ValidationSupportChain(new IpsTerminologySvc(), myFhirContext.getValidationSupport())); + + NpmPackageValidationSupport npmSupport = new NpmPackageValidationSupport(myFhirContext); + npmSupport.loadPackageFromClasspath("/ips-package-1.1.0.tgz"); + + instanceValidator.setValidationSupport(new ValidationSupportChain(npmSupport, new IpsTerminologySvc(), myFhirContext.getValidationSupport())); validator.registerValidatorModule(instanceValidator); ValidationResult validation = validator.validateWithResult(theOutcome); Optional failure = validation.getMessages().stream().filter(t -> t.getSeverity().ordinal() >= ResultSeverityEnum.ERROR.ordinal()).findFirst(); - assertFalse(failure.isPresent(), () -> failure.get().toString()); + assertFalse(failure.isPresent(), () -> failure.orElseThrow().toString()); } @Configuration @@ -294,7 +303,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { } @Bean - public IIpsGeneratorSvc ipsGeneratorSvc(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy, DaoRegistry theDaoRegistry) { + public IIpsGeneratorSvc ipsGeneratorSvc(FhirContext theFhirContext, IIpsGenerationStrategy theGenerationStrategy) { return new IpsGeneratorSvcImpl(theFhirContext, theGenerationStrategy); } diff --git a/hapi-fhir-jpaserver-ips/src/test/resources/ips-package-1.1.0.tgz b/hapi-fhir-jpaserver-ips/src/test/resources/ips-package-1.1.0.tgz new file mode 100644 index 0000000000000000000000000000000000000000..d43871cdd482a8446fadf5c8f7d5de2a5c59d5d3 GIT binary patch literal 1065105 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
    s?sRb(M~ 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𝔔%^Luc1sG6C>k9L1vTR14XRZnN# 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%0D(wsL{*7up{!{1`D0SDaCdoL)NMAjde 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 z%0A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

    Z8XOWUpF9wE3nw^N&}F=qH(4>5?fr** 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%0AgFh`l|2MeWHj+4C9OE5Az#Lyu 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 z%0A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 Date: Thu, 16 May 2024 14:02:53 -0700 Subject: [PATCH 14/15] Add support for returning subproperties for RemoteTerminologyService lookup (#5936) * Add support for returning subproperties in the RemoteTerminologyService * Add clarifying comments to code. Simplify logic to filter properties. * Update sub-property iteration logic in the conversion code to make it more readable * Fix spotless errors * Add a few more test cases to test property filtering for the lookup --- .../context/support/IValidationSupport.java | 121 ++++-- .../java/ca/uhn/fhir/util/ParametersUtil.java | 13 +- ...-subproperty-codesystem-lookup-output.yaml | 5 + ...teTerminologyServiceValidationSupport.java | 144 ++++--- .../hapi/validation/ILookupCodeTest.java | 400 ++++++++++-------- .../hapi/validation/LookupCodeDstu3Test.java | 251 ----------- .../RemoteTerminologyLookupCodeDstu3Test.java | 202 +++++++++ ...ologyServiceResourceProviderDstu3Test.java | 294 +++++++++++++ .../fhir/r4/validation/LookupCodeR4Test.java | 242 ----------- .../RemoteTerminologyLookupCodeR4Test.java | 201 +++++++++ ...minologyServiceResourceProviderR4Test.java | 74 +++- ...inologyServiceValidationSupportR4Test.java | 10 + ...stem-lookup-output-with-subproperties.json | 113 +++++ 13 files changed, 1273 insertions(+), 797 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5935-add-subproperty-codesystem-lookup-output.yaml delete mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceResourceProviderDstu3Test.java delete mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java create mode 100644 hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java rename {hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4 => hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation}/RemoteTerminologyServiceResourceProviderR4Test.java (73%) create mode 100644 hapi-fhir-validation/src/test/resources/r4/CodeSystem-lookup-output-with-subproperties.json diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java index 36dba38c0d7..328cd53f445 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/IValidationSupport.java @@ -530,8 +530,13 @@ public interface IValidationSupport { public abstract String getType(); } + // The reason these cannot be declared within an enum is because a Remote Terminology Service + // can support arbitrary types. We do not restrict against the types in the spec. + // Some of the types in the spec are not yet implemented as well. + // @see https://github.com/hapifhir/hapi-fhir/issues/5700 String TYPE_STRING = "string"; String TYPE_CODING = "Coding"; + String TYPE_GROUP = "group"; class StringConceptProperty extends BaseConceptProperty { private final String myValue; @@ -589,6 +594,31 @@ public interface IValidationSupport { } } + class GroupConceptProperty extends BaseConceptProperty { + public GroupConceptProperty(String thePropertyName) { + super(thePropertyName); + } + + private List subProperties; + + public BaseConceptProperty addSubProperty(BaseConceptProperty theProperty) { + if (subProperties == null) { + subProperties = new ArrayList<>(); + } + subProperties.add(theProperty); + return this; + } + + public List getSubProperties() { + return subProperties != null ? subProperties : Collections.emptyList(); + } + + @Override + public String getType() { + return TYPE_GROUP; + } + } + class CodeValidationResult { public static final String SOURCE_DETAILS = "sourceDetails"; public static final String RESULT = "result"; @@ -871,8 +901,15 @@ public interface IValidationSupport { } } + /** + * Converts the current LookupCodeResult instance into a IBaseParameters instance which is returned + * to the client of the $lookup operation. + * @param theContext the FHIR context used for running the operation + * @param thePropertyNamesToFilter the properties which are passed as parameter to filter the result. + * @return the output for the lookup operation. + */ public IBaseParameters toParameters( - FhirContext theContext, List> thePropertyNames) { + FhirContext theContext, List> thePropertyNamesToFilter) { IBaseParameters retVal = ParametersUtil.newInstance(theContext); if (isNotBlank(getCodeSystemDisplayName())) { @@ -886,50 +923,29 @@ public interface IValidationSupport { if (myProperties != null) { - Set properties = Collections.emptySet(); - if (thePropertyNames != null) { - properties = thePropertyNames.stream() + final List propertiesToReturn; + if (thePropertyNamesToFilter != null && !thePropertyNamesToFilter.isEmpty()) { + // TODO MM: The logic to filter of properties could actually be moved to the lookupCode provider. + // That is where the rest of the lookupCode input parameter handling is done. + // This was left as is for now but can be done with next opportunity. + Set propertyNameList = thePropertyNamesToFilter.stream() .map(IPrimitiveType::getValueAsString) .collect(Collectors.toSet()); + propertiesToReturn = myProperties.stream() + .filter(p -> propertyNameList.contains(p.getPropertyName())) + .collect(Collectors.toList()); + } else { + propertiesToReturn = myProperties; } - for (BaseConceptProperty next : myProperties) { - String propertyName = next.getPropertyName(); - - if (!properties.isEmpty() && !properties.contains(propertyName)) { - continue; - } - + for (BaseConceptProperty next : propertiesToReturn) { IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "property"); - ParametersUtil.addPartCode(theContext, property, "code", propertyName); - - String propertyType = next.getType(); - switch (propertyType) { - case TYPE_STRING: - StringConceptProperty stringConceptProperty = (StringConceptProperty) next; - ParametersUtil.addPartString( - theContext, property, "value", stringConceptProperty.getValue()); - break; - case TYPE_CODING: - CodingConceptProperty codingConceptProperty = (CodingConceptProperty) next; - ParametersUtil.addPartCoding( - theContext, - property, - "value", - codingConceptProperty.getCodeSystem(), - codingConceptProperty.getCode(), - codingConceptProperty.getDisplay()); - break; - default: - throw new IllegalStateException( - Msg.code(1739) + "Don't know how to handle " + next.getClass()); - } + populateProperty(theContext, property, next); } } if (myDesignations != null) { for (ConceptDesignation next : myDesignations) { - IBase property = ParametersUtil.addParameterToParameters(theContext, retVal, "designation"); ParametersUtil.addPartCode(theContext, property, "language", next.getLanguage()); ParametersUtil.addPartCoding( @@ -941,6 +957,41 @@ public interface IValidationSupport { return retVal; } + private void populateProperty( + FhirContext theContext, IBase theProperty, BaseConceptProperty theConceptProperty) { + ParametersUtil.addPartCode(theContext, theProperty, "code", theConceptProperty.getPropertyName()); + String propertyType = theConceptProperty.getType(); + switch (propertyType) { + case TYPE_STRING: + StringConceptProperty stringConceptProperty = (StringConceptProperty) theConceptProperty; + ParametersUtil.addPartString(theContext, theProperty, "value", stringConceptProperty.getValue()); + break; + case TYPE_CODING: + CodingConceptProperty codingConceptProperty = (CodingConceptProperty) theConceptProperty; + ParametersUtil.addPartCoding( + theContext, + theProperty, + "value", + codingConceptProperty.getCodeSystem(), + codingConceptProperty.getCode(), + codingConceptProperty.getDisplay()); + break; + case TYPE_GROUP: + GroupConceptProperty groupConceptProperty = (GroupConceptProperty) theConceptProperty; + if (groupConceptProperty.getSubProperties().isEmpty()) { + break; + } + groupConceptProperty.getSubProperties().forEach(p -> { + IBase subProperty = ParametersUtil.addPart(theContext, theProperty, "subproperty", null); + populateProperty(theContext, subProperty, p); + }); + break; + default: + throw new IllegalStateException( + Msg.code(1739) + "Don't know how to handle " + theConceptProperty.getClass()); + } + } + public void setErrorMessage(String theErrorMessage) { myErrorMessage = theErrorMessage; } diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java index 63b36e069b1..11fb8d6c012 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/ParametersUtil.java @@ -433,7 +433,7 @@ public class ParametersUtil { addPart(theContext, theParameter, theName, coding); } - public static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) { + public static IBase addPart(FhirContext theContext, IBase theParameter, String theName, @Nullable IBase theValue) { BaseRuntimeElementCompositeDefinition def = (BaseRuntimeElementCompositeDefinition) theContext.getElementDefinition(theParameter.getClass()); BaseRuntimeChildDefinition partChild = def.getChildByName("part"); @@ -448,11 +448,14 @@ public class ParametersUtil { name.setValue(theName); partChildElem.getChildByName("name").getMutator().addValue(part, name); - if (theValue instanceof IBaseResource) { - partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); - } else { - partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue); + if (theValue != null) { + if (theValue instanceof IBaseResource) { + partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); + } else { + partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue); + } } + return part; } public static void addPartResource( diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5935-add-subproperty-codesystem-lookup-output.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5935-add-subproperty-codesystem-lookup-output.yaml new file mode 100644 index 00000000000..ea3e05b38c3 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5935-add-subproperty-codesystem-lookup-output.yaml @@ -0,0 +1,5 @@ +--- +type: add +issue: 5935 +title: "Remote Terminology Service can now return subproperty fields for a CodeSystem lookup operation. +This can be done in DSTU3 and R4. R5 is not yet implemented." 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 2e69b1a46cf..a75e7c73406 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 @@ -216,7 +216,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup ParametersUtil.addParameterToParametersString(fhirContext, params, "language", displayLanguage); } for (String propertyName : theLookupCodeRequest.getPropertyNames()) { - ParametersUtil.addParameterToParametersString(fhirContext, params, "property", propertyName); + ParametersUtil.addParameterToParametersCode(fhirContext, params, "property", propertyName); } Class codeSystemClass = myCtx.getResourceDefinition("CodeSystem").getImplementingClass(); @@ -229,7 +229,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup if (outcome != null && !outcome.isEmpty()) { switch (fhirVersion) { case DSTU3: - return generateLookupCodeResultDSTU3( + return generateLookupCodeResultDstu3( code, system, (org.hl7.fhir.dstu3.model.Parameters) outcome); case R4: return generateLookupCodeResultR4(code, system, (Parameters) outcome); @@ -243,10 +243,10 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return null; } - private LookupCodeResult generateLookupCodeResultDSTU3( + private LookupCodeResult generateLookupCodeResultDstu3( String theCode, String theSystem, org.hl7.fhir.dstu3.model.Parameters outcomeDSTU3) { // NOTE: I wanted to put all of this logic into the IValidationSupport Class, but it would've required adding - // several new dependencies on version-specific libraries and that is explicitly forbidden (see comment in + // several new dependencies on version-specific libraries and that is explicitly forbidden (see comment in // POM). LookupCodeResult result = new LookupCodeResult(); result.setSearchedForCode(theCode); @@ -257,13 +257,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup String parameterTypeAsString = Objects.toString(parameterComponent.getValue(), null); switch (parameterComponent.getName()) { case "property": - org.hl7.fhir.dstu3.model.Property part = parameterComponent.getChildByName("part"); - // The assumption here is that we may only have 2 elements in this part, and if so, these 2 will be - // saved - if (part == null || part.getValues().size() < 2) { - continue; - } - BaseConceptProperty conceptProperty = createBaseConceptPropertyDstu3(part.getValues()); + BaseConceptProperty conceptProperty = createConceptPropertyDstu3(parameterComponent); if (conceptProperty != null) { result.getProperties().add(conceptProperty); } @@ -289,36 +283,47 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return result; } - private static BaseConceptProperty createBaseConceptPropertyDstu3(List theValues) { - org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent part1 = - (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) theValues.get(0); - String propertyName = ((org.hl7.fhir.dstu3.model.CodeType) part1.getValue()).getValue(); + private static BaseConceptProperty createConceptPropertyDstu3( + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent theParameterComponent) { + org.hl7.fhir.dstu3.model.Property property = theParameterComponent.getChildByName("part"); - BaseConceptProperty conceptProperty = null; - org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent part2 = - (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) theValues.get(1); + // The assumption here is that we may at east 2 elements in this part + if (property == null || property.getValues().size() < 2) { + return null; + } - org.hl7.fhir.dstu3.model.Type value = part2.getValue(); - if (value == null) { - return conceptProperty; + List values = property.getValues(); + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent firstPart = + (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) values.get(0); + String propertyName = ((org.hl7.fhir.dstu3.model.CodeType) firstPart.getValue()).getValue(); + + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent secondPart = + (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) values.get(1); + org.hl7.fhir.dstu3.model.Type value = secondPart.getValue(); + + if (value != null) { + return createConceptPropertyDstu3(propertyName, value); } - String fhirType = value.fhirType(); - switch (fhirType) { - case TYPE_STRING: - org.hl7.fhir.dstu3.model.StringType stringType = (org.hl7.fhir.dstu3.model.StringType) part2.getValue(); - conceptProperty = new StringConceptProperty(propertyName, stringType.getValue()); - break; - case TYPE_CODING: - org.hl7.fhir.dstu3.model.Coding coding = (org.hl7.fhir.dstu3.model.Coding) part2.getValue(); - conceptProperty = new CodingConceptProperty( - propertyName, coding.getSystem(), coding.getCode(), coding.getDisplay()); - break; - // TODO: add other property types as per FHIR spec https://github.com/hapifhir/hapi-fhir/issues/5699 - default: - // other types will not fail for Remote Terminology - conceptProperty = new StringConceptProperty(propertyName, value.toString()); + + String groupName = secondPart.getName(); + if (!"subproperty".equals(groupName)) { + return null; } - return conceptProperty; + + // handle property group (a property containing sub-properties) + GroupConceptProperty groupConceptProperty = new GroupConceptProperty(propertyName); + + // we already retrieved the property name (group name) as first element, next will be the sub-properties. + // there is no dedicated value for a property group as it is an aggregate + for (int i = 1; i < values.size(); i++) { + org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent nextPart = + (org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent) values.get(i); + BaseConceptProperty subProperty = createConceptPropertyDstu3(nextPart); + if (subProperty != null) { + groupConceptProperty.addSubProperty(subProperty); + } + } + return groupConceptProperty; } public static BaseConceptProperty createConceptProperty(final String theName, final IBaseDatatype theValue) { @@ -396,13 +401,7 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup String parameterTypeAsString = Objects.toString(parameterComponent.getValue(), null); switch (parameterComponent.getName()) { case "property": - Property part = parameterComponent.getChildByName("part"); - // The assumption here is that we may only have 2 elements in this part, and if so, these 2 will be - // saved - if (part == null || part.getValues().size() < 2) { - continue; - } - BaseConceptProperty conceptProperty = createBaseConceptPropertyR4(part.getValues()); + BaseConceptProperty conceptProperty = createConceptPropertyR4(parameterComponent); if (conceptProperty != null) { result.getProperties().add(conceptProperty); } @@ -428,34 +427,43 @@ public class RemoteTerminologyServiceValidationSupport extends BaseValidationSup return result; } - private static BaseConceptProperty createBaseConceptPropertyR4(List values) { - ParametersParameterComponent part1 = (ParametersParameterComponent) values.get(0); - String propertyName = ((CodeType) part1.getValue()).getValue(); + private static BaseConceptProperty createConceptPropertyR4(ParametersParameterComponent thePropertyComponent) { + Property property = thePropertyComponent.getChildByName("part"); - ParametersParameterComponent part2 = (ParametersParameterComponent) values.get(1); - - Type value = part2.getValue(); - if (value == null) { + // The assumption here is that we may at east 2 elements in this part + if (property == null || property.getValues().size() < 2) { return null; } - BaseConceptProperty conceptProperty; - String fhirType = value.fhirType(); - switch (fhirType) { - case IValidationSupport.TYPE_STRING: - StringType stringType = (StringType) part2.getValue(); - conceptProperty = new StringConceptProperty(propertyName, stringType.getValue()); - break; - case IValidationSupport.TYPE_CODING: - Coding coding = (Coding) part2.getValue(); - conceptProperty = new CodingConceptProperty( - propertyName, coding.getSystem(), coding.getCode(), coding.getDisplay()); - break; - // TODO: add other property types as per FHIR spec https://github.com/hapifhir/hapi-fhir/issues/5699 - default: - // other types will not fail for Remote Terminology - conceptProperty = new StringConceptProperty(propertyName, value.toString()); + + List values = property.getValues(); + ParametersParameterComponent firstPart = (ParametersParameterComponent) values.get(0); + String propertyName = ((CodeType) firstPart.getValue()).getValue(); + + ParametersParameterComponent secondPart = (ParametersParameterComponent) values.get(1); + Type value = secondPart.getValue(); + + if (value != null) { + return createConceptPropertyR4(propertyName, value); } - return conceptProperty; + + String groupName = secondPart.getName(); + if (!"subproperty".equals(groupName)) { + return null; + } + + // handle property group (a property containing sub-properties) + GroupConceptProperty groupConceptProperty = new GroupConceptProperty(propertyName); + + // we already retrieved the property name (group name) as first element, next will be the sub-properties. + // there is no dedicated value for a property group as it is an aggregate + for (int i = 1; i < values.size(); i++) { + ParametersParameterComponent nextPart = (ParametersParameterComponent) values.get(i); + BaseConceptProperty subProperty = createConceptPropertyR4(nextPart); + if (subProperty != null) { + groupConceptProperty.addSubProperty(subProperty); + } + } + return groupConceptProperty; } private static BaseConceptProperty createConceptPropertyR4(final String theName, final Type theValue) { 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 0b4624d733f..a282a611ceb 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 @@ -1,23 +1,26 @@ package org.hl7.fhir.common.hapi.validation; import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport.BaseConceptProperty; +import ca.uhn.fhir.context.support.IValidationSupport.CodingConceptProperty; +import ca.uhn.fhir.context.support.IValidationSupport.ConceptDesignation; +import ca.uhn.fhir.context.support.IValidationSupport.GroupConceptProperty; import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; +import ca.uhn.fhir.context.support.IValidationSupport.StringConceptProperty; import ca.uhn.fhir.context.support.LookupCodeRequest; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport; import org.hl7.fhir.instance.model.api.IBaseDatatype; -import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.Arguments; -import org.junit.jupiter.params.provider.MethodSource; -import java.util.Collection; +import java.util.ArrayList; import java.util.List; import java.util.Optional; -import java.util.stream.Stream; +import static ca.uhn.fhir.context.support.IValidationSupport.TYPE_CODING; +import static ca.uhn.fhir.context.support.IValidationSupport.TYPE_GROUP; +import static ca.uhn.fhir.context.support.IValidationSupport.TYPE_STRING; +import static java.util.stream.IntStream.range; 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; @@ -25,6 +28,17 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +/** + * Contains basic test setup for the $lookup operation against a {@link org.hl7.fhir.dstu3.model.CodeSystem}. + * The provider for CodeSystem and the validation service needs to be configured by the implementing class. + * This test interface contains the following: + * (1) basic tests which are version independent, without any parameters, declared as default with @Test annotation + * e.g. lookupCode_forCodeSystemWithBlankCode_throwsException + * (2) test template methods for running version dependent tests with parameters, declared as default, without annotations + * e.g. @see #verifyLookupCodeResult + * (3) methods which help to assert part of the output (designation, property), declared as private + * e.g. assertEqualConceptProperty + */ public interface ILookupCodeTest { String DISPLAY = "DISPLAY"; String LANGUAGE = "en"; @@ -33,186 +47,202 @@ public interface ILookupCodeTest { String CODE_SYSTEM_NAME = "Code System"; String CODE = "CODE"; - interface IValidationTest { + IValidationSupport getService(); + IMyCodeSystemProvider getCodeSystemProvider(); - RemoteTerminologyServiceValidationSupport getService(); - IResourceProvider getCodeSystemProvider(); - } - - @Nested - interface ILookupCodeSupportedPropertyTest extends IValidationTest { - IMyCodeSystemProvider getCodeSystemProvider(); - - Stream getEmptyPropertyValues(); - - Stream getPropertyValues(); - - Stream getDesignations(); - - void verifyProperty(IValidationSupport.BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue); - - @Test - default void testLookupCode_forCodeSystemWithBlankCode_throwsException() { - try { - getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, "")); - fail(); - } catch (IllegalArgumentException e) { - assertEquals("theCode must be provided", e.getMessage()); - } - } - - @Test - default void testLookupCode_forCodeSystemWithPropertyInvalidType_throwsException() { - LookupCodeResult result = new LookupCodeResult(); - result.getProperties().add(new IValidationSupport.BaseConceptProperty("someProperty") { - public String getType() { - return "someUnsupportedType"; - } - }); - getCodeSystemProvider().setLookupCodeResult(result); - - try { - getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); - fail(); - } catch (InternalErrorException e) { - assertTrue(e.getMessage().contains("HAPI-1739: Don't know how to handle ")); - } - } - - @ParameterizedTest - @MethodSource(value = "getEmptyPropertyValues") - default void testLookupCode_forCodeSystemWithPropertyEmptyValue_returnsCorrectParameters(IBaseDatatype thePropertyValue) { - // setup - final String propertyName = "someProperty"; - IValidationSupport.BaseConceptProperty property = createConceptProperty(propertyName, thePropertyValue); - LookupCodeResult result = new LookupCodeResult(); - result.getProperties().add(property); - getCodeSystemProvider().setLookupCodeResult(result); - - // test - LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(propertyName))); - - // verify - assertNotNull(outcome); - Optional propertyOptional = outcome.getProperties().stream().findFirst().filter(a -> propertyName.equals(a.getPropertyName())); - assertFalse(propertyOptional.isPresent()); - } - - @Test - default void testLookupCode_forCodeSystemWithParameters_returnsCorrectParameters() { - // setup - LookupCodeResult result = new LookupCodeResult().setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); - result.setCodeIsAbstract(false); - result.setCodeSystemVersion(CODE_SYSTEM_VERSION); - result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); - result.setCodeDisplay(DISPLAY); - getCodeSystemProvider().setLookupCodeResult(result); - - // test - LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); - - // verify - assertNotNull(outcome); - assertEquals(CODE, getCodeSystemProvider().getCode()); - assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem()); - assertEquals(result.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName()); - assertEquals(result.getCodeDisplay(), outcome.getCodeDisplay()); - assertEquals(result.getCodeSystemVersion(), outcome.getCodeSystemVersion()); - assertEquals(result.isCodeIsAbstract(), outcome.isCodeIsAbstract()); - } - - @ParameterizedTest - @MethodSource(value = "getPropertyValues") - default void testLookupCode_forCodeSystemWithProperty_returnsCorrectProperty(IBaseDatatype thePropertyValue) { - // setup - final String propertyName = "someProperty"; - LookupCodeResult result = new LookupCodeResult() - .setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); - result.setCodeIsAbstract(false); - result.setCodeSystemVersion(CODE_SYSTEM_VERSION); - result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); - result.setCodeDisplay(DISPLAY); - IValidationSupport.BaseConceptProperty property = createConceptProperty(propertyName, thePropertyValue); - result.getProperties().add(property); - getCodeSystemProvider().setLookupCodeResult(result); - - // test - LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(propertyName))); - - // verify - assertNotNull(outcome); - assertEquals(CODE, getCodeSystemProvider().getCode()); - assertEquals(CODE_SYSTEM, getCodeSystemProvider().getSystem()); - assertEquals(result.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName()); - assertEquals(result.getCodeDisplay(), outcome.getCodeDisplay()); - assertEquals(result.getCodeSystemVersion(), outcome.getCodeSystemVersion()); - assertEquals(result.isCodeIsAbstract(), outcome.isCodeIsAbstract()); - - Optional propertyOptional = outcome.getProperties().stream().findFirst().filter(a -> propertyName.equals(a.getPropertyName())); - assertTrue(propertyOptional.isPresent()); - IValidationSupport.BaseConceptProperty outputProperty = propertyOptional.get(); - - verifyProperty(outputProperty, propertyName, thePropertyValue); - } - - @ParameterizedTest - @MethodSource(value = "getDesignations") - default void testLookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IValidationSupport.ConceptDesignation theConceptDesignation) { - // setup - LookupCodeResult result = new LookupCodeResult(); - result.getDesignations().add(theConceptDesignation); - getCodeSystemProvider().setLookupCodeResult(result); - - // test - LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); - - // verify - assertNotNull(outcome); - - Collection designations = outcome.getDesignations(); - assertEquals(1, designations.size()); - - IValidationSupport.ConceptDesignation designation = designations.iterator().next(); - assertEquals(theConceptDesignation.getValue(), designation.getValue()); - assertEquals(theConceptDesignation.getLanguage(), designation.getLanguage()); - assertEquals(theConceptDesignation.getUseCode(), designation.getUseCode()); - assertEquals(theConceptDesignation.getUseSystem(), designation.getUseSystem()); - assertEquals(theConceptDesignation.getUseDisplay(), designation.getUseDisplay()); - } - - @Test - default void testLookupCode_withCodeSystemWithMultipleDesignations_returnsCorrectDesignations() { - // setup - final String code1 = "code1"; - final String code2 = "code2"; - - IValidationSupport.ConceptDesignation designation1 = new IValidationSupport.ConceptDesignation().setUseCode(code1).setUseSystem("system1").setValue("value1").setLanguage("en"); - IValidationSupport.ConceptDesignation designation2 = new IValidationSupport.ConceptDesignation().setUseCode(code2).setUseSystem("system2").setValue("value2").setLanguage("es"); - LookupCodeResult result = new LookupCodeResult(); - result.getDesignations().add(designation1); - result.getDesignations().add(designation2); - getCodeSystemProvider().setLookupCodeResult(result); - - // test - LookupCodeResult outcome = getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null)); - - // verify - assertNotNull(outcome); - - Collection designations = outcome.getDesignations(); - assertEquals(2, designations.size()); - - for (IValidationSupport.ConceptDesignation designation : designations) { - IValidationSupport.ConceptDesignation expectedDesignation = code1.equals(designation.getUseCode()) ? designation1 : designation2; - assertEquals(expectedDesignation.getValue(), designation.getValue()); - assertEquals(expectedDesignation.getLanguage(), designation.getLanguage()); - assertEquals(expectedDesignation.getUseCode(), designation.getUseCode()); - assertEquals(expectedDesignation.getUseSystem(), designation.getUseSystem()); - assertEquals(expectedDesignation.getUseDisplay(), designation.getUseDisplay()); - } + @Test + default void lookupCode_forCodeSystemWithBlankCode_throwsException() { + try { + getService().lookupCode(null, new LookupCodeRequest(CODE_SYSTEM, "")); + fail(); + } catch (IllegalArgumentException e) { + assertEquals("theCode must be provided", e.getMessage()); } } + @Test + default void lookupCode_forCodeSystemWithPropertyInvalidType_throwsException() { + // test + LookupCodeResult result = new LookupCodeResult(); + result.getProperties().add(new BaseConceptProperty("someProperty") { + public String getType() { + return "someUnsupportedType"; + } + }); + getCodeSystemProvider().setLookupCodeResult(result); + + // test and verify + try { + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null); + getService().lookupCode(null, request); + fail(); + } catch (InternalErrorException e) { + assertTrue(e.getMessage().contains("HAPI-1739: Don't know how to handle ")); + } + } + + @Test + default void lookupCode_forCodeSystem_returnsCorrectResult() { + LookupCodeResult result = new LookupCodeResult().setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); + result.setCodeIsAbstract(false); + result.setCodeSystemVersion(CODE_SYSTEM_VERSION); + result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); + result.setCodeDisplay(DISPLAY); + getCodeSystemProvider().setLookupCodeResult(result); + + // test and verify + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null); + verifyLookupCodeResult(request, result); + } + + @Test + default void lookupCode_withCodeSystemWithMultipleDesignations_returnsCorrectDesignations() { + // setup + final String code1 = "code1"; + final String code2 = "code2"; + + ConceptDesignation designation1 = new ConceptDesignation().setUseCode(code1).setUseSystem("system1").setValue("value1").setLanguage("en"); + ConceptDesignation designation2 = new ConceptDesignation().setUseCode(code2).setUseSystem("system2").setValue("value2").setLanguage("es"); + LookupCodeResult result = new LookupCodeResult(); + result.getDesignations().add(designation1); + result.getDesignations().add(designation2); + getCodeSystemProvider().setLookupCodeResult(result); + + // test and verify + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null); + verifyLookupCodeResult(request, result); + } + + default void verifyLookupWithEmptyPropertyValue(IBaseDatatype thePropertyValue) { + // setup + final String propertyName = "someProperty"; + BaseConceptProperty property = createConceptProperty(propertyName, thePropertyValue); + LookupCodeResult result = new LookupCodeResult(); + result.getProperties().add(property); + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(propertyName)); + LookupCodeResult outcome = getService().lookupCode(null, request); + + // verify + assertNotNull(outcome); + Optional propertyOptional = outcome.getProperties().stream().findFirst().filter(a -> propertyName.equals(a.getPropertyName())); + assertFalse(propertyOptional.isPresent()); + } + + default void verifyLookupWithProperty(List thePropertyValues, List thePropertyIndexesToFilter) { + // setup + final String propertyName = "someProperty"; + LookupCodeResult result = new LookupCodeResult().setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); + result.setCodeIsAbstract(false); + result.setCodeSystemVersion(CODE_SYSTEM_VERSION); + result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); + result.setCodeDisplay(DISPLAY); + List propertyNamesToFilter = new ArrayList<>(); + for (int i = 0; i < thePropertyValues.size(); i++) { + String currentPropertyName = propertyName + i; + result.getProperties().add(createConceptProperty(currentPropertyName, thePropertyValues.get(i))); + if (thePropertyIndexesToFilter.contains(i)) { + propertyNamesToFilter.add(currentPropertyName); + } + } + getCodeSystemProvider().setLookupCodeResult(result); + + // test + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, propertyNamesToFilter); + + // verify + result.getProperties().removeIf(p -> !propertyNamesToFilter.contains(p.getPropertyName())); + verifyLookupCodeResult(request, result); + } + + default void verifyLookupWithSubProperties(List thePropertyValues) { + // setup + final String groupName = "group"; + LookupCodeResult result = new LookupCodeResult().setFound(true).setSearchedForCode(CODE).setSearchedForSystem(CODE_SYSTEM); + result.setCodeIsAbstract(false); + result.setCodeSystemVersion(CODE_SYSTEM_VERSION); + result.setCodeSystemDisplayName(CODE_SYSTEM_NAME); + result.setCodeDisplay(DISPLAY); + final String subPropertyName = "someSubProperty"; + GroupConceptProperty group = new GroupConceptProperty(groupName); + for (int i = 0; i < thePropertyValues.size(); i++) { + group.addSubProperty(createConceptProperty(subPropertyName + i, thePropertyValues.get(i))); + } + result.getProperties().add(group); + getCodeSystemProvider().setLookupCodeResult(result); + + // test and verify + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, List.of(groupName)); + verifyLookupCodeResult(request, result); + } + + default void verifyLookupCodeResult(LookupCodeRequest theRequest, LookupCodeResult theExpectedResult) { + // test + LookupCodeResult outcome = getService().lookupCode(null, theRequest); + assertNotNull(outcome); + + // verify + assertNotNull(outcome); + assertEquals(theRequest.getCode(), getCodeSystemProvider().getCode()); + assertEquals(theRequest.getSystem(), getCodeSystemProvider().getSystem()); + assertEquals(theExpectedResult.getCodeSystemDisplayName(), outcome.getCodeSystemDisplayName()); + assertEquals(theExpectedResult.getCodeDisplay(), outcome.getCodeDisplay()); + assertEquals(theExpectedResult.getCodeSystemVersion(), outcome.getCodeSystemVersion()); + assertEquals(theExpectedResult.isCodeIsAbstract(), outcome.isCodeIsAbstract()); + + assertEquals(theExpectedResult.getProperties().size(), outcome.getProperties().size()); + range(0, outcome.getProperties().size()).forEach(i -> assertEqualConceptProperty(theExpectedResult.getProperties().get(i), outcome.getProperties().get(i))); + + assertEquals(theExpectedResult.getDesignations().size(), outcome.getDesignations().size()); + range(0, outcome.getDesignations().size()).forEach(i -> assertEqualConceptDesignation(theExpectedResult.getDesignations().get(i), outcome.getDesignations().get(i))); + } + + default void verifyLookupWithConceptDesignation(final ConceptDesignation theConceptDesignation) { + // setup + LookupCodeResult result = new LookupCodeResult(); + result.getDesignations().add(theConceptDesignation); + getCodeSystemProvider().setLookupCodeResult(result); + + // test and verify + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, LANGUAGE, null); + verifyLookupCodeResult(request, result); + } + + private void assertEqualConceptProperty(BaseConceptProperty theProperty, BaseConceptProperty theExpectedProperty) { + assertEquals(theExpectedProperty.getPropertyName(), theProperty.getPropertyName()); + assertEquals(theExpectedProperty.getType(), theProperty.getType()); + switch (theProperty.getType()) { + case TYPE_STRING -> { + StringConceptProperty expected = (StringConceptProperty) theExpectedProperty; + StringConceptProperty actual = (StringConceptProperty) theProperty; + assertEquals(expected.getValue(), actual.getValue()); + } + case TYPE_CODING -> { + CodingConceptProperty expected = (CodingConceptProperty) theExpectedProperty; + CodingConceptProperty actual = (CodingConceptProperty) theProperty; + assertEquals(expected.getCode(), actual.getCode()); + assertEquals(expected.getCodeSystem(), actual.getCodeSystem()); + assertEquals(expected.getDisplay(), actual.getDisplay()); + } + case TYPE_GROUP -> { + GroupConceptProperty expected = (GroupConceptProperty) theExpectedProperty; + GroupConceptProperty actual = (GroupConceptProperty) theProperty; + assertEquals(expected.getSubProperties().size(), actual.getSubProperties().size()); + range(0, actual.getSubProperties().size()).forEach(i -> assertEqualConceptProperty(expected.getSubProperties().get(i), actual.getSubProperties().get(i))); + } + default -> fail(); + } + } + + private void assertEqualConceptDesignation(final ConceptDesignation theActualDesignation, final ConceptDesignation theExpectedDesignation) { + assertEquals(theActualDesignation.getValue(), theExpectedDesignation.getValue()); + assertEquals(theActualDesignation.getLanguage(), theExpectedDesignation.getLanguage()); + assertEquals(theActualDesignation.getUseCode(), theExpectedDesignation.getUseCode()); + assertEquals(theActualDesignation.getUseSystem(), theExpectedDesignation.getUseSystem()); + assertEquals(theActualDesignation.getUseDisplay(), theExpectedDesignation.getUseDisplay()); + } interface IMyCodeSystemProvider extends IResourceProvider { String getCode(); @@ -220,8 +250,4 @@ public interface ILookupCodeTest { void setLookupCodeResult(LookupCodeResult theLookupCodeResult); } - - interface IMySimpleCodeSystemProvider extends IResourceProvider { - IBaseDatatype getPropertyValue(); - } } diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java deleted file mode 100644 index 404d971928e..00000000000 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/LookupCodeDstu3Test.java +++ /dev/null @@ -1,251 +0,0 @@ -package org.hl7.fhir.dstu3.hapi.validation; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.support.IValidationSupport; -import ca.uhn.fhir.context.support.IValidationSupport.ConceptDesignation; -import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; -import ca.uhn.fhir.jpa.model.util.JpaConstants; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; -import jakarta.servlet.http.HttpServletRequest; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeSupportedPropertyTest; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMyCodeSystemProvider; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMySimpleCodeSystemProvider; -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.CodeType; -import org.hl7.fhir.dstu3.model.Coding; -import org.hl7.fhir.dstu3.model.Parameters; -import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; -import org.hl7.fhir.dstu3.model.StringType; -import org.hl7.fhir.dstu3.model.Type; -import org.hl7.fhir.dstu3.model.UriType; -import org.hl7.fhir.instance.model.api.IBaseDatatype; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.r4.model.DateTimeType; -import org.hl7.fhir.r4.model.DecimalType; -import org.hl7.fhir.r4.model.InstantType; -import org.hl7.fhir.r4.model.IntegerType; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.provider.Arguments; - -import java.util.Calendar; -import java.util.List; -import java.util.stream.Stream; - -import static ca.uhn.fhir.context.support.IValidationSupport.BaseConceptProperty; -import static ca.uhn.fhir.context.support.IValidationSupport.CodingConceptProperty; -import static ca.uhn.fhir.context.support.IValidationSupport.StringConceptProperty; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class LookupCodeDstu3Test { - private static final FhirContext ourCtx = FhirContext.forDstu3Cached(); - @RegisterExtension - public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); - private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); - - @BeforeEach - public void before() { - String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); - mySvc.setBaseUrl(baseUrl); - mySvc.addClientInterceptor(new LoggingInterceptor(true)); - } - - @TestInstance(TestInstance.Lifecycle.PER_CLASS) - @Nested - class ILookupCodeSupportedPropertyDstu3Test implements ILookupCodeSupportedPropertyTest { - private final MyCodeSystemProviderDstu3 myCodeSystemProvider = new MyCodeSystemProviderDstu3(); - - @Override - public IMyCodeSystemProvider getCodeSystemProvider() { - return myCodeSystemProvider; - } - - @Override - public RemoteTerminologyServiceValidationSupport getService() { - return mySvc; - } - - @BeforeEach - public void before() { - ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); - } - - public void verifyProperty(BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue) { - assertEquals(theExpectedPropertName, theConceptProperty.getPropertyName()); - String type = theConceptProperty.getType(); - switch (type) { - case IValidationSupport.TYPE_STRING -> { - if (!(theExpectedValue instanceof StringType stringValue)) { - // TODO: remove this branch to test other property types as per FHIR spec https://github.com/hapifhir/hapi-fhir/issues/5699 - IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; - assertEquals(theExpectedValue.toString(), stringConceptProperty.getValue()); - break; - } - // StringType stringValue = (StringType) theExpectedValue; - assertTrue(theConceptProperty instanceof StringConceptProperty); - StringConceptProperty stringConceptProperty = (StringConceptProperty) theConceptProperty; - assertEquals(stringValue.getValue(), stringConceptProperty.getValue()); - } - case IValidationSupport.TYPE_CODING -> { - assertTrue(theExpectedValue instanceof Coding); - Coding coding = (Coding) theExpectedValue; - assertTrue(theConceptProperty instanceof CodingConceptProperty); - CodingConceptProperty codingConceptProperty = (CodingConceptProperty) theConceptProperty; - assertEquals(coding.getCode(), codingConceptProperty.getCode()); - assertEquals(coding.getSystem(), codingConceptProperty.getCodeSystem()); - assertEquals(coding.getDisplay(), codingConceptProperty.getDisplay()); - } - default -> { - IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; - assertEquals(theExpectedValue.toString(), stringConceptProperty.getValue()); - } - } - } - - public Stream getEmptyPropertyValues() { - return Stream.of( - Arguments.arguments(new StringType()), - Arguments.arguments(new StringType("")), - Arguments.arguments(new Coding()), - Arguments.arguments(new Coding("", null, null)), - Arguments.arguments(new Coding("", "", null)), - Arguments.arguments(new Coding(null, "", null)) - ); - } - - public Stream getPropertyValues() { - return Stream.of( - // FHIR DSTU3 spec types - Arguments.arguments(new StringType("value")), - Arguments.arguments(new Coding("code", "system", "display")), - Arguments.arguments(new CodeType("code")), - Arguments.arguments(new BooleanType(true)), - Arguments.arguments(new IntegerType(1)), - Arguments.arguments(new DateTimeType(Calendar.getInstance())), - // other types will also not fail for Remote Terminology - Arguments.arguments(new DecimalType(1.1)), - Arguments.arguments(new InstantType(Calendar.getInstance())), - Arguments.arguments(new Type() { - @Override - protected Type typedCopy() { - return this; - } - - @Override - public String toString() { - return "randomType"; - } - }) - ); - } - - public Stream getDesignations() { - return Stream.of( - Arguments.arguments(new ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), - Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), - Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), - Arguments.arguments(new ConceptDesignation().setUseCode("code2").setUseSystem("system1")), - Arguments.arguments(new ConceptDesignation().setUseCode("code2")) - ); - } - } - - static class MySimplePropertyCodeSystemProviderDstu3 implements IMySimpleCodeSystemProvider { - - String myPropertyName; - Type myPropertyValue; - - @Override - public IBaseDatatype getPropertyValue() { - return myPropertyValue; - } - - @Override - public Class getResourceType() { - return CodeSystem.class; - } - - @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { - @OperationParam(name = "name", type = StringType.class, min = 1), - @OperationParam(name = "version", type = StringType.class, min = 0), - @OperationParam(name = "display", type = StringType.class, min = 1), - @OperationParam(name = "abstract", type = BooleanType.class, min = 1), - @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) - }) - public Parameters 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 - ) { - ParametersParameterComponent component = new ParametersParameterComponent(); - component.setName("property"); - component.addPart(new ParametersParameterComponent().setName("code").setValue(new CodeType(myPropertyName))); - component.addPart(new ParametersParameterComponent().setName("value").setValue(myPropertyValue)); - return new Parameters().addParameter(component); - } - - } - - static class MyCodeSystemProviderDstu3 implements IMyCodeSystemProvider { - private UriType mySystemUrl; - private CodeType myCode; - private LookupCodeResult myLookupCodeResult; - - @Override - public Class getResourceType() { - return CodeSystem.class; - } - - @Override - public String getCode() { - return myCode != null ? myCode.getValueAsString() : null; - } - - @Override - public String getSystem() { - return mySystemUrl != null ? mySystemUrl.getValueAsString() : null; - } - - @Override - public void setLookupCodeResult(LookupCodeResult theLookupCodeResult) { - myLookupCodeResult = theLookupCodeResult; - } - - @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { - @OperationParam(name = "name", type = StringType.class, min = 1), - @OperationParam(name = "version", type = StringType.class, min = 0), - @OperationParam(name = "display", type = StringType.class, min = 1), - @OperationParam(name = "abstract", type = BooleanType.class, min = 1), - @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) - }) - public Parameters 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 - ) { - myCode = theCode; - mySystemUrl = theSystem; - - return (Parameters)myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); - } - } -} 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 new file mode 100644 index 00000000000..6269733654e --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyLookupCodeDstu3Test.java @@ -0,0 +1,202 @@ +package org.hl7.fhir.dstu3.hapi.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.IValidationSupport.ConceptDesignation; +import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; +import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import jakarta.servlet.http.HttpServletRequest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest; +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.CodeType; +import org.hl7.fhir.dstu3.model.Coding; +import org.hl7.fhir.dstu3.model.StringType; +import org.hl7.fhir.dstu3.model.Type; +import org.hl7.fhir.dstu3.model.UriType; +import org.hl7.fhir.instance.model.api.IBaseDatatype; +import org.hl7.fhir.instance.model.api.IBaseParameters; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.InstantType; +import org.hl7.fhir.r4.model.IntegerType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Calendar; +import java.util.List; +import java.util.stream.Stream; + +/** + * Version specific tests for CodeSystem $lookup against RemoteTerminologyValidationSupport. + * @see RemoteTerminologyServiceValidationSupport + */ +public class RemoteTerminologyLookupCodeDstu3Test implements ILookupCodeTest { + private static final FhirContext ourCtx = FhirContext.forDstu3Cached(); + @RegisterExtension + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); + private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); + + @BeforeEach + public void before() { + String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); + mySvc.setBaseUrl(baseUrl); + mySvc.addClientInterceptor(new LoggingInterceptor(true)); + ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); + } + + private final MyCodeSystemProviderDstu3 myCodeSystemProvider = new MyCodeSystemProviderDstu3(); + + @Override + public IMyCodeSystemProvider getCodeSystemProvider() { + return myCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + public static Stream getEmptyPropertyValues() { + return Stream.of( + Arguments.of(new StringType()), + Arguments.of(new StringType("")), + Arguments.of(new Coding()), + Arguments.of(new Coding("", null, null)), + Arguments.of(new Coding("", "", null)), + Arguments.of(new Coding(null, "", null)) + ); + } + + @ParameterizedTest + @MethodSource(value = "getEmptyPropertyValues") + public void lookupCode_forCodeSystemWithPropertyEmptyValue_returnsCorrectParameters(IBaseDatatype thePropertyValue) { + verifyLookupWithEmptyPropertyValue(thePropertyValue); + } + + public static Stream getPropertyValueArguments() { + return Stream.of( + // FHIR DSTU3 spec types + Arguments.of(new StringType("value")), + Arguments.of(new Coding("code", "system", "display")), + Arguments.of(new CodeType("code")), + Arguments.of(new BooleanType(true)), + Arguments.of(new IntegerType(1)), + Arguments.of(new DateTimeType(Calendar.getInstance())), + // other types will also not fail for Remote Terminology + Arguments.of(new DecimalType(1.1)), + Arguments.of(new InstantType(Calendar.getInstance())), + Arguments.of(new Type() { + @Override + protected Type typedCopy() { + return this; + } + + @Override + public String toString() { + return "randomType"; + } + }) + ); + } + + public static Stream getPropertyValueListArguments() { + return Stream.of( + Arguments.of(List.of(new StringType("value1")), new StringType("value2")), + Arguments.of(List.of(new StringType("value1")), new Coding("code", "system", "display")) + ); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueArguments") + public void lookupCode_forCodeSystemWithProperty_returnsCorrectProperty(IBaseDatatype thePropertyValue) { + verifyLookupWithProperty(List.of(thePropertyValue), List.of()); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueListArguments") + public void lookupCode_forCodeSystemWithPropertyFilter_returnsCorrectProperty(List thePropertyValues) { + verifyLookupWithProperty(thePropertyValues, List.of()); + verifyLookupWithProperty(thePropertyValues, List.of(thePropertyValues.size() - 1)); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueListArguments") + public void lookupCode_forCodeSystemWithPropertyGroup_returnsCorrectProperty(List thePropertyValues) { + verifyLookupWithSubProperties(thePropertyValues); + } + + public static Stream getDesignations() { + return Stream.of( + Arguments.of(new ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1")), + Arguments.of(new ConceptDesignation().setUseCode("code2")) + ); + } + + @ParameterizedTest + @MethodSource(value = "getDesignations") + void lookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IValidationSupport.ConceptDesignation theConceptDesignation) { + verifyLookupWithConceptDesignation(theConceptDesignation); + } + + static class MyCodeSystemProviderDstu3 implements IMyCodeSystemProvider { + private UriType mySystemUrl; + private CodeType myCode; + private LookupCodeResult myLookupCodeResult; + + @Override + public void setLookupCodeResult(LookupCodeResult theLookupCodeResult) { + myLookupCodeResult = theLookupCodeResult; + } + + @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { + @OperationParam(name = "name", type = StringType.class, min = 1), + @OperationParam(name = "version", type = StringType.class, min = 0), + @OperationParam(name = "display", type = StringType.class, min = 1), + @OperationParam(name = "abstract", type = BooleanType.class, min = 1), + @OperationParam(name = "property", 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 + ) { + myCode = theCode; + mySystemUrl = theSystem; + return myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); + } + + @Override + public Class 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/RemoteTerminologyServiceResourceProviderDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceResourceProviderDstu3Test.java new file mode 100644 index 00000000000..f71552dc750 --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/RemoteTerminologyServiceResourceProviderDstu3Test.java @@ -0,0 +1,294 @@ +package org.hl7.fhir.dstu3.hapi.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.LookupCodeRequest; +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 ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import ca.uhn.fhir.util.ClasspathUtil; +import jakarta.servlet.http.HttpServletRequest; +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.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.Type; +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 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 java.util.List; +import java.util.Optional; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +/** + * Version specific tests for validation using RemoteTerminologyValidationSupport. + * The tests in this class simulate the call to a remote server and therefore, only tests the code in + * the RemoteTerminologyServiceValidationSupport itself. The remote client call is simulated using the test providers. + * @see RemoteTerminologyServiceValidationSupport + * + * Other operations are tested separately. + * @see RemoteTerminologyLookupCodeDstu3Test + */ +public class RemoteTerminologyServiceResourceProviderDstu3Test { + private static final String DISPLAY = "DISPLAY"; + private static final String CODE_SYSTEM = "CODE_SYS"; + private static final String CODE = "CODE"; + private static final String VALUE_SET_URL = "http://value.set/url"; + private static final String SAMPLE_MESSAGE = "This is a sample message"; + private static final FhirContext ourCtx = FhirContext.forDstu3Cached(); + private static final MyCodeSystemProvider ourCodeSystemProvider = new MyCodeSystemProvider(); + private static final MyValueSetProvider ourValueSetProvider = new MyValueSetProvider(); + + @RegisterExtension + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx, ourCodeSystemProvider, + ourValueSetProvider); + + private RemoteTerminologyServiceValidationSupport mySvc; + + @BeforeEach + public void before_ConfigureService() { + String myBaseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); + mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx, myBaseUrl); + mySvc.addClientInterceptor(new LoggingInterceptor(false).setLogRequestSummary(true).setLogResponseSummary(true)); + } + + @AfterEach + public void after_UnregisterProviders() { + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE); + ourRestfulServerExtension.getRestfulServer().getInterceptorService().unregisterAllInterceptors(); + } + + @Test + public void testValidateCodeInCodeSystem_BlankCode_ReturnsNull() { + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, null, DISPLAY, null); + assertNull(outcome); + } + + @Test + public void testValidateCodeInCodeSystem_ProvidingMinimalInputs_ReturnsSuccess() { + createNextCodeSystemReturnParameters(true, null, null); + + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, CODE, null, null); + assertNotNull(outcome); + assertEquals(CODE, outcome.getCode()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); + + assertEquals(CODE, ourCodeSystemProvider.myLastCode.getValue()); + assertEquals(CODE_SYSTEM, ourCodeSystemProvider.myLastUrl.getValueAsString()); + } + + @Test + public void testValidateCodeInCodeSystem_WithMessageValue_ReturnsMessage() { + createNextCodeSystemReturnParameters(true, DISPLAY, SAMPLE_MESSAGE); + + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, null); + assertNotNull(outcome); + assertEquals(CODE, outcome.getCode()); + assertEquals(DISPLAY, outcome.getDisplay()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); + + assertEquals(CODE, ourCodeSystemProvider.myLastCode.getValue()); + assertEquals(DISPLAY, ourCodeSystemProvider.myLastDisplay.getValue()); + assertEquals(CODE_SYSTEM, ourCodeSystemProvider.myLastUrl.getValueAsString()); + assertEquals(SAMPLE_MESSAGE, getParameterValue(ourCodeSystemProvider.myNextReturnParams, "message").toString()); + } + + @Test + public void testValidateCodeInCodeSystem_AssumeFailure_ReturnsFailureCodeAndFailureMessage() { + createNextCodeSystemReturnParameters(false, null, SAMPLE_MESSAGE); + + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, CODE, null, null); + assertNotNull(outcome); + assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity()); + assertEquals(SAMPLE_MESSAGE, outcome.getMessage()); + + assertFalse(((BooleanType) getParameterValue(ourCodeSystemProvider.myNextReturnParams, "result")).booleanValue()); + } + + @Test + public void testValidateCodeInValueSet_ProvidingMinimalInputs_ReturnsSuccess() { + ourValueSetProvider.myNextReturnParams = new Parameters(); + ourValueSetProvider.myNextReturnParams.addParameter().setName("result").setValue(new BooleanType(true)); + + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, CODE, null, VALUE_SET_URL); + assertNotNull(outcome); + assertEquals(CODE, outcome.getCode()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); + + assertEquals(CODE, ourValueSetProvider.myLastCode.getValue()); + assertEquals(VALUE_SET_URL, ourValueSetProvider.myLastUrl.getValueAsString()); + } + + @Test + public void testValidateCodeInValueSet_WithMessageValue_ReturnsMessage() { + ourValueSetProvider.myNextReturnParams = new Parameters(); + ourValueSetProvider.myNextReturnParams.addParameter().setName("result").setValue(new BooleanType(true)); + ourValueSetProvider.myNextReturnParams.addParameter().setName("display").setValue(new StringType(DISPLAY)); + ourValueSetProvider.myNextReturnParams.addParameter().setName("message").setValue(new StringType(SAMPLE_MESSAGE)); + + IValidationSupport.CodeValidationResult outcome = mySvc + .validateCode(null, null, CODE_SYSTEM, CODE, DISPLAY, VALUE_SET_URL); + assertNotNull(outcome); + assertEquals(CODE, outcome.getCode()); + assertEquals(DISPLAY, outcome.getDisplay()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); + + assertEquals(CODE, ourValueSetProvider.myLastCode.getValue()); + assertEquals(DISPLAY, ourValueSetProvider.myLastDisplay.getValue()); + assertEquals(VALUE_SET_URL, ourValueSetProvider.myLastUrl.getValueAsString()); + assertEquals(SAMPLE_MESSAGE, getParameterValue(ourValueSetProvider.myNextReturnParams, "message").toString()); + } + + @Test + public void lookupCode_withParametersOutput_convertsCorrectly() { + String paramsAsString = ClasspathUtil.loadResource("/r4/CodeSystem-lookup-output-with-subproperties.json"); + IBaseResource baseResource = ourCtx.newJsonParser().parseResource(paramsAsString); + assertTrue(baseResource instanceof Parameters); + Parameters resultParameters = (Parameters) baseResource; + ourCodeSystemProvider.myNextReturnParams = resultParameters; + + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, null, List.of("interfaces")); + + // test + IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, request); + assertNotNull(outcome); + + IBaseParameters theActualParameters = outcome.toParameters(ourCtx, request.getPropertyNames().stream().map(StringType::new).toList()); + String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theActualParameters); + String expected = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resultParameters); + + assertEquals(expected, actual); + } + + private void createNextCodeSystemReturnParameters(boolean theResult, String theDisplay, String theMessage) { + ourCodeSystemProvider.myNextReturnParams = new Parameters(); + ourCodeSystemProvider.myNextReturnParams.addParameter().setName("result").setValue(new BooleanType(theResult)); + ourCodeSystemProvider.myNextReturnParams.addParameter().setName("display").setValue(new StringType(theDisplay)); + if (theMessage != null) { + ourCodeSystemProvider.myNextReturnParams.addParameter().setName("message").setValue(new StringType(theMessage)); + } + } + + private Type getParameterValue(Parameters theParameters, String theParameterName) { + Optional paramOpt = theParameters.getParameter() + .stream().filter(param -> param.getName().equals(theParameterName)).findFirst(); + assertTrue(paramOpt.isPresent()); + return paramOpt.get().getValue(); + } + + private static class MyCodeSystemProvider implements IResourceProvider { + private UriType myLastUrl; + private CodeType myLastCode; + private StringType myLastDisplay; + private Parameters myNextReturnParams; + + @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 + ) { + myLastUrl = theCodeSystemUrl; + myLastCode = theCode; + myLastDisplay = theDisplay; + return myNextReturnParams; + + } + + @Operation(name = JpaConstants.OPERATION_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 + ) { + myLastCode = theCode; + return myNextReturnParams; + } + + @Override + public Class getResourceType() { + return CodeSystem.class; + } + } + + + private static class MyValueSetProvider implements IResourceProvider { + private Parameters myNextReturnParams; + private UriType myLastUrl; + private CodeType myLastCode; + private StringType myLastDisplay; + + @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 + ) { + myLastUrl = theValueSetUrl; + myLastCode = theCode; + myLastDisplay = theDisplay; + return myNextReturnParams; + } + + @Override + public Class getResourceType() { + return ValueSet.class; + } + + } +} diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java deleted file mode 100644 index f01e66c16c2..00000000000 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/LookupCodeR4Test.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.hl7.fhir.r4.validation; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.support.IValidationSupport; -import ca.uhn.fhir.jpa.model.util.JpaConstants; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; -import jakarta.servlet.http.HttpServletRequest; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.ILookupCodeSupportedPropertyTest; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMyCodeSystemProvider; -import org.hl7.fhir.common.hapi.validation.ILookupCodeTest.IMySimpleCodeSystemProvider; -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; -import org.hl7.fhir.instance.model.api.IBaseResource; -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.DateTimeType; -import org.hl7.fhir.r4.model.DecimalType; -import org.hl7.fhir.r4.model.InstantType; -import org.hl7.fhir.r4.model.IntegerType; -import org.hl7.fhir.r4.model.Parameters; -import org.hl7.fhir.r4.model.StringType; -import org.hl7.fhir.r4.model.Type; -import org.hl7.fhir.r4.model.UriType; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.extension.RegisterExtension; -import org.junit.jupiter.params.provider.Arguments; - -import java.util.Calendar; -import java.util.List; -import java.util.stream.Stream; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - -public class LookupCodeR4Test { - private static final FhirContext ourCtx = FhirContext.forR4Cached(); - @RegisterExtension - public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); - private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); - - @BeforeEach - public void before() { - String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); - mySvc.setBaseUrl(baseUrl); - mySvc.addClientInterceptor(new LoggingInterceptor(true)); - } - - @TestInstance(TestInstance.Lifecycle.PER_CLASS) - @Nested - class ILookupCodeSupportedPropertyR4Test implements ILookupCodeSupportedPropertyTest { - private final MyCodeSystemProviderR4 myCodeSystemProvider = new MyCodeSystemProviderR4(); - - @Override - public IMyCodeSystemProvider getCodeSystemProvider() { - return myCodeSystemProvider; - } - - @Override - public RemoteTerminologyServiceValidationSupport getService() { - return mySvc; - } - - @BeforeEach - public void before() { - ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); - } - - @Override - public void verifyProperty(IValidationSupport.BaseConceptProperty theConceptProperty, String theExpectedPropertName, IBaseDatatype theExpectedValue) { - assertEquals(theExpectedPropertName, theConceptProperty.getPropertyName()); - String type = theConceptProperty.getType(); - switch (type) { - case IValidationSupport.TYPE_STRING -> { - if (!(theExpectedValue instanceof StringType stringValue)) { - // TODO: remove this branch to test other property types as per FHIR spec https://github.com/hapifhir/hapi-fhir/issues/5699 - IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; - assertEquals(theExpectedValue.toString(), stringConceptProperty.getValue()); - break; - } - // StringType stringValue = (StringType) theExpectedValue; - assertTrue(theConceptProperty instanceof IValidationSupport.StringConceptProperty); - IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; - assertEquals(stringValue.getValue(), stringConceptProperty.getValue()); - } - case IValidationSupport.TYPE_CODING -> { - assertTrue(theExpectedValue instanceof Coding); - Coding coding = (Coding) theExpectedValue; - assertTrue(theConceptProperty instanceof IValidationSupport.CodingConceptProperty); - IValidationSupport.CodingConceptProperty codingConceptProperty = (IValidationSupport.CodingConceptProperty) theConceptProperty; - assertEquals(coding.getCode(), codingConceptProperty.getCode()); - assertEquals(coding.getSystem(), codingConceptProperty.getCodeSystem()); - assertEquals(coding.getDisplay(), codingConceptProperty.getDisplay()); - } - default -> { - IValidationSupport.StringConceptProperty stringConceptProperty = (IValidationSupport.StringConceptProperty) theConceptProperty; - assertEquals(theExpectedValue.toString(), stringConceptProperty.getValue()); - } - } - } - - public Stream getEmptyPropertyValues() { - return Stream.of( - Arguments.arguments(new StringType()), - Arguments.arguments(new StringType("")), - Arguments.arguments(new Coding()), - Arguments.arguments(new Coding("", null, null)), - Arguments.arguments(new Coding("", "", null)), - Arguments.arguments(new Coding(null, "", null)) - ); - } - - public Stream getPropertyValues() { - return Stream.of( - // FHIR R4 spec types - Arguments.arguments(new StringType("value")), - Arguments.arguments(new Coding("code", "system", "display")), - Arguments.arguments(new CodeType("code")), - Arguments.arguments(new BooleanType(true)), - Arguments.arguments(new IntegerType(1)), - Arguments.arguments(new DateTimeType(Calendar.getInstance())), - Arguments.arguments(new DecimalType(1.1)), - // other types will also not fail for Remote Terminology - Arguments.arguments(new InstantType(Calendar.getInstance())), - Arguments.arguments(new Type() { - @Override - protected Type typedCopy() { - return this; - } - @Override - public String toString() { - return "randomType"; - } - }) - ); - } - - public Stream getDesignations() { - return Stream.of( - Arguments.arguments(new IValidationSupport.ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), - Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), - Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), - Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2").setUseSystem("system1")), - Arguments.arguments(new IValidationSupport.ConceptDesignation().setUseCode("code2")) - ); - } - } - - static class MySimplePropertyCodeSystemProviderR4 implements IMySimpleCodeSystemProvider { - String myPropertyName; - Type myPropertyValue; - - @Override - public IBaseDatatype getPropertyValue() { - return myPropertyValue; - } - - @Override - public Class getResourceType() { - return CodeSystem.class; - } - - @Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= { - @OperationParam(name = "name", type = StringType.class, min = 1), - @OperationParam(name = "version", type = StringType.class, min = 0), - @OperationParam(name = "display", type = StringType.class, min = 1), - @OperationParam(name = "abstract", type = BooleanType.class, min = 1), - @OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) - }) - public Parameters 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 - ) { - Parameters.ParametersParameterComponent component = new Parameters.ParametersParameterComponent(); - component.setName("property"); - component.addPart(new Parameters.ParametersParameterComponent().setName("code").setValue(new CodeType(myPropertyName))); - component.addPart(new Parameters.ParametersParameterComponent().setName("value").setValue(myPropertyValue)); - return new Parameters().addParameter(component); - } - } - - static class MyCodeSystemProviderR4 implements IMyCodeSystemProvider { - private UriType mySystemUrl; - private CodeType myCode; - private IValidationSupport.LookupCodeResult myLookupCodeResult; - - @Override - public void setLookupCodeResult(IValidationSupport.LookupCodeResult theLookupCodeResult) { - myLookupCodeResult = theLookupCodeResult; - } - - @Operation(name = JpaConstants.OPERATION_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 - ) { - myCode = theCode; - mySystemUrl = theSystem; - return myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); - } - @Override - public Class 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/RemoteTerminologyLookupCodeR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java new file mode 100644 index 00000000000..ec6c018bb5f --- /dev/null +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyLookupCodeR4Test.java @@ -0,0 +1,201 @@ +package org.hl7.fhir.r4.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.jpa.model.util.JpaConstants; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import jakarta.servlet.http.HttpServletRequest; +import org.hl7.fhir.common.hapi.validation.ILookupCodeTest; +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; +import org.hl7.fhir.instance.model.api.IBaseResource; +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.DateTimeType; +import org.hl7.fhir.r4.model.DecimalType; +import org.hl7.fhir.r4.model.InstantType; +import org.hl7.fhir.r4.model.IntegerType; +import org.hl7.fhir.r4.model.StringType; +import org.hl7.fhir.r4.model.Type; +import org.hl7.fhir.r4.model.UriType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.extension.RegisterExtension; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Calendar; +import java.util.List; +import java.util.stream.Stream; + +import static ca.uhn.fhir.context.support.IValidationSupport.ConceptDesignation; +import static ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; + +/** + * Version specific tests for CodeSystem $lookup against RemoteTerminologyValidationSupport. + * @see RemoteTerminologyServiceValidationSupport + */ +public class RemoteTerminologyLookupCodeR4Test implements ILookupCodeTest { + private static final FhirContext ourCtx = FhirContext.forR4Cached(); + @RegisterExtension + public static RestfulServerExtension ourRestfulServerExtension = new RestfulServerExtension(ourCtx); + private final RemoteTerminologyServiceValidationSupport mySvc = new RemoteTerminologyServiceValidationSupport(ourCtx); + private final MyCodeSystemProviderR4 myCodeSystemProvider = new MyCodeSystemProviderR4(); + + @BeforeEach + public void before() { + String baseUrl = "http://localhost:" + ourRestfulServerExtension.getPort(); + mySvc.setBaseUrl(baseUrl); + mySvc.addClientInterceptor(new LoggingInterceptor(true)); + ourRestfulServerExtension.getRestfulServer().registerProvider(myCodeSystemProvider); + } + + @Override + public IMyCodeSystemProvider getCodeSystemProvider() { + return myCodeSystemProvider; + } + + @Override + public RemoteTerminologyServiceValidationSupport getService() { + return mySvc; + } + + public static Stream getEmptyPropertyValues() { + return Stream.of( + Arguments.of(new StringType()), + Arguments.of(new StringType("")), + Arguments.of(new Coding()), + Arguments.of(new Coding("", null, null)), + Arguments.of(new Coding("", "", null)), + Arguments.of(new Coding(null, "", null)) + ); + } + + @ParameterizedTest + @MethodSource(value = "getEmptyPropertyValues") + public void lookupCode_forCodeSystemWithPropertyEmptyValue_returnsCorrectParameters(IBaseDatatype thePropertyValue) { + verifyLookupWithEmptyPropertyValue(thePropertyValue); + } + + + public static Stream getPropertyValueArguments() { + return Stream.of( + // FHIR R4 spec types + Arguments.of(new StringType("test-value")), + Arguments.of(new Coding("test-system", "test-code", "test-display")), + Arguments.of(new CodeType("test-code")), + Arguments.of(new BooleanType(true)), + Arguments.of(new IntegerType(1)), + Arguments.of(new DateTimeType(Calendar.getInstance())), + Arguments.of(new DecimalType(1.1)), + // other types will also not fail for Remote Terminology + Arguments.of(new InstantType(Calendar.getInstance())), + Arguments.of(new Type() { + @Override + protected Type typedCopy() { + return this; + } + @Override + public String toString() { + return "randomType"; + } + }) + ); + } + + public static Stream getPropertyValueListArguments() { + return Stream.of( + Arguments.of(List.of(new StringType("value1")), new StringType("value2")), + Arguments.of(List.of(new StringType("value1")), new Coding("code", "system", "display")) + ); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueArguments") + public void lookupCode_forCodeSystemWithProperty_returnsCorrectProperty(IBaseDatatype thePropertyValue) { + verifyLookupWithProperty(List.of(thePropertyValue), List.of()); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueListArguments") + public void lookupCode_forCodeSystemWithPropertyFilter_returnsCorrectProperty(List thePropertyValues) { + verifyLookupWithProperty(thePropertyValues, List.of()); + verifyLookupWithProperty(thePropertyValues, List.of(thePropertyValues.size() - 1)); + } + + @ParameterizedTest + @MethodSource(value = "getPropertyValueListArguments") + public void lookupCode_forCodeSystemWithPropertyGroup_returnsCorrectProperty(List thePropertyValues) { + verifyLookupWithSubProperties(thePropertyValues); + } + + public static Stream getDesignations() { + return Stream.of( + Arguments.of(new ConceptDesignation().setLanguage("en").setUseCode("code1").setUseSystem("system-1").setUseDisplay("display").setValue("some value")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setUseDisplay("display").setValue("someValue")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1").setValue("someValue")), + Arguments.of(new ConceptDesignation().setUseCode("code2").setUseSystem("system1")), + Arguments.of(new ConceptDesignation().setUseCode("code2")) + ); + } + + @ParameterizedTest + @MethodSource(value = "getDesignations") + void lookupCode_withCodeSystemWithDesignation_returnsCorrectDesignation(final IValidationSupport.ConceptDesignation theConceptDesignation) { + verifyLookupWithConceptDesignation(theConceptDesignation); + } + + static class MyCodeSystemProviderR4 implements IMyCodeSystemProvider { + private UriType mySystemUrl; + private CodeType myCode; + private LookupCodeResult myLookupCodeResult; + + @Override + public void setLookupCodeResult(LookupCodeResult theLookupCodeResult) { + myLookupCodeResult = theLookupCodeResult; + } + + @Operation(name = JpaConstants.OPERATION_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 + ) { + myCode = theCode; + mySystemUrl = theSystem; + return myLookupCodeResult.toParameters(theRequestDetails.getFhirContext(), thePropertyNames); + } + @Override + public Class 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-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceResourceProviderR4Test.java similarity index 73% rename from hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java rename to hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceResourceProviderR4Test.java index 823438e450e..488a404850e 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/RemoteTerminologyServiceResourceProviderR4Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceResourceProviderR4Test.java @@ -1,20 +1,26 @@ -package ca.uhn.fhir.jpa.provider.r4; +package org.hl7.fhir.r4.validation; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.support.IValidationSupport; +import ca.uhn.fhir.context.support.LookupCodeRequest; +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 ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.test.utilities.server.RestfulServerExtension; +import ca.uhn.fhir.util.ClasspathUtil; import jakarta.servlet.http.HttpServletRequest; 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.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; @@ -25,15 +31,23 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.RegisterExtension; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; -/* - * This set of Unit Tests simulates the call to a remote server and therefore, only tests the code in the - * {@link org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport#invokeRemoteValidateCode} - * method, before and after it makes that remote client call. +/** + * Version specific tests for validation using RemoteTerminologyValidationSupport. + * The tests in this class simulate the call to a remote server and therefore, only tests the code in + * the RemoteTerminologyServiceValidationSupport itself. The remote client call is simulated using the test providers. + * @see RemoteTerminologyServiceValidationSupport + * + * Other operations are tested separately. + * @see RemoteTerminologyLookupCodeR4Test + * @see RemoteTerminologyServiceValidationSupportR4Test */ public class RemoteTerminologyServiceResourceProviderR4Test { private static final String DISPLAY = "DISPLAY"; @@ -79,8 +93,8 @@ public class RemoteTerminologyServiceResourceProviderR4Test { .validateCode(null, null, CODE_SYSTEM, CODE, null, null); assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); - assertNull(outcome.getSeverity()); - assertNull(outcome.getMessage()); + assertNull(outcome.getSeverity()); + assertNull(outcome.getMessage()); assertEquals(CODE, ourCodeSystemProvider.myLastCode.getCode()); assertEquals(CODE_SYSTEM, ourCodeSystemProvider.myLastUrl.getValueAsString()); @@ -114,7 +128,7 @@ public class RemoteTerminologyServiceResourceProviderR4Test { assertEquals(IValidationSupport.IssueSeverity.ERROR, outcome.getSeverity()); assertEquals(SAMPLE_MESSAGE, outcome.getMessage()); - assertFalse(((BooleanType) ourCodeSystemProvider.myNextReturnParams.getParameterValue("result")).booleanValue()); + assertFalse(((BooleanType) ourCodeSystemProvider.myNextReturnParams.getParameterValue("result")).booleanValue()); } @Test @@ -143,7 +157,7 @@ public class RemoteTerminologyServiceResourceProviderR4Test { assertNotNull(outcome); assertEquals(CODE, outcome.getCode()); assertEquals(DISPLAY, outcome.getDisplay()); - assertNull(outcome.getSeverity()); + assertNull(outcome.getSeverity()); assertNull(outcome.getMessage()); assertEquals(CODE, ourValueSetProvider.myLastCode.getCode()); @@ -152,6 +166,27 @@ public class RemoteTerminologyServiceResourceProviderR4Test { assertEquals(SAMPLE_MESSAGE, ourValueSetProvider.myNextReturnParams.getParameterValue("message").toString()); } + @Test + public void lookupCode_withParametersOutput_convertsCorrectly() { + String paramsAsString = ClasspathUtil.loadResource("/r4/CodeSystem-lookup-output-with-subproperties.json"); + IBaseResource baseResource = ourCtx.newJsonParser().parseResource(paramsAsString); + assertTrue(baseResource instanceof Parameters); + Parameters resultParameters = (Parameters) baseResource; + ourCodeSystemProvider.myNextReturnParams = resultParameters; + + LookupCodeRequest request = new LookupCodeRequest(CODE_SYSTEM, CODE, null, List.of("interfaces")); + + // test + IValidationSupport.LookupCodeResult outcome = mySvc.lookupCode(null, request); + assertNotNull(outcome); + + IBaseParameters theActualParameters = outcome.toParameters(ourCtx, request.getPropertyNames().stream().map(StringType::new).toList()); + String actual = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(theActualParameters); + String expected = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resultParameters); + + assertEquals(expected, actual); + } + private void createNextCodeSystemReturnParameters(boolean theResult, String theDisplay, String theMessage) { ourCodeSystemProvider.myNextReturnParams = new Parameters(); ourCodeSystemProvider.myNextReturnParams.addParameter("result", theResult); @@ -186,6 +221,27 @@ public class RemoteTerminologyServiceResourceProviderR4Test { } + @Operation(name = JpaConstants.OPERATION_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 + ) { + myLastCode = theCode; + return myNextReturnParams; + } + @Override public Class getResourceType() { return CodeSystem.class; diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java index eaa13bd30ac..708773d61bb 100644 --- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java +++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/RemoteTerminologyServiceValidationSupportR4Test.java @@ -59,6 +59,16 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; +/** + * Version specific tests for validation using RemoteTerminologyValidationSupport. + * The tests in this class simulate the call to a remote server and therefore, only tests the code in + * the RemoteTerminologyServiceValidationSupport itself. The remote client call is simulated using the test providers. + * @see RemoteTerminologyServiceValidationSupport + * + * Other operations are tested separately. + * @see RemoteTerminologyLookupCodeR4Test + * @see RemoteTerminologyServiceResourceProviderR4Test + */ public class RemoteTerminologyServiceValidationSupportR4Test extends BaseValidationTestWithInlineMocks { private static final String DISPLAY = "DISPLAY"; private static final String CODE_SYSTEM = "CODE_SYS"; diff --git a/hapi-fhir-validation/src/test/resources/r4/CodeSystem-lookup-output-with-subproperties.json b/hapi-fhir-validation/src/test/resources/r4/CodeSystem-lookup-output-with-subproperties.json new file mode 100644 index 00000000000..af666e9103f --- /dev/null +++ b/hapi-fhir-validation/src/test/resources/r4/CodeSystem-lookup-output-with-subproperties.json @@ -0,0 +1,113 @@ +{ + "resourceType": "Parameters", + "parameter": [ + { + "name": "name", + "valueString": "Client_Config_CodeSystem" + }, + { + "name": "display", + "valueString": "Value to display" + }, + { + "name": "abstract", + "valueBoolean": false + }, + { + "name": "property", + "part": [ + { + "name": "code", + "valueCode": "interfaces" + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "dataType" + }, + { + "name": "value", + "valueString": "drugs" + } + ] + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "apiVersion" + }, + { + "name": "value", + "valueString": "4.5.0" + } + ] + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "onboardStatus" + }, + { + "name": "value", + "valueString": "unauthorized" + } + ] + } + ] + }, + { + "name": "property", + "part": [ + { + "name": "code", + "valueCode": "interfaces" + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "dataType" + }, + { + "name": "value", + "valueString": "ps" + } + ] + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "apiVersion" + }, + { + "name": "value", + "valueString": "4.0.0" + } + ] + }, + { + "name": "subproperty", + "part": [ + { + "name": "code", + "valueCode": "onboardStatus" + }, + { + "name": "value", + "valueString": "contributor-testing" + } + ] + } + ] + } + ] +} \ No newline at end of file From 97cfb6de37719c94c24255aaaeb091a521486ff3 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Mon, 20 May 2024 17:00:18 -0400 Subject: [PATCH 15/15] Add utility method to convert Bundle into transaction (#5945) * Add utility method to convert Bundle into transaction * Add utility method * Spotless * Build fix --- .../java/ca/uhn/fhir/util/BundleUtil.java | 68 ++++++++++++++++++ ...-utility-transaction-converter-method.yaml | 6 ++ .../ips/generator/IpsGenerationR4Test.java | 46 ++++++------ .../large-patient-everything-4.json.gz | Bin 0 -> 5797 bytes .../uhn/fhir/util/bundle/BundleUtilTest.java | 50 +++++++++++++ 5 files changed, 150 insertions(+), 20 deletions(-) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml create mode 100644 hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java index 770aa1498c9..f0872b62287 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/BundleUtil.java @@ -39,6 +39,7 @@ import ca.uhn.fhir.util.bundle.SearchBundleEntryParts; import com.google.common.collect.Sets; import jakarta.annotation.Nonnull; import jakarta.annotation.Nullable; +import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.tuple.Pair; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseBinary; @@ -59,6 +60,7 @@ import java.util.Set; import java.util.function.Consumer; import java.util.stream.Collectors; +import static org.apache.commons.lang3.StringUtils.defaultString; import static org.apache.commons.lang3.StringUtils.isBlank; import static org.apache.commons.lang3.StringUtils.isNotBlank; import static org.hl7.fhir.instance.model.api.IBaseBundle.LINK_PREV; @@ -67,6 +69,12 @@ import static org.hl7.fhir.instance.model.api.IBaseBundle.LINK_PREV; * Fetch resources from a bundle */ public class BundleUtil { + + /** Non instantiable */ + private BundleUtil() { + // nothing + } + private static final Logger ourLog = LoggerFactory.getLogger(BundleUtil.class); private static final String PREVIOUS = LINK_PREV; @@ -339,6 +347,66 @@ public class BundleUtil { TerserUtil.setField(theContext, "entry", theBundle, retVal.toArray(new IBase[0])); } + /** + * Converts a Bundle containing resources into a FHIR transaction which + * creates/updates the resources. This method does not modify the original + * bundle, but returns a new copy. + *

    + * This method is mostly intended for test scenarios where you have a Bundle + * containing search results or other sourced resources, and want to upload + * these resources to a server using a single FHIR transaction. + *

    + *

    + * The Bundle is converted using the following logic: + *

      + *
    • Bundle.type is changed to transaction
    • + *
    • Bundle.request.method is changed to PUT
    • + *
    • Bundle.request.url is changed to [resourceType]/[id]
    • + *
    • Bundle.fullUrl is changed to [resourceType]/[id]
    • + *
    + *

    + * + * @param theContext The FhirContext to use with the bundle + * @param theBundle The Bundle to modify. All resources in the Bundle should have an ID. + * @param thePrefixIdsOrNull If not null, all resource IDs and all references in the Bundle will be + * modified to such that their IDs contain the given prefix. For example, for a value + * of "A", the resource "Patient/123" will be changed to be "Patient/A123". If set to + * null, resource IDs are unchanged. + * @since 7.4.0 + */ + public static T convertBundleIntoTransaction( + @Nonnull FhirContext theContext, @Nonnull T theBundle, @Nullable String thePrefixIdsOrNull) { + String prefix = defaultString(thePrefixIdsOrNull); + + BundleBuilder bb = new BundleBuilder(theContext); + + FhirTerser terser = theContext.newTerser(); + List entries = terser.getValues(theBundle, "Bundle.entry"); + for (var entry : entries) { + IBaseResource resource = terser.getSingleValueOrNull(entry, "resource", IBaseResource.class); + if (resource != null) { + Validate.isTrue(resource.getIdElement().hasIdPart(), "Resource in bundle has no ID"); + String newId = theContext.getResourceType(resource) + "/" + prefix + + resource.getIdElement().getIdPart(); + + IBaseResource resourceClone = terser.clone(resource); + resourceClone.setId(newId); + + if (isNotBlank(prefix)) { + for (var ref : terser.getAllResourceReferences(resourceClone)) { + var refElement = ref.getResourceReference().getReferenceElement(); + ref.getResourceReference() + .setReference(refElement.getResourceType() + "/" + prefix + refElement.getIdPart()); + } + } + + bb.addTransactionUpdateEntry(resourceClone); + } + } + + return bb.getBundleTyped(); + } + private static void validatePartsNotNull(LinkedHashSet theDeleteParts) { if (theDeleteParts == null) { throw new IllegalStateException( diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml new file mode 100644 index 00000000000..a397012f304 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_4_0/5945-add-bundleutil-utility-transaction-converter-method.yaml @@ -0,0 +1,6 @@ +--- +type: add +issue: 5945 +title: "A new utility method has been added to `BundleUtil` which converts a FHIR Bundle + containing resources (e.g. a search result bundle) into a FHIR transaction bundle which + could be used to upload those resources to a server." diff --git a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java index e697ef20b2a..34cf71c0435 100644 --- a/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java +++ b/hapi-fhir-jpaserver-ips/src/test/java/ca/uhn/fhir/jpa/ips/generator/IpsGenerationR4Test.java @@ -47,6 +47,7 @@ import java.util.List; import java.util.Optional; import java.util.stream.Collectors; +import static ca.uhn.fhir.util.BundleUtil.convertBundleIntoTransaction; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; import static org.hamcrest.Matchers.stringContainsInOrder; @@ -81,11 +82,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { @Test public void testGenerateLargePatientSummary() throws IOException { Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything.json.gz"); - sourceData.setType(Bundle.BundleType.TRANSACTION); - for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) { - nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT); - nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); - } + sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null); Bundle outcome = mySystemDao.transaction(mySrd, sourceData); ourLog.info("Created {} resources", outcome.getEntry().size()); @@ -119,11 +116,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY); Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-2.json.gz"); - sourceData.setType(Bundle.BundleType.TRANSACTION); - for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) { - nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT); - nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); - } + sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null); Bundle outcome = mySystemDao.transaction(mySrd, sourceData); ourLog.info("Created {} resources", outcome.getEntry().size()); @@ -145,11 +138,7 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY); Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-3.json.gz"); - sourceData.setType(Bundle.BundleType.TRANSACTION); - for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) { - nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT); - nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); - } + sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null); Bundle outcome = mySystemDao.transaction(mySrd, sourceData); ourLog.info("Created {} resources", outcome.getEntry().size()); @@ -166,16 +155,33 @@ public class IpsGenerationR4Test extends BaseResourceProviderR4Test { assertEquals(80, output.getEntry().size()); } + @Test + public void testGenerateLargePatientSummary4() { + Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/large-patient-everything-4.json.gz"); + sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, "EPD"); + + Bundle outcome = mySystemDao.transaction(mySrd, sourceData); + ourLog.info("Created {} resources", outcome.getEntry().size()); + + Bundle output = myClient + .operation() + .onInstance("Patient/EPD2223") + .named(JpaConstants.OPERATION_SUMMARY) + .withNoParameters(Parameters.class) + .returnResourceType(Bundle.class) + .execute(); + ourLog.info("Output: {}", myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(output)); + + // Verify + assertEquals(55, output.getEntry().size()); + } + @Test public void testGenerateTinyPatientSummary() throws IOException { myStorageSettings.setResourceClientIdStrategy(JpaStorageSettings.ClientIdStrategyEnum.ANY); Bundle sourceData = ClasspathUtil.loadCompressedResource(myFhirContext, Bundle.class, "/tiny-patient-everything.json.gz"); - sourceData.setType(Bundle.BundleType.TRANSACTION); - for (Bundle.BundleEntryComponent nextEntry : sourceData.getEntry()) { - nextEntry.getRequest().setMethod(Bundle.HTTPVerb.PUT); - nextEntry.getRequest().setUrl(nextEntry.getResource().getIdElement().toUnqualifiedVersionless().getValue()); - } + sourceData = convertBundleIntoTransaction(myFhirContext, sourceData, null); Bundle outcome = mySystemDao.transaction(mySrd, sourceData); ourLog.info("Created {} resources", outcome.getEntry().size()); diff --git a/hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz b/hapi-fhir-jpaserver-ips/src/test/resources/large-patient-everything-4.json.gz new file mode 100644 index 0000000000000000000000000000000000000000..cc2fd1e4eaa59c19648a483421c40745d0901f7d GIT binary patch literal 5797 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 literal 0 HcmV?d00001 diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java index ccbb3c60080..85d6c4b4a96 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/util/bundle/BundleUtilTest.java @@ -680,6 +680,56 @@ public class BundleUtilTest { assertNull(BundleUtil.getBundleTypeEnum(ourCtx, bundle)); } + @Test + public void testConvertBundleIntoTransaction() { + Bundle input = createBundleWithPatientAndObservation(); + + Bundle output = BundleUtil.convertBundleIntoTransaction(ourCtx, input, null); + assertEquals(Bundle.BundleType.TRANSACTION, output.getType()); + assertEquals("Patient/123", output.getEntry().get(0).getFullUrl()); + assertEquals("Patient/123", output.getEntry().get(0).getRequest().getUrl()); + assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(0).getRequest().getMethod()); + assertTrue(((Patient) output.getEntry().get(0).getResource()).getActive()); + assertEquals("Observation/456", output.getEntry().get(1).getFullUrl()); + assertEquals("Observation/456", output.getEntry().get(1).getRequest().getUrl()); + assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(1).getRequest().getMethod()); + assertEquals("Patient/123", ((Observation)output.getEntry().get(1).getResource()).getSubject().getReference()); + assertEquals(Observation.ObservationStatus.AMENDED, ((Observation)output.getEntry().get(1).getResource()).getStatus()); + } + + @Test + public void testConvertBundleIntoTransaction_WithPrefix() { + Bundle input = createBundleWithPatientAndObservation(); + + Bundle output = BundleUtil.convertBundleIntoTransaction(ourCtx, input, "A"); + assertEquals(Bundle.BundleType.TRANSACTION, output.getType()); + assertEquals("Patient/A123", output.getEntry().get(0).getFullUrl()); + assertEquals("Patient/A123", output.getEntry().get(0).getRequest().getUrl()); + assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(0).getRequest().getMethod()); + assertTrue(((Patient) output.getEntry().get(0).getResource()).getActive()); + assertEquals("Observation/A456", output.getEntry().get(1).getFullUrl()); + assertEquals("Observation/A456", output.getEntry().get(1).getRequest().getUrl()); + assertEquals(Bundle.HTTPVerb.PUT, output.getEntry().get(1).getRequest().getMethod()); + assertEquals("Patient/A123", ((Observation)output.getEntry().get(1).getResource()).getSubject().getReference()); + assertEquals(Observation.ObservationStatus.AMENDED, ((Observation)output.getEntry().get(1).getResource()).getStatus()); + } + + private static @Nonnull Bundle createBundleWithPatientAndObservation() { + Bundle input = new Bundle(); + input.setType(Bundle.BundleType.COLLECTION); + Patient patient = new Patient(); + patient.setActive(true); + patient.setId("123"); + input.addEntry().setResource(patient); + Observation observation = new Observation(); + observation.setId("456"); + observation.setStatus(Observation.ObservationStatus.AMENDED); + observation.setSubject(new Reference("Patient/123")); + input.addEntry().setResource(observation); + return input; + } + + @Nonnull private static Bundle withBundle(Resource theResource) { final Bundle bundle = new Bundle();

    lN1)dnEVuUteJqm_GNPMWl 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 z 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