diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml
index f355e618585..da68153960c 100644
--- a/hapi-deployable-pom/pom.xml
+++ b/hapi-deployable-pom/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index 133fc5b84a3..87e1a34e732 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml
index d462afc3955..33f1131d643 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/i18n/Msg.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/i18n/Msg.java
index d330f036673..645b10e659d 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/i18n/Msg.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/i18n/Msg.java
@@ -25,7 +25,7 @@ public final class Msg {
/**
* IMPORTANT: Please update the following comment after you add a new code
- * Last code value: 2073
+ * Last code value: 2075
*/
private Msg() {}
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 cf0ffaaeda6..c66c2b8296a 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
@@ -85,7 +85,7 @@ public class Constants {
public static final String EXTOP_VALIDATE_RESOURCE = "resource";
public static final String FORMAT_HTML = "html";
public static final String FORMAT_JSON = "json";
- public static final String FORMAT_NDJSON = "ndjson";
+ public static final String FORMAT_NDJSON = "ndjson";
public static final String FORMAT_XML = "xml";
public static final String CT_RDF_TURTLE_LEGACY = "text/turtle";
public static final String FORMAT_TURTLE = "ttl";
@@ -285,6 +285,7 @@ public class Constants {
* key will be of type {@link ca.uhn.fhir.interceptor.model.RequestPartitionId}.
*/
public static final String RESOURCE_PARTITION_ID = Constants.class.getName() + "_RESOURCE_PARTITION_ID";
+ public static final String PARTITION_IDS = "partitionIds";
public static final String CT_APPLICATION_GZIP = "application/gzip";
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final String SUBSCRIPTION_MULTITYPE_PREFIX = "[";
diff --git a/hapi-fhir-batch/pom.xml b/hapi-fhir-batch/pom.xml
index 1f1d66e96f0..2772d9bc7df 100644
--- a/hapi-fhir-batch/pom.xml
+++ b/hapi-fhir-batch/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml
index a12b5cdae53..56570535d76 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
pom
HAPI FHIR BOM
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml
index 4c844ee23ad..b4e608a18b8 100644
--- a/hapi-fhir-checkstyle/pom.xml
+++ b/hapi-fhir-checkstyle/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 066edbc4620..e5baefcefcc 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml
index d9a94154152..8ba8d4ec4fe 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 804231857ea..f960b2aaf83 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../../hapi-deployable-pom
diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml
index f77fb638d69..ac947055ef7 100644
--- a/hapi-fhir-cli/pom.xml
+++ b/hapi-fhir-cli/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml
index ec6e3695a25..9b6f9c2afd9 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml
index 39788725a86..888c2a7351f 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml
index 674f0d6ba85..ab42df96803 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml
index cc9995e267f..c91ddfa728a 100644
--- a/hapi-fhir-dist/pom.xml
+++ b/hapi-fhir-dist/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml
index 694fc7f8c28..63aaa6b1269 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml
index c6d0495f30a..b13bae1377d 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index 0a9f6b0184e..5334eefc48c 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml
index cbcee55b472..d265bab29ec 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index fe123ed2975..7e1d64298a8 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch/mdm/job/ReverseCronologicalBatchMdmLinkPidReader.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch/mdm/job/ReverseCronologicalBatchMdmLinkPidReader.java
index 2d4a483fb1f..816db083fb1 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch/mdm/job/ReverseCronologicalBatchMdmLinkPidReader.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch/mdm/job/ReverseCronologicalBatchMdmLinkPidReader.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.batch.mdm.job;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.batch.reader.BaseReverseCronologicalBatchPidReader;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.searchparam.ResourceSearch;
@@ -28,6 +29,7 @@ import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
/**
@@ -41,8 +43,13 @@ public class ReverseCronologicalBatchMdmLinkPidReader extends BaseReverseCronolo
protected Set getNextPidBatch(ResourceSearch resourceSearch) {
String resourceName = resourceSearch.getResourceName();
Pageable pageable = PageRequest.of(0, getBatchSize());
+ RequestPartitionId requestPartitionId = resourceSearch.getRequestPartitionId();
+ if (requestPartitionId.isAllPartitions()){
+ return new HashSet<>(myMdmLinkDao.findPidByResourceNameAndThreshold(resourceName, getCurrentHighThreshold(), pageable));
+ }
+ List partitionIds = requestPartitionId.getPartitionIds();
//Expand out the list to handle the REDIRECT/POSSIBLE DUPLICATE ones.
- return new HashSet<>(myMdmLinkDao.findPidByResourceNameAndThreshold(resourceName, getCurrentHighThreshold(), pageable));
+ return new HashSet<>(myMdmLinkDao.findPidByResourceNameAndThresholdAndPartitionId(resourceName, getCurrentHighThreshold(), partitionIds, pageable));
}
@Override
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkDao.java
index 8a366cdfaa8..08f3904fbd2 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkDao.java
@@ -73,4 +73,7 @@ public interface IMdmLinkDao extends JpaRepository, IHapiFhirJpaR
@Query("SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold ORDER BY ml.myCreated DESC")
List findPidByResourceNameAndThreshold(@Param("resourceName") String theResourceName, @Param("highThreshold") Date theHighThreshold, Pageable thePageable);
+
+ @Query("SELECT ml.myId FROM MdmLink ml WHERE ml.myMdmSourceType = :resourceName AND ml.myCreated <= :highThreshold AND ml.myPartitionIdValue IN :partitionId ORDER BY ml.myCreated DESC")
+ List findPidByResourceNameAndThresholdAndPartitionId(@Param("resourceName") String theResourceName, @Param("highThreshold") Date theHighThreshold, @Param("partitionId") List thePartitionIds, Pageable thePageable);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/MdmLink.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/MdmLink.java
index 8a09013cca2..1934c3fc60e 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/MdmLink.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/MdmLink.java
@@ -20,10 +20,11 @@ package ca.uhn.fhir.jpa.entity;
* #L%
*/
+import ca.uhn.fhir.jpa.model.entity.BasePartitionable;
+import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
-import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import org.apache.commons.lang3.builder.ToStringBuilder;
import javax.persistence.Column;
@@ -52,7 +53,7 @@ import java.util.Date;
//TODO GGG revisit adding this: @UniqueConstraint(name = "IDX_EMPI_GR_TGT", columnNames = {"GOLDEN_RESOURCE_PID", "TARGET_PID"}),
//TODO GGG Should i make individual indices for PERSON/TARGET?
})
-public class MdmLink implements IMdmLink {
+public class MdmLink extends BasePartitionable implements IMdmLink {
public static final int VERSION_LENGTH = 16;
private static final int MATCH_RESULT_LENGTH = 16;
private static final int LINK_SOURCE_LENGTH = 16;
@@ -331,6 +332,7 @@ public class MdmLink implements IMdmLink {
.append("myHadToCreateNewResource", myHadToCreateNewGoldenResource)
.append("myScore", myScore)
.append("myRuleCount", myRuleCount)
+ .append("myPartitionId", getPartitionId())
.toString();
}
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 58b9f66a28f..e1186bc9113 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
@@ -49,11 +49,12 @@ import java.util.stream.Collectors;
@SuppressWarnings({"SqlNoDataSourceInspection", "SpellCheckingInspection"})
public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
- // H2, Derby, MariaDB, and MySql automatically add indexes to foreign keys
- public static final DriverTypeEnum[] NON_AUTOMATIC_FK_INDEX_PLATFORMS = new DriverTypeEnum[] {
- DriverTypeEnum.POSTGRES_9_4, DriverTypeEnum.ORACLE_12C, DriverTypeEnum.MSSQL_2012 };
private final Set myFlags;
+ // H2, Derby, MariaDB, and MySql automatically add indexes to foreign keys
+ public static final DriverTypeEnum[] NON_AUTOMATIC_FK_INDEX_PLATFORMS = new DriverTypeEnum[]{
+ DriverTypeEnum.POSTGRES_9_4, DriverTypeEnum.ORACLE_12C, DriverTypeEnum.MSSQL_2012};
+
/**
* Constructor
@@ -434,14 +435,14 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
*/
private void addIndexesForDeleteExpunge(Builder theVersion) {
- theVersion.onTable( "HFJ_HISTORY_TAG")
- .addIndex("20211210.2", "IDX_RESHISTTAG_RESID" )
+ theVersion.onTable("HFJ_HISTORY_TAG")
+ .addIndex("20211210.2", "IDX_RESHISTTAG_RESID")
.unique(false)
.withColumns("RES_ID");
- theVersion.onTable( "HFJ_RES_VER_PROV")
- .addIndex("20211210.3", "FK_RESVERPROV_RES_PID" )
+ theVersion.onTable("HFJ_RES_VER_PROV")
+ .addIndex("20211210.3", "FK_RESVERPROV_RES_PID")
.unique(false)
.withColumns("RES_PID")
.onlyAppliesToPlatforms(NON_AUTOMATIC_FK_INDEX_PLATFORMS);
@@ -494,6 +495,15 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
.nullable()
.type(ColumnTypeEnum.STRING, 4000);
+ // Add partition id column for mdm
+ Builder.BuilderWithTableName empiLink = version.onTable("MPI_LINK");
+
+ empiLink.addColumn("20220324.1", "PARTITION_ID")
+ .nullable()
+ .type(ColumnTypeEnum.INT);
+ empiLink.addColumn("20220324.2", "PARTITION_DATE")
+ .nullable()
+ .type(ColumnTypeEnum.DATE_ONLY);
}
@@ -523,15 +533,15 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
// Bump ConceptMap display lengths
version.onTable("TRM_CONCEPT_MAP_GRP_ELM_TGT")
- .modifyColumn("20210617.1","TARGET_DISPLAY").nullable().withType(ColumnTypeEnum.STRING, 500);
+ .modifyColumn("20210617.1", "TARGET_DISPLAY").nullable().withType(ColumnTypeEnum.STRING, 500);
version.onTable("TRM_CONCEPT_MAP_GRP_ELEMENT")
.modifyColumn("20210617.2", "SOURCE_DISPLAY").nullable().withType(ColumnTypeEnum.STRING, 500);
version.onTable("HFJ_BLK_EXPORT_JOB")
- .modifyColumn("20210624.1","REQUEST").nonNullable().withType(ColumnTypeEnum.STRING, 1024);
+ .modifyColumn("20210624.1", "REQUEST").nonNullable().withType(ColumnTypeEnum.STRING, 1024);
version.onTable("HFJ_IDX_CMP_STRING_UNIQ")
- .modifyColumn("20210713.1","IDX_STRING").nonNullable().withType(ColumnTypeEnum.STRING, 500);
+ .modifyColumn("20210713.1", "IDX_STRING").nonNullable().withType(ColumnTypeEnum.STRING, 500);
version.onTable("HFJ_RESOURCE")
.addColumn("20210720.1", "SP_CMPTOKS_PRESENT").nullable().type(ColumnTypeEnum.BOOLEAN);
@@ -563,7 +573,7 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
.addColumn("20210915.1", "EXPANDED_AT")
.nullable()
.type(ColumnTypeEnum.DATE_TIMESTAMP);
-
+
/*
* Replace CLOB columns with BLOB columns
*/
@@ -579,7 +589,6 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
// HFJ_SEARCH.SEARCH_QUERY_STRING
version.onTable("HFJ_SEARCH")
.migratePostgresTextClobToBinaryClob("20211003.3", "SEARCH_QUERY_STRING");
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java
index 4102f4bf746..07c7dccc5f6 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/partition/RequestPartitionHelperSvc.java
@@ -37,6 +37,8 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
+import ca.uhn.fhir.util.StringUtil;
+import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@@ -249,7 +251,7 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
* If the partition has both, they are validated to ensure that they correspond.
*/
@Nonnull
- private RequestPartitionId validateNormalizeAndNotifyHooksForRead(@Nonnull RequestPartitionId theRequestPartitionId, RequestDetails theRequest, String theResourceType) {
+ private RequestPartitionId validateNormalizeAndNotifyHooksForRead(@Nonnull RequestPartitionId theRequestPartitionId, RequestDetails theRequest, @Nonnull String theResourceType) {
RequestPartitionId retVal = theRequestPartitionId;
if (retVal.getPartitionNames() != null) {
@@ -260,18 +262,25 @@ public class RequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
// Note: It's still possible that the partition only has a date but no name/id
+ if (StringUtils.isNotBlank(theResourceType)) {
+ validateHasPartitionPermissions(theRequest, theResourceType, retVal);
+ }
+
+ return retVal;
+
+ }
+
+ public void validateHasPartitionPermissions(RequestDetails theRequest, String theResourceType, RequestPartitionId theRequestPartitionId) {
if (myInterceptorBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_SELECTED)) {
- RuntimeResourceDefinition runtimeResourceDefinition = myFhirContext.getResourceDefinition(theResourceType);
+ RuntimeResourceDefinition runtimeResourceDefinition;
+ runtimeResourceDefinition = myFhirContext.getResourceDefinition(theResourceType);
HookParams params = new HookParams()
- .add(RequestPartitionId.class, retVal)
+ .add(RequestPartitionId.class, theRequestPartitionId)
.add(RequestDetails.class, theRequest)
.addIfMatchesType(ServletRequestDetails.class, theRequest)
.add(RuntimeResourceDefinition.class, runtimeResourceDefinition);
doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PARTITION_SELECTED, params);
}
-
- return retVal;
-
}
private RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) {
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaResourceLoader.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaResourceLoader.java
index 8cf7fdfaf85..9f9e56e1c23 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaResourceLoader.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/validation/JpaResourceLoader.java
@@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.validation;
*/
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.validation.IResourceLoader;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -35,6 +36,7 @@ public class JpaResourceLoader implements IResourceLoader {
@Override
public T load(Class theType, IIdType theId) throws ResourceNotFoundException {
- return myDaoRegistry.getResourceDao(theType).read(theId);
+ SystemRequestDetails systemRequestDetails = SystemRequestDetails.forAllPartitions();
+ return myDaoRegistry.getResourceDao(theType).read(theId, systemRequestDetails);
}
}
diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml
index 88c8303e659..00a7850e6f1 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml
index 1dbf2e29ca4..e158b4c1c91 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/broker/MdmMessageHandler.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/broker/MdmMessageHandler.java
index 41a30250705..e8e2b575ad5 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/broker/MdmMessageHandler.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/broker/MdmMessageHandler.java
@@ -37,6 +37,7 @@ import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmLinkEvent;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage;
@@ -166,7 +167,9 @@ public class MdmMessageHandler implements MessageHandler {
}
private IAnyResource getResourceFromPayload(ResourceModifiedMessage theMsg) {
- return (IAnyResource) theMsg.getNewPayload(myFhirContext);
+ IBaseResource newPayload = theMsg.getNewPayload(myFhirContext);
+ newPayload.setUserData(Constants.RESOURCE_PARTITION_ID, theMsg.getPartitionId());
+ return (IAnyResource) newPayload;
}
private void handleUpdateResource(ResourceModifiedMessage theMsg, MdmTransactionContext theMdmTransactionContext) {
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
index 2316df7165e..52e69e34d3d 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmConsumerConfig.java
@@ -51,6 +51,8 @@ import ca.uhn.fhir.jpa.mdm.svc.candidate.FindCandidateByLinkSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchCriteriaBuilderSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
+import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
+import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
@@ -244,12 +246,14 @@ public class MdmConsumerConfig {
IResourceLoader theResourceLoader,
IMdmSettings theMdmSettings,
IMdmMatchFinderSvc theMdmMatchFinderSvc,
- MessageHelper messageHelper) {
+ MessageHelper messageHelper,
+ IRequestPartitionHelperSvc partitionHelperSvc) {
return new MdmControllerHelper(theFhirContext,
theResourceLoader,
theMdmMatchFinderSvc,
theMdmSettings,
- messageHelper);
+ messageHelper,
+ partitionHelperSvc);
}
@Bean
@@ -257,4 +261,6 @@ public class MdmConsumerConfig {
return new MdmControllerSvcImpl();
}
+ @Bean
+ MdmPartitionHelper mdmPartitionHelper() {return new MdmPartitionHelper();}
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoader.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoader.java
index b3ea94080cd..1a129b73867 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoader.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoader.java
@@ -25,6 +25,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
@@ -33,7 +34,9 @@ import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
+import ca.uhn.fhir.util.HapiExtensions;
import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Subscription;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
@@ -88,10 +91,10 @@ public class MdmSubscriptionLoader {
synchronized void updateIfNotPresent(IBaseResource theSubscription) {
try {
- mySubscriptionDao.read(theSubscription.getIdElement());
+ mySubscriptionDao.read(theSubscription.getIdElement(), SystemRequestDetails.forAllPartitions());
} catch (ResourceNotFoundException | ResourceGoneException e) {
- ourLog.info("Creating subsription " + theSubscription.getIdElement());
- mySubscriptionDao.update(theSubscription);
+ ourLog.info("Creating subscription " + theSubscription.getIdElement());
+ mySubscriptionDao.update(theSubscription, SystemRequestDetails.forAllPartitions());
}
}
@@ -102,6 +105,7 @@ public class MdmSubscriptionLoader {
retval.setStatus(org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus.REQUESTED);
retval.setCriteria(theCriteria);
retval.getMeta().addTag().setSystem(MdmConstants.SYSTEM_MDM_MANAGED).setCode(MdmConstants.CODE_HAPI_MDM_MANAGED);
+ retval.addExtension().setUrl(HapiExtensions.EXTENSION_SUBSCRIPTION_CROSS_PARTITION).setValue(new org.hl7.fhir.dstu3.model.BooleanType().setValue(true));
org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelComponent channel = retval.getChannel();
channel.setType(org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType.MESSAGE);
channel.setEndpoint("channel:" + myChannelNamer.getChannelName(IMdmSettings.EMPI_CHANNEL_NAME, new ChannelProducerSettings()));
@@ -116,6 +120,7 @@ public class MdmSubscriptionLoader {
retval.setStatus(Subscription.SubscriptionStatus.REQUESTED);
retval.setCriteria(theCriteria);
retval.getMeta().addTag().setSystem(MdmConstants.SYSTEM_MDM_MANAGED).setCode(MdmConstants.CODE_HAPI_MDM_MANAGED);
+ retval.addExtension().setUrl(HapiExtensions.EXTENSION_SUBSCRIPTION_CROSS_PARTITION).setValue(new BooleanType().setValue(true));
Subscription.SubscriptionChannelComponent channel = retval.getChannel();
channel.setType(Subscription.SubscriptionChannelType.MESSAGE);
channel.setEndpoint("channel:" + myChannelNamer.getChannelName(IMdmSettings.EMPI_CHANNEL_NAME, new ChannelProducerSettings()));
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/dao/MdmLinkDaoSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/dao/MdmLinkDaoSvc.java
index afd66b90280..1212bb4a7ba 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/dao/MdmLinkDaoSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/dao/MdmLinkDaoSvc.java
@@ -21,26 +21,42 @@ package ca.uhn.fhir.jpa.mdm.dao;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
+import ca.uhn.fhir.rest.api.Constants;
+import org.apache.commons.collections4.CollectionUtils;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.data.domain.Sort;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Expression;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -58,6 +74,8 @@ public class MdmLinkDaoSvc {
private IJpaIdHelperService myJpaIdHelperService;
@Autowired
private FhirContext myFhirContext;
+ @Autowired
+ protected EntityManager myEntityManager;
@Transactional
public MdmLink createOrUpdateLinkEntity(IBaseResource theGoldenResource, IBaseResource theSourceResource, MdmMatchOutcome theMatchOutcome, MdmLinkSourceEnum theLinkSource, @Nullable MdmTransactionContext theMdmTransactionContext) {
@@ -76,6 +94,11 @@ public class MdmLinkDaoSvc {
} else {
mdmLink.setScore(theMatchOutcome.score);
}
+ // Add partition for the mdm link if it's available in the source resource
+ RequestPartitionId partitionId = (RequestPartitionId) theSourceResource.getUserData(Constants.RESOURCE_PARTITION_ID);
+ if (partitionId != null && partitionId.getFirstPartitionIdOrNull() != null) {
+ mdmLink.setPartitionId(new PartitionablePartitionId(partitionId.getFirstPartitionIdOrNull(), partitionId.getPartitionDate()));
+ }
String message = String.format("Creating MdmLink from %s to %s -> %s", theGoldenResource.getIdElement().toUnqualifiedVersionless(), theSourceResource.getIdElement().toUnqualifiedVersionless(), theMatchOutcome);
theMdmTransactionContext.addTransactionLogMessage(message);
@@ -253,13 +276,57 @@ public class MdmLinkDaoSvc {
/**
- * Given an example {@link MdmLink}, return all links from the database which match the example.
+ * Given a list of criteria, return all links from the database which fits the criteria provided
*
- * @param theExampleLink The MDM link containing the data we would like to search for.
+ * @param theGoldenResourceId The resource ID of the golden resource being searched.
+ * @param theSourceId The resource ID of the source resource being searched.
+ * @param theMatchResult the {@link MdmMatchResultEnum} being searched.
+ * @param theLinkSource the {@link MdmLinkSourceEnum} being searched.
+ * @param thePageRequest the {@link MdmPageRequest} paging information
+ * @param thePartitionId List of partitions ID being searched, where the link's partition must be in the list.
* @return a list of {@link MdmLink} entities which match the example.
*/
- public Page findMdmLinkByExample(Example theExampleLink, MdmPageRequest thePageRequest) {
- return myMdmLinkDao.findAll(theExampleLink, thePageRequest.toPageRequest());
+ public PageImpl executeTypedQuery(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmPageRequest thePageRequest, List thePartitionId) {
+ CriteriaBuilder criteriaBuilder = myEntityManager.getCriteriaBuilder();
+ CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(MdmLink.class);
+ Root from = criteriaQuery.from(MdmLink.class);
+
+ List andPredicates = new ArrayList<>();
+
+ if (theGoldenResourceId != null) {
+ Predicate goldenResourcePredicate = criteriaBuilder.equal(from.get("myGoldenResourcePid").as(Long.class), myJpaIdHelperService.getPidOrThrowException(theGoldenResourceId));
+ andPredicates.add(goldenResourcePredicate);
+ }
+ if (theSourceId != null) {
+ Predicate sourceIdPredicate = criteriaBuilder.equal(from.get("mySourcePid").as(Long.class), myJpaIdHelperService.getPidOrThrowException(theSourceId));
+ andPredicates.add(sourceIdPredicate);
+ }
+ if (theMatchResult != null) {
+ Predicate matchResultPredicate = criteriaBuilder.equal(from.get("myMatchResult").as(MdmMatchResultEnum.class), theMatchResult);
+ andPredicates.add(matchResultPredicate);
+ }
+ if (theLinkSource != null) {
+ Predicate linkSourcePredicate = criteriaBuilder.equal(from.get("myLinkSource").as(MdmLinkSourceEnum.class), theLinkSource);
+ andPredicates.add(linkSourcePredicate);
+ }
+ if (!CollectionUtils.isEmpty(thePartitionId)) {
+ Expression exp = from.get("myPartitionId").get("myPartitionId").as(Integer.class);
+ Predicate linkSourcePredicate = exp.in(thePartitionId);
+ andPredicates.add(linkSourcePredicate);
+ }
+
+ Predicate finalQuery = criteriaBuilder.and(andPredicates.toArray(new Predicate[0]));
+ TypedQuery typedQuery = myEntityManager.createQuery(criteriaQuery.where(finalQuery));
+
+ CriteriaQuery countQuery = criteriaBuilder.createQuery(Long.class);
+ countQuery.select(criteriaBuilder.count(countQuery.from(MdmLink.class)))
+ .where(finalQuery);
+
+ Long totalResults = myEntityManager.createQuery(countQuery).getSingleResult();
+
+ return new PageImpl<>(typedQuery.setFirstResult(thePageRequest.getOffset()).setMaxResults(thePageRequest.getCount()).getResultList(),
+ PageRequest.of(thePageRequest.getPage(), thePageRequest.getCount()),
+ totalResults);
}
/**
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java
index 86352d5e221..7b0ed9f41f0 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/GoldenResourceMergerSvcImpl.java
@@ -24,6 +24,7 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
+import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@@ -32,6 +33,7 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
+import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@@ -58,6 +60,10 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
IJpaIdHelperService myIdHelperService;
@Autowired
MdmResourceDaoSvc myMdmResourceDaoSvc;
+ @Autowired
+ MessageHelper myMessageHelper;
+ @Autowired
+ MdmPartitionHelper myMdmPartitionHelper;
@Override
@Transactional
@@ -82,6 +88,9 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
myMdmResourceDaoSvc.upsertGoldenResource(theToGoldenResource, resourceType);
}
+ // check if the golden resource and the source resource are in the same partition, throw error if not
+ myMdmPartitionHelper.validateResourcesInSamePartition(theFromGoldenResource, theToGoldenResource);
+
//Merge the links from the FROM to the TO resource. Clean up dangling links.
mergeGoldenResourceLinks(theFromGoldenResource, theToGoldenResource, toGoldenResourcePid, theMdmTransactionContext);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmChannelSubmitterSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmChannelSubmitterSvcImpl.java
index fcad44daf7f..cd4d41e61b8 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmChannelSubmitterSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmChannelSubmitterSvcImpl.java
@@ -21,12 +21,14 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
import ca.uhn.fhir.mdm.api.IMdmChannelSubmitterSvc;
import ca.uhn.fhir.mdm.log.Logs;
+import ca.uhn.fhir.rest.api.Constants;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
@@ -50,7 +52,7 @@ public class MdmChannelSubmitterSvcImpl implements IMdmChannelSubmitterSvc {
@Override
public void submitResourceToMdmChannel(IBaseResource theResource) {
ResourceModifiedJsonMessage resourceModifiedJsonMessage = new ResourceModifiedJsonMessage();
- ResourceModifiedMessage resourceModifiedMessage = new ResourceModifiedMessage(myFhirContext, theResource, ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED);
+ ResourceModifiedMessage resourceModifiedMessage = new ResourceModifiedMessage(myFhirContext, theResource, ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED, null, (RequestPartitionId) theResource.getUserData(Constants.RESOURCE_PARTITION_ID));
resourceModifiedMessage.setOperationType(ResourceModifiedMessage.OperationTypeEnum.MANUALLY_TRIGGERED);
resourceModifiedJsonMessage.setPayload(resourceModifiedMessage);
boolean success = getMdmChannelProducer().send(resourceModifiedJsonMessage);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
index 3399fd7617e..87aad2e4742 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImpl.java
@@ -21,6 +21,8 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmBatchJobSubmitterFactory;
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
@@ -34,6 +36,8 @@ import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.provider.MdmControllerHelper;
import ca.uhn.fhir.mdm.provider.MdmControllerUtil;
+import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.provider.MultiUrlProcessor;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@@ -47,7 +51,9 @@ import org.springframework.stereotype.Service;
import javax.annotation.Nullable;
import java.math.BigDecimal;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/**
* This class acts as a layer between MdmProviders and MDM services to support a REST API that's not a FHIR Operation API.
@@ -69,6 +75,8 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
IMdmLinkCreateSvc myIMdmLinkCreateSvc;
@Autowired
IMdmBatchJobSubmitterFactory myMdmBatchJobSubmitterFactory;
+ @Autowired
+ IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
public MdmControllerSvcImpl() {
}
@@ -86,11 +94,33 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
@Override
public Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest) {
+ return queryLinksFromPartitionList(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, theMdmTransactionContext, thePageRequest, null);
+ }
+
+
+ @Override
+ public Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, @Nullable RequestDetails theRequestDetails) {
+ RequestPartitionId theReadPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequest(theRequestDetails, null, null);
+ Page resultPage;
+ if (theReadPartitionId.hasPartitionIds()) {
+ resultPage = queryLinksFromPartitionList(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, theMdmTransactionContext, thePageRequest, theReadPartitionId.getPartitionIds());
+ validateMdmQueryPermissions(theReadPartitionId, resultPage.getContent(), theRequestDetails);
+ }
+ else {
+ resultPage = queryLinksFromPartitionList(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, theMdmTransactionContext, thePageRequest, null);
+ }
+
+ return resultPage;
+ }
+
+ @Override
+ public Page queryLinksFromPartitionList(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, @Nullable List thePartitionIds) {
IIdType goldenResourceId = MdmControllerUtil.extractGoldenResourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId);
IIdType sourceId = MdmControllerUtil.extractSourceIdDtOrNull(ProviderConstants.MDM_QUERY_LINKS_RESOURCE_ID, theSourceResourceId);
MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
MdmLinkSourceEnum linkSource = MdmControllerUtil.extractLinkSourceOrNull(theLinkSource);
- return myMdmLinkQuerySvc.queryLinks(goldenResourceId, sourceId, matchResult, linkSource, theMdmTransactionContext, thePageRequest);
+
+ return myMdmLinkQuerySvc.queryLinks(goldenResourceId, sourceId, matchResult, linkSource, theMdmTransactionContext, thePageRequest, thePartitionIds);
}
@Override
@@ -98,6 +128,22 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
return myMdmLinkQuerySvc.getDuplicateGoldenResources(theMdmTransactionContext, thePageRequest);
}
+ @Override
+ public Page getDuplicateGoldenResources(MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, RequestDetails theRequestDetails) {
+ Page resultPage;
+ RequestPartitionId readPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequest(theRequestDetails, null, null);
+ if (readPartitionId.isAllPartitions()){
+ resultPage = myMdmLinkQuerySvc.getDuplicateGoldenResources(theMdmTransactionContext, thePageRequest);
+ }
+ else {
+ resultPage = myMdmLinkQuerySvc.getDuplicateGoldenResources(theMdmTransactionContext, thePageRequest, readPartitionId.getPartitionIds());
+ }
+
+ validateMdmQueryPermissions(readPartitionId, resultPage.getContent(), theRequestDetails);
+
+ return resultPage;
+ }
+
@Override
public IAnyResource updateLink(String theGoldenResourceId, String theSourceResourceId, String theMatchResult, MdmTransactionContext theMdmTransactionContext) {
MdmMatchResultEnum matchResult = MdmControllerUtil.extractMatchResultOrNull(theMatchResult);
@@ -133,4 +179,16 @@ public class MdmControllerSvcImpl implements IMdmControllerSvc {
myIMdmLinkUpdaterSvc.notDuplicateGoldenResource(goldenResource, target, theMdmTransactionContext);
}
+
+ private void validateMdmQueryPermissions(RequestPartitionId theRequestPartitionId, List theMdmLinkJsonList, RequestDetails theRequestDetails){
+ Set seenResourceTypes = new HashSet<>();
+ for (MdmLinkJson mdmLinkJson : theMdmLinkJsonList){
+ IdDt idDt = new IdDt(mdmLinkJson.getSourceId());
+
+ if (!seenResourceTypes.contains(idDt.getResourceType())){
+ myRequestPartitionHelperSvc.validateHasPartitionPermissions(theRequestDetails, idDt.getResourceType(), theRequestPartitionId);
+ seenResourceTypes.add(idDt.getResourceType());
+ }
+ }
+ }
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkCreateSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkCreateSvcImpl.java
index 974f0131958..649b1bc46e7 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkCreateSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkCreateSvcImpl.java
@@ -21,10 +21,14 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
+import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
+import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.mdm.api.IMdmLinkCreateSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@@ -33,6 +37,7 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@@ -56,6 +61,8 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
IMdmSettings myMdmSettings;
@Autowired
MessageHelper myMessageHelper;
+ @Autowired
+ MdmPartitionHelper myMdmPartitionHelper;
@Transactional
@Override
@@ -67,6 +74,9 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
+ // check if the golden resource and the source resource are in the same partition, throw error if not
+ myMdmPartitionHelper.validateResourcesInSamePartition(theGoldenResource, theSourceResource);
+
Optional optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (optionalMdmLink.isPresent()) {
throw new InvalidRequestException(Msg.code(753) + myMessageHelper.getMessageForPresentLink(theGoldenResource, theSourceResource));
@@ -84,6 +94,12 @@ public class MdmLinkCreateSvcImpl implements IMdmLinkCreateSvc {
} else {
mdmLink.setMatchResult(theMatchResult);
}
+ // Add partition for the mdm link if it doesn't exist
+ RequestPartitionId goldenResourcePartitionId = (RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
+ if (goldenResourcePartitionId != null && goldenResourcePartitionId.hasPartitionIds() && goldenResourcePartitionId.getFirstPartitionIdOrNull() != null &&
+ (mdmLink.getPartitionId() == null || mdmLink.getPartitionId().getPartitionId() == null)) {
+ mdmLink.setPartitionId(new PartitionablePartitionId(goldenResourcePartitionId.getFirstPartitionIdOrNull(), goldenResourcePartitionId.getPartitionDate()));
+ }
ourLog.info("Manually creating a " + theGoldenResource.getIdElement().toVersionless() + " to " + theSourceResource.getIdElement().toVersionless() + " mdm link.");
myMdmLinkDaoSvc.save(mdmLink);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
index 3e2773fc68b..e7be7b46279 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkQuerySvcImplSvc.java
@@ -20,7 +20,6 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
-import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
@@ -33,10 +32,11 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.transaction.annotation.Transactional;
+import java.util.List;
+
public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
private static final Logger ourLog = LoggerFactory.getLogger(MdmLinkQuerySvcImplSvc.class);
@@ -44,44 +44,33 @@ public class MdmLinkQuerySvcImplSvc implements IMdmLinkQuerySvc {
@Autowired
MdmLinkDaoSvc myMdmLinkDaoSvc;
- @Autowired
- IJpaIdHelperService myIdHelperService;
-
@Autowired
IMdmModelConverterSvc myMdmModelConverterSvc;
@Override
+ @Deprecated
@Transactional
public Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest) {
- Example exampleLink = exampleLinkFromParameters(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource);
- Page mdmLinkByExample = myMdmLinkDaoSvc.findMdmLinkByExample(exampleLink, thePageRequest);
- Page map = mdmLinkByExample.map(myMdmModelConverterSvc::toJson);
- return map;
+ return queryLinks(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, theMdmContext, thePageRequest, null);
+ }
+
+ @Override
+ @Transactional
+ public Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId) {
+ Page mdmLinks = myMdmLinkDaoSvc.executeTypedQuery(theGoldenResourceId, theSourceResourceId, theMatchResult, theLinkSource, thePageRequest, thePartitionId);
+ return mdmLinks.map(myMdmModelConverterSvc::toJson);
}
@Override
@Transactional
public Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest) {
- Example exampleLink = exampleLinkFromParameters(null, null, MdmMatchResultEnum.POSSIBLE_DUPLICATE, null);
- Page mdmLinkPage = myMdmLinkDaoSvc.findMdmLinkByExample(exampleLink, thePageRequest);
- Page map = mdmLinkPage.map(myMdmModelConverterSvc::toJson);
- return map;
+ return getDuplicateGoldenResources(theMdmContext, thePageRequest, null);
}
- private Example exampleLinkFromParameters(IIdType theGoldenResourceId, IIdType theSourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource) {
- MdmLink mdmLink = myMdmLinkDaoSvc.newMdmLink();
- if (theGoldenResourceId != null) {
- mdmLink.setGoldenResourcePid(myIdHelperService.getPidOrThrowException(theGoldenResourceId));
- }
- if (theSourceId != null) {
- mdmLink.setSourcePid(myIdHelperService.getPidOrThrowException(theSourceId));
- }
- if (theMatchResult != null) {
- mdmLink.setMatchResult(theMatchResult);
- }
- if (theLinkSource != null) {
- mdmLink.setLinkSource(theLinkSource);
- }
- return Example.of(mdmLink);
+ @Override
+ @Transactional
+ public Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId) {
+ Page mdmLinkPage = myMdmLinkDaoSvc.executeTypedQuery(null, null, MdmMatchResultEnum.POSSIBLE_DUPLICATE, null, thePageRequest, thePartitionId);
+ return mdmLinkPage.map(myMdmModelConverterSvc::toJson);
}
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImpl.java
index 1aa5d272dbf..07ccb9bcf42 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImpl.java
@@ -21,6 +21,12 @@ package ca.uhn.fhir.jpa.mdm.svc;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.dao.index.IdHelperService;
+import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
+import ca.uhn.fhir.jpa.mdm.util.MdmPartitionHelper;
+import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
@@ -35,6 +41,7 @@ import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.hl7.fhir.instance.model.api.IAnyResource;
@@ -67,6 +74,8 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
MessageHelper myMessageHelper;
@Autowired
IMdmSurvivorshipService myMdmSurvivorshipService;
+ @Autowired
+ MdmPartitionHelper myMdmPartitionHelper;
@Transactional
@Override
@@ -78,6 +87,9 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
Long goldenResourceId = myIdHelperService.getPidOrThrowException(theGoldenResource);
Long targetId = myIdHelperService.getPidOrThrowException(theSourceResource);
+ // check if the golden resource and the source resource are in the same partition, throw error if not
+ myMdmPartitionHelper.validateResourcesInSamePartition(theGoldenResource, theSourceResource);
+
Optional optionalMdmLink = myMdmLinkDaoSvc.getLinkByGoldenResourcePidAndSourceResourcePid(goldenResourceId, targetId);
if (!optionalMdmLink.isPresent()) {
throw new InvalidRequestException(Msg.code(738) + myMessageHelper.getMessageForNoLink(theGoldenResource, theSourceResource));
@@ -92,6 +104,13 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
ourLog.info("Manually updating MDM Link for " + theGoldenResource.getIdElement().toVersionless() + ", " + theSourceResource.getIdElement().toVersionless() + " from " + mdmLink.getMatchResult() + " to " + theMatchResult + ".");
mdmLink.setMatchResult(theMatchResult);
mdmLink.setLinkSource(MdmLinkSourceEnum.MANUAL);
+
+ // Add partition for the mdm link if it doesn't exist
+ RequestPartitionId goldenResourcePartitionId = (RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID);
+ if (goldenResourcePartitionId != null && goldenResourcePartitionId.hasPartitionIds() && goldenResourcePartitionId.getFirstPartitionIdOrNull() != null &&
+ (mdmLink.getPartitionId() == null || mdmLink.getPartitionId().getPartitionId() == null)) {
+ mdmLink.setPartitionId(new PartitionablePartitionId(goldenResourcePartitionId.getFirstPartitionIdOrNull(), goldenResourcePartitionId.getPartitionDate()));
+ }
myMdmLinkDaoSvc.save(mdmLink);
if (theMatchResult == MdmMatchResultEnum.MATCH) {
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchFinderSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchFinderSvcImpl.java
index df770f256b4..a224e14293c 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchFinderSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchFinderSvcImpl.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
import ca.uhn.fhir.mdm.api.MatchedTarget;
import ca.uhn.fhir.mdm.log.Logs;
@@ -49,8 +50,8 @@ public class MdmMatchFinderSvcImpl implements IMdmMatchFinderSvc {
@Override
@Nonnull
@Transactional
- public List getMatchedTargets(String theResourceType, IAnyResource theResource) {
- Collection targetCandidates = myMdmCandidateSearchSvc.findCandidates(theResourceType, theResource);
+ public List getMatchedTargets(String theResourceType, IAnyResource theResource, RequestPartitionId theRequestPartitionId) {
+ Collection targetCandidates = myMdmCandidateSearchSvc.findCandidates(theResourceType, theResource, theRequestPartitionId);
List matches = targetCandidates.stream()
.map(candidate -> new MatchedTarget(candidate, myMdmResourceMatcherSvc.getMatchResult(theResource, candidate)))
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvc.java
index 9fecea10157..c73399f5804 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvc.java
@@ -20,16 +20,16 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
+import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateList;
+import ca.uhn.fhir.jpa.mdm.svc.candidate.MatchedGoldenResourceCandidate;
+import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
+import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
-import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
-import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
-import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateList;
-import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
-import ca.uhn.fhir.jpa.mdm.svc.candidate.MatchedGoldenResourceCandidate;
+import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvc.java
index e5d3ab7ff44..92b6cf52d17 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvc.java
@@ -20,15 +20,19 @@ package ca.uhn.fhir.jpa.mdm.svc;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmConstants;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
@@ -53,10 +57,11 @@ public class MdmResourceDaoSvc {
public DaoMethodOutcome upsertGoldenResource(IAnyResource theGoldenResource, String theResourceType) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
+ RequestDetails requestDetails = new SystemRequestDetails().setRequestPartitionId((RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID));
if (theGoldenResource.getIdElement().hasIdPart()) {
- return resourceDao.update(theGoldenResource);
+ return resourceDao.update(theGoldenResource, requestDetails);
} else {
- return resourceDao.create(theGoldenResource);
+ return resourceDao.create(theGoldenResource, requestDetails);
}
}
@@ -68,7 +73,8 @@ public class MdmResourceDaoSvc {
*/
public void removeGoldenResourceTag(IAnyResource theGoldenResource, String theResourcetype) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourcetype);
- resourceDao.removeTag(theGoldenResource.getIdElement(), TagTypeEnum.TAG, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD);
+ RequestDetails requestDetails = new SystemRequestDetails().setRequestPartitionId((RequestPartitionId) theGoldenResource.getUserData(Constants.RESOURCE_PARTITION_ID));
+ resourceDao.removeTag(theGoldenResource.getIdElement(), TagTypeEnum.TAG, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD, requestDetails);
}
public IAnyResource readGoldenResourceByPid(ResourcePersistentId theGoldenResourcePid, String theResourceType) {
@@ -76,12 +82,17 @@ public class MdmResourceDaoSvc {
return (IAnyResource) resourceDao.readByPid(theGoldenResourcePid);
}
- //TODO GGG MDM address this
public Optional searchGoldenResourceByEID(String theEid, String theResourceType) {
+ return this.searchGoldenResourceByEID(theEid, theResourceType, null);
+ }
+
+ public Optional searchGoldenResourceByEID(String theEid, String theResourceType, RequestPartitionId thePartitionId) {
SearchParameterMap map = buildEidSearchParameterMap(theEid, theResourceType);
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
- IBundleProvider search = resourceDao.search(map);
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(thePartitionId);
+ IBundleProvider search = resourceDao.search(map, systemRequestDetails);
List resources = search.getResources(0, MAX_MATCHING_GOLDEN_RESOURCES);
if (resources.isEmpty()) {
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmSubmitSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmSubmitSvcImpl.java
index a5bc5403c62..6cd321dc494 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmSubmitSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmSubmitSvcImpl.java
@@ -27,11 +27,13 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IResultIterator;
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
+import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmChannelSubmitterSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
import ca.uhn.fhir.mdm.log.Logs;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
@@ -42,6 +44,7 @@ import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.util.ArrayList;
@@ -66,6 +69,9 @@ public class MdmSubmitSvcImpl implements IMdmSubmitSvc {
@Autowired
private IMdmSettings myMdmSettings;
+ @Autowired
+ private IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
+
public static final int DEFAULT_BUFFER_SIZE = 100;
private int myBufferSize = DEFAULT_BUFFER_SIZE;
@@ -75,9 +81,9 @@ public class MdmSubmitSvcImpl implements IMdmSubmitSvc {
@Override
@Transactional
- public long submitAllSourceTypesToMdm(@Nullable String theCriteria) {
+ public long submitAllSourceTypesToMdm(@Nullable String theCriteria, @Nonnull RequestDetails theRequestDetails) {
long submittedCount = myMdmSettings.getMdmRules().getMdmTypes().stream()
- .mapToLong(type -> submitSourceResourceTypeToMdm(type, theCriteria))
+ .mapToLong(type -> submitSourceResourceTypeToMdm(type, theCriteria, theRequestDetails))
.sum();
return submittedCount;
@@ -85,7 +91,7 @@ public class MdmSubmitSvcImpl implements IMdmSubmitSvc {
@Override
@Transactional
- public long submitSourceResourceTypeToMdm(String theSourceResourceType, @Nullable String theCriteria) {
+ public long submitSourceResourceTypeToMdm(String theSourceResourceType, @Nullable String theCriteria, @Nonnull RequestDetails theRequestDetails) {
if (theCriteria == null) {
ourLog.info("Submitting all resources of type {} to MDM", theSourceResourceType);
} else {
@@ -97,13 +103,15 @@ public class MdmSubmitSvcImpl implements IMdmSubmitSvc {
spMap.setLoadSynchronous(true);
spMap.setCount(myBufferSize);
ISearchBuilder searchBuilder = myMdmSearchParamSvc.generateSearchBuilderForType(theSourceResourceType);
- return submitAllMatchingResourcesToMdmChannel(spMap, searchBuilder);
+
+ RequestPartitionId requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(theRequestDetails, theSourceResourceType, spMap, null);
+ return submitAllMatchingResourcesToMdmChannel(spMap, searchBuilder, requestPartitionId);
}
- private long submitAllMatchingResourcesToMdmChannel(SearchParameterMap theSpMap, ISearchBuilder theSearchBuilder) {
+ private long submitAllMatchingResourcesToMdmChannel(SearchParameterMap theSpMap, ISearchBuilder theSearchBuilder, RequestPartitionId theRequestPartitionId) {
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(null, UUID.randomUUID().toString());
long total = 0;
- try (IResultIterator query = theSearchBuilder.createQuery(theSpMap, searchRuntimeDetails, null, RequestPartitionId.defaultPartition())) {
+ try (IResultIterator query = theSearchBuilder.createQuery(theSpMap, searchRuntimeDetails, null, theRequestPartitionId)) {
Collection pidBatch;
do {
pidBatch = query.getNextResultBatch(myBufferSize);
@@ -136,22 +144,22 @@ public class MdmSubmitSvcImpl implements IMdmSubmitSvc {
@Override
@Transactional
- public long submitPractitionerTypeToMdm(@Nullable String theCriteria) {
- return submitSourceResourceTypeToMdm("Practitioner", theCriteria);
+ public long submitPractitionerTypeToMdm(@Nullable String theCriteria, @Nonnull RequestDetails theRequestDetails) {
+ return submitSourceResourceTypeToMdm("Practitioner", theCriteria, theRequestDetails);
}
@Override
@Transactional
- public long submitPatientTypeToMdm(@Nullable String theCriteria) {
- return submitSourceResourceTypeToMdm("Patient", theCriteria);
+ public long submitPatientTypeToMdm(@Nullable String theCriteria, @Nonnull RequestDetails theRequestDetails) {
+ return submitSourceResourceTypeToMdm("Patient", theCriteria, theRequestDetails);
}
@Override
@Transactional
- public long submitSourceResourceToMdm(IIdType theId) {
+ public long submitSourceResourceToMdm(IIdType theId, RequestDetails theRequestDetails) {
validateSourceType(theId.getResourceType());
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theId.getResourceType());
- IBaseResource read = resourceDao.read(theId);
+ IBaseResource read = resourceDao.read(theId, theRequestDetails);
myMdmChannelSubmitterSvc.submitResourceToMdmChannel(read);
return 1;
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcher.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcher.java
index a98d8b4175c..866590cfad4 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcher.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcher.java
@@ -20,9 +20,11 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.mdm.svc.MdmSearchParamSvc;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
@@ -50,20 +52,35 @@ public class CandidateSearcher {
*
* @param theResourceType the type of resources searched on
* @param theResourceCriteria the criteria used to search for the candidates
+ * @param partitionId the partition for the search
* @return Optional.empty() if >= IMdmSettings.getCandidateSearchLimit() candidates are found, otherwise
* return the bundle provider for the search results.
*/
- public Optional search(String theResourceType, String theResourceCriteria) {
+ public Optional search(String theResourceType, String theResourceCriteria, RequestPartitionId partitionId) {
SearchParameterMap searchParameterMap = myMdmSearchParamSvc.mapFromCriteria(theResourceType, theResourceCriteria);
searchParameterMap.setLoadSynchronousUpTo(myMdmSettings.getCandidateSearchLimit());
IFhirResourceDao> resourceDao = myDaoRegistry.getResourceDao(theResourceType);
- IBundleProvider retval = resourceDao.search(searchParameterMap);
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(partitionId);
+ IBundleProvider retval = resourceDao.search(searchParameterMap, systemRequestDetails);
if (retval.size() != null && retval.size() >= myMdmSettings.getCandidateSearchLimit()) {
return Optional.empty();
}
return Optional.of(retval);
}
+
+ /**
+ * Perform a search for mdm candidates.
+ *
+ * @param theResourceType the type of resources searched on
+ * @param theResourceCriteria the criteria used to search for the candidates
+ * @return Optional.empty() if >= IMdmSettings.getCandidateSearchLimit() candidates are found, otherwise
+ * return the bundle provider for the search results.
+ */
+ public Optional search(String theResourceType, String theResourceCriteria) {
+ return this.search(theResourceType, theResourceCriteria, RequestPartitionId.allPartitions());
+ }
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByEidSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByEidSvc.java
index 8d2f39448cf..9adf4e524c1 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByEidSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByEidSvc.java
@@ -20,11 +20,13 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.mdm.util.EIDHelper;
-import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.slf4j.Logger;
@@ -52,7 +54,7 @@ public class FindCandidateByEidSvc extends BaseCandidateFinder {
List eidFromResource = myEIDHelper.getExternalEid(theBaseResource);
if (!eidFromResource.isEmpty()) {
for (CanonicalEID eid : eidFromResource) {
- Optional oFoundGoldenResource = myMdmResourceDaoSvc.searchGoldenResourceByEID(eid.getValue(), theBaseResource.getIdElement().getResourceType());
+ Optional oFoundGoldenResource = myMdmResourceDaoSvc.searchGoldenResourceByEID(eid.getValue(), theBaseResource.getIdElement().getResourceType(), (RequestPartitionId) theBaseResource.getUserData(Constants.RESOURCE_PARTITION_ID));
if (oFoundGoldenResource.isPresent()) {
IAnyResource foundGoldenResource = oFoundGoldenResource.get();
Long pidOrNull = myIdHelperService.getPidOrNull(foundGoldenResource);
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByExampleSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByExampleSvc.java
index e1ad5eb02aa..e2b590226ee 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByExampleSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/FindCandidateByExampleSvc.java
@@ -21,6 +21,8 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
@@ -28,6 +30,7 @@ import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
import ca.uhn.fhir.mdm.api.MatchedTarget;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.log.Logs;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -66,7 +69,7 @@ public class FindCandidateByExampleSvc extends BaseCandidateFinder {
List goldenResourcePidsToExclude = getNoMatchGoldenResourcePids(theTarget);
- List matchedCandidates = myMdmMatchFinderSvc.getMatchedTargets(myFhirContext.getResourceType(theTarget), theTarget);
+ List matchedCandidates = myMdmMatchFinderSvc.getMatchedTargets(myFhirContext.getResourceType(theTarget), theTarget, (RequestPartitionId) theTarget.getUserData(Constants.RESOURCE_PARTITION_ID));
// Convert all possible match targets to their equivalent Golden Resources by looking up in the MdmLink table,
// while ensuring that the matches aren't in our NO_MATCH list.
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmCandidateSearchSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmCandidateSearchSvc.java
index 92f2f38f047..369ad4d7c28 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmCandidateSearchSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmCandidateSearchSvc.java
@@ -20,6 +20,8 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
import ca.uhn.fhir.mdm.api.IMdmSettings;
@@ -64,12 +66,14 @@ public class MdmCandidateSearchSvc {
/**
* Given a source resource, search for all resources that are considered an MDM match based on defined MDM rules.
*
- * @param theResourceType
- * @param theResource the {@link IBaseResource} we are attempting to match.
+ * @param theResourceType the resource type of the resource being matched
+ * @param theResource the {@link IBaseResource} we are attempting to match.
+ * @param theRequestPartitionId the {@link RequestPartitionId} representation of the partitions we are limited to when attempting to match
+ *
* @return the list of candidate {@link IBaseResource} which could be matches to theResource
*/
@Transactional
- public Collection findCandidates(String theResourceType, IAnyResource theResource) {
+ public Collection findCandidates(String theResourceType, IAnyResource theResource, RequestPartitionId theRequestPartitionId) {
Map matchedPidsToResources = new HashMap<>();
List filterSearchParams = myMdmSettings.getMdmRules().getCandidateFilterSearchParams();
List filterCriteria = buildFilterQuery(filterSearchParams, theResourceType);
@@ -78,7 +82,7 @@ public class MdmCandidateSearchSvc {
//If there are zero MdmResourceSearchParamJson, we end up only making a single search, otherwise we
//must perform one search per MdmResourceSearchParamJson.
if (candidateSearchParams.isEmpty()) {
- searchForIdsAndAddToMap(theResourceType, theResource, matchedPidsToResources, filterCriteria, null);
+ searchForIdsAndAddToMap(theResourceType, theResource, matchedPidsToResources, filterCriteria, null, theRequestPartitionId);
} else {
for (MdmResourceSearchParamJson resourceSearchParam : candidateSearchParams) {
@@ -86,7 +90,7 @@ public class MdmCandidateSearchSvc {
continue;
}
- searchForIdsAndAddToMap(theResourceType, theResource, matchedPidsToResources, filterCriteria, resourceSearchParam);
+ searchForIdsAndAddToMap(theResourceType, theResource, matchedPidsToResources, filterCriteria, resourceSearchParam, theRequestPartitionId);
}
}
//Obviously we don't want to consider the freshly added resource as a potential candidate.
@@ -113,7 +117,7 @@ public class MdmCandidateSearchSvc {
* 4. Store all results in `theMatchedPidsToResources`
*/
@SuppressWarnings("rawtypes")
- private void searchForIdsAndAddToMap(String theResourceType, IAnyResource theResource, Map theMatchedPidsToResources, List theFilterCriteria, MdmResourceSearchParamJson resourceSearchParam) {
+ private void searchForIdsAndAddToMap(String theResourceType, IAnyResource theResource, Map theMatchedPidsToResources, List theFilterCriteria, MdmResourceSearchParamJson resourceSearchParam, RequestPartitionId theRequestPartitionId) {
//1.
Optional oResourceCriteria = myMdmCandidateSearchCriteriaBuilderSvc.buildResourceQueryString(theResourceType, theResource, theFilterCriteria, resourceSearchParam);
if (!oResourceCriteria.isPresent()) {
@@ -123,7 +127,7 @@ public class MdmCandidateSearchSvc {
ourLog.debug("Searching for {} candidates with {}", theResourceType, resourceCriteria);
//2.
- Optional bundleProvider = myCandidateSearcher.search(theResourceType, resourceCriteria);
+ Optional bundleProvider = myCandidateSearcher.search(theResourceType, resourceCriteria, theRequestPartitionId);
if (!bundleProvider.isPresent()) {
throw new TooManyCandidatesException(Msg.code(762) + "More than " + myMdmSettings.getCandidateSearchLimit() + " candidate matches found for " + resourceCriteria + ". Aborting mdm matching.");
}
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmPartitionHelper.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmPartitionHelper.java
new file mode 100644
index 00000000000..7585813786a
--- /dev/null
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmPartitionHelper.java
@@ -0,0 +1,25 @@
+package ca.uhn.fhir.jpa.mdm.util;
+
+import ca.uhn.fhir.i18n.Msg;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.mdm.util.MessageHelper;
+import ca.uhn.fhir.rest.api.Constants;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import org.hl7.fhir.instance.model.api.IAnyResource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class MdmPartitionHelper {
+ @Autowired
+ MessageHelper myMessageHelper;
+
+ public void validateResourcesInSamePartition(IAnyResource theFromResource, IAnyResource theToResource){
+ RequestPartitionId fromGoldenResourcePartitionId = (RequestPartitionId) theFromResource.getUserData(Constants.RESOURCE_PARTITION_ID);
+ RequestPartitionId toGoldenPartitionId = (RequestPartitionId) theToResource.getUserData(Constants.RESOURCE_PARTITION_ID);
+ if (fromGoldenResourcePartitionId != null && toGoldenPartitionId != null && fromGoldenResourcePartitionId.hasPartitionIds() && toGoldenPartitionId.hasPartitionIds() &&
+ !fromGoldenResourcePartitionId.hasPartitionId(toGoldenPartitionId.getFirstPartitionIdOrNull())) {
+ throw new InvalidRequestException(Msg.code(2075) + myMessageHelper.getMessageForMismatchPartition(theFromResource, theToResource));
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
index d3aab6e9999..fc0dddd805e 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/BaseMdmR4Test.java
@@ -1,12 +1,12 @@
package ca.uhn.fhir.jpa.mdm;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.IMdmLinkDao;
import ca.uhn.fhir.jpa.dao.index.IJpaIdHelperService;
-import ca.uhn.fhir.jpa.dao.index.IdHelperService;
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.config.MdmConsumerConfig;
@@ -20,6 +20,9 @@ import ca.uhn.fhir.jpa.mdm.matcher.IsPossibleLinkedTo;
import ca.uhn.fhir.jpa.mdm.matcher.IsPossibleMatchWith;
import ca.uhn.fhir.jpa.mdm.matcher.IsSameGoldenResourceAs;
import ca.uhn.fhir.jpa.mdm.svc.MdmMatchLinkSvc;
+import ca.uhn.fhir.jpa.model.config.PartitionSettings;
+import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
@@ -32,6 +35,7 @@ import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc;
import ca.uhn.fhir.mdm.util.EIDHelper;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.param.TokenParam;
@@ -74,6 +78,8 @@ import static org.slf4j.LoggerFactory.getLogger;
@ContextConfiguration(classes = {MdmSubmitterConfig.class, MdmConsumerConfig.class, TestMdmConfigR4.class, SubscriptionProcessorConfig.class})
abstract public class BaseMdmR4Test extends BaseJpaR4Test {
+ protected static final String PARTITION_1 = "PART-1";
+ protected static final String PARTITION_2 = "PART-2";
public static final String NAME_GIVEN_JANE = "Jane";
public static final String NAME_GIVEN_PAUL = "Paul";
public static final String TEST_NAME_FAMILY = "Doe";
@@ -118,6 +124,10 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
private IInterceptorBroadcaster myInterceptorBroadcaster;
@Autowired
private DaoRegistry myDaoRegistry;
+ @Autowired
+ protected PartitionSettings myPartitionSettings;
+ @Autowired
+ protected IPartitionLookupSvc myPartitionLookupSvc;
@BeforeEach
public void beforeSetRequestDetails() {
@@ -183,8 +193,40 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
}
@Nonnull
- protected Medication createMedication(Medication theMedication) {
+ protected Patient createPatientOnPartition(Patient thePatient, boolean theMdmManaged, boolean isRedirect, RequestPartitionId theRequestPartitionId) {
+ if (theMdmManaged) {
+ MdmResourceUtil.setMdmManaged(thePatient);
+ if (isRedirect) {
+ MdmResourceUtil.setGoldenResourceRedirected(thePatient);
+ } else {
+ MdmResourceUtil.setGoldenResource(thePatient);
+ }
+ }
+
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(theRequestPartitionId);
+ DaoMethodOutcome outcome = myPatientDao.create(thePatient, systemRequestDetails);
+ Patient patient = (Patient) outcome.getResource();
+ patient.setId(outcome.getId());
+ patient.setUserData(Constants.RESOURCE_PARTITION_ID, theRequestPartitionId);
+ return patient;
+ }
+
+ @Nonnull
+ protected Patient createPatientOnPartition(Patient thePatient, RequestPartitionId theRequestPartitionId) {
//Note that since our mdm-rules block on active=true, all patients must be active.
+ thePatient.setActive(true);
+
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(theRequestPartitionId);
+ DaoMethodOutcome outcome = myPatientDao.create(thePatient, systemRequestDetails);
+ Patient patient = (Patient) outcome.getResource();
+ patient.setId(outcome.getId());
+ return patient;
+ }
+
+ @Nonnull
+ protected Medication createMedication(Medication theMedication) {
DaoMethodOutcome outcome = myMedicationDao.create(theMedication);
Medication medication = (Medication) outcome.getResource();
medication.setId(outcome.getId());
@@ -307,7 +349,7 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
String resourceType = theBaseResource.getIdElement().getResourceType();
IFhirResourceDao relevantDao = myDaoRegistry.getResourceDao(resourceType);
- Optional matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(runInTransaction(()->myIdHelperService.getPidOrNull(theBaseResource)));
+ Optional matchedLinkForTargetPid = myMdmLinkDaoSvc.getMatchedLinkForSourcePid(runInTransaction(() -> myIdHelperService.getPidOrNull(theBaseResource)));
if (matchedLinkForTargetPid.isPresent()) {
Long goldenResourcePid = matchedLinkForTargetPid.get().getGoldenResourcePid();
return (T) relevantDao.readByPid(new ResourcePersistentId(goldenResourcePid));
@@ -337,6 +379,13 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
return thePatient;
}
+ protected Patient createPatientAndUpdateLinksOnPartition(Patient thePatient, RequestPartitionId theRequestPartitionId) {
+ thePatient = createPatientOnPartition(thePatient, theRequestPartitionId);
+ thePatient.setUserData(Constants.RESOURCE_PARTITION_ID, theRequestPartitionId);
+ myMdmMatchLinkSvc.updateMdmLinksForMdmSource(thePatient, createContextForCreate("Patient"));
+ return thePatient;
+ }
+
protected Medication buildMedication(String theManufacturerReference) {
Medication medication = new Medication();
medication.setManufacturer(new Reference(theManufacturerReference));
@@ -387,16 +436,27 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
return thePractitioner;
}
+ protected Practitioner createPractitionerAndUpdateLinksOnPartition(Practitioner thePractitioner, RequestPartitionId theRequestPartitionId) {
+ thePractitioner.setActive(true);
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(theRequestPartitionId);
+ DaoMethodOutcome daoMethodOutcome = myPractitionerDao.create(thePractitioner, systemRequestDetails);
+ thePractitioner.setId(daoMethodOutcome.getId());
+ thePractitioner.setUserData(Constants.RESOURCE_PARTITION_ID, theRequestPartitionId);
+ myMdmMatchLinkSvc.updateMdmLinksForMdmSource(thePractitioner, createContextForCreate("Practitioner"));
+ return thePractitioner;
+ }
+
private Matcher wrapMatcherInTransaction(Supplier> theFunction) {
return new Matcher() {
@Override
public boolean matches(Object actual) {
- return runInTransaction(()->theFunction.get().matches(actual));
+ return runInTransaction(() -> theFunction.get().matches(actual));
}
@Override
public void describeMismatch(Object actual, Description mismatchDescription) {
- runInTransaction(()->theFunction.get().describeMismatch(actual, mismatchDescription));
+ runInTransaction(() -> theFunction.get().describeMismatch(actual, mismatchDescription));
}
@Override
@@ -406,33 +466,33 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
@Override
public void describeTo(Description description) {
- runInTransaction(()->theFunction.get().describeTo(description));
+ runInTransaction(() -> theFunction.get().describeTo(description));
}
};
}
protected Matcher sameGoldenResourceAs(IAnyResource... theBaseResource) {
- return wrapMatcherInTransaction(()->IsSameGoldenResourceAs.sameGoldenResourceAs(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
+ return wrapMatcherInTransaction(() -> IsSameGoldenResourceAs.sameGoldenResourceAs(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
}
protected Matcher linkedTo(IAnyResource... theBaseResource) {
- return wrapMatcherInTransaction(()->IsLinkedTo.linkedTo(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
+ return wrapMatcherInTransaction(() -> IsLinkedTo.linkedTo(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
}
protected Matcher possibleLinkedTo(IAnyResource... theBaseResource) {
- return wrapMatcherInTransaction(()->IsPossibleLinkedTo.possibleLinkedTo(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
+ return wrapMatcherInTransaction(() -> IsPossibleLinkedTo.possibleLinkedTo(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
}
protected Matcher possibleMatchWith(IAnyResource... theBaseResource) {
- return wrapMatcherInTransaction(()->IsPossibleMatchWith.possibleMatchWith(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
+ return wrapMatcherInTransaction(() -> IsPossibleMatchWith.possibleMatchWith(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
}
protected Matcher possibleDuplicateOf(IAnyResource... theBaseResource) {
- return wrapMatcherInTransaction(()->IsPossibleDuplicateOf.possibleDuplicateOf(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
+ return wrapMatcherInTransaction(() -> IsPossibleDuplicateOf.possibleDuplicateOf(myIdHelperService, myMdmLinkDaoSvc, theBaseResource));
}
protected Matcher matchedToAGoldenResource() {
- return wrapMatcherInTransaction(()->IsMatchedToAGoldenResource.matchedToAGoldenResource(myIdHelperService, myMdmLinkDaoSvc));
+ return wrapMatcherInTransaction(() -> IsMatchedToAGoldenResource.matchedToAGoldenResource(myIdHelperService, myMdmLinkDaoSvc));
}
protected Patient getOnlyGoldenPatient() {
@@ -458,7 +518,8 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
map.setLoadSynchronous(true);
//TODO GGG ensure that this tag search works effectively.
map.add("_tag", new TokenParam(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, theCode));
- IBundleProvider bundle = myPatientDao.search(map);
+ SystemRequestDetails systemRequestDetails = SystemRequestDetails.forAllPartitions();
+ IBundleProvider bundle = myPatientDao.search(map, systemRequestDetails);
return bundle.getResources(0, 999);
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoaderTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoaderTest.java
index 5dd7ca74d18..02d7003915d 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoaderTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/config/MdmSubscriptionLoaderTest.java
@@ -1,19 +1,40 @@
package ca.uhn.fhir.jpa.mdm.config;
+import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
+import ca.uhn.fhir.mdm.api.IMdmSettings;
+import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
+import ca.uhn.fhir.model.api.IFhirVersion;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
+import ca.uhn.fhir.util.ExtensionUtil;
+import ca.uhn.fhir.util.HapiExtensions;
+import org.hl7.fhir.instance.model.api.IBaseExtension;
import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Subscription;
import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
+import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
+import org.springframework.beans.factory.annotation.Autowired;
+import java.util.Arrays;
+
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -24,6 +45,18 @@ class MdmSubscriptionLoaderTest {
@Mock
IFhirResourceDao mySubscriptionDao;
+ @Mock
+ DaoRegistry myDaoRegistry;
+
+ @Mock
+ IMdmSettings myMdmSettings;
+
+ @Spy
+ FhirContext myFhirContext = FhirContext.forR4Cached();
+
+ @Mock
+ IChannelNamer myChannelNamer;
+
@InjectMocks
MdmSubscriptionLoader mySvc = new MdmSubscriptionLoader();
@@ -37,9 +70,9 @@ class MdmSubscriptionLoaderTest {
Subscription subscription = new Subscription();
IdType id = new IdType("2401");
subscription.setIdElement(id);
- when(mySubscriptionDao.read(id)).thenThrow(new ResourceGoneException(""));
+ when(mySubscriptionDao.read(eq(id), any())).thenThrow(new ResourceGoneException(""));
mySvc.updateIfNotPresent(subscription);
- verify(mySubscriptionDao).update(subscription);
+ verify(mySubscriptionDao).update(eq(subscription), any(RequestDetails.class));
}
@Test
@@ -47,9 +80,9 @@ class MdmSubscriptionLoaderTest {
Subscription subscription = new Subscription();
IdType id = new IdType("2401");
subscription.setIdElement(id);
- when(mySubscriptionDao.read(id)).thenThrow(new ResourceNotFoundException(""));
+ when(mySubscriptionDao.read(eq(id), any())).thenThrow(new ResourceNotFoundException(""));
mySvc.updateIfNotPresent(subscription);
- verify(mySubscriptionDao).update(subscription);
+ verify(mySubscriptionDao).update(eq(subscription), any(RequestDetails.class));
}
@Test
@@ -57,8 +90,29 @@ class MdmSubscriptionLoaderTest {
Subscription subscription = new Subscription();
IdType id = new IdType("2401");
subscription.setIdElement(id);
- when(mySubscriptionDao.read(id)).thenReturn(subscription);
+ when(mySubscriptionDao.read(eq(id), any())).thenReturn(subscription);
mySvc.updateIfNotPresent(subscription);
- verify(mySubscriptionDao, never()).update(any());
+ verify(mySubscriptionDao, never()).update(any(), any(RequestDetails.class));
+ }
+
+ @Test
+ public void testDaoUpdateMdmSubscriptions() {
+ MdmRulesJson mdmRulesJson = new MdmRulesJson();
+ mdmRulesJson.setMdmTypes(Arrays.asList("Patient"));
+ when(myMdmSettings.getMdmRules()).thenReturn(mdmRulesJson);
+ when(myChannelNamer.getChannelName(any(), any())).thenReturn("Test");
+ when(myDaoRegistry.getResourceDao(eq("Subscription"))).thenReturn(mySubscriptionDao);
+ when(mySubscriptionDao.read(any(), any())).thenThrow(new ResourceGoneException(""));
+
+ mySvc.daoUpdateMdmSubscriptions();
+
+ ArgumentCaptor subscriptionCaptor = ArgumentCaptor.forClass(Subscription.class);
+ verify(mySubscriptionDao).update(subscriptionCaptor.capture(), any(RequestDetails.class));
+
+ IBaseExtension extension = ExtensionUtil.getExtensionByUrl(subscriptionCaptor.getValue(), HapiExtensions.EXTENSION_SUBSCRIPTION_CROSS_PARTITION);
+
+ assertNotNull(extension);
+
+ assertTrue(((BooleanType)extension.getValue()).booleanValue());
}
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseLinkR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseLinkR4Test.java
index c1d201cec50..98a53c9ce0d 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseLinkR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseLinkR4Test.java
@@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.mdm.provider;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import org.hl7.fhir.instance.model.api.IAnyResource;
@@ -59,6 +60,7 @@ public abstract class BaseLinkR4Test extends BaseProviderR4Test {
@AfterEach
public void after() throws IOException {
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
+ myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
super.after();
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java
index 6b98fe189c4..1a63e0c9d1a 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java
@@ -27,7 +27,7 @@ import java.util.ArrayList;
import java.util.List;
public abstract class BaseProviderR4Test extends BaseMdmR4Test {
- MdmProviderDstu3Plus myMdmProvider;
+ protected MdmProviderDstu3Plus myMdmProvider;
@Autowired
private IMdmControllerSvc myMdmControllerSvc;
@Autowired
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderCreateLinkR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderCreateLinkR4Test.java
index c7ac52de974..3a86186cd75 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderCreateLinkR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderCreateLinkR4Test.java
@@ -1,6 +1,9 @@
package ca.uhn.fhir.jpa.mdm.provider;
+
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@@ -17,7 +20,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.startsWith;
import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.fail;
public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
@@ -43,6 +46,53 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
+ @Test
+ public void testCreateLinkWithMatchResultOnSamePartition() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ assertLinkCount(1);
+
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ Patient patient = createPatientOnPartition(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false, requestPartitionId);
+ StringType patientId = new StringType(patient.getIdElement().getValue());
+
+ Patient sourcePatient = createPatientOnPartition(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false, requestPartitionId);
+ StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
+
+ myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
+ assertLinkCount(2);
+
+ List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
+ assertEquals(links.size(), 1);
+ assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
+ assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
+ assertNotNull(links.get(0).getPartitionId());
+ assertEquals(1, links.get(0).getPartitionId().getPartitionId());
+ }
+
+ @Test
+ public void testCreateLinkWithMatchResultOnDifferentPartitions() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ assertLinkCount(1);
+
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ Patient patient = createPatientOnPartition(buildPatientWithNameAndId("PatientGiven", "ID.PatientGiven.123"), true, false, requestPartitionId1);
+ StringType patientId = new StringType(patient.getIdElement().getValue());
+
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ Patient sourcePatient = createPatientOnPartition(buildPatientWithNameAndId("SourcePatientGiven", "ID.SourcePatientGiven.123"), true, false, requestPartitionId2);
+ StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
+
+ try {
+ myMdmProvider.createLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), endsWith("This operation is only available for resources on the same partition."));
+ }
+ }
+
@Test
public void testCreateLinkWithNullMatchResult() {
assertLinkCount(1);
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMatchR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMatchR4Test.java
index 5e45d5260ec..3551facb44a 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMatchR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMatchR4Test.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.mdm.provider;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.mdm.api.MdmConstants;
import com.google.common.collect.Ordering;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -40,7 +41,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Patient createdJane = createPatient(jane);
Patient newJane = buildJanePatient();
- Bundle result = (Bundle) myMdmProvider.match(newJane);
+ Bundle result = (Bundle) myMdmProvider.match(newJane, new SystemRequestDetails());
assertEquals(1, result.getEntry().size());
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
@@ -64,7 +65,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Medication createdMedication = createMedication(medication);
Medication newMedication = buildMedication("Organization/mfr");
- Bundle result = (Bundle) myMdmProvider.serverMatch(newMedication, new StringType("Medication"));
+ Bundle result = (Bundle) myMdmProvider.serverMatch(newMedication, new StringType("Medication"), new SystemRequestDetails());
assertEquals(1, result.getEntry().size());
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
@@ -89,7 +90,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Patient createdJane = createPatient(jane);
Patient newJane = buildJanePatient();
- Bundle result = (Bundle) myMdmProvider.serverMatch(newJane, new StringType("Patient"));
+ Bundle result = (Bundle) myMdmProvider.serverMatch(newJane, new StringType("Patient"), new SystemRequestDetails());
assertEquals(1, result.getEntry().size());
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
@@ -115,7 +116,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Patient newJane = buildJanePatient();
- Bundle result = (Bundle) myMdmProvider.match(newJane);
+ Bundle result = (Bundle) myMdmProvider.match(newJane, new SystemRequestDetails());
assertEquals(2, result.getEntry().size());
Bundle.BundleEntryComponent entry0 = result.getEntry().get(0);
@@ -139,7 +140,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Patient paul = buildPaulPatient();
paul.setActive(true);
- Bundle result = (Bundle) myMdmProvider.match(paul);
+ Bundle result = (Bundle) myMdmProvider.match(paul, new SystemRequestDetails());
assertEquals(0, result.getEntry().size());
}
@@ -151,7 +152,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
Patient createdJane = createPatient(jane);
Patient newJane = buildJanePatient();
- Bundle result = (Bundle) myMdmProvider.match(newJane);
+ Bundle result = (Bundle) myMdmProvider.match(newJane, new SystemRequestDetails());
assertEquals(1, result.getEntry().size());
assertEquals(createdJane.getId(), result.getEntryFirstRep().getResource().getId());
}
@@ -221,7 +222,7 @@ public class MdmProviderMatchR4Test extends BaseProviderR4Test {
"}";
IBaseResource coarseResource = myFhirContext.newJsonParser().parseResource(coarsePatient);
- Bundle result = (Bundle) myMdmProvider.match((Patient) coarseResource);
+ Bundle result = (Bundle) myMdmProvider.match((Patient) coarseResource, new SystemRequestDetails());
assertEquals(1, result.getEntry().size());
}
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMergeGoldenResourcesR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMergeGoldenResourcesR4Test.java
index 60e97c2449e..74ca94ea1f1 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMergeGoldenResourcesR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderMergeGoldenResourcesR4Test.java
@@ -1,7 +1,10 @@
package ca.uhn.fhir.jpa.mdm.provider;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
+import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
@@ -10,15 +13,19 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.TerserUtil;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import java.io.IOException;
import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail;
@@ -40,6 +47,11 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
myToGoldenPatientId = new StringType(myToGoldenPatient.getIdElement().getValue());
}
+ @AfterEach
+ public void after() throws IOException {
+ myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
+ super.after();
+ }
@Test
public void testMergeWithOverride() {
@@ -69,7 +81,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
// we do not check setActive anymore - as not all types support that
assertTrue(MdmResourceUtil.isGoldenRecord(mergedSourcePatient));
- assertTrue(!MdmResourceUtil.isGoldenRecordRedirected(mergedSourcePatient));
+ assertFalse(MdmResourceUtil.isGoldenRecordRedirected(mergedSourcePatient));
assertEquals(myToGoldenPatient.getIdElement(), mergedSourcePatient.getIdElement());
assertThat(mergedSourcePatient, is(sameGoldenResourceAs(myToGoldenPatient)));
@@ -78,7 +90,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
Patient fromSourcePatient = myPatientDao.read(myFromGoldenPatient.getIdElement().toUnqualifiedVersionless());
- assertTrue(!MdmResourceUtil.isGoldenRecord(fromSourcePatient));
+ assertFalse(MdmResourceUtil.isGoldenRecord(fromSourcePatient));
assertTrue(MdmResourceUtil.isGoldenRecordRedirected(fromSourcePatient));
//TODO GGG eventually this will need to check a redirect... this is a hack which doesnt work
@@ -95,6 +107,58 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
assertEquals(link.getLinkSource(), MdmLinkSourceEnum.MANUAL);
}
+ @Test
+ public void testMergeOnSamePartition() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
+ StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
+ Patient toGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
+ StringType toGoldenPatientId = new StringType(toGoldenPatient.getIdElement().getValue());
+
+ Patient mergedSourcePatient = (Patient) myMdmProvider.mergeGoldenResources(fromGoldenPatientId,
+ toGoldenPatientId, null, myRequestDetails);
+
+ assertTrue(MdmResourceUtil.isGoldenRecord(mergedSourcePatient));
+ assertFalse(MdmResourceUtil.isGoldenRecordRedirected(mergedSourcePatient));
+
+ assertEquals(toGoldenPatient.getIdElement(), mergedSourcePatient.getIdElement());
+ assertThat(mergedSourcePatient, is(sameGoldenResourceAs(toGoldenPatient)));
+ assertEquals(1, getAllRedirectedGoldenPatients().size());
+ // 2 from the set-up and only one from this test should be golden resource
+ assertEquals(3, getAllGoldenPatients().size());
+
+ List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(fromGoldenPatient);
+ assertThat(links, hasSize(1));
+
+ MdmLink link = links.get(0);
+ assertEquals(link.getSourcePid(), fromGoldenPatient.getIdElement().toUnqualifiedVersionless().getIdPartAsLong());
+ assertEquals(link.getGoldenResourcePid(), toGoldenPatient.getIdElement().toUnqualifiedVersionless().getIdPartAsLong());
+ assertEquals(link.getMatchResult(), MdmMatchResultEnum.REDIRECT);
+ assertEquals(link.getLinkSource(), MdmLinkSourceEnum.MANUAL);
+ }
+
+ @Test
+ public void testMergeOnDifferentPartitions() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
+ StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
+ Patient toGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId2);
+ StringType toGoldenPatientId = new StringType(toGoldenPatient.getIdElement().getValue());
+
+ try {
+ myMdmProvider.mergeGoldenResources(fromGoldenPatientId, toGoldenPatientId, null, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), endsWith("This operation is only available for resources on the same partition."));
+ }
+ }
+
@Test
public void testMergeWithManualOverride() {
Patient patient = TerserUtil.clone(myFhirContext, myFromGoldenPatient);
@@ -109,7 +173,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
assertEquals(1, getAllGoldenPatients().size());
Patient fromSourcePatient = myPatientDao.read(myFromGoldenPatient.getIdElement().toUnqualifiedVersionless());
- assertTrue(!MdmResourceUtil.isGoldenRecord(fromSourcePatient));
+ assertFalse(MdmResourceUtil.isGoldenRecord(fromSourcePatient));
assertTrue(MdmResourceUtil.isGoldenRecordRedirected(fromSourcePatient));
List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(myFromGoldenPatient);
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderNotDuplicateGoldenResourceR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderNotDuplicateGoldenResourceR4Test.java
new file mode 100644
index 00000000000..1a2c1c65279
--- /dev/null
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderNotDuplicateGoldenResourceR4Test.java
@@ -0,0 +1,125 @@
+package ca.uhn.fhir.jpa.mdm.provider;
+
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
+import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
+import org.hl7.fhir.r4.model.Patient;
+import org.hl7.fhir.r4.model.StringType;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.io.IOException;
+import java.util.List;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.endsWith;
+import static org.hamcrest.Matchers.startsWith;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4Test {
+ @Autowired
+ IMdmLinkSvc myMdmLinkSvc;
+ private Patient myGoldenPatient;
+ private StringType myGoldenPatientId;
+ private Patient myTargetPatient;
+ private StringType myTargetPatientId;
+
+ @Override
+ @BeforeEach
+ public void before() {
+ super.before();
+
+ myGoldenPatient = createGoldenPatient();
+ myGoldenPatientId = new StringType(myGoldenPatient.getIdElement().getValue());
+ myTargetPatient = createGoldenPatient();
+ myTargetPatientId = new StringType(myTargetPatient.getIdElement().getValue());
+ }
+
+ @AfterEach
+ public void after() throws IOException {
+ myPartitionSettings.setPartitioningEnabled(false);
+ super.after();
+ }
+
+ @Test
+ public void testNotDuplicateGoldenResource() {
+ myMdmLinkSvc.updateLink(myGoldenPatient, myTargetPatient, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
+ assertLinkCount(1);
+ myMdmProvider.notDuplicate(myGoldenPatientId, myTargetPatientId, myRequestDetails);
+ assertLinkCount(1);
+
+ List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(myTargetPatient);
+ assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
+ assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(0).getMatchResult());
+ }
+
+ @Test
+ public void testNotDuplicateGoldenResourceNoLinkBetweenResources() {
+ try {
+ myMdmProvider.notDuplicate(myGoldenPatientId, myTargetPatientId, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), startsWith("HAPI-0745: No link exists between"));
+ }
+ }
+
+ @Test
+ public void testNotDuplicateGoldenResourceNotPossibleDuplicate() {
+ myMdmLinkSvc.updateLink(myGoldenPatient, myTargetPatient, MdmMatchOutcome.POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
+ assertLinkCount(1);
+ try {
+ myMdmProvider.notDuplicate(myGoldenPatientId, myTargetPatientId, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), endsWith("are not linked as POSSIBLE_DUPLICATE."));
+ }
+ }
+
+ @Test
+ public void testNotDuplicateGoldenResourceOnSamePartition() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
+ StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
+ Patient targetPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
+ StringType targetPatientId = new StringType(targetPatient.getIdElement().getValue());
+
+ myMdmLinkSvc.updateLink(goldenPatient, targetPatient, MdmMatchOutcome.POSSIBLE_DUPLICATE, MdmLinkSourceEnum.AUTO, createContextForCreate("Patient"));
+ assertLinkCount(1);
+ myMdmProvider.notDuplicate(goldenPatientId, targetPatientId, myRequestDetails);
+ assertLinkCount(1);
+
+ List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(targetPatient);
+ assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
+ assertEquals(MdmMatchResultEnum.NO_MATCH, links.get(0).getMatchResult());
+ }
+
+ @Test
+ public void testNotDuplicateGoldenResourceOnDifferentPartitions() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
+ StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
+ Patient targetPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId2);
+ StringType targetPatientId = new StringType(targetPatient.getIdElement().getValue());
+
+ try {
+ myMdmProvider.notDuplicate(goldenPatientId, targetPatientId, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), startsWith("HAPI-0745: No link exists between"));
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderUpdateLinkR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderUpdateLinkR4Test.java
index d8496638cb4..91810fa20ec 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderUpdateLinkR4Test.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/MdmProviderUpdateLinkR4Test.java
@@ -1,7 +1,9 @@
package ca.uhn.fhir.jpa.mdm.provider;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@@ -54,6 +56,52 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
}
+ @Test
+ public void testUpdateLinkMatchOnSamePartition() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
+ StringType patientId = new StringType(patient.getIdElement().getValue());
+
+ Patient sourcePatient = getGoldenResourceFromTargetResource(patient);
+ StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
+ MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
+ link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
+ saveLink(link);
+ assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
+ assertLinkCount(2);
+ myMdmProvider.updateLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
+ assertLinkCount(2);
+
+ List links = myMdmLinkDaoSvc.findMdmLinksBySourceResource(patient);
+ assertEquals(MdmLinkSourceEnum.MANUAL, links.get(0).getLinkSource());
+ assertEquals(MdmMatchResultEnum.MATCH, links.get(0).getMatchResult());
+ assertNotNull(links.get(0).getPartitionId());
+ assertEquals(1, links.get(0).getPartitionId().getPartitionId());
+ }
+
+ @Test
+ public void testUpdateLinkMatchOnDifferentPartitions() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ Patient patient = createPatientOnPartition(buildFrankPatient(), true, false, requestPartitionId1);
+ StringType patientId = new StringType(patient.getIdElement().getValue());
+
+ Patient sourcePatient = createPatientOnPartition(buildJanePatient(), true, false, requestPartitionId2);
+ StringType sourcePatientId = new StringType(sourcePatient.getIdElement().getValue());
+ assertLinkCount(1);
+ try {
+ myMdmProvider.updateLink(sourcePatientId, patientId, MATCH_RESULT, myRequestDetails);
+ fail();
+ } catch (InvalidRequestException e) {
+ assertThat(e.getMessage(), endsWith("This operation is only available for resources on the same partition."));
+ }
+ }
+
@Test
public void testUpdateLinkTwiceFailsDueToWrongVersion() {
myMdmProvider.updateLink(mySourcePatientId, myPatientId, MATCH_RESULT, myRequestDetails);
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmBatchSvcImplIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmBatchSvcImplIT.java
index 4486cb3c389..9eef716d031 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmBatchSvcImplIT.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmBatchSvcImplIT.java
@@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
import ca.uhn.test.concurrency.PointcutLatch;
import org.apache.commons.lang3.time.DateUtils;
@@ -56,7 +57,7 @@ class MdmBatchSvcImplIT extends BaseMdmR4Test {
assertLinkCount(0);
//SUT
- afterMdmLatch.runWithExpectedCount(30, () -> myMdmSubmitSvc.submitAllSourceTypesToMdm(null));
+ afterMdmLatch.runWithExpectedCount(30, () -> myMdmSubmitSvc.submitAllSourceTypesToMdm(null, SystemRequestDetails.forAllPartitions()));
assertLinkCount(30);
}
@@ -72,7 +73,7 @@ class MdmBatchSvcImplIT extends BaseMdmR4Test {
//SUT
myMdmSubmitSvc.setBufferSize(5);
- afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Patient", null));
+ afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Patient", null, SystemRequestDetails.newSystemRequestAllPartitions()));
assertLinkCount(10);
}
@@ -89,7 +90,7 @@ class MdmBatchSvcImplIT extends BaseMdmR4Test {
assertLinkCount(0);
//SUT
- afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Medication", null));
+ afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Medication", null, SystemRequestDetails.newSystemRequestAllPartitions()));
assertLinkCount(10);
}
@@ -104,7 +105,7 @@ class MdmBatchSvcImplIT extends BaseMdmR4Test {
assertLinkCount(0);
//SUT
- afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitAllSourceTypesToMdm(null));
+ afterMdmLatch.runWithExpectedCount(10, () -> myMdmSubmitSvc.submitAllSourceTypesToMdm(null, SystemRequestDetails.newSystemRequestAllPartitions()));
assertLinkCount(10);
}
@@ -117,7 +118,7 @@ class MdmBatchSvcImplIT extends BaseMdmR4Test {
assertLinkCount(0);
//SUT
- afterMdmLatch.runWithExpectedCount(1, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Patient", "Patient?name=gary"));
+ afterMdmLatch.runWithExpectedCount(1, () -> myMdmSubmitSvc.submitSourceResourceTypeToMdm("Patient", "Patient?name=gary", SystemRequestDetails.newSystemRequestAllPartitions()));
assertLinkCount(1);
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java
index 318c427a365..da1f30f0bea 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.mdm.svc;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.TooManyCandidatesException;
@@ -38,7 +39,7 @@ public class MdmCandidateSearchSvcIT extends BaseMdmR4Test {
createActivePatient();
Patient newJane = buildJanePatient();
- Collection result = myMdmCandidateSearchSvc.findCandidates("Patient", newJane);
+ Collection result = myMdmCandidateSearchSvc.findCandidates("Patient", newJane, RequestPartitionId.allPartitions());
assertEquals(1, result.size());
}
@@ -53,7 +54,7 @@ public class MdmCandidateSearchSvcIT extends BaseMdmR4Test {
Patient newJane = buildJaneWithBirthday(today);
- Collection result = myMdmCandidateSearchSvc.findCandidates("Patient", newJane);
+ Collection result = myMdmCandidateSearchSvc.findCandidates("Patient", newJane, RequestPartitionId.allPartitions());
assertEquals(1, result.size());
}
@@ -71,7 +72,7 @@ public class MdmCandidateSearchSvcIT extends BaseMdmR4Test {
incomingPatient.setActive(true);
incomingPatient.setGeneralPractitioner(Collections.singletonList(new Reference(practitionerAndUpdateLinks.getId())));
- Collection patient = myMdmCandidateSearchSvc.findCandidates("Patient", incomingPatient);
+ Collection patient = myMdmCandidateSearchSvc.findCandidates("Patient", incomingPatient, RequestPartitionId.allPartitions());
assertThat(patient, hasSize(1));
}
@@ -82,13 +83,13 @@ public class MdmCandidateSearchSvcIT extends BaseMdmR4Test {
Patient newJane = buildJanePatient();
createActivePatient();
- assertEquals(1, runInTransaction(()->myMdmCandidateSearchSvc.findCandidates("Patient", newJane).size()));
+ assertEquals(1, runInTransaction(()->myMdmCandidateSearchSvc.findCandidates("Patient", newJane, RequestPartitionId.allPartitions()).size()));
createActivePatient();
- assertEquals(2, runInTransaction(()->myMdmCandidateSearchSvc.findCandidates("Patient", newJane).size()));
+ assertEquals(2, runInTransaction(()->myMdmCandidateSearchSvc.findCandidates("Patient", newJane, RequestPartitionId.allPartitions()).size()));
try {
createActivePatient();
- myMdmCandidateSearchSvc.findCandidates("Patient", newJane);
+ myMdmCandidateSearchSvc.findCandidates("Patient", newJane, RequestPartitionId.allPartitions());
fail();
} catch (TooManyCandidatesException e) {
assertEquals("More than 3 candidate matches found for Patient?identifier=http%3A%2F%2Fa.tv%2F%7CID.JANE.123&active=true. Aborting mdm matching.", e.getMessage());
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java
new file mode 100644
index 00000000000..7835331bbaf
--- /dev/null
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmControllerSvcImplTest.java
@@ -0,0 +1,158 @@
+package ca.uhn.fhir.jpa.mdm.svc;
+
+import ca.uhn.fhir.interceptor.api.IInterceptorService;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
+import ca.uhn.fhir.jpa.mdm.provider.BaseLinkR4Test;
+import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
+import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
+import ca.uhn.fhir.mdm.api.MdmLinkJson;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
+import ca.uhn.fhir.mdm.model.MdmTransactionContext;
+import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
+import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
+import ca.uhn.fhir.test.utilities.BatchJobHelper;
+import org.hl7.fhir.instance.model.api.IBaseParameters;
+import org.hl7.fhir.instance.model.api.IPrimitiveType;
+import org.hl7.fhir.r4.model.DecimalType;
+import org.hl7.fhir.r4.model.Parameters;
+import org.hl7.fhir.r4.model.Patient;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentMatcher;
+import org.mockito.Mockito;
+import org.springframework.batch.core.ExitStatus;
+import org.springframework.batch.core.JobExecution;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.data.domain.Page;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+
+import static ca.uhn.fhir.mdm.provider.MdmProviderDstu3Plus.DEFAULT_PAGE_SIZE;
+import static ca.uhn.fhir.mdm.provider.MdmProviderDstu3Plus.MAX_PAGE_SIZE;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
+
+public class MdmControllerSvcImplTest extends BaseLinkR4Test {
+ @Autowired
+ IMdmControllerSvc myMdmControllerSvc;
+
+ @SpyBean
+ @Autowired
+ IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
+
+ @Autowired
+ private IInterceptorService myInterceptorService;
+ @Autowired
+ private BatchJobHelper myBatchJobHelper;
+
+ @BeforeEach
+ public void before() {
+ super.before();
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ myInterceptorService.registerInterceptor(new RequestTenantPartitionInterceptor());
+ }
+
+ @Test
+ public void testSurvivorshipIsCalledOnMatchingToTheSameGoldenResource() {
+ assertLinkCount(1);
+
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+
+ Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
+
+ getGoldenResourceFromTargetResource(patient);
+
+ MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
+ link.setMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH);
+ saveLink(link);
+ assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
+ assertLinkCount(2);
+
+ Page resultPage = myMdmControllerSvc.queryLinks(null, myPatientId.getIdElement().getValue(), null, null,
+ new MdmTransactionContext(MdmTransactionContext.OperationType.QUERY_LINKS),
+ new MdmPageRequest((Integer) null, null, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE),
+ new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.fromPartitionId(1)));
+
+ assertEquals(resultPage.getContent().size(), 1);
+
+ assertEquals(resultPage.getContent().get(0).getSourceId(), patient.getIdElement().getResourceType() + "/" + patient.getIdElement().getIdPart());
+
+ Mockito.verify(myRequestPartitionHelperSvc, Mockito.atLeastOnce()).validateHasPartitionPermissions(any(), eq("Patient"), argThat(new PartitionIdMatcher(requestPartitionId)));
+ }
+
+ @Test
+ public void testMdmDuplicateGoldenResource() {
+ assertLinkCount(1);
+
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+
+ Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
+
+ getGoldenResourceFromTargetResource(patient);
+
+ MdmLink link = myMdmLinkDaoSvc.findMdmLinkBySource(patient).get();
+ link.setMatchResult(MdmMatchResultEnum.POSSIBLE_DUPLICATE);
+ saveLink(link);
+ assertEquals(MdmLinkSourceEnum.AUTO, link.getLinkSource());
+ assertLinkCount(2);
+
+ Page resultPage = myMdmControllerSvc.getDuplicateGoldenResources(null,
+ new MdmPageRequest((Integer) null, null, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE),
+ new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.fromPartitionId(1)));
+
+ assertEquals(resultPage.getContent().size(), 1);
+
+ assertEquals(resultPage.getContent().get(0).getSourceId(), patient.getIdElement().getResourceType() + "/" + patient.getIdElement().getIdPart());
+
+ Mockito.verify(myRequestPartitionHelperSvc, Mockito.atLeastOnce()).validateHasPartitionPermissions(any(), eq("Patient"), argThat(new PartitionIdMatcher(requestPartitionId)));
+ }
+
+ @Test
+ public void testMdmClearWithProvidedResources() {
+ assertLinkCount(1);
+
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ createPractitionerAndUpdateLinksOnPartition(buildJanePractitioner(), requestPartitionId1);
+ createPractitionerAndUpdateLinksOnPartition(buildJanePractitioner(), requestPartitionId2);
+ assertLinkCount(3);
+
+ List urls = new ArrayList<>();
+ urls.add("Practitioner?");
+ IPrimitiveType batchSize = new DecimalType(new BigDecimal(100));
+ ServletRequestDetails details = new ServletRequestDetails();
+ details.setTenantId(PARTITION_2);
+ IBaseParameters clearJob = myMdmControllerSvc.submitMdmClearJob(urls, batchSize, details);
+ Long jobId = Long.valueOf(((DecimalType) ((Parameters) clearJob).getParameter("jobId")).getValueAsString());
+ JobExecution jobExecution = myBatchJobHelper.awaitJobExecution(jobId);
+ assertEquals(ExitStatus.COMPLETED, jobExecution.getExitStatus());
+
+ assertLinkCount(2);
+ }
+
+ private class PartitionIdMatcher implements ArgumentMatcher {
+ private RequestPartitionId myRequestPartitionId;
+
+ PartitionIdMatcher(RequestPartitionId theRequestPartitionId) {
+ myRequestPartitionId = theRequestPartitionId;
+ }
+
+ @Override
+ public boolean matches(RequestPartitionId theRequestPartitionId) {
+ return myRequestPartitionId.getPartitionIds().equals(theRequestPartitionId.getPartitionIds());
+ }
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcTest.java
index 629ae40b2f1..3c3c63e3d0d 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcTest.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.mdm.svc;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.dao.expunge.ExpungeEverythingService;
import ca.uhn.fhir.jpa.entity.MdmLink;
@@ -8,6 +9,7 @@ import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hamcrest.Matchers;
import org.hl7.fhir.r4.model.IdType;
@@ -182,4 +184,19 @@ public class MdmLinkSvcTest extends BaseMdmR4Test {
assertThat(actual, Matchers.containsInAnyOrder(expected.toArray()));
}
+
+ @Test
+ public void testMdmLinksHasPartitionIdForResourceOnNonDefaultPartition() {
+ Patient goldenPatient = createGoldenPatient(buildJanePatient());
+ Patient patient1 = createPatient(buildJanePatient());
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ patient1.setUserData(Constants.RESOURCE_PARTITION_ID, requestPartitionId);
+ assertEquals(0, myMdmLinkDao.count());
+
+ myMdmLinkDaoSvc.createOrUpdateLinkEntity(goldenPatient, patient1, MdmMatchOutcome.NEW_GOLDEN_RESOURCE_MATCH, MdmLinkSourceEnum.MANUAL, createContextForCreate("Patient"));
+ List targets = myMdmLinkDaoSvc.findMdmLinksByGoldenResource(goldenPatient);
+ assertFalse(targets.isEmpty());
+ assertEquals(1, targets.size());
+ assertEquals(requestPartitionId.getFirstPartitionIdOrNull(), targets.get(0).getPartitionId().getPartitionId());
+ }
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvcSurvivorshipTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvcSurvivorshipTest.java
index 2a1d563d085..6131d911bbd 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvcSurvivorshipTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmMatchLinkSvcSurvivorshipTest.java
@@ -1,19 +1,10 @@
package ca.uhn.fhir.jpa.mdm.svc;
-import ca.uhn.fhir.jpa.entity.MdmLink;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
-import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
-import ca.uhn.fhir.mdm.api.MdmConstants;
-import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
-import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.mdm.util.GoldenResourceHelper;
-import ca.uhn.fhir.rest.api.server.IBundleProvider;
-import ca.uhn.fhir.rest.param.TokenParam;
-import org.hl7.fhir.instance.model.api.IAnyResource;
-import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@@ -23,11 +14,6 @@ import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.mock.mockito.SpyBean;
-import javax.annotation.Nullable;
-
-import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.*;
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.*;
import static org.mockito.Mockito.times;
import static org.slf4j.LoggerFactory.getLogger;
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvcTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvcTest.java
index 4dbac482c9b..56601cb5b10 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvcTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvcTest.java
@@ -1,16 +1,23 @@
package ca.uhn.fhir.jpa.mdm.svc;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.entity.PartitionEntity;
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
+import ca.uhn.fhir.jpa.model.config.PartitionSettings;
+import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.r4.model.Patient;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
+import java.io.IOException;
import java.util.Optional;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
+import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
@@ -18,6 +25,12 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
@Autowired
MdmResourceDaoSvc myResourceDaoSvc;
+ @AfterEach
+ public void after() throws IOException {
+ myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
+ super.after();
+ }
+
@Test
public void testSearchPatientByEidExcludesNonGoldenPatients() {
Patient goodSourcePatient = addExternalEID(createGoldenPatient(), TEST_EID);
@@ -35,7 +48,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
}
@Test
- public void testSearcGoldenResourceByEidExcludesNonMdmManaged() {
+ public void testSearchGoldenResourceByEidExcludesNonMdmManaged() {
Patient goodSourcePatient = addExternalEID(createGoldenPatient(), TEST_EID);
myPatientDao.update(goodSourcePatient);
@@ -46,4 +59,37 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
assertTrue(foundSourcePatient.isPresent());
assertThat(foundSourcePatient.get().getIdElement().toUnqualifiedVersionless().getValue(), is(goodSourcePatient.getIdElement().toUnqualifiedVersionless().getValue()));
}
+
+ @Test
+ public void testSearchGoldenResourceOnSamePartition() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
+ Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
+ Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(requestPartitionId);
+ myPatientDao.update(goodSourcePatient, systemRequestDetails);
+
+ Optional foundSourcePatient = myResourceDaoSvc.searchGoldenResourceByEID(TEST_EID, "Patient", requestPartitionId);
+ assertTrue(foundSourcePatient.isPresent());
+ assertThat(foundSourcePatient.get().getIdElement().toUnqualifiedVersionless().getValue(), is(goodSourcePatient.getIdElement().toUnqualifiedVersionless().getValue()));
+ }
+
+ @Test
+ public void testSearchGoldenResourceOnDifferentPartitions() {
+ myPartitionSettings.setPartitioningEnabled(true);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
+ RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
+ myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
+ RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
+ Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
+ Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
+ SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
+ systemRequestDetails.setRequestPartitionId(requestPartitionId1);
+ myPatientDao.update(goodSourcePatient, systemRequestDetails);
+
+ Optional foundSourcePatient = myResourceDaoSvc.searchGoldenResourceByEID(TEST_EID, "Patient", requestPartitionId2);
+ assertFalse(foundSourcePatient.isPresent());
+ }
}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcherTest.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcherTest.java
index 18befab3b40..db4089cb895 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcherTest.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/candidate/CandidateSearcherTest.java
@@ -20,6 +20,8 @@ import java.util.Optional;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -54,7 +56,7 @@ class CandidateSearcherTest {
SimpleBundleProvider bundleProvider = new SimpleBundleProvider();
bundleProvider.setSize(candidateSearchLimit + offset);
- when(dao.search(map)).thenReturn(bundleProvider);
+ when(dao.search(eq(map), any())).thenReturn(bundleProvider);
Optional result = myCandidateSearcher.search(resourceType, criteria);
diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml
index 428843dce66..1af24e1adad 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml
index 663b59cb9a6..fd7db5ee903 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml
index e954cd1363e..3b9c200a3a8 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/config/SubscriptionProcessorConfig.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/config/SubscriptionProcessorConfig.java
index d1fbd8025e2..3ef04335bb1 100644
--- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/config/SubscriptionProcessorConfig.java
+++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/config/SubscriptionProcessorConfig.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.subscription.match.config;
* #L%
*/
+import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionChannelRegistry;
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryChannelNamer;
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory;
@@ -38,6 +39,7 @@ import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionRegiste
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
import ca.uhn.fhir.jpa.subscription.model.config.SubscriptionModelConfig;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Primary;
@@ -103,8 +105,8 @@ public class SubscriptionProcessorConfig {
@Bean
@Scope("prototype")
- public SubscriptionDeliveringMessageSubscriber subscriptionDeliveringMessageSubscriber() {
- return new SubscriptionDeliveringMessageSubscriber();
+ public SubscriptionDeliveringMessageSubscriber subscriptionDeliveringMessageSubscriber(IChannelFactory theChannelFactory) {
+ return new SubscriptionDeliveringMessageSubscriber(theChannelFactory);
}
@Bean
diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/deliver/message/SubscriptionDeliveringMessageSubscriber.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/deliver/message/SubscriptionDeliveringMessageSubscriber.java
index 8f5f575c9a0..e514681d5ec 100644
--- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/deliver/message/SubscriptionDeliveringMessageSubscriber.java
+++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/deliver/message/SubscriptionDeliveringMessageSubscriber.java
@@ -32,6 +32,7 @@ import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
import ca.uhn.fhir.rest.api.EncodingEnum;
+import com.google.common.annotations.VisibleForTesting;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -44,16 +45,16 @@ import java.net.URISyntaxException;
@Scope("prototype")
public class SubscriptionDeliveringMessageSubscriber extends BaseSubscriptionDeliverySubscriber {
- private static Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringMessageSubscriber.class);
+ private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringMessageSubscriber.class);
- @Autowired
- private IChannelFactory myChannelFactory;
+ private final IChannelFactory myChannelFactory;
/**
* Constructor
*/
- public SubscriptionDeliveringMessageSubscriber() {
+ public SubscriptionDeliveringMessageSubscriber(IChannelFactory theChannelFactory) {
super();
+ myChannelFactory = theChannelFactory;
}
protected void deliverPayload(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription, IChannelProducer theChannelProducer) {
@@ -67,6 +68,7 @@ public class SubscriptionDeliveringMessageSubscriber extends BaseSubscriptionDel
ResourceModifiedMessage payload = new ResourceModifiedMessage(myFhirContext, thePayloadResource, theMsg.getOperationType());
payload.setMessageKey(theMsg.getMessageKeyOrNull());
payload.setTransactionId(theMsg.getTransactionId());
+ payload.setPartitionId(theMsg.getRequestPartitionId());
ResourceModifiedJsonMessage message = new ResourceModifiedJsonMessage(payload);
theChannelProducer.send(message);
ourLog.debug("Delivering {} message payload {} for {}", theMsg.getOperationType(), theMsg.getPayloadId(), theSubscription.getIdElement(myFhirContext).toUnqualifiedVersionless().getValue());
diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/SubscriptionActivatingSubscriber.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/SubscriptionActivatingSubscriber.java
index 3d152f9e650..445022a6a66 100644
--- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/SubscriptionActivatingSubscriber.java
+++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/matcher/subscriber/SubscriptionActivatingSubscriber.java
@@ -118,13 +118,13 @@ public class SubscriptionActivatingSubscriber extends BaseSubscriberForSubscript
@SuppressWarnings("unchecked")
private boolean activateSubscription(final IBaseResource theSubscription) {
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
- SystemRequestDetails srd = SystemRequestDetails.forAllPartition();
+ SystemRequestDetails srd = SystemRequestDetails.forAllPartitions();
IBaseResource subscription = null;
try {
// read can throw ResourceGoneException
// if this happens, we will treat this as a failure to activate
- subscription = subscriptionDao.read(theSubscription.getIdElement(), SystemRequestDetails.forAllPartition());
+ subscription = subscriptionDao.read(theSubscription.getIdElement(), SystemRequestDetails.forAllPartitions());
subscription.setId(subscription.getIdElement().toVersionless());
ourLog.info("Activating subscription {} from status {} to {}", subscription.getIdElement().toUnqualified().getValue(), SubscriptionConstants.REQUESTED_STATUS, SubscriptionConstants.ACTIVE_STATUS);
diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionLoader.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionLoader.java
index 4d7ffed2cef..3b8089b2170 100644
--- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionLoader.java
+++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/match/registry/SubscriptionLoader.java
@@ -90,7 +90,7 @@ public class SubscriptionLoader implements IResourceChangeListener {
@PostConstruct
public void registerListener() {
mySearchParameterMap = getSearchParameterMap();
- mySystemRequestDetails = SystemRequestDetails.forAllPartition();
+ mySystemRequestDetails = SystemRequestDetails.forAllPartitions();
IResourceChangeListenerCache subscriptionCache = myResourceChangeListenerRegistry.registerResourceResourceChangeListener("Subscription", mySearchParameterMap, this, REFRESH_INTERVAL);
subscriptionCache.forceRefresh();
@@ -252,7 +252,7 @@ public class SubscriptionLoader implements IResourceChangeListener {
return;
}
IFhirResourceDao> subscriptionDao = getSubscriptionDao();
- SystemRequestDetails systemRequestDetails = SystemRequestDetails.forAllPartition();
+ SystemRequestDetails systemRequestDetails = SystemRequestDetails.forAllPartitions();
List resourceList = theResourceIds.stream().map(n -> subscriptionDao.read(n, systemRequestDetails)).collect(Collectors.toList());
updateSubscriptionRegistry(resourceList);
}
diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/triggering/SubscriptionTriggeringSvcImpl.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/triggering/SubscriptionTriggeringSvcImpl.java
index 30b44d0cd51..ff489d29d97 100644
--- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/triggering/SubscriptionTriggeringSvcImpl.java
+++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/triggering/SubscriptionTriggeringSvcImpl.java
@@ -116,7 +116,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
if (!subscriptionId.hasResourceType()) {
subscriptionId = subscriptionId.withResourceType(ResourceTypeEnum.SUBSCRIPTION.getCode());
}
- subscriptionDao.read(subscriptionId, SystemRequestDetails.forAllPartition());
+ subscriptionDao.read(subscriptionId, SystemRequestDetails.forAllPartitions());
}
List> resourceIds = ObjectUtils.defaultIfNull(theResourceIds, Collections.emptyList());
@@ -300,7 +300,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
private Future submitResource(String theSubscriptionId, String theResourceIdToTrigger) {
org.hl7.fhir.r4.model.IdType resourceId = new org.hl7.fhir.r4.model.IdType(theResourceIdToTrigger);
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceId.getResourceType());
- IBaseResource resourceToTrigger = dao.read(resourceId, SystemRequestDetails.forAllPartition());
+ IBaseResource resourceToTrigger = dao.read(resourceId, SystemRequestDetails.forAllPartitions());
return submitResource(theSubscriptionId, resourceToTrigger);
}
diff --git a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/deliver/BaseSubscriptionDeliverySubscriberTest.java b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/deliver/BaseSubscriptionDeliverySubscriberTest.java
index 7610e9ca0a4..426f07c91a9 100644
--- a/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/deliver/BaseSubscriptionDeliverySubscriberTest.java
+++ b/hapi-fhir-jpaserver-subscription/src/test/java/ca/uhn/fhir/jpa/subscription/match/deliver/BaseSubscriptionDeliverySubscriberTest.java
@@ -5,11 +5,15 @@ import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory;
+import ca.uhn.fhir.jpa.subscription.channel.api.IChannelProducer;
+import ca.uhn.fhir.jpa.subscription.match.deliver.message.SubscriptionDeliveringMessageSubscriber;
import ca.uhn.fhir.jpa.subscription.match.deliver.resthook.SubscriptionDeliveringRestHookSubscriber;
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceDeliveryMessage;
+import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedMessage;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
@@ -23,6 +27,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.slf4j.Logger;
@@ -31,7 +36,9 @@ import org.springframework.messaging.Message;
import org.springframework.messaging.MessagingException;
import org.springframework.messaging.support.GenericMessage;
+import java.net.URISyntaxException;
import java.time.LocalDate;
+import java.util.List;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@@ -49,12 +56,18 @@ public class BaseSubscriptionDeliverySubscriberTest {
private static final Logger ourLog = LoggerFactory.getLogger(BaseSubscriptionDeliverySubscriberTest.class);
private SubscriptionDeliveringRestHookSubscriber mySubscriber;
+ private SubscriptionDeliveringMessageSubscriber myMessageSubscriber;
private final FhirContext myCtx = FhirContext.forR4();
@Mock
private IInterceptorBroadcaster myInterceptorBroadcaster;
@Mock
protected SubscriptionRegistry mySubscriptionRegistry;
+ @Mock
+ private IChannelFactory myChannelFactory;
+ @Mock
+ private IChannelProducer myChannelProducer;
+
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
private IRestfulClientFactory myRestfulClientFactory;
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
@@ -67,6 +80,11 @@ public class BaseSubscriptionDeliverySubscriberTest {
mySubscriber.setInterceptorBroadcasterForUnitTest(myInterceptorBroadcaster);
mySubscriber.setSubscriptionRegistryForUnitTest(mySubscriptionRegistry);
+ myMessageSubscriber = new SubscriptionDeliveringMessageSubscriber(myChannelFactory);
+ myMessageSubscriber.setFhirContextForUnitTest(myCtx);
+ myMessageSubscriber.setInterceptorBroadcasterForUnitTest(myInterceptorBroadcaster);
+ myMessageSubscriber.setSubscriptionRegistryForUnitTest(mySubscriptionRegistry);
+
myCtx.setRestfulClientFactory(myRestfulClientFactory);
when(myRestfulClientFactory.newGenericClient(any())).thenReturn(myGenericClient);
}
@@ -194,7 +212,6 @@ public class BaseSubscriptionDeliverySubscriberTest {
ourLog.info(jsonString);
-
// Assert that the partitionID is being serialized in JSON
assertThat(jsonString, containsString("\"partitionDate\":[2020,1,1]"));
assertThat(jsonString, containsString("\"partitionIds\":[123]"));
@@ -223,6 +240,30 @@ public class BaseSubscriptionDeliverySubscriberTest {
assertThat(jsonString, containsString("\"partitionIds\":[null]"));
}
+ @Test
+ public void testDeliveryMessageWithPartition() throws URISyntaxException {
+ RequestPartitionId thePartitionId = RequestPartitionId.fromPartitionId(123, LocalDate.of(2020, 1, 1));
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_BEFORE_MESSAGE_DELIVERY), any())).thenReturn(true);
+ when(myInterceptorBroadcaster.callHooks(eq(Pointcut.SUBSCRIPTION_AFTER_MESSAGE_DELIVERY), any())).thenReturn(false);
+ when(myChannelFactory.getOrCreateProducer(any(), any(), any())).thenReturn(myChannelProducer);
+
+ CanonicalSubscription subscription = generateSubscription();
+ Patient patient = generatePatient();
+
+ ResourceDeliveryMessage payload = new ResourceDeliveryMessage();
+ payload.setSubscription(subscription);
+ payload.setPayload(myCtx, patient, EncodingEnum.JSON);
+ payload.setOperationType(ResourceModifiedMessage.OperationTypeEnum.CREATE);
+ payload.setPartitionId(thePartitionId);
+
+ myMessageSubscriber.handleMessage(payload);
+ verify(myChannelFactory).getOrCreateProducer(any(), any(), any());
+ ArgumentCaptor captor = ArgumentCaptor.forClass(ResourceModifiedJsonMessage.class);
+ verify(myChannelProducer).send(captor.capture());
+ final List params = captor.getAllValues();
+ assertEquals(thePartitionId, params.get(0).getPayload().getPartitionId());
+ }
+
@Test
public void testSerializeLegacyDeliveryMessage() throws JsonProcessingException {
String legacyDeliveryMessageJson = "{\"headers\":{\"retryCount\":0,\"customHeaders\":{}},\"payload\":{\"operationType\":\"CREATE\",\"canonicalSubscription\":{\"id\":\"Subscription/123\",\"endpointUrl\":\"http://example.com/fhir\",\"payload\":\"application/fhir+json\"},\"payload\":\"{\\\"resourceType\\\":\\\"Patient\\\",\\\"active\\\":true}\"}}";
@@ -250,4 +291,5 @@ public class BaseSubscriptionDeliverySubscriberTest {
subscription.setPayloadString("application/fhir+json");
return subscription;
}
+
}
diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml
index e5e85064d3b..5b627067f66 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index 6e2a4733b10..d14b2441926 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml
index b41c4db1bf6..953e9979ebf 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmControllerSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmControllerSvc.java
index 46048e15292..cfbd8600725 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmControllerSvc.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmControllerSvc.java
@@ -22,6 +22,7 @@ package ca.uhn.fhir.mdm.api;
import ca.uhn.fhir.mdm.api.paging.MdmPageRequest;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseParameters;
@@ -34,10 +35,17 @@ import java.util.List;
public interface IMdmControllerSvc {
+ @Deprecated
Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest);
+ Page queryLinks(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, RequestDetails theRequestDetails);
+
+ Page queryLinksFromPartitionList(@Nullable String theGoldenResourceId, @Nullable String theSourceResourceId, @Nullable String theMatchResult, @Nullable String theLinkSource, MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, List thePartitionIds);
+
Page getDuplicateGoldenResources(MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest);
+ Page getDuplicateGoldenResources(MdmTransactionContext theMdmTransactionContext, MdmPageRequest thePageRequest, RequestDetails theRequestDetails);
+
void notDuplicateGoldenResource(String theGoldenResourceId, String theTargetGoldenResourceId, MdmTransactionContext theMdmTransactionContext);
IAnyResource mergeGoldenResources(String theFromGoldenResourceId, String theToGoldenResourceId, IAnyResource theManuallyMergedGoldenResource, MdmTransactionContext theMdmTransactionContext);
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmLinkQuerySvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmLinkQuerySvc.java
index 6d427ffece0..4147528e0ad 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmLinkQuerySvc.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmLinkQuerySvc.java
@@ -25,10 +25,14 @@ import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.data.domain.Page;
+import java.util.List;
+
/**
* This service supports the MDM operation providers for those services that return multiple MDM links.
*/
public interface IMdmLinkQuerySvc {
Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest);
+ Page queryLinks(IIdType theGoldenResourceId, IIdType theSourceResourceId, MdmMatchResultEnum theMatchResult, MdmLinkSourceEnum theLinkSource, MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId);
Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest);
+ Page getDuplicateGoldenResources(MdmTransactionContext theMdmContext, MdmPageRequest thePageRequest, List thePartitionId);
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMatchFinderSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMatchFinderSvc.java
index 5c6f450a00f..c5f8a3e4ce5 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMatchFinderSvc.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMatchFinderSvc.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.mdm.api;
* #L%
*/
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import org.hl7.fhir.instance.model.api.IAnyResource;
import javax.annotation.Nonnull;
@@ -36,5 +37,5 @@ public interface IMdmMatchFinderSvc {
* @return a List of {@link MatchedTarget} representing POSSIBLE_MATCH and MATCH outcomes.
*/
@Nonnull
- List getMatchedTargets(String theResourceType, IAnyResource theResource);
+ List getMatchedTargets(String theResourceType, IAnyResource theResource, RequestPartitionId theRequestPartitionId);
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSubmitSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSubmitSvc.java
index 0e9589d1dca..d4e3c77473d 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSubmitSvc.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSubmitSvc.java
@@ -20,6 +20,7 @@ package ca.uhn.fhir.mdm.api;
* #L%
*/
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import org.hl7.fhir.instance.model.api.IIdType;
import javax.annotation.Nullable;
@@ -37,7 +38,7 @@ public interface IMdmSubmitSvc {
*
* @return
*/
- long submitAllSourceTypesToMdm(@Nullable String theCriteria);
+ long submitAllSourceTypesToMdm(@Nullable String theCriteria, RequestDetails theRequestDetails);
/**
* Given a type and a search criteria, submit all found resources for MDM processing.
@@ -46,7 +47,7 @@ public interface IMdmSubmitSvc {
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for MDM processing..
* @return the number of resources submitted for MDM processing.
*/
- long submitSourceResourceTypeToMdm(String theSourceResourceType, String theCriteria);
+ long submitSourceResourceTypeToMdm(String theSourceResourceType, String theCriteria, RequestDetails theRequestDetails);
/**
* Convenience method that calls {@link #submitSourceResourceTypeToMdm(String, String)} with the type pre-populated.
@@ -54,7 +55,7 @@ public interface IMdmSubmitSvc {
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for MDM processing.
* @return the number of resources submitted for MDM processing.
*/
- long submitPractitionerTypeToMdm(String theCriteria);
+ long submitPractitionerTypeToMdm(String theCriteria, RequestDetails theRequestDetails);
/**
* Convenience method that calls {@link #submitSourceResourceTypeToMdm(String, String)} with the type pre-populated.
@@ -62,7 +63,7 @@ public interface IMdmSubmitSvc {
* @param theCriteria The FHIR search critieria for filtering the resources to be submitted for MDM processing.
* @return the number of resources submitted for MDM processing.
*/
- long submitPatientTypeToMdm(String theCriteria);
+ long submitPatientTypeToMdm(String theCriteria, RequestDetails theRequestDetails);
/**
* Given an ID and a source resource type valid for MDM, manually submit the given ID for MDM processing.
@@ -70,7 +71,7 @@ public interface IMdmSubmitSvc {
* @param theId the ID of the resource to process for MDM.
* @return the constant `1`, as if this function returns successfully, it will have processed one resource for MDM.
*/
- long submitSourceResourceToMdm(IIdType theId);
+ long submitSourceResourceToMdm(IIdType theId, RequestDetails theRequestDetails);
/**
* This setter exists to allow imported modules to override settings.
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
index 886e6145047..58637c6ca38 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/BaseMdmProvider.java
@@ -118,7 +118,7 @@ public abstract class BaseMdmProvider {
protected IBaseParameters parametersFromMdmLinks(Page theMdmLinkStream, boolean includeResultAndSource, ServletRequestDetails theServletRequestDetails, MdmPageRequest thePageRequest) {
IBaseParameters retval = ParametersUtil.newInstance(myFhirContext);
addPagingParameters(retval, theMdmLinkStream, theServletRequestDetails, thePageRequest);
- theMdmLinkStream.forEach(mdmLink -> {
+ theMdmLinkStream.getContent().forEach(mdmLink -> {
IBase resultPart = ParametersUtil.addParameterToParameters(myFhirContext, retval, "link");
ParametersUtil.addPartString(myFhirContext, resultPart, "goldenResourceId", mdmLink.getGoldenResourceId());
ParametersUtil.addPartString(myFhirContext, resultPart, "sourceResourceId", mdmLink.getSourceId());
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java
index f1f48b26080..6f4b067ba2b 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java
@@ -22,6 +22,8 @@ package ca.uhn.fhir.mdm.provider;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MatchedTarget;
@@ -29,6 +31,7 @@ import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.mdm.util.MessageHelper;
import ca.uhn.fhir.model.primitive.IdDt;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
@@ -60,18 +63,21 @@ public class MdmControllerHelper {
private final IMdmSettings myMdmSettings;
private final MessageHelper myMessageHelper;
private final IMdmMatchFinderSvc myMdmMatchFinderSvc;
+ private final IRequestPartitionHelperSvc myRequestPartitionHelperSvc;
@Autowired
public MdmControllerHelper(FhirContext theFhirContext,
IResourceLoader theResourceLoader,
IMdmMatchFinderSvc theMdmMatchFinderSvc,
IMdmSettings theMdmSettings,
- MessageHelper theMessageHelper) {
+ MessageHelper theMessageHelper,
+ IRequestPartitionHelperSvc theRequestPartitionHelperSvc) {
myFhirContext = theFhirContext;
myResourceLoader = theResourceLoader;
myMdmSettings = theMdmSettings;
myMdmMatchFinderSvc = theMdmMatchFinderSvc;
myMessageHelper = theMessageHelper;
+ myRequestPartitionHelperSvc = theRequestPartitionHelperSvc;
}
public void validateSameVersion(IAnyResource theResource, String theResourceId) {
@@ -130,8 +136,9 @@ public class MdmControllerHelper {
/**
* Helper method which will return a bundle of all Matches and Possible Matches.
*/
- public IBaseBundle getMatchesAndPossibleMatchesForResource(IAnyResource theResource, String theResourceType) {
- List matches = myMdmMatchFinderSvc.getMatchedTargets(theResourceType, theResource);
+ public IBaseBundle getMatchesAndPossibleMatchesForResource(IAnyResource theResource, String theResourceType, RequestDetails theRequestDetails) {
+ RequestPartitionId requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequest(theRequestDetails, theResourceType, null);
+ List matches = myMdmMatchFinderSvc.getMatchedTargets(theResourceType, theResource, requestPartitionId);
matches.sort(Comparator.comparing((MatchedTarget m) -> m.getMatchResult().getNormalizedScore()).reversed());
BundleBuilder builder = new BundleBuilder(myFhirContext);
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
index 64a193eda22..0d28d9300a5 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmProviderDstu3Plus.java
@@ -87,21 +87,23 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
}
@Operation(name = ProviderConstants.EMPI_MATCH, typeName = "Patient")
- public IBaseBundle match(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1, typeName = "Patient") IAnyResource thePatient) {
+ public IBaseBundle match(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1, typeName = "Patient") IAnyResource thePatient,
+ RequestDetails theRequestDetails) {
if (thePatient == null) {
throw new InvalidRequestException(Msg.code(1498) + "resource may not be null");
}
- return myMdmControllerHelper.getMatchesAndPossibleMatchesForResource(thePatient, "Patient");
+ return myMdmControllerHelper.getMatchesAndPossibleMatchesForResource(thePatient, "Patient", theRequestDetails);
}
@Operation(name = ProviderConstants.MDM_MATCH)
public IBaseBundle serverMatch(@OperationParam(name = ProviderConstants.MDM_MATCH_RESOURCE, min = 1, max = 1) IAnyResource theResource,
- @OperationParam(name = ProviderConstants.MDM_RESOURCE_TYPE, min = 1, max = 1, typeName = "string") IPrimitiveType theResourceType
+ @OperationParam(name = ProviderConstants.MDM_RESOURCE_TYPE, min = 1, max = 1, typeName = "string") IPrimitiveType theResourceType,
+ RequestDetails theRequestDetails
) {
if (theResource == null) {
throw new InvalidRequestException(Msg.code(1499) + "resource may not be null");
}
- return myMdmControllerHelper.getMatchesAndPossibleMatchesForResource(theResource, theResourceType.getValueAsString());
+ return myMdmControllerHelper.getMatchesAndPossibleMatchesForResource(theResource, theResourceType.getValueAsString(), theRequestDetails);
}
@Operation(name = ProviderConstants.MDM_MERGE_GOLDEN_RESOURCES)
@@ -184,13 +186,13 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT, min = 0, max = 1, typeName = "integer")
IPrimitiveType theCount,
-
ServletRequestDetails theRequestDetails) {
MdmPageRequest mdmPageRequest = new MdmPageRequest(theOffset, theCount, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
Page mdmLinkJson = myMdmControllerSvc.queryLinks(extractStringOrNull(theGoldenResourceId),
extractStringOrNull(theResourceId), extractStringOrNull(theMatchResult), extractStringOrNull(theLinkSource),
createMdmContext(theRequestDetails, MdmTransactionContext.OperationType.QUERY_LINKS,
- getResourceType(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId)), mdmPageRequest);
+ getResourceType(ProviderConstants.MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID, theGoldenResourceId)),
+ mdmPageRequest, theRequestDetails);
return parametersFromMdmLinks(mdmLinkJson, true, theRequestDetails, mdmPageRequest);
}
@@ -207,7 +209,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
MdmPageRequest mdmPageRequest = new MdmPageRequest(theOffset, theCount, DEFAULT_PAGE_SIZE, MAX_PAGE_SIZE);
- Page possibleDuplicates = myMdmControllerSvc.getDuplicateGoldenResources(createMdmContext(theRequestDetails, MdmTransactionContext.OperationType.DUPLICATE_GOLDEN_RESOURCES, null), mdmPageRequest);
+ Page possibleDuplicates = myMdmControllerSvc.getDuplicateGoldenResources(createMdmContext(theRequestDetails, MdmTransactionContext.OperationType.DUPLICATE_GOLDEN_RESOURCES, null), mdmPageRequest, theRequestDetails);
return parametersFromMdmLinks(possibleDuplicates, false, theRequestDetails, mdmPageRequest);
}
@@ -239,9 +241,9 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
String resourceType = convertStringTypeToString(theResourceType);
long submittedCount;
if (resourceType != null) {
- submittedCount = myMdmSubmitSvc.submitSourceResourceTypeToMdm(resourceType, criteria);
+ submittedCount = myMdmSubmitSvc.submitSourceResourceTypeToMdm(resourceType, criteria, theRequestDetails);
} else {
- submittedCount = myMdmSubmitSvc.submitAllSourceTypesToMdm(criteria);
+ submittedCount = myMdmSubmitSvc.submitAllSourceTypesToMdm(criteria, theRequestDetails);
}
return buildMdmOutParametersWithCount(submittedCount);
}
@@ -257,7 +259,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
public IBaseParameters mdmBatchPatientInstance(
@IdParam IIdType theIdParam,
RequestDetails theRequest) {
- long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam);
+ long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam, theRequest);
return buildMdmOutParametersWithCount(submittedCount);
}
@@ -268,7 +270,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA, typeName = "string") IPrimitiveType theCriteria,
RequestDetails theRequest) {
String criteria = convertStringTypeToString(theCriteria);
- long submittedCount = myMdmSubmitSvc.submitPatientTypeToMdm(criteria);
+ long submittedCount = myMdmSubmitSvc.submitPatientTypeToMdm(criteria, theRequest);
return buildMdmOutParametersWithCount(submittedCount);
}
@@ -278,7 +280,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
public IBaseParameters mdmBatchPractitionerInstance(
@IdParam IIdType theIdParam,
RequestDetails theRequest) {
- long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam);
+ long submittedCount = myMdmSubmitSvc.submitSourceResourceToMdm(theIdParam, theRequest);
return buildMdmOutParametersWithCount(submittedCount);
}
@@ -289,7 +291,7 @@ public class MdmProviderDstu3Plus extends BaseMdmProvider {
@OperationParam(name = ProviderConstants.MDM_BATCH_RUN_CRITERIA, typeName = "string") IPrimitiveType theCriteria,
RequestDetails theRequest) {
String criteria = convertStringTypeToString(theCriteria);
- long submittedCount = myMdmSubmitSvc.submitPractitionerTypeToMdm(criteria);
+ long submittedCount = myMdmSubmitSvc.submitPractitionerTypeToMdm(criteria, theRequest);
return buildMdmOutParametersWithCount(submittedCount);
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/GoldenResourceHelper.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/GoldenResourceHelper.java
index a4d6aa973c6..2fdd66a58f2 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/GoldenResourceHelper.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/GoldenResourceHelper.java
@@ -32,6 +32,7 @@ import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.CanonicalEID;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
+import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.util.FhirTerser;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBase;
@@ -98,6 +99,9 @@ public class GoldenResourceHelper {
MdmResourceUtil.setMdmManaged(newGoldenResource);
MdmResourceUtil.setGoldenResource(newGoldenResource);
+ // add the partition id to the new resource
+ newGoldenResource.setUserData(Constants.RESOURCE_PARTITION_ID, theIncomingResource.getUserData(Constants.RESOURCE_PARTITION_ID));
+
return (T) newGoldenResource;
}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MessageHelper.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MessageHelper.java
index a20c4ecaa9d..7f8f05335da 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MessageHelper.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MessageHelper.java
@@ -21,9 +21,9 @@ package ca.uhn.fhir.mdm.util;
*/
import ca.uhn.fhir.context.FhirContext;
+import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmConstants;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
-import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.springframework.beans.factory.annotation.Autowired;
@@ -111,4 +111,13 @@ public class MessageHelper {
public String getMessageForFailedGoldenResourceLoad(String theParamName, String theGoldenResourceId) {
return theGoldenResourceId + " used as parameter [" + theParamName + "] could not be loaded as a golden resource, as it appears to be lacking the golden resource meta tags.";
}
+
+ public String getMessageForMismatchPartition(IAnyResource theGoldenRecord, IAnyResource theSourceResource) {
+ return getMessageForMismatchPartition(theGoldenRecord.getIdElement().toVersionless().toString(),
+ theSourceResource.getIdElement().toVersionless().toString());
+ }
+
+ public String getMessageForMismatchPartition(String theGoldenRecord, String theSourceResource) {
+ return theGoldenRecord + " and " + theSourceResource + " are stored in different partitions. This operation is only available for resources on the same partition.";
+ }
}
diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml
index 3b4d7b79fb0..84bd20d691f 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml
index 182be5d0d91..e0fcd4bad9a 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/provider/ProviderConstants.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/provider/ProviderConstants.java
index 46c11aa6cba..c56013d9264 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/provider/ProviderConstants.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/provider/ProviderConstants.java
@@ -88,6 +88,7 @@ public class ProviderConstants {
public static final String MDM_QUERY_LINKS = "$mdm-query-links";
public static final String MDM_QUERY_LINKS_GOLDEN_RESOURCE_ID = "goldenResourceId";
public static final String MDM_QUERY_LINKS_RESOURCE_ID = "resourceId";
+ public static final String MDM_QUERY_PARTITION_IDS = "partitionIds";
public static final String MDM_QUERY_LINKS_MATCH_RESULT = "matchResult";
public static final String MDM_QUERY_LINKS_LINK_SOURCE = "linkSource";
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 5f8e9a6b9e8..156612065f4 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 c18ba0fe5d1..d7e02a72215 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 33a06a40522..b958bf16589 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 e49dcb4b634..8c9d210c4ac 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 0353eca64d5..495255f0e32 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 580e8c84eaf..eacf28a7391 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml
index 3c1d2d50cf5..bc2ec54701b 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml
index abc281b0919..146e2a10aee 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 cd2f77337b0..f06eeae2dcd 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
4.0.0
diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml
index cbf54f816fa..209422bcedb 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml
index 8613fd361ea..cedcaa104c0 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java
index cccc42881a7..d17a004d232 100644
--- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java
+++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/IRequestPartitionHelperSvc.java
@@ -35,7 +35,7 @@ import java.util.Set;
public interface IRequestPartitionHelperSvc {
@Nonnull
- RequestPartitionId determineReadPartitionForRequest(@Nullable RequestDetails theRequest, String theResourceType, @Nonnull ReadPartitionIdRequestDetails theDetails);
+ RequestPartitionId determineReadPartitionForRequest(@Nullable RequestDetails theRequest, String theResourceType, ReadPartitionIdRequestDetails theDetails);
@Nonnull
default RequestPartitionId determineReadPartitionForRequestForRead(RequestDetails theRequest, String theResourceType, IIdType theId) {
@@ -55,6 +55,9 @@ public interface IRequestPartitionHelperSvc {
return determineReadPartitionForRequest(theRequest, theResourceType, details);
}
+ @Nonnull
+ default void validateHasPartitionPermissions(RequestDetails theRequest, String theResourceType, RequestPartitionId theRequestPartitionId){}
+
@Nonnull
RequestPartitionId determineCreatePartitionForRequest(@Nullable RequestDetails theRequest, @Nonnull IBaseResource theResource, @Nonnull String theResourceType);
diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/SystemRequestDetails.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/SystemRequestDetails.java
index 9e27d1dc5b8..0d740335134 100644
--- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/SystemRequestDetails.java
+++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/partition/SystemRequestDetails.java
@@ -57,7 +57,7 @@ public class SystemRequestDetails extends RequestDetails {
super(new MyInterceptorBroadcaster());
}
- public static SystemRequestDetails forAllPartition(){
+ public static SystemRequestDetails forAllPartitions(){
return new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.allPartitions());
}
diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml
index 55362f80b65..2ffa4be5db1 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index 8c1b0f5b9ba..b4c347d03da 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml
index 62165125e54..7e515aa94b8 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 18f8e9b4b7b..7cb8d1bd89f 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml
index 80eea6b82f5..d32002b239b 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml
index 5d80472cb26..dc06844df85 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml
index 085ba424fa6..f349c3d8867 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index e3a5131c087..0724aa8a34a 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml
index 56fcb133bab..a04333f2928 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 7bfbeaf23ac..40cb90ce17e 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 7e006905e85..69ef0bca7c2 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 9e60a65b368..cd548fb3885 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 2638ce3ea7d..36347eb9d0a 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml
index 2ea9d1f9bf0..dd952554961 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml
index 4f87e0e7bfa..32b1648774d 100644
--- a/hapi-tinder-plugin/pom.xml
+++ b/hapi-tinder-plugin/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
@@ -58,37 +58,37 @@
ca.uhn.hapi.fhir
hapi-fhir-structures-dstu3
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-hl7org-dstu2
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r4
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r5
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu2
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu3
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-r4
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
org.apache.velocity
diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml
index f7a3a430de8..19ba66d4e44 100644
--- a/hapi-tinder-test/pom.xml
+++ b/hapi-tinder-test/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../pom.xml
diff --git a/pom.xml b/pom.xml
index 920a6629beb..3a8d6d08400 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
pom
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
HAPI-FHIR
An open-source implementation of the FHIR specification in Java.
https://hapifhir.io
@@ -2004,7 +2004,7 @@
ca.uhn.hapi.fhir
hapi-fhir-checkstyle
- 6.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
index f82171b6b1d..18e5614d0f2 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 6db480a3e3e..c54b8366b2f 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-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 abba9a6d26e..3c393fd4623 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.0.0-PRE9-SNAPSHOT
+ 6.0.0-PRE10-SNAPSHOT
../../pom.xml