diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 8fb97f3a25b..47494c203c2 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml @@ -129,8 +129,11 @@ check - true true + true + ${maven.multiModuleProjectDirectory}/src/checkstyle/checkstyle_suppressions.xml + true + true true ${maven.multiModuleProjectDirectory}/src/checkstyle/checkstyle.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 2e056223602..4a78ea60bf1 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index a54df006844..cce36d7979e 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java index b66f1b4438d..c157847e894 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/rest/api/Constants.java @@ -145,6 +145,9 @@ public class Constants { public static final String HEADER_SUFFIX_CT_UTF_8 = "; charset=UTF-8"; public static final String HEADERVALUE_CORS_ALLOW_METHODS_ALL = "GET, POST, PUT, DELETE, OPTIONS"; public static final String HEADER_REWRITE_HISTORY = "X-Rewrite-History"; + public static final String HEADER_RETRY_ON_VERSION_CONFLICT = "X-Retry-On-Version-Conflict"; + public static final String HEADER_MAX_RETRIES = "max-retries"; + public static final String HEADER_RETRY = "retry"; public static final Map HTTP_STATUS_NAMES; public static final String LINK_FHIR_BASE = "fhir-base"; public static final String LINK_FIRST = "first"; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/system/HapiSystemProperties.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/system/HapiSystemProperties.java index 6f50600d54d..8817045a20a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/system/HapiSystemProperties.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/system/HapiSystemProperties.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.system; +/*- + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 - 2022 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import org.apache.commons.lang3.time.DateUtils; public final class HapiSystemProperties { diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java index 9bf12999bf2..90afa7d8603 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java @@ -106,6 +106,7 @@ public enum VersionEnum { V6_1_3, V6_1_4, V6_2_0, + V6_2_1, V6_3_0 ; diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index 78cab5db542..26dece1bad3 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -3,14 +3,14 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT pom HAPI FHIR BOM ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index d5c61832f60..102c8d05f98 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 bd262c3d80e..4438b06e2a5 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ValidationSupportChainCreator.java b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ValidationSupportChainCreator.java index cd49f9db28f..52dd02172e1 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ValidationSupportChainCreator.java +++ b/hapi-fhir-cli/hapi-fhir-cli-api/src/main/java/ca/uhn/fhir/cli/ValidationSupportChainCreator.java @@ -48,7 +48,7 @@ public class ValidationSupportChainCreator { chain.addValidationSupport(localFileValidationSupport); chain.addValidationSupport(new SnapshotGeneratingValidationSupport(ctx)); } catch (IOException e) { - throw new RuntimeException(Msg.code(2141) + "Failed to load local profile.", e); + throw new RuntimeException(Msg.code(2207) + "Failed to load local profile.", e); } } if (commandLine.hasOption("r")) { diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index 3bb5ed16fa6..c06f3c80624 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml index 2faba268a5e..ce2ded17b1c 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../../hapi-deployable-pom diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index 68cc1f434ca..70082a0bfb5 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index 3b4ff982dc9..acacb532a70 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 53d739dfb25..e782b4908bf 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index bd6b3a626cc..578544de925 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index bc11c967b57..72205e3c27d 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index c9c200d12f8..6f79396cb4e 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4240-document-reference-with-long-attachment-url.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4240-document-reference-with-long-attachment-url.yaml new file mode 100644 index 00000000000..84fa052936d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4240-document-reference-with-long-attachment-url.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4240 +jira: SMILE-4892 +title: "Previously, when creating a `DocumentReference` with an `Attachment` containing a URL over 254 characters +an error was thrown. This has been corrected and now an `Attachment` URL can be up to 500 characters." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4250-overlapping-searchparameter-with-the-same-code-and-base-are-undetected.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4250-overlapping-searchparameter-with-the-same-code-and-base-are-undetected.yaml new file mode 100644 index 00000000000..1582202b68c --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4250-overlapping-searchparameter-with-the-same-code-and-base-are-undetected.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 4250 +title: "Previously, SearchParameters with identical codes and bases could be created. This has been corrected. If a SearchParameter is submitted which is a duplicate, it will be rejected." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4267-reindex-behaviour-issues.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4267-reindex-behaviour-issues.yaml new file mode 100644 index 00000000000..7e5a33a92f4 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4267-reindex-behaviour-issues.yaml @@ -0,0 +1,8 @@ +--- +type: fix +issue: 4267 +title: "Previously, if the `$reindex` operation failed with a `ResourceVersionConflictException` the related +batch job would fail. This has been corrected by adding 10 retry attempts for transactions that have +failed with a `ResourceVersionConflictException` during the `$reindex` operation. In addition, the `ResourceIdListStep` +was submitting one more resource than expected (i.e. 1001 records processed during a `$reindex` operation if only 1000 +`Resources` were in the database). This has been corrected." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4271-migration-failure-with-oracle-19c-as-database-support.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4271-migration-failure-with-oracle-19c-as-database-support.yaml new file mode 100644 index 00000000000..cf693a6bd5d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4271-migration-failure-with-oracle-19c-as-database-support.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 4271 +title: "Database migration steps were failing with Oracle 19C. This has been fixed by allowing the database engine to skip dropping non-existent indexes." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml index 92d154bf813..7ffb32a7262 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml @@ -1,3 +1,3 @@ --- -release-date: "2022-11-18" +release-date: "2022-11-17" codename: "Vishwa" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/upgrade.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/upgrade.md new file mode 100644 index 00000000000..76f1edbad3f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/upgrade.md @@ -0,0 +1 @@ +This version fixes a bug with 6.2.0 and previous releases wherein batch jobs that created very large chunk counts could occasionally fail to submit a small proportion of chunks. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/version.yaml new file mode 100644 index 00000000000..7ffb32a7262 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_1/version.yaml @@ -0,0 +1,3 @@ +--- +release-date: "2022-11-17" +codename: "Vishwa" diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index 4951bb88153..5c6003337ae 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index 3dc58871804..b7c7b774506 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index ca0c2c5829f..08d16f554dc 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 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 10c199956c9..ccc60fec412 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 @@ -184,6 +184,7 @@ public abstract class BaseHapiScheduler implements IHapiScheduler { ScheduleBuilder schedule = SimpleScheduleBuilder .simpleSchedule() .withIntervalInMilliseconds(theIntervalMillis) + .withMisfireHandlingInstructionIgnoreMisfires()//We ignore misfires in cases of multiple JVMs each trying to fire. .repeatForever(); Trigger trigger = TriggerBuilder.newTrigger() diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 352c4783a36..8b5babed5aa 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 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 4b856422e97..79b331e20e9 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 @@ -270,6 +270,14 @@ public class JpaJobPersistenceImpl implements IJobPersistence { myWorkChunkRepository.incrementWorkChunkErrorCount(theChunkId, theIncrementBy); } + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW) + public boolean canAdvanceInstanceToNextStep(String theInstanceId, String theCurrentStepId) { + List statusesForStep = myWorkChunkRepository.getDistinctStatusesForStep(theInstanceId, theCurrentStepId); + ourLog.debug("Checking whether gated job can advanced to next step. [instanceId={}, currentStepId={}, statusesForStep={}]", theInstanceId, theCurrentStepId, statusesForStep); + return statusesForStep.stream().noneMatch(StatusEnum::isIncomplete) && statusesForStep.stream().anyMatch(status -> status == StatusEnum.COMPLETED); + } + /** * Note: Not @Transactional because {@link #fetchChunks(String, boolean, int, int, Consumer)} starts a transaction */ @@ -289,6 +297,11 @@ public class JpaJobPersistenceImpl implements IJobPersistence { }); } + @Override + public List fetchallchunkidsforstepWithStatus(String theInstanceId, String theStepId, StatusEnum theStatusEnum) { + return myTxTemplate.execute(tx -> myWorkChunkRepository.fetchAllChunkIdsForStepWithStatus(theInstanceId, theStepId, theStatusEnum)); + } + private void fetchChunksForStep(String theInstanceId, String theStepId, int thePageSize, int thePageIndex, Consumer theConsumer) { myTxTemplate.executeWithoutResult(tx -> { List chunks = myWorkChunkRepository.fetchChunksForStep(PageRequest.of(thePageIndex, thePageSize), theInstanceId, theStepId); 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 dc2cda61f1c..d060e57c70e 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 @@ -36,6 +36,9 @@ public interface IBatch2WorkChunkRepository extends JpaRepository fetchChunks(Pageable thePageRequest, @Param("instanceId") String theInstanceId); + @Query("SELECT DISTINCT e.myStatus from Batch2WorkChunkEntity e where e.myInstanceId = :instanceId AND e.myTargetStepId = :stepId") + List getDistinctStatusesForStep(@Param("instanceId") String theInstanceId, @Param("stepId") String theStepId); + @Query("SELECT e FROM Batch2WorkChunkEntity e WHERE e.myInstanceId = :instanceId AND e.myTargetStepId = :targetStepId ORDER BY e.mySequence ASC") List fetchChunksForStep(Pageable thePageRequest, @Param("instanceId") String theInstanceId, @Param("targetStepId") String theTargetStepId); @@ -62,4 +65,10 @@ public interface IBatch2WorkChunkRepository extends JpaRepository fetchAllChunkIdsForStep(@Param("instanceId") String theInstanceId, @Param("stepId") String theStepId); + + @Query("SELECT e.myId from Batch2WorkChunkEntity e where e.myInstanceId = :instanceId AND e.myTargetStepId = :stepId AND e.myStatus = :status") + List fetchAllChunkIdsForStepWithStatus(@Param("instanceId")String theInstanceId, @Param("stepId")String theStepId, @Param("status")StatusEnum theStatus); } 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 2d20af3d426..fe1a490281e 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 @@ -117,6 +117,11 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { .modifyColumn("20221017.1", "BLOB_SIZE") .nullable() .withType(ColumnTypeEnum.LONG); + + version.onTable("HFJ_SPIDX_URI") + .modifyColumn("20221103.1", "SP_URI") + .nullable() + .withType(ColumnTypeEnum.STRING, 500); } private void init610() { @@ -942,7 +947,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { //ConceptMap add version for search Builder.BuilderWithTableName trmConceptMap = version.onTable("TRM_CONCEPT_MAP"); trmConceptMap.addColumn("20200910.1", "VER").nullable().type(ColumnTypeEnum.STRING, 200); - trmConceptMap.dropIndex("20200910.2", "IDX_CONCEPT_MAP_URL"); + trmConceptMap.dropIndex("20200910.2", "IDX_CONCEPT_MAP_URL").failureAllowed(); trmConceptMap.addIndex("20200910.3", "IDX_CONCEPT_MAP_URL").unique(true).withColumns("URL", "VER"); //Term CodeSystem Version and Term ValueSet Version @@ -950,13 +955,13 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { trmCodeSystemVer.addIndex("20200923.1", "IDX_CODESYSTEM_AND_VER").unique(true).withColumns("CODESYSTEM_PID", "CS_VERSION_ID"); Builder.BuilderWithTableName trmValueSet = version.onTable("TRM_VALUESET"); trmValueSet.addColumn("20200923.2", "VER").nullable().type(ColumnTypeEnum.STRING, 200); - trmValueSet.dropIndex("20200923.3", "IDX_VALUESET_URL"); + trmValueSet.dropIndex("20200923.3", "IDX_VALUESET_URL").failureAllowed(); trmValueSet.addIndex("20200923.4", "IDX_VALUESET_URL").unique(true).withColumns("URL", "VER"); //Term ValueSet Component add system version Builder.BuilderWithTableName trmValueSetComp = version.onTable("TRM_VALUESET_CONCEPT"); trmValueSetComp.addColumn("20201028.1", "SYSTEM_VER").nullable().type(ColumnTypeEnum.STRING, 200); - trmValueSetComp.dropIndex("20201028.2", "IDX_VS_CONCEPT_CS_CD"); + trmValueSetComp.dropIndex("20201028.2", "IDX_VS_CONCEPT_CS_CD").failureAllowed(); trmValueSetComp.addIndex("20201028.3", "IDX_VS_CONCEPT_CS_CODE").unique(true).withColumns("VALUESET_PID", "SYSTEM_URL", "SYSTEM_VER", "CODEVAL").doNothing(); } diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml index 2de9692219c..b104e7f84a4 100644 --- a/hapi-fhir-jpaserver-cql/pom.xml +++ b/hapi-fhir-jpaserver-cql/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index 24e1fecdb5f..d301eadd9c1 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index bcf125a1203..0155cdfef91 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSearchExpandingInterceptorIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSearchExpandingInterceptorIT.java index c23b6fabf01..c71e6017814 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSearchExpandingInterceptorIT.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/interceptor/MdmSearchExpandingInterceptorIT.java @@ -93,6 +93,72 @@ public class MdmSearchExpandingInterceptorIT extends BaseMdmR4Test { return createdResourceIds; } + private List updateAndLinkNewResources(int theResourceCount) throws InterruptedException { + boolean expansion = myDaoConfig.isAllowMdmExpansion(); + myDaoConfig.setAllowMdmExpansion(false); + List createdResourceIds = new ArrayList<>(); + + List observationIds = new ArrayList<>(); + for (int i = 0; i < theResourceCount; i++) { + // create patient + Patient patient = buildJanePatient(); + patient.setId("jane-" + i); + MdmHelperR4.OutcomeAndLogMessageWrapper withLatch = myMdmHelper.updateWithLatch(addExternalEID(patient, "123")); + createdResourceIds.add(withLatch.getDaoMethodOutcome().getId().getIdPart()); + + // create observation with patient + Observation observation = createObservationWithSubject(createdResourceIds.get(i)); + // we put the observation ids in a separate list so we can + // ensure our returned list is + // patient ids, followed by observation ids + observationIds.add(observation.getIdElement().getIdPart()); + } + + assertLinkCount(theResourceCount); + + // add in our observationIds + createdResourceIds.addAll(observationIds); + + myDaoConfig.setAllowMdmExpansion(expansion); + return createdResourceIds; + } + + + @Test + public void testReferenceExpansionWorksWithForcedIds() throws InterruptedException { + int resourceCount = 4; + List ids = updateAndLinkNewResources(resourceCount); + String id = ids.get(0); + + SearchParameterMap searchParameterMap = new SearchParameterMap(); + searchParameterMap.setLoadSynchronous(true); + ReferenceOrListParam referenceOrListParam = new ReferenceOrListParam(); + referenceOrListParam.addOr(new ReferenceParam("Patient/" + id).setMdmExpand(true)); + searchParameterMap.add(Observation.SP_SUBJECT, referenceOrListParam); + + //With MDM Expansion disabled, this should return 1 result. + myDaoConfig.setAllowMdmExpansion(false); + IBundleProvider search = myObservationDao.search(searchParameterMap); + assertThat(search.size(), is(equalTo(1))); + + //Once MDM Expansion is allowed, this should now return 4 resourecs. + myDaoConfig.setAllowMdmExpansion(true); + search = myObservationDao.search(searchParameterMap); + assertThat(search.size(), is(equalTo(4))); + List all = myMdmLinkDao.findAll(); + Long goldenPid = all.get(0).getGoldenResourcePid(); + IIdType goldenId = myIdHelperService.translatePidIdToForcedId(myFhirContext, "Patient", new ResourcePersistentId(goldenPid)); + //Verify that expansion by the golden resource id resolves down to everything its links have. + + SearchParameterMap goldenSpMap = new SearchParameterMap(); + goldenSpMap.setLoadSynchronous(true); + ReferenceOrListParam goldenReferenceOrListParam = new ReferenceOrListParam(); + goldenReferenceOrListParam.addOr(new ReferenceParam(goldenId).setMdmExpand(true)); + goldenSpMap.add(Observation.SP_SUBJECT, goldenReferenceOrListParam); + + search = myObservationDao.search(goldenSpMap); + assertThat(search.size(), is(equalTo(resourceCount))); + } @Test public void testReferenceExpansionWorks() throws InterruptedException { int resourceCount = 4; diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 294e118ae06..81b2a142592 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamUri.java b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamUri.java index 6ef437cdb2a..94055f832ef 100644 --- a/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamUri.java +++ b/hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/ResourceIndexedSearchParamUri.java @@ -59,9 +59,11 @@ import static org.apache.commons.lang3.StringUtils.defaultString; public class ResourceIndexedSearchParamUri extends BaseResourceIndexedSearchParam { /* - * Note that MYSQL chokes on unique indexes for lengths > 255 so be careful here + * Be careful when modifying this value + * MySQL chokes on indexes with combined column length greater than 3052 bytes (768 chars) + * https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html */ - public static final int MAX_LENGTH = 254; + public static final int MAX_LENGTH = 500; private static final long serialVersionUID = 1L; @Column(name = "SP_URI", nullable = true, length = MAX_LENGTH) diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index 15ad0732352..08ee6fb1b56 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 3f94dfd0326..2210b8808f3 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index 1f6ee6345f1..4cbf912c4a2 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java index d2f176c97e3..8fc23513cf7 100644 --- a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java +++ b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java @@ -37,6 +37,7 @@ import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index 5fb3680bda7..434f88fa1d5 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java index 58e6d2b0428..41e0eb898fc 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java @@ -130,6 +130,7 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.test.util.AopTestUtils; import org.springframework.transaction.TransactionStatus; import org.springframework.transaction.support.TransactionCallback; @@ -4823,6 +4824,33 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { } + @Test + public void testDocumentReferenceWith500CharAttachmentUrl() throws IOException { + final DocumentReference.ReferredDocumentStatus docStatus = DocumentReference.ReferredDocumentStatus.FINAL; + final String longUrl = StringUtils.repeat("a", 500); + + DocumentReference submittedDocumentReference = new DocumentReference(); + submittedDocumentReference.setDocStatus(docStatus); + + Attachment attachment = new Attachment(); + attachment.setUrl(longUrl); + submittedDocumentReference.getContentFirstRep().setAttachment(attachment); + + String json = myFhirContext.newJsonParser().encodeResourceToString(submittedDocumentReference); + HttpPost post = new HttpPost(myServerBase + "/DocumentReference"); + post.setEntity(new StringEntity(json, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + try (CloseableHttpResponse response = ourHttpClient.execute(post)) { + String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8); + ourLog.info(resp); + assertEquals(HttpStatus.CREATED.value(), response.getStatusLine().getStatusCode()); + + DocumentReference createdDocumentReferenced = myFhirContext.newJsonParser().parseResource(DocumentReference.class, resp); + assertEquals(docStatus, createdDocumentReferenced.getDocStatus()); + assertEquals(longUrl, createdDocumentReferenced.getContentFirstRep().getAttachment().getUrl()); + } + } + private String toStr(Date theDate) { return new InstantDt(theDate).getValueAsString(); } diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index d68da53a525..6bd5d059b23 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 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 f6d2ddb4867..c64293160a7 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 @@ -305,6 +305,39 @@ public class JpaJobPersistenceImplTest extends BaseJpaR4Test { assertEquals(1, chunks.size()); assertEquals(5, chunks.get(0).getErrorCount()); } + @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.markWorkChunkAsCompletedAndClearData(chunkId, 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.markWorkChunkAsCompletedAndClearData(newChunkId, 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.fetchWorkChunkSetStartTimeAndMarkInProgress(newerChunkId); + canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); + assertFalse(canAdvance); + + //Toggle IN_PROGRESS to complete + mySvc.markWorkChunkAsCompletedAndClearData(newerChunkId, 0); + canAdvance = mySvc.canAdvanceInstanceToNextStep(instanceId, STEP_CHUNK_ID); + assertTrue(canAdvance); + } @Test public void testMarkChunkAsCompleted_Error() { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java index 2097c6d1f2c..6bca18c08b5 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java @@ -43,6 +43,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -59,6 +60,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java index 64681ca6ef2..ef3646d3543 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java @@ -40,6 +40,11 @@ import org.mockito.junit.jupiter.MockitoExtension; import javax.persistence.EntityManager; import java.util.List; + +import java.util.List; + +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java index 29b9a00472a..e436bfe9dab 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ConcurrentWriteTest.java @@ -332,8 +332,7 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { @Test public void testCreateWithClientAssignedId() { myInterceptorRegistry.registerInterceptor(myRetryInterceptor); - String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10"; - when(mySrd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + setupRetryBehaviour(mySrd); List> futures = new ArrayList<>(); for (int i = 0; i < 5; i++) { @@ -502,8 +501,7 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { @Test public void testDelete() { myInterceptorRegistry.registerInterceptor(myRetryInterceptor); - String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=100"; - when(mySrd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + setupRetryBehaviour(mySrd); IIdType patientId = runInTransaction(() -> { Patient p = new Patient(); @@ -664,8 +662,7 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { @Test public void testPatch() { myInterceptorRegistry.registerInterceptor(myRetryInterceptor); - String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10"; - when(mySrd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + setupRetryBehaviour(mySrd); Patient p = new Patient(); p.addName().setFamily("FAMILY"); @@ -719,8 +716,7 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { myInterceptorRegistry.registerInterceptor(myRetryInterceptor); ServletRequestDetails srd = mock(ServletRequestDetails.class); - String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10"; - when(srd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + setupRetryBehaviour(srd); when(srd.getUserData()).thenReturn(new HashMap<>()); when(srd.getServer()).thenReturn(new RestfulServer(myFhirContext)); when(srd.getInterceptorBroadcaster()).thenReturn(new InterceptorService()); @@ -772,8 +768,7 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { myDaoConfig.setDeleteEnabled(false); ServletRequestDetails srd = mock(ServletRequestDetails.class); - String value = UserRequestRetryVersionConflictsInterceptor.RETRY + "; " + UserRequestRetryVersionConflictsInterceptor.MAX_RETRIES + "=10"; - when(srd.getHeaders(eq(UserRequestRetryVersionConflictsInterceptor.HEADER_NAME))).thenReturn(Collections.singletonList(value)); + setupRetryBehaviour(srd); when(srd.getUserData()).thenReturn(new HashMap<>()); when(srd.getServer()).thenReturn(new RestfulServer(myFhirContext)); when(srd.getInterceptorBroadcaster()).thenReturn(new InterceptorService()); @@ -824,4 +819,9 @@ public class FhirResourceDaoR4ConcurrentWriteTest extends BaseJpaR4Test { } + private void setupRetryBehaviour(ServletRequestDetails theServletRequestDetails) { + when(theServletRequestDetails.isRetry()).thenReturn(true); + when(theServletRequestDetails.getMaxRetries()).thenReturn(10); + } + } 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 60f997893f4..50c405bbba8 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 @@ -11,14 +11,20 @@ import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.test.BaseJpaR4Test; +import ca.uhn.fhir.jpa.test.PatientReindexTestHelper; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4.model.Observation; import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Disabled; 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 org.springframework.beans.factory.annotation.Autowired; import javax.annotation.PostConstruct; import java.util.List; +import java.util.stream.Stream; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; @@ -30,10 +36,13 @@ public class ReindexJobTest extends BaseJpaR4Test { private IJobCoordinator myJobCoordinator; private ReindexTestHelper myReindexTestHelper; + private PatientReindexTestHelper myPatientReindexTestHelper; @PostConstruct public void postConstruct() { myReindexTestHelper = new ReindexTestHelper(myFhirContext, myDaoRegistry, mySearchParamRegistry); + boolean incrementVersionAfterReindex = false; + myPatientReindexTestHelper = new PatientReindexTestHelper(myJobCoordinator, myBatch2JobHelper, myPatientDao, incrementVersionAfterReindex); } @AfterEach @@ -167,4 +176,29 @@ public class ReindexJobTest extends BaseJpaR4Test { assertEquals("java.lang.Error: foo message", outcome.getErrorMessage()); } + private static Stream numResourcesParams(){ + return PatientReindexTestHelper.numResourcesParams(); + } + + @ParameterizedTest + @MethodSource("numResourcesParams") + @Disabled//TODO Nathan, this is failing intermittently in CI. + public void testReindex(int theNumResources){ + myPatientReindexTestHelper.testReindex(theNumResources); + } + + @ParameterizedTest + @MethodSource("numResourcesParams") + @Disabled//TODO Nathan, this is failing intermittently in CI. + public void testSequentialReindexOperation(int theNumResources){ + myPatientReindexTestHelper.testSequentialReindexOperation(theNumResources); + } + + @ParameterizedTest + @MethodSource("numResourcesParams") + @Disabled//TODO Nathan, this is failing intermittently in CI. + public void testParallelReindexOperation(int theNumResources){ + myPatientReindexTestHelper.testParallelReindexOperation(theNumResources); + } + } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java index c54d612fb25..98355bd7caa 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java @@ -165,6 +165,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import javax.annotation.Nonnull; +import javax.sql.DataSource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index f63968fa685..f6aa32ae643 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 d68ae1de3ab..3d965df565e 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 47af00475ab..24fe721cc6b 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -144,6 +144,11 @@ junit-jupiter-engine compile + + org.junit.jupiter + junit-jupiter-params + compile + org.hamcrest hamcrest diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/PatientReindexTestHelper.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/PatientReindexTestHelper.java new file mode 100644 index 00000000000..a0385253d91 --- /dev/null +++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/test/PatientReindexTestHelper.java @@ -0,0 +1,185 @@ +package ca.uhn.fhir.jpa.test; + +/*- + * #%L + * HAPI FHIR JPA Server Test Utilities + * %% + * Copyright (C) 2014 - 2022 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import ca.uhn.fhir.batch2.api.IJobCoordinator; +import ca.uhn.fhir.batch2.jobs.reindex.ReindexAppCtx; +import ca.uhn.fhir.batch2.jobs.reindex.ReindexJobParameters; +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.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.batch.models.Batch2JobStartResponse; +import ca.uhn.fhir.jpa.partition.SystemRequestDetails; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.jpa.util.TestUtil; +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.params.provider.Arguments; + +import java.util.List; +import java.util.stream.Stream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.fail; + +public class PatientReindexTestHelper { + + private static final int VERSION_1 = 1; + private static final int VERSION_2 = 2; + private static final int VERSION_3 = 3; + public static final int JOB_WAIT_TIME = 60; + + private final IJobCoordinator myJobCoordinator; + private final Batch2JobHelper myBatch2JobHelper; + private final IFhirResourceDao myPatientDao; + private final boolean myIncrementVersionOnReindex; + + public static Stream numResourcesParams(){ + return Stream.of( + Arguments.of(0), + Arguments.of(1), + Arguments.of(499), + Arguments.of(500), + Arguments.of(750), + Arguments.of(1000), + Arguments.of(1001) + ); + } + + public PatientReindexTestHelper(IJobCoordinator theJobCoordinator, Batch2JobHelper theBatch2JobHelper, IFhirResourceDao thePatientDao, boolean theIncrementVersionOnReindex) { + myJobCoordinator = theJobCoordinator; + myBatch2JobHelper = theBatch2JobHelper; + myPatientDao = thePatientDao; + myIncrementVersionOnReindex = theIncrementVersionOnReindex; + } + + public void testReindex(int theNumResources){ + createPatients(theNumResources); + + validatePersistedPatients(theNumResources, VERSION_1); + + // Reindex 1 + JobInstanceStartRequest reindexRequest1 = createPatientReindexRequest(theNumResources); + Batch2JobStartResponse reindexResponse1 = myJobCoordinator.startInstance(reindexRequest1); + JobInstance instance1 = myBatch2JobHelper.awaitJobHasStatus(reindexResponse1.getJobId(), JOB_WAIT_TIME, StatusEnum.COMPLETED); + + validateReindexJob(instance1, theNumResources); + + int expectedVersion = myIncrementVersionOnReindex ? VERSION_2 : VERSION_1; + validatePersistedPatients(theNumResources, expectedVersion); + } + + public void testSequentialReindexOperation(int theNumResources){ + createPatients(theNumResources); + + validatePersistedPatients(theNumResources, VERSION_1); + + // Reindex 1 + JobInstanceStartRequest reindexRequest1 = createPatientReindexRequest(theNumResources); + Batch2JobStartResponse reindexResponse1 = myJobCoordinator.startInstance(reindexRequest1); + JobInstance instance1 = myBatch2JobHelper.awaitJobHasStatus(reindexResponse1.getJobId(), JOB_WAIT_TIME, StatusEnum.COMPLETED); + + validateReindexJob(instance1, theNumResources); + int expectedVersion = myIncrementVersionOnReindex ? VERSION_2 : VERSION_1; + validatePersistedPatients(theNumResources, expectedVersion); + + // Reindex 2 + JobInstanceStartRequest reindexRequest2 = createPatientReindexRequest(theNumResources); + Batch2JobStartResponse reindexResponse2 = myJobCoordinator.startInstance(reindexRequest2); + JobInstance instance2 = myBatch2JobHelper.awaitJobHasStatus(reindexResponse2.getJobId(), JOB_WAIT_TIME, StatusEnum.COMPLETED); + + validateReindexJob(instance2, theNumResources); + expectedVersion = myIncrementVersionOnReindex ? VERSION_3 : VERSION_1; + validatePersistedPatients(theNumResources, expectedVersion); + } + + public void testParallelReindexOperation(int theNumResources){ + createPatients(theNumResources); + + validatePersistedPatients(theNumResources, VERSION_1); + + // Reindex 1 + JobInstanceStartRequest reindexRequest1 = createPatientReindexRequest(theNumResources); + Batch2JobStartResponse reindexResponse1 = myJobCoordinator.startInstance(reindexRequest1); + + // Reindex 2 + JobInstanceStartRequest reindexRequest2 = createPatientReindexRequest(theNumResources); + Batch2JobStartResponse reindexResponse2 = myJobCoordinator.startInstance(reindexRequest2); + + // Wait for jobs to finish + JobInstance instance1 = myBatch2JobHelper.awaitJobHasStatus(reindexResponse1.getJobId(), JOB_WAIT_TIME, StatusEnum.COMPLETED); + JobInstance instance2 = myBatch2JobHelper.awaitJobHasStatus(reindexResponse2.getJobId(), JOB_WAIT_TIME, StatusEnum.COMPLETED); + + validateReindexJob(instance1, theNumResources); + + validateReindexJob(instance2, theNumResources); + + int expectedVersion = myIncrementVersionOnReindex ? VERSION_3 : VERSION_1; + validatePersistedPatients(theNumResources, expectedVersion); + } + + + private void createPatients(int theNumPatients) { + RequestDetails requestDetails = new SystemRequestDetails(); + for(int i = 0; i < theNumPatients; i++){ + Patient patient = new Patient(); + patient.getNameFirstRep().setFamily("Family-"+i).addGiven("Given-"+i); + patient.getIdentifierFirstRep().setValue("Id-"+i); + myPatientDao.create(patient, requestDetails); + } + TestUtil.sleepOneClick(); + } + + private void validatePersistedPatients(int theExpectedNumPatients, long theExpectedVersion) { + RequestDetails requestDetails = new SystemRequestDetails(); + List resources = myPatientDao.search(SearchParameterMap.newSynchronous(), requestDetails).getAllResources(); + assertEquals(theExpectedNumPatients, resources.size()); + for(IBaseResource resource : resources){ + assertEquals(Patient.class, resource.getClass()); + Patient patient = (Patient) resource; + Long actualVersion = patient.getIdElement().getVersionIdPartAsLong(); + if(theExpectedVersion != actualVersion){ + String failureMessage = String.format("Failure for Resource [%s] with index [%s]. Expected version: %s, Actual version: %s", + patient.getId(), resources.indexOf(resource), theExpectedVersion, actualVersion); + fail(failureMessage); + } + } + } + + private JobInstanceStartRequest createPatientReindexRequest(int theBatchSize) { + JobInstanceStartRequest startRequest = new JobInstanceStartRequest(); + startRequest.setJobDefinitionId(ReindexAppCtx.JOB_REINDEX); + + ReindexJobParameters reindexJobParameters = new ReindexJobParameters(); + reindexJobParameters.setBatchSize(theBatchSize); + reindexJobParameters.addUrl("Patient?"); + + startRequest.setParameters(reindexJobParameters); + return startRequest; + } + + private void validateReindexJob(JobInstance theJobInstance, int theRecordsProcessed) { + assertEquals(0, theJobInstance.getErrorCount()); + assertEquals(theRecordsProcessed, theJobInstance.getCombinedRecordsProcessed()); + } +} diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 3eab5a19cd1..983d182a888 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 2d5ef95aba1..74406036383 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/interceptor/MdmSearchExpandingInterceptor.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/interceptor/MdmSearchExpandingInterceptor.java index 28ada0df2e7..f2a9149579f 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/interceptor/MdmSearchExpandingInterceptor.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/interceptor/MdmSearchExpandingInterceptor.java @@ -25,7 +25,6 @@ import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.mdm.api.IMdmLinkExpandSvc; -import ca.uhn.fhir.mdm.svc.MdmLinkExpandSvc; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.mdm.log.Logs; import ca.uhn.fhir.model.api.IQueryParameterType; @@ -99,7 +98,8 @@ public class MdmSearchExpandingInterceptor { ourLog.debug("Parameter has been expanded to: {}", String.join(", ", expandedResourceIds)); toRemove.add(refParam); expandedResourceIds.stream() - .map(resourceId -> new ReferenceParam(refParam.getResourceType() + "/" + resourceId)) + .map(resourceId -> addResourceTypeIfNecessary(refParam.getResourceType(), resourceId)) + .map(ReferenceParam::new) .forEach(toAdd::add); } } @@ -112,6 +112,14 @@ public class MdmSearchExpandingInterceptor { orList.addAll(toAdd); } + private String addResourceTypeIfNecessary(String theResourceType, String theResourceId) { + if (theResourceId.contains("/")) { + return theResourceId; + } else { + return theResourceType + "/" + theResourceId; + } + } + /** * Expands out the provided _id parameter into all the various * ids of linked resources. diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index 5b2cdbcd4fe..d14c31a24fc 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index 84184071283..a05ff319863 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/RequestDetails.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/RequestDetails.java index 0878b8f4cef..305bf943974 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/RequestDetails.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/api/server/RequestDetails.java @@ -77,6 +77,8 @@ public abstract class RequestDetails { private String myTransactionGuid; private String myFixedConditionalUrl; private boolean myRewriteHistory; + private int myMaxRetries; + private boolean myRetry; /** * Constructor @@ -542,4 +544,21 @@ public abstract class RequestDetails { public void setRewriteHistory(boolean theRewriteHistory) { myRewriteHistory = theRewriteHistory; } + + + public int getMaxRetries() { + return myMaxRetries; + } + + public void setMaxRetries(int theMaxRetries) { + myMaxRetries = theMaxRetries; + } + + public boolean isRetry() { + return myRetry; + } + + public void setRetry(boolean theRetry) { + myRetry = theRetry; + } } diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java index 9cf18c6bfa1..f166f5902a4 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/servlet/ServletRequestDetails.java @@ -44,11 +44,14 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.HashMap; +import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.StringTokenizer; import java.util.zip.GZIPInputStream; import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.trim; public class ServletRequestDetails extends RequestDetails { @@ -186,9 +189,36 @@ public class ServletRequestDetails extends RequestDetails { if ("true".equals(myServletRequest.getHeader(Constants.HEADER_REWRITE_HISTORY))) { setRewriteHistory(true); } + setRetryFields(myServletRequest); return this; } + private void setRetryFields(HttpServletRequest theRequest){ + if (theRequest == null){ + return; + } + Enumeration headers = theRequest.getHeaders(Constants.HEADER_RETRY_ON_VERSION_CONFLICT); + if (headers != null) { + Iterator headerIterator = headers.asIterator(); + while(headerIterator.hasNext()){ + String headerValue = headerIterator.next(); + if (isNotBlank(headerValue)) { + StringTokenizer tok = new StringTokenizer(headerValue, ";"); + while (tok.hasMoreTokens()) { + String next = trim(tok.nextToken()); + if (next.equals(Constants.HEADER_RETRY)) { + setRetry(true); + } else if (next.startsWith(Constants.HEADER_MAX_RETRIES + "=")) { + String val = trim(next.substring((Constants.HEADER_MAX_RETRIES + "=").length())); + int maxRetries = Integer.parseInt(val); + setMaxRetries(maxRetries); + } + } + } + } + } + } + public void setServletResponse(HttpServletResponse myServletResponse) { this.myServletResponse = myServletResponse; } diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml index 861da0a89e3..c59d014ba2b 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 cbbc0ff57df..a77c67dfda3 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml @@ -20,7 +20,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT com.github.ben-manes.caffeine diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index f25381f3871..ea8eda5e404 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 7d4c63504ff..910d572cc66 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index 0f77474def6..47996d5d96b 100644 --- a/hapi-fhir-serviceloaders/pom.xml +++ b/hapi-fhir-serviceloaders/pom.xml @@ -5,7 +5,7 @@ hapi-fhir ca.uhn.hapi.fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../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 53c965b9d7b..9c3e9aef6cd 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 87ce61a0215..e5b689b27db 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 857645f328e..34c3d8a4547 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT hapi-fhir-spring-boot-sample-client-okhttp diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index be76fd51a3f..9def3808e97 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT hapi-fhir-spring-boot-sample-server-jersey diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index e8ee2fb2a6c..1ac037d7169 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT hapi-fhir-spring-boot-samples diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index 83426433ac8..e693fd2ebb4 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index 001e7a15878..de87a1bebc2 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 7ef25346890..8e6d8683d1c 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 482eaf6cca2..1cb4a3c4b81 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java index bcb7bf0682a..a76b0b77987 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java @@ -31,6 +31,7 @@ import ca.uhn.fhir.batch2.jobs.export.models.ResourceIdList; import ca.uhn.fhir.batch2.jobs.models.Id; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.bulk.export.api.IBulkExportProcessor; import ca.uhn.fhir.jpa.bulk.export.model.ExportPIDIteratorParameters; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexStep.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexStep.java index 0f2a378cf57..9d950e0ab82 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexStep.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/reindex/ReindexStep.java @@ -51,6 +51,8 @@ import java.util.concurrent.TimeUnit; public class ReindexStep implements IJobStepWorker { + public static final int REINDEX_MAX_RETRIES = 10; + private static final Logger ourLog = LoggerFactory.getLogger(ReindexStep.class); @Autowired private HapiTransactionService myHapiTransactionService; @@ -73,6 +75,8 @@ public class ReindexStep implements IJobStepWorker theDataSink, String theInstanceId, String theChunkId) { RequestDetails requestDetails = new SystemRequestDetails(); + requestDetails.setRetry(true); + requestDetails.setMaxRetries(REINDEX_MAX_RETRIES); TransactionDetails transactionDetails = new TransactionDetails(); myHapiTransactionService.execute(requestDetails, transactionDetails, new ReindexJob(data, requestDetails, transactionDetails, theDataSink, theInstanceId, theChunkId)); diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 23373392c8c..7368d5d7fee 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 4705dfafc90..a0114138883 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 @@ -28,6 +28,8 @@ import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; import ca.uhn.fhir.batch2.models.JobInstanceFetchRequest; import org.springframework.data.domain.Page; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; import java.util.Iterator; import java.util.List; @@ -163,6 +165,9 @@ public interface IJobPersistence { */ void incrementWorkChunkErrorCount(String theChunkId, int theIncrementBy); + @Transactional(propagation = Propagation.REQUIRES_NEW) + boolean canAdvanceInstanceToNextStep(String theInstanceId, String theCurrentStepId); + /** * Fetches all chunks for a given instance, without loading the data * @@ -172,12 +177,14 @@ public interface IJobPersistence { */ List fetchWorkChunksWithoutData(String theInstanceId, int thePageSize, int thePageIndex); - /** - * Fetch all chunks for a given instance. - * @param theInstanceId - instance id - * @param theWithData - whether or not to include the data - * @return - an iterator for fetching work chunks - */ + + + /** + * Fetch all chunks for a given instance. + * @param theInstanceId - instance id + * @param theWithData - whether or not to include the data + * @return - an iterator for fetching work chunks + */ Iterator fetchAllWorkChunksIterator(String theInstanceId, boolean theWithData); /** @@ -226,4 +233,6 @@ public interface IJobPersistence { * @param theInstanceId The instance ID */ JobOperationResultJson cancelInstance(String theInstanceId); + + List fetchallchunkidsforstepWithStatus(String theInstanceId, String theStepId, StatusEnum theStatusEnum); } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java index ba9595f14b2..992dc989960 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/SynchronizedJobPersistenceWrapper.java @@ -126,6 +126,11 @@ public class SynchronizedJobPersistenceWrapper implements IJobPersistence { myWrap.incrementWorkChunkErrorCount(theChunkId, theIncrementBy); } + @Override + public boolean canAdvanceInstanceToNextStep(String theInstanceId, String theCurrentStepId) { + return myWrap.canAdvanceInstanceToNextStep(theInstanceId, theCurrentStepId); + } + @Override public synchronized List fetchWorkChunksWithoutData(String theInstanceId, int thePageSize, int thePageIndex) { return myWrap.fetchWorkChunksWithoutData(theInstanceId, thePageSize, thePageIndex); @@ -141,7 +146,6 @@ public class SynchronizedJobPersistenceWrapper implements IJobPersistence { return myWrap.fetchAllWorkChunksForStepIterator(theInstanceId, theStepId); } - @Override public synchronized boolean updateInstance(JobInstance theInstance) { return myWrap.updateInstance(theInstance); @@ -166,4 +170,9 @@ public class SynchronizedJobPersistenceWrapper implements IJobPersistence { public JobOperationResultJson cancelInstance(String theInstanceId) { return myWrap.cancelInstance(theInstanceId); } + + @Override + public List fetchallchunkidsforstepWithStatus(String theInstanceId, String theStepId, StatusEnum theStatusEnum) { + return myWrap.fetchallchunkidsforstepWithStatus(theInstanceId, theStepId, theStatusEnum); + } } 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 a814b6c8b2e..4056df8901c 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 @@ -81,6 +81,7 @@ class WorkChannelMessageHandler implements MessageHandler { return; } WorkChunk workChunk = chunkOpt.get(); + ourLog.debug("Worker picked up chunk. [chunkId={}, stepId={}, startTime={}]", chunkId, workChunk.getTargetStepId(), workChunk.getStartTime()); JobWorkCursor cursor = buildCursorFromNotification(workNotification); diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/jobs/step/ResourceIdListStep.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/jobs/step/ResourceIdListStep.java index 0b4963c9f96..2eb9d99ec2b 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/jobs/step/ResourceIdListStep.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/jobs/step/ResourceIdListStep.java @@ -100,12 +100,12 @@ public class ResourceIdListStep= MAX_BATCH_OF_IDS) { + while (idBuffer.size() > MAX_BATCH_OF_IDS) { List submissionIds = new ArrayList<>(); for (Iterator iter = idBuffer.iterator(); iter.hasNext(); ) { submissionIds.add(iter.next()); iter.remove(); - if (submissionIds.size() >= MAX_BATCH_OF_IDS) { + if (submissionIds.size() == MAX_BATCH_OF_IDS) { break; } } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobChunkProgressAccumulator.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobChunkProgressAccumulator.java index 1b51c1f213e..78b22f996d4 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobChunkProgressAccumulator.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/maintenance/JobChunkProgressAccumulator.java @@ -23,9 +23,11 @@ package ca.uhn.fhir.batch2.maintenance; import ca.uhn.fhir.batch2.model.StatusEnum; import ca.uhn.fhir.batch2.model.WorkChunk; +import ca.uhn.fhir.jpa.batch.log.Logs; import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; import org.apache.commons.lang3.ArrayUtils; +import org.slf4j.Logger; import javax.annotation.Nonnull; import java.util.Collection; @@ -36,6 +38,7 @@ import java.util.stream.Collectors; import static java.util.Collections.emptyList; import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; +import static org.slf4j.LoggerFactory.getLogger; /** * While performing cleanup, the cleanup job loads all of the known @@ -44,6 +47,7 @@ import static org.apache.commons.lang3.ObjectUtils.defaultIfNull; * needing to hit the database a second time. */ public class JobChunkProgressAccumulator { + private static final Logger ourLog = Logs.getBatchTroubleshootingLog(); private final Set myConsumedInstanceAndChunkIds = new HashSet<>(); private final Multimap myInstanceIdToChunkStatuses = ArrayListMultimap.create(); @@ -52,6 +56,10 @@ public class JobChunkProgressAccumulator { return getChunkIdsWithStatus(theInstanceId, theStepId, theStatuses).size(); } + int getTotalChunkCountForInstanceAndStep(String theInstanceId, String theStepId) { + return myInstanceIdToChunkStatuses.get(theInstanceId).stream().filter(chunkCount -> chunkCount.myStepId.equals(theStepId)).collect(Collectors.toList()).size(); + } + public List getChunkIdsWithStatus(String theInstanceId, String theStepId, StatusEnum... theStatuses) { return getChunkStatuses(theInstanceId).stream() .filter(t -> t.myStepId.equals(theStepId)) @@ -73,6 +81,7 @@ public class JobChunkProgressAccumulator { // Note: If chunks are being written while we're executing, we may see the same chunk twice. This // check avoids adding it twice. if (myConsumedInstanceAndChunkIds.add(instanceId + " " + chunkId)) { + ourLog.debug("Adding chunk to accumulator. [chunkId={}, instanceId={}, status={}]", chunkId, instanceId, theChunk.getStatus()); myInstanceIdToChunkStatuses.put(instanceId, new ChunkStatusCountValue(chunkId, theChunk.getTargetStepId(), theChunk.getStatus())); } } @@ -88,6 +97,4 @@ public class JobChunkProgressAccumulator { myStatus = theStatus; } } - - } 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 af8a278de62..0d803e9944a 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 @@ -140,11 +140,9 @@ public class JobInstanceProcessor { String instanceId = myInstance.getInstanceId(); String currentStepId = jobWorkCursor.getCurrentStepId(); - int incompleteChunks = myProgressAccumulator.countChunksWithStatus(instanceId, currentStepId, StatusEnum.getIncompleteStatuses()); - - if (incompleteChunks == 0) { + 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); if (jobWorkCursor.nextStep.isReductionStep()) { @@ -154,18 +152,23 @@ public class JobInstanceProcessor { processChunksForNextSteps(instanceId, nextStepId); } } else { - ourLog.debug("Not ready to advance gated execution of instance {} from step {} to {} because there are {} incomplete work chunks", - instanceId, currentStepId, jobWorkCursor.nextStep.getStepId(), incompleteChunks); + ourLog.debug("Not ready to advance gated execution of instance {} from step {} to {}.", + instanceId, currentStepId, jobWorkCursor.nextStep.getStepId()); } } private void processChunksForNextSteps(String instanceId, String nextStepId) { - List chunksForNextStep = myProgressAccumulator.getChunkIdsWithStatus(instanceId, nextStepId, StatusEnum.QUEUED); - for (String nextChunkId : chunksForNextStep) { + List queuedChunksForNextStep = myProgressAccumulator.getChunkIdsWithStatus(instanceId, nextStepId, StatusEnum.QUEUED); + int totalChunksForNextStep = myProgressAccumulator.getTotalChunkCountForInstanceAndStep(instanceId, nextStepId); + if (totalChunksForNextStep != queuedChunksForNextStep.size()) { + ourLog.debug("Total ProgressAccumulator QUEUED chunk count does not match QUEUED chunk size! [instanceId={}, stepId={}, totalChunks={}, queuedChunks={}]", instanceId, nextStepId, totalChunksForNextStep, queuedChunksForNextStep.size()); + } + List chunksToSubmit = myJobPersistence.fetchallchunkidsforstepWithStatus(instanceId, nextStepId, StatusEnum.QUEUED); + for (String nextChunkId : chunksToSubmit) { JobWorkNotification workNotification = new JobWorkNotification(myInstance, nextStepId, nextChunkId); myBatchJobSender.sendWorkChannelMessage(workNotification); } - + ourLog.debug("Submitted a batch of chunks for processing. [chunkCount={}, instanceId={}, stepId={}]", chunksToSubmit.size(), instanceId, nextStepId); myInstance.setCurrentGatedStepId(nextStepId); myJobPersistence.updateInstance(myInstance); } diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java index 40be01e160a..94564129063 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/model/StatusEnum.java @@ -21,6 +21,9 @@ package ca.uhn.fhir.batch2.model; */ import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.jpa.batch.log.Logs; +import net.bytebuddy.dynamic.ClassFileLocator; +import org.slf4j.Logger; import javax.annotation.Nonnull; import java.util.Collections; @@ -61,6 +64,8 @@ public enum StatusEnum { */ CANCELLED(true, true); + private static final Logger ourLog = Logs.getBatchTroubleshootingLog(); + private final boolean myIncomplete; private final boolean myEnded; private static StatusEnum[] ourIncompleteStatuses; @@ -138,23 +143,37 @@ public enum StatusEnum { if (theOrigStatus == theNewStatus) { return true; } - + Boolean canTransition; switch (theOrigStatus) { case QUEUED: // initial state can transition to anything - return true; + canTransition = true; + break; case IN_PROGRESS: - return theNewStatus != QUEUED; + canTransition = theNewStatus != QUEUED; + break; case ERRORED: - return theNewStatus == FAILED || theNewStatus == COMPLETED || theNewStatus == CANCELLED; + canTransition = theNewStatus == FAILED || theNewStatus == COMPLETED || theNewStatus == CANCELLED; + break; case COMPLETED: case CANCELLED: case FAILED: // terminal state cannot transition - return false; + canTransition = false; + break; + default: + canTransition = null; + break; } - throw new IllegalStateException(Msg.code(2131) + "Unknown batch state " + theOrigStatus); + if (canTransition == null){ + throw new IllegalStateException(Msg.code(2131) + "Unknown batch state " + theOrigStatus); + } else { + if (!canTransition) { + ourLog.trace("Tried to execute an illegal state transition. [origStatus={}, newStatus={}]", theOrigStatus, theNewStatus); + } + return canTransition; + } } public boolean isIncomplete() { 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 8b1bb64b859..e7d9edaa9fd 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 @@ -29,6 +29,8 @@ import org.apache.commons.lang3.builder.ToStringBuilder; import org.slf4j.Logger; import java.util.Date; +import java.util.HashMap; +import java.util.Map; import java.util.concurrent.TimeUnit; class InstanceProgress { @@ -36,6 +38,7 @@ class InstanceProgress { private int myRecordsProcessed = 0; private int myIncompleteChunkCount = 0; + private int myQueuedCount = 0; private int myCompleteChunkCount = 0; private int myErroredChunkCount = 0; private int myFailedChunkCount = 0; @@ -44,6 +47,7 @@ class InstanceProgress { private Long myLatestEndTime = null; private String myErrormessage = null; private StatusEnum myNewStatus = null; + private Map> myStepToStatusCountMap = new HashMap<>(); public void addChunk(WorkChunk theChunk) { myErrorCountForAllStatuses += theChunk.getErrorCount(); @@ -55,6 +59,10 @@ class InstanceProgress { } private void updateCompletionStatus(WorkChunk theChunk) { + //Update the status map first. + Map statusToCountMap = myStepToStatusCountMap.getOrDefault(theChunk.getTargetStepId(), new HashMap<>()); + statusToCountMap.put(theChunk.getStatus(), statusToCountMap.getOrDefault(theChunk.getStatus(), 0) + 1); + switch (theChunk.getStatus()) { case QUEUED: case IN_PROGRESS: @@ -166,14 +174,19 @@ class InstanceProgress { @Override public String toString() { - return new ToStringBuilder(this) + ToStringBuilder builder = new ToStringBuilder(this) .append("myIncompleteChunkCount", myIncompleteChunkCount) .append("myCompleteChunkCount", myCompleteChunkCount) .append("myErroredChunkCount", myErroredChunkCount) .append("myFailedChunkCount", myFailedChunkCount) .append("myErrormessage", myErrormessage) - .append("myRecordsProcessed", myRecordsProcessed) - .toString(); + .append("myRecordsProcessed", myRecordsProcessed); + + builder.append("myStepToStatusCountMap", myStepToStatusCountMap); + + return builder.toString(); + + } public StatusEnum getNewStatus() { diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceStatusUpdater.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceStatusUpdater.java index 400587c7dcf..66317f3b27f 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceStatusUpdater.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/progress/JobInstanceStatusUpdater.java @@ -50,6 +50,7 @@ public class JobInstanceStatusUpdater { return false; } theJobInstance.setStatus(theNewStatus); + ourLog.debug("Updating job instance {} of type {} from {} to {}", theJobInstance.getInstanceId(), theJobInstance.getJobDefinitionId(), origStatus, theNewStatus); return updateInstance(theJobInstance); } 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 79da318bcb2..75c1e922609 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 @@ -43,6 +43,7 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/jobs/step/LoadIdsStepTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/jobs/step/LoadIdsStepTest.java index 699cbfcd54d..1e510b578ba 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/jobs/step/LoadIdsStepTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/jobs/step/LoadIdsStepTest.java @@ -6,6 +6,7 @@ import ca.uhn.fhir.batch2.jobs.chunk.PartitionedUrlChunkRangeJson; import ca.uhn.fhir.batch2.jobs.chunk.ResourceIdListWorkChunkJson; import ca.uhn.fhir.batch2.jobs.parameters.PartitionedUrlListJobParameters; import ca.uhn.fhir.batch2.model.JobInstance; +import ca.uhn.fhir.jpa.api.pid.EmptyResourcePidList; import ca.uhn.fhir.jpa.api.pid.HomogeneousResourcePidList; import ca.uhn.fhir.jpa.api.pid.IResourcePidList; import ca.uhn.fhir.jpa.api.svc.IBatch2DaoSvc; @@ -74,7 +75,9 @@ public class LoadIdsStepTest { when(myBatch2DaoSvc.fetchResourceIdsPage(eq(DATE_2), eq(DATE_END), eq(DEFAULT_PAGE_SIZE), isNull(), isNull())) .thenReturn(createIdChunk(20000L, 40000L, DATE_3)); when(myBatch2DaoSvc.fetchResourceIdsPage(eq(DATE_3), eq(DATE_END), eq(DEFAULT_PAGE_SIZE), isNull(), isNull())) - .thenReturn(createIdChunk(40000L, 40040L, DATE_3)); + .thenReturn(createIdChunk(40000L, 40040L, DATE_4)); + when(myBatch2DaoSvc.fetchResourceIdsPage(eq(DATE_4), eq(DATE_END), eq(DEFAULT_PAGE_SIZE), isNull(), isNull())) + .thenReturn(new EmptyResourcePidList()); mySvc.run(details, mySink); 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 8b3fcb05eb6..3768bb52267 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 @@ -38,6 +38,7 @@ import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.Future; +import java.util.stream.Collectors; import static ca.uhn.fhir.batch2.coordinator.JobCoordinatorImplTest.createWorkChunkStep1; import static org.awaitility.Awaitility.await; @@ -180,9 +181,12 @@ public class JobMaintenanceServiceImplTest extends BaseBatch2Test { JobCoordinatorImplTest.createWorkChunkStep2().setStatus(StatusEnum.QUEUED).setId(CHUNK_ID), JobCoordinatorImplTest.createWorkChunkStep2().setStatus(StatusEnum.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(StatusEnum.QUEUED))) + .thenReturn(chunks.stream().map(chunk -> chunk.getId()).collect(Collectors.toList())); JobInstance instance1 = createInstance(); instance1.setCurrentGatedStepId(STEP_1); when(myJobPersistence.fetchInstances(anyInt(), eq(0))).thenReturn(Lists.newArrayList(instance1)); diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index bf69f2b48ba..07ed13bd630 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index a9961d594b8..d7fb772809d 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index dacdee5290b..10f4772125a 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/interceptor/UserRequestRetryVersionConflictsInterceptor.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/interceptor/UserRequestRetryVersionConflictsInterceptor.java index ac0381d2ffc..9ad14b49d95 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/interceptor/UserRequestRetryVersionConflictsInterceptor.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/interceptor/UserRequestRetryVersionConflictsInterceptor.java @@ -25,6 +25,7 @@ import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.jpa.api.model.ResourceVersionConflictResolutionStrategy; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; +import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.RequestDetails; import org.apache.commons.lang3.Validate; @@ -46,39 +47,26 @@ import static org.apache.commons.lang3.StringUtils.trim; @Interceptor public class UserRequestRetryVersionConflictsInterceptor { + /** Deprecated and moved to {@link ca.uhn.fhir.rest.api.Constants#HEADER_RETRY_ON_VERSION_CONFLICT} */ + @Deprecated public static final String HEADER_NAME = "X-Retry-On-Version-Conflict"; + + /** Deprecated and moved to {@link ca.uhn.fhir.rest.api.Constants#HEADER_MAX_RETRIES} */ + @Deprecated public static final String MAX_RETRIES = "max-retries"; + + /** Deprecated and moved to {@link ca.uhn.fhir.rest.api.Constants#HEADER_RETRY} */ + @Deprecated public static final String RETRY = "retry"; @Hook(value = Pointcut.STORAGE_VERSION_CONFLICT, order = 100) public ResourceVersionConflictResolutionStrategy check(RequestDetails theRequestDetails) { ResourceVersionConflictResolutionStrategy retVal = new ResourceVersionConflictResolutionStrategy(); - - if (theRequestDetails != null) { - List headers = theRequestDetails.getHeaders(HEADER_NAME); - if (headers != null) { - for (String headerValue : headers) { - if (isNotBlank(headerValue)) { - - StringTokenizer tok = new StringTokenizer(headerValue, ";"); - while (tok.hasMoreTokens()) { - String next = trim(tok.nextToken()); - if (next.equals(RETRY)) { - retVal.setRetry(true); - } else if (next.startsWith(MAX_RETRIES + "=")) { - - String val = trim(next.substring((MAX_RETRIES + "=").length())); - int maxRetries = Integer.parseInt(val); - maxRetries = Math.min(100, maxRetries); - retVal.setMaxRetries(maxRetries); - - } - - } - - } - } - } + boolean shouldSetRetries = theRequestDetails != null && theRequestDetails.isRetry(); + if (shouldSetRetries) { + retVal.setRetry(true); + int maxRetries = Math.min(100, theRequestDetails.getMaxRetries()); + retVal.setMaxRetries(maxRetries); } return retVal; @@ -90,7 +78,7 @@ public class UserRequestRetryVersionConflictsInterceptor { */ public static void addRetryHeader(SystemRequestDetails theRequestDetails, int theMaxRetries) { Validate.inclusiveBetween(1, Integer.MAX_VALUE, theMaxRetries, "Max retries must be > 0"); - String value = RETRY + "; " + MAX_RETRIES + "=" + theMaxRetries; - theRequestDetails.addHeader(HEADER_NAME, value); + theRequestDetails.setRetry(true); + theRequestDetails.setMaxRetries(theMaxRetries); } } diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/searchparam/submit/interceptor/SearchParamValidatingInterceptor.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/searchparam/submit/interceptor/SearchParamValidatingInterceptor.java index 6903ff010cf..74bd16c5657 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/searchparam/submit/interceptor/SearchParamValidatingInterceptor.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/searchparam/submit/interceptor/SearchParamValidatingInterceptor.java @@ -92,11 +92,7 @@ public class SearchParamValidatingInterceptor { SearchParameterMap searchParameterMap = extractSearchParameterMap(runtimeSearchParam); if (searchParameterMap != null) { - if (isUpliftSearchParam(theResource)) { - validateUpliftSp(theRequestDetails, runtimeSearchParam, searchParameterMap); - } else { - validateStandardSpOnCreate(theRequestDetails, searchParameterMap); - } + validateStandardSpOnCreate(theRequestDetails, searchParameterMap); } } @@ -118,58 +114,10 @@ public class SearchParamValidatingInterceptor { SearchParameterMap searchParameterMap = extractSearchParameterMap(runtimeSearchParam); if (searchParameterMap != null) { - if (isUpliftSearchParam(theResource)) { - validateUpliftSp(theRequestDetails, runtimeSearchParam, searchParameterMap); - } else { - validateStandardSpOnUpdate(theRequestDetails, runtimeSearchParam, searchParameterMap); - } + validateStandardSpOnUpdate(theRequestDetails, runtimeSearchParam, searchParameterMap); } } - private void validateUpliftSp(RequestDetails theRequestDetails, @Nonnull RuntimeSearchParam theRuntimeSearchParam, SearchParameterMap theSearchParameterMap) { - Validate.notEmpty(getUpliftExtensions(), "You are attempting to validate an Uplift Search Parameter, but have not defined which URLs correspond to uplifted search parameter extensions."); - - IBundleProvider bundleProvider = getDao().search(theSearchParameterMap, theRequestDetails); - List allResources = bundleProvider.getAllResources(); - if(isNotEmpty(allResources)) { - Set existingIds = allResources.stream().map(resource -> resource.getIdElement().getIdPart()).collect(Collectors.toSet()); - if (isNewSearchParam(theRuntimeSearchParam, existingIds)) { - for (String upliftExtensionUrl: getUpliftExtensions()) { - boolean matchesExistingUplift = allResources.stream() - .map(sp -> mySearchParameterCanonicalizer.canonicalizeSearchParameter(sp)) - .filter(sp -> !sp.getExtensions(upliftExtensionUrl).isEmpty()) - .anyMatch(sp -> isDuplicateUpliftParameter(theRuntimeSearchParam, sp, upliftExtensionUrl)); - - if (matchesExistingUplift) { - throwDuplicateError(); - } - } - } - } - } - - private boolean isDuplicateUpliftParameter(RuntimeSearchParam theRuntimeSearchParam, RuntimeSearchParam theSp, String theUpliftUrl) { - String firstCode = getUpliftChildExtensionValueByUrl(theRuntimeSearchParam, "code", theUpliftUrl); - String secondCode = getUpliftChildExtensionValueByUrl(theSp, "code", theUpliftUrl); - String firstElementName = getUpliftChildExtensionValueByUrl(theRuntimeSearchParam, "element-name", theUpliftUrl); - String secondElementName = getUpliftChildExtensionValueByUrl(theSp, "element-name", theUpliftUrl); - return firstCode.equals(secondCode) && firstElementName.equals(secondElementName); - } - - - private String getUpliftChildExtensionValueByUrl(RuntimeSearchParam theSp, String theUrl, String theUpliftUrl) { - List> extensions = theSp.getExtensions(theUpliftUrl); - Validate.isTrue(extensions.size() == 1); - IBaseExtension topLevelExtension = extensions.get(0); - List extension = (List) topLevelExtension.getExtension(); - String subExtensionValue = extension.stream().filter(ext -> ext.getUrl().equals(theUrl)).map(IBaseExtension::getValue) - .map(IPrimitiveType.class::cast) - .map(IPrimitiveType::getValueAsString) - .findFirst() - .orElseThrow(() -> new UnprocessableEntityException(Msg.code(2198), "Unable to process Uplift SP addition as the SearchParameter is malformed.")); - return subExtensionValue; - } - private boolean isNewSearchParam(RuntimeSearchParam theSearchParam, Set theExistingIds) { return theExistingIds .stream() @@ -190,17 +138,6 @@ public class SearchParamValidatingInterceptor { throw new UnprocessableEntityException(Msg.code(2125) + "Can't process submitted SearchParameter as it is overlapping an existing one."); } - private boolean isUpliftSearchParam(IBaseResource theResource) { - if (theResource instanceof IBaseHasExtensions) { - IBaseHasExtensions resource = (IBaseHasExtensions) theResource; - return resource.getExtension() - .stream() - .anyMatch(ext -> getUpliftExtensions().contains(ext.getUrl())); - } else { - return false; - } - } - private boolean isNotSearchParameterResource(IBaseResource theResource){ return ! SEARCH_PARAM.equalsIgnoreCase(myFhirContext.getResourceType(theResource)); } diff --git a/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/SearchParameterValidatingInterceptorTest.java b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/SearchParameterValidatingInterceptorTest.java index fd29849fb30..8fbfe3c99d4 100644 --- a/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/SearchParameterValidatingInterceptorTest.java +++ b/hapi-fhir-storage/src/test/java/ca/uhn/fhir/jpa/interceptor/validation/SearchParameterValidatingInterceptorTest.java @@ -146,54 +146,6 @@ public class SearchParameterValidatingInterceptorTest { } - @Test - public void whenUpliftSearchParameter_thenMoreGranularComparisonSucceeds() { - when(myDaoRegistry.getResourceDao(eq(SearchParamValidatingInterceptor.SEARCH_PARAM))).thenReturn(myIFhirResourceDao); - - setPersistedSearchParameters(asList(myExistingSearchParameter)); - - SearchParameter newSearchParam = buildSearchParameterWithUpliftExtension(ID2); - - mySearchParamValidatingInterceptor.resourcePreUpdate(null, newSearchParam, myRequestDetails); - } - - @Test - public void whenUpliftSearchParameter_thenMoreGranularComparisonFails() { - when(myDaoRegistry.getResourceDao(eq(SearchParamValidatingInterceptor.SEARCH_PARAM))).thenReturn(myIFhirResourceDao); - SearchParameter existingUpliftSp = buildSearchParameterWithUpliftExtension(ID1); - setPersistedSearchParameters(asList(existingUpliftSp)); - - SearchParameter newSearchParam = buildSearchParameterWithUpliftExtension(ID2); - - try { - mySearchParamValidatingInterceptor.resourcePreUpdate(null, newSearchParam, myRequestDetails); - fail(); - } catch (UnprocessableEntityException e) { - assertTrue(e.getMessage().contains("2125")); - } - } - - @Nonnull - private SearchParameter buildSearchParameterWithUpliftExtension(String theID) { - SearchParameter newSearchParam = buildSearchParameterWithId(theID); - - Extension topLevelExtension = new Extension(); - topLevelExtension.setUrl(UPLIFT_URL); - - Extension codeExtension = new Extension(); - codeExtension.setUrl("code"); - codeExtension.setValue(new CodeType("identifier")); - - Extension elementExtension = new Extension(); - elementExtension.setUrl("element-name"); - elementExtension.setValue(new CodeType("patient-identifier")); - - topLevelExtension.addExtension(codeExtension); - topLevelExtension.addExtension(elementExtension); - newSearchParam.addExtension(topLevelExtension); - return newSearchParam; - } - private void setPersistedSearchParameterIds(List theSearchParams) { List resourcePersistentIds = theSearchParams .stream() @@ -203,9 +155,6 @@ public class SearchParameterValidatingInterceptorTest { when(myIFhirResourceDao.searchForIds(any(), any())).thenReturn(resourcePersistentIds); } - private void setPersistedSearchParameters(List theSearchParams) { - when(myIFhirResourceDao.search(any(), any())).thenReturn(new SimpleBundleProvider(theSearchParams)); - } private SearchParameter buildSearchParameterWithId(String id) { SearchParameter retVal = new SearchParameter(); diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 082d48fd675..c8d3e773720 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 987b2345f44..ead0e7a428e 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index a22c13c8c50..7c58d7360c3 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 5138d1de44c..a741082fe19 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 387c63d5552..cdc42d9eb54 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index 630dbdbb8d1..3791b658748 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index dece4553872..edcf552eef2 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index b1c0a4d97b8..5c8559ec5db 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/system/HapiTestSystemProperties.java b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/system/HapiTestSystemProperties.java index afbc174c4f8..efd19f7e73c 100644 --- a/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/system/HapiTestSystemProperties.java +++ b/hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/system/HapiTestSystemProperties.java @@ -1,5 +1,25 @@ package ca.uhn.fhir.system; +/*- + * #%L + * HAPI FHIR Test Utilities + * %% + * Copyright (C) 2014 - 2022 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% + */ + public final class HapiTestSystemProperties { private static final String MASS_INGESTION_MODE = "mass_ingestion_mode"; private static final String SINGLE_DB_CONNECTION = "single_db_connection"; diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 56cc8d5c6f5..e35f60e3bfb 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index 0f4fe66a88f..3165748424a 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 6701f2e7d4d..f942c0487f8 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 5cab58201cf..12a2a9d62d8 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 20bd4e14c3e..b6ca945f0f4 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 9c7518dcc24..ae52667cf94 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 2833dc64474..cbe0e7f6cac 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 06445471bc3..13c0527c46e 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index 01850262332..11c48358944 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index cbc4979eadc..737d0de5cbe 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. https://hapifhir.io @@ -2102,7 +2102,7 @@ ca.uhn.hapi.fhir hapi-fhir-checkstyle - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index 083ea4078fb..afa2b2bbf9e 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 ddb24aca1a0..afa380d3ce3 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-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 9745bf1c374..45b78c07508 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 - 6.3.0-PRE4-SNAPSHOT + 6.3.0-PRE5-SNAPSHOT ../../pom.xml