diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml
index d6f65b91794..17dbf26162e 100644
--- a/hapi-deployable-pom/pom.xml
+++ b/hapi-deployable-pom/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml
index 3d3a0683523..150ce2c1295 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml
index 8f8e138ac7a..98e10ec3c10 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml
index fb52d568b9f..346a929a547 100644
--- a/hapi-fhir-bom/pom.xml
+++ b/hapi-fhir-bom/pom.xml
@@ -4,7 +4,7 @@
4.0.0
ca.uhn.hapi.fhir
hapi-fhir-bom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
pom
HAPI FHIR BOM
@@ -12,7 +12,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml
index 7b4c1afe91d..4f4df91ba18 100644
--- a/hapi-fhir-checkstyle/pom.xml
+++ b/hapi-fhir-checkstyle/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-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 cbd07617e0f..c378ea02796 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.9.8-SNAPSHOT
+ 6.9.9-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 982c6c46480..04a840db292 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml
index cd84edbca81..a98004d7d99 100644
--- a/hapi-fhir-cli/pom.xml
+++ b/hapi-fhir-cli/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml
index 08d53f813c0..b91cee3d080 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml
index 38cac3e4603..ab4e11fa4c1 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml
index c067f7e19c9..f736e14d80d 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml
index bef8a3b2810..a08d329cbee 100644
--- a/hapi-fhir-dist/pom.xml
+++ b/hapi-fhir-dist/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml
index e6042b475df..2d137c54951 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5274-adding-metric-svc-to-mdm.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5274-adding-metric-svc-to-mdm.yaml
new file mode 100644
index 00000000000..6d9b3be278f
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/7_0_0/5274-adding-metric-svc-to-mdm.yaml
@@ -0,0 +1,6 @@
+---
+type: add
+issue: 5274
+title: "Added a service for generating metrics on mdm links and resources.
+ This includes JPA queries and updated indices.
+ "
diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml
index 5e82fe2a42b..89cc744fcc2 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml
index 9ed9b7cc147..17ae3e225c7 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml
index cd0d62fd93a..32ffc32391c 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml
index 223eb3c1ffa..954eac61b5f 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkJpaMetricsRepository.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkJpaMetricsRepository.java
new file mode 100644
index 00000000000..03566ca238a
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/data/IMdmLinkJpaMetricsRepository.java
@@ -0,0 +1,27 @@
+package ca.uhn.fhir.jpa.dao.data;
+
+import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.Query;
+import org.springframework.data.repository.query.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository("metricsRepository")
+public interface IMdmLinkJpaMetricsRepository extends JpaRepository, IHapiFhirJpaRepository {
+
+ @Query("SELECT ml.myMatchResult AS match_result, ml.myLinkSource AS link_source, count(*) AS c "
+ + "FROM MdmLink ml "
+ + "WHERE ml.myMdmSourceType = :resourceName "
+ + "AND ml.myLinkSource in (:linkSource) "
+ + "AND ml.myMatchResult in (:matchResult) "
+ + "GROUP BY match_result, link_source "
+ + "ORDER BY match_result")
+ Object[][] generateMetrics(
+ @Param("resourceName") String theResourceType,
+ @Param("linkSource") List theLinkSources,
+ @Param("matchResult") List theMatchTypes);
+}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmMetricSvcJpaImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmMetricSvcJpaImpl.java
new file mode 100644
index 00000000000..6f1b4a57ff4
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/mdm/MdmMetricSvcJpaImpl.java
@@ -0,0 +1,136 @@
+package ca.uhn.fhir.jpa.dao.mdm;
+
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaMetricsRepository;
+import ca.uhn.fhir.mdm.api.BaseMdmMetricSvc;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.api.params.GenerateMdmMetricsParameters;
+import ca.uhn.fhir.mdm.model.MdmLinkMetrics;
+import ca.uhn.fhir.mdm.model.MdmLinkScoreMetrics;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+import ca.uhn.fhir.mdm.model.MdmResourceMetrics;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.math.BigInteger;
+import java.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.persistence.Query;
+
+public class MdmMetricSvcJpaImpl extends BaseMdmMetricSvc {
+
+ private final IMdmLinkJpaMetricsRepository myJpaRepository;
+
+ private final EntityManagerFactory myEntityManagerFactory;
+
+ public MdmMetricSvcJpaImpl(
+ IMdmLinkJpaMetricsRepository theRepository,
+ DaoRegistry theDaoRegistry,
+ EntityManagerFactory theEntityManagerFactory) {
+ super(theDaoRegistry);
+ myJpaRepository = theRepository;
+ myEntityManagerFactory = theEntityManagerFactory;
+ }
+
+ protected MdmLinkMetrics generateLinkMetrics(GenerateMdmMetricsParameters theParameters) {
+ List linkSources = theParameters.getLinkSourceFilters();
+ List matchResults = theParameters.getMatchResultFilters();
+
+ if (linkSources.isEmpty()) {
+ linkSources = Arrays.asList(MdmLinkSourceEnum.values());
+ }
+ if (matchResults.isEmpty()) {
+ matchResults = Arrays.asList(MdmMatchResultEnum.values());
+ }
+
+ Object[][] data = myJpaRepository.generateMetrics(theParameters.getResourceType(), linkSources, matchResults);
+ MdmLinkMetrics metrics = new MdmLinkMetrics();
+ metrics.setResourceType(theParameters.getResourceType());
+ for (Object[] row : data) {
+ MdmMatchResultEnum matchResult = (MdmMatchResultEnum) row[0];
+ MdmLinkSourceEnum source = (MdmLinkSourceEnum) row[1];
+ long count = (Long) row[2];
+ metrics.addMetric(matchResult, source, count);
+ }
+ return metrics;
+ }
+
+ protected MdmLinkScoreMetrics generateLinkScoreMetrics(GenerateMdmMetricsParameters theParameters) {
+ String resourceType = theParameters.getResourceType();
+
+ List matchResultTypes = theParameters.getMatchResultFilters();
+
+ // if no result type filter, add all result types
+ if (matchResultTypes.isEmpty()) {
+ matchResultTypes = Arrays.asList(MdmMatchResultEnum.values());
+ }
+
+ String sql = "SELECT %s FROM MPI_LINK ml WHERE ml.TARGET_TYPE = :resourceType "
+ + "AND ml.MATCH_RESULT in (:matchResult)";
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("sum(case when ml.SCORE is null then 1 else 0 end) as B_" + NULL_VALUE);
+
+ for (int i = 0; i < BUCKETS; i++) {
+ double bucket = getBucket(i + 1);
+ sb.append(",\n");
+ if (i == 0) {
+ // score <= .01
+ sb.append(String.format("sum(case when ml.SCORE <= %.2f then 1 else 0 end) as B%d", bucket, i));
+ } else {
+ // score > i/100 && score <= i/100
+ sb.append(String.format(
+ "sum(case when ml.score > %.2f and ml.SCORE <= %.2f then 1 else 0 end) as B%d",
+ getBucket(i), bucket, i));
+ }
+ }
+
+ EntityManager em = myEntityManagerFactory.createEntityManager();
+
+ Query nativeQuery = em.createNativeQuery(String.format(sql, sb.toString()));
+
+ org.hibernate.query.Query> hibernateQuery = (org.hibernate.query.Query>) nativeQuery;
+
+ hibernateQuery.setParameter("resourceType", resourceType);
+ hibernateQuery.setParameter(
+ "matchResult", matchResultTypes.stream().map(Enum::ordinal).collect(Collectors.toList()));
+
+ List> results = hibernateQuery.getResultList();
+
+ em.close();
+
+ MdmLinkScoreMetrics metrics = new MdmLinkScoreMetrics();
+
+ // we only get one row back
+ Object[] row = (Object[]) results.get(0);
+ int length = row.length;
+ for (int i = 0; i < length; i++) {
+ // if there's nothing in the db, these values will all be null
+ BigInteger bi = row[i] != null ? (BigInteger) row[i] : BigInteger.valueOf(0);
+ double bucket = getBucket(i);
+ if (i == 0) {
+ metrics.addScore(NULL_VALUE, bi.longValue());
+ } else if (i == 1) {
+ metrics.addScore(String.format(FIRST_BUCKET, bucket), bi.longValue());
+ } else {
+ metrics.addScore(String.format(NTH_BUCKET, getBucket(i - 1), bucket), bi.longValue());
+ }
+ }
+
+ return metrics;
+ }
+
+ @Transactional
+ @Override
+ public MdmMetrics generateMdmMetrics(GenerateMdmMetricsParameters theParameters) {
+ MdmResourceMetrics resourceMetrics = generateResourceMetrics(theParameters);
+ MdmLinkMetrics linkMetrics = generateLinkMetrics(theParameters);
+ MdmLinkScoreMetrics scoreMetrics = generateLinkScoreMetrics(theParameters);
+
+ MdmMetrics metrics = MdmMetrics.fromSeperableMetrics(resourceMetrics, linkMetrics, scoreMetrics);
+ return metrics;
+ }
+}
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 24e5063ab0c..4363bde74c5 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
@@ -64,7 +64,10 @@ import javax.persistence.UniqueConstraint;
@Index(name = "IDX_EMPI_MATCH_TGT_VER", columnList = "MATCH_RESULT, TARGET_PID, VERSION"),
// v---- this one
@Index(name = "IDX_EMPI_GR_TGT", columnList = "GOLDEN_RESOURCE_PID, TARGET_PID"),
- @Index(name = "FK_EMPI_LINK_TARGET", columnList = "TARGET_PID")
+ @Index(name = "FK_EMPI_LINK_TARGET", columnList = "TARGET_PID"),
+ // indexes for metrics
+ @Index(name = "IDX_EMPI_TGT_MR_LS", columnList = "TARGET_TYPE, MATCH_RESULT, LINK_SOURCE"),
+ @Index(name = "IDX_EMPI_TGT_MR_SCORE", columnList = "TARGET_TYPE, MATCH_RESULT, SCORE")
})
@Audited
// This is the table name generated by default by envers, but we set it explicitly for clarity
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 b68af9bc768..c17de307498 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
@@ -93,6 +93,23 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks {
init640_after_20230126();
init660();
init680();
+ init700();
+ }
+
+ protected void init700() {
+ Builder version = forVersion(VersionEnum.V7_0_0);
+
+ // new indices on MdmLink
+ Builder.BuilderWithTableName mdmLinkTable = version.onTable("MPI_LINK");
+
+ mdmLinkTable
+ .addIndex("20230911.1", "IDX_EMPI_TGT_MR_LS")
+ .unique(false)
+ .withColumns("TARGET_TYPE", "MATCH_RESULT", "LINK_SOURCE");
+ mdmLinkTable
+ .addIndex("20230911.2", "IDX_EMPi_TGT_MR_SCore")
+ .unique(false)
+ .withColumns("TARGET_TYPE", "MATCH_RESULT", "SCORE");
}
protected void init680() {
diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
index 6f7859823db..bee277633ec 100644
--- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
+++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-hfql/pom.xml b/hapi-fhir-jpaserver-hfql/pom.xml
index 452671378ab..a2ac4d063a4 100644
--- a/hapi-fhir-jpaserver-hfql/pom.xml
+++ b/hapi-fhir-jpaserver-hfql/pom.xml
@@ -3,7 +3,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml
index c48e50f0fc4..db9e2677280 100644
--- a/hapi-fhir-jpaserver-ips/pom.xml
+++ b/hapi-fhir-jpaserver-ips/pom.xml
@@ -3,7 +3,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml
index 3ee942fbcd1..b7e925ea214 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
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 1d82d9e49a1..2c80e680249 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
@@ -39,7 +39,7 @@ import ca.uhn.fhir.jpa.mdm.svc.MdmLinkUpdaterSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmMatchFinderSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmMatchLinkSvc;
import ca.uhn.fhir.jpa.mdm.svc.MdmModelConverterSvcImpl;
-import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
+import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvcImpl;
import ca.uhn.fhir.jpa.mdm.svc.MdmResourceFilteringSvc;
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateSearcher;
import ca.uhn.fhir.jpa.mdm.svc.candidate.FindCandidateByEidSvc;
@@ -57,6 +57,7 @@ import ca.uhn.fhir.mdm.api.IMdmLinkQuerySvc;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
import ca.uhn.fhir.mdm.api.IMdmMatchFinderSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.batch2.MdmBatch2Config;
import ca.uhn.fhir.mdm.blocklist.svc.IBlockListRuleProvider;
@@ -123,8 +124,8 @@ public class MdmConsumerConfig {
}
@Bean
- MdmResourceDaoSvc mdmResourceDaoSvc() {
- return new MdmResourceDaoSvc();
+ IMdmResourceDaoSvc mdmResourceDaoSvc() {
+ return new MdmResourceDaoSvcImpl();
}
@Bean
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 b1e15c91a40..fb60e425f57 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
@@ -29,6 +29,7 @@ import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IGoldenResourceMergerSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
@@ -74,7 +75,7 @@ public class GoldenResourceMergerSvcImpl implements IGoldenResourceMergerSvc {
IIdHelperService myIdHelperService;
@Autowired
- MdmResourceDaoSvc myMdmResourceDaoSvc;
+ IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
MdmPartitionHelper myMdmPartitionHelper;
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmEidUpdateService.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmEidUpdateService.java
index 95e445012d3..52677a69b51 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmEidUpdateService.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmEidUpdateService.java
@@ -24,6 +24,7 @@ import ca.uhn.fhir.jpa.mdm.svc.candidate.MatchedGoldenResourceCandidate;
import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@@ -49,7 +50,7 @@ public class MdmEidUpdateService {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
- private MdmResourceDaoSvc myMdmResourceDaoSvc;
+ private IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
private IMdmLinkSvc myMdmLinkSvc;
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcImpl.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcImpl.java
index 3870b5d3393..027f69e3b7f 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcImpl.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkSvcImpl.java
@@ -25,6 +25,7 @@ import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
@@ -51,7 +52,7 @@ public class MdmLinkSvcImpl implements IMdmLinkSvc {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
- private MdmResourceDaoSvc myMdmResourceDaoSvc;
+ private IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
private MdmLinkDaoSvc myMdmLinkDaoSvc;
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 96892d37965..c37ff21be1d 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
@@ -30,6 +30,7 @@ import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
import ca.uhn.fhir.mdm.api.IMdmLink;
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.IMdmSurvivorshipService;
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
@@ -72,7 +73,7 @@ public class MdmLinkUpdaterSvcImpl implements IMdmLinkUpdaterSvc {
MdmLinkDaoSvc myMdmLinkDaoSvc;
@Autowired
- MdmResourceDaoSvc myMdmResourceDaoSvc;
+ IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
MdmMatchLinkSvc myMdmMatchLinkSvc;
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 b7fba3ab877..f3512ea535a 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
@@ -19,6 +19,7 @@
*/
package ca.uhn.fhir.jpa.mdm.svc;
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.mdm.models.FindGoldenResourceCandidatesParams;
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateList;
import ca.uhn.fhir.jpa.mdm.svc.candidate.CandidateStrategyEnum;
@@ -70,6 +71,9 @@ public class MdmMatchLinkSvc {
@Autowired
private IBlockRuleEvaluationSvc myBlockRuleEvaluationSvc;
+ @Autowired
+ private DaoRegistry myDaoRegistry;
+
@Autowired
private IMdmSurvivorshipService myMdmSurvivorshipService;
@@ -106,6 +110,8 @@ public class MdmMatchLinkSvc {
* (so that future resources may match to it).
*/
boolean isResourceBlocked = myBlockRuleEvaluationSvc.isMdmMatchingBlocked(theResource);
+ // we will mark the golden resource special for this
+ theMdmTransactionContext.setIsBlocked(isResourceBlocked);
if (!isResourceBlocked) {
FindGoldenResourceCandidatesParams params =
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/MdmResourceDaoSvcImpl.java
similarity index 83%
rename from hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvc.java
rename to hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/MdmResourceDaoSvcImpl.java
index 90d581ca649..2cf9489ee13 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/MdmResourceDaoSvcImpl.java
@@ -26,14 +26,15 @@ 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.searchparam.SearchParameterMap;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmSettings;
import ca.uhn.fhir.mdm.api.MdmConstants;
+import ca.uhn.fhir.mdm.util.MdmSearchParamBuildingUtils;
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.SystemRequestDetails;
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
-import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
@@ -42,10 +43,9 @@ import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Optional;
-import javax.annotation.Nonnull;
@Service
-public class MdmResourceDaoSvc {
+public class MdmResourceDaoSvcImpl implements IMdmResourceDaoSvc {
private static final int MAX_MATCHING_GOLDEN_RESOURCES = 1000;
@@ -55,6 +55,7 @@ public class MdmResourceDaoSvc {
@Autowired
IMdmSettings myMdmSettings;
+ @Override
public DaoMethodOutcome upsertGoldenResource(IAnyResource theGoldenResource, String theResourceType) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
RequestDetails requestDetails = new SystemRequestDetails().setRequestPartitionId((RequestPartitionId)
@@ -66,12 +67,7 @@ public class MdmResourceDaoSvc {
}
}
- /**
- * Given a resource, remove its Golden Resource tag.
- *
- * @param theGoldenResource the {@link IAnyResource} to remove the tag from.
- * @param theResourcetype the type of that resource
- */
+ @Override
public void removeGoldenResourceTag(IAnyResource theGoldenResource, String theResourcetype) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourcetype);
RequestDetails requestDetails = new SystemRequestDetails().setRequestPartitionId((RequestPartitionId)
@@ -84,18 +80,22 @@ public class MdmResourceDaoSvc {
requestDetails);
}
+ @Override
public IAnyResource readGoldenResourceByPid(IResourcePersistentId theGoldenResourcePid, String theResourceType) {
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
return (IAnyResource) resourceDao.readByPid(theGoldenResourcePid);
}
+ @Override
public Optional searchGoldenResourceByEID(String theEid, String theResourceType) {
return this.searchGoldenResourceByEID(theEid, theResourceType, null);
}
+ @Override
public Optional searchGoldenResourceByEID(
String theEid, String theResourceType, RequestPartitionId thePartitionId) {
- SearchParameterMap map = buildEidSearchParameterMap(theEid, theResourceType);
+ SearchParameterMap map = MdmSearchParamBuildingUtils.buildEidSearchParameterMap(
+ theEid, theResourceType, myMdmSettings.getMdmRules());
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theResourceType);
SystemRequestDetails systemRequestDetails = new SystemRequestDetails();
@@ -118,16 +118,4 @@ public class MdmResourceDaoSvc {
return Optional.of((IAnyResource) resources.get(0));
}
}
-
- @Nonnull
- private SearchParameterMap buildEidSearchParameterMap(String theEid, String theResourceType) {
- SearchParameterMap map = new SearchParameterMap();
- map.setLoadSynchronous(true);
- map.add(
- "identifier",
- new TokenParam(
- myMdmSettings.getMdmRules().getEnterpriseEIDSystemForResourceType(theResourceType), theEid));
- map.add("_tag", new TokenParam(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD));
- return map;
- }
}
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 2ab9e19ace0..e887cb47b39 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
@@ -21,8 +21,8 @@ package ca.uhn.fhir.jpa.mdm.svc.candidate;
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
import ca.uhn.fhir.jpa.mdm.dao.MdmLinkDaoSvc;
-import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.IMdmLink;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.CanonicalEID;
@@ -47,7 +47,7 @@ public class FindCandidateByEidSvc extends BaseCandidateFinder {
private EIDHelper myEIDHelper;
@Autowired
- private MdmResourceDaoSvc myMdmResourceDaoSvc;
+ private IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
private MdmLinkDaoSvc myMdmLinkDaoSvc;
diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmGoldenResourceFindingSvc.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmGoldenResourceFindingSvc.java
index 073ca1ced2b..c6f235eda67 100644
--- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmGoldenResourceFindingSvc.java
+++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/svc/candidate/MdmGoldenResourceFindingSvc.java
@@ -20,7 +20,7 @@
package ca.uhn.fhir.jpa.mdm.svc.candidate;
import ca.uhn.fhir.jpa.mdm.models.FindGoldenResourceCandidatesParams;
-import ca.uhn.fhir.jpa.mdm.svc.MdmResourceDaoSvc;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.log.Logs;
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
@@ -36,7 +36,7 @@ public class MdmGoldenResourceFindingSvc {
private static final Logger ourLog = Logs.getMdmTroubleshootingLog();
@Autowired
- private MdmResourceDaoSvc myMdmResourceDaoSvc;
+ private IMdmResourceDaoSvc myMdmResourceDaoSvc;
@Autowired
private FindCandidateByEidSvc myFindCandidateByEidSvc;
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 e1474eada1a..3e9d31edb6b 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
@@ -98,8 +98,6 @@ abstract public class BaseMdmR4Test extends BaseJpaR4Test {
.setValue("555-555-5555");
private static final String NAME_GIVEN_FRANK = "Frank";
-
-
@Autowired
protected IFhirResourceDao myPatientDao;
@Autowired
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/dao/MdmMetricSvcJpaIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/dao/MdmMetricSvcJpaIT.java
new file mode 100644
index 00000000000..77a186cc549
--- /dev/null
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/dao/MdmMetricSvcJpaIT.java
@@ -0,0 +1,172 @@
+package ca.uhn.fhir.jpa.mdm.dao;
+
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.config.HapiFhirLocalContainerEntityManagerFactoryBean;
+import ca.uhn.fhir.jpa.dao.data.IMdmLinkJpaMetricsRepository;
+import ca.uhn.fhir.jpa.dao.mdm.MdmMetricSvcJpaImpl;
+import ca.uhn.fhir.jpa.entity.MdmLink;
+import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
+import ca.uhn.fhir.jpa.mdm.IMdmMetricSvcTest;
+import ca.uhn.fhir.jpa.mdm.helper.MdmLinkHelper;
+import ca.uhn.fhir.jpa.mdm.helper.testmodels.MDMState;
+import ca.uhn.fhir.jpa.mdm.models.GenerateMetricsTestParameters;
+import ca.uhn.fhir.jpa.mdm.models.LinkMetricTestParameters;
+import ca.uhn.fhir.jpa.mdm.models.LinkScoreMetricTestParams;
+import ca.uhn.fhir.jpa.mdm.models.ResourceMetricTestParams;
+import ca.uhn.fhir.jpa.model.dao.JpaPid;
+import ca.uhn.fhir.mdm.api.IMdmMetricSvc;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+import ca.uhn.fhir.mdm.util.MdmResourceUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.hl7.fhir.r4.model.Patient;
+import org.junit.jupiter.api.BeforeEach;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.test.context.ContextConfiguration;
+
+import javax.persistence.EntityManagerFactory;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.fail;
+
+@ContextConfiguration(classes = {
+ MdmMetricSvcJpaIT.TestConfig.class
+})
+public class MdmMetricSvcJpaIT extends BaseMdmR4Test implements IMdmMetricSvcTest {
+
+ private static final Logger ourLog = LoggerFactory.getLogger(MdmMetricSvcJpaIT.class);
+
+ @Configuration
+ public static class TestConfig {
+
+ @Autowired
+ @Qualifier("metricsRepository")
+ private IMdmLinkJpaMetricsRepository myJpaRepository;
+
+ @Autowired
+ private DaoRegistry myDaoRegistry;
+
+ @Autowired
+ private EntityManagerFactory myEntityManagerFactory;
+
+ @Autowired
+ private HapiFhirLocalContainerEntityManagerFactoryBean myEntityFactory;
+
+ // this has to be provided via spring, or the
+ // @Transactional barrier is never invoked
+ @Bean
+ IMdmMetricSvc mdmMetricSvc() {
+ return new MdmMetricSvcJpaImpl(
+ myJpaRepository,
+ myDaoRegistry,
+ myEntityManagerFactory
+ );
+ }
+ }
+
+ private final ObjectMapper myObjectMapper = new ObjectMapper();
+
+ @Autowired
+ private MdmLinkHelper myLinkHelper;
+
+ @Autowired
+ private IMdmMetricSvc mySvc;
+
+ @BeforeEach
+ public void before() throws Exception {
+ super.before();
+ }
+
+ @Override
+ public IMdmMetricSvc getMetricsSvc() {
+ return mySvc;
+ }
+
+ @Override
+ public void generateMdmMetricsSetup(GenerateMetricsTestParameters theParameters) {
+ if (StringUtils.isNotBlank(theParameters.getInitialState())) {
+ MDMState state = new MDMState<>();
+ state.setInputState(theParameters.getInitialState());
+ myLinkHelper.setup(state);
+
+ // update scores if needed
+ setupScores(theParameters.getScores());
+ }
+ }
+
+ @Override
+ public void generateLinkMetricsSetup(LinkMetricTestParameters theParameters) {
+ ourLog.info(theParameters.getInitialState());
+ if (StringUtils.isNotBlank(theParameters.getInitialState())) {
+ // we can only initialize the state if there is a state to initialize
+ MDMState state = new MDMState<>();
+ state.setInputState(theParameters.getInitialState());
+ myLinkHelper.setup(state);
+ }
+ }
+
+ @Override
+ public void generateResourceMetricsSetup(ResourceMetricTestParams theParams) {
+ MDMState state = new MDMState<>();
+ String initialState = theParams.getInitialState();
+ if (StringUtils.isNotBlank(initialState)) {
+ state.setInputState(initialState);
+
+ for (String forcedBlockedGRId : theParams.getBlockedResourceGoldenResourceIds()) {
+ Patient gr = new Patient();
+ gr.setActive(true);
+ gr.setId("Patient/" + forcedBlockedGRId);
+ MdmResourceUtil.setMdmManaged(gr);
+ MdmResourceUtil.setGoldenResource(gr);
+ MdmResourceUtil.setGoldenResourceAsBlockedResourceGoldenResource(gr);
+
+ Patient p = createPatient(gr, true, false);
+ state.addParameter(forcedBlockedGRId, p);
+ }
+
+ myLinkHelper.setup(state);
+ }
+ }
+
+ @Override
+ public void generateLinkScoreMetricsSetup(LinkScoreMetricTestParams theParams) {
+ MDMState state = new MDMState<>();
+ String initialState = theParams.getInitialState();
+
+ if (StringUtils.isNotBlank(initialState)) {
+ state.setInputState(initialState);
+
+ myLinkHelper.setup(state);
+
+ // update scores if needed
+ setupScores(theParams.getScores());
+ }
+ }
+
+ private void setupScores(List theParams) {
+ List links = myMdmLinkDao.findAll();
+ for (int i = 0; i < theParams.size() && i < links.size(); i++) {
+ Double score = theParams.get(i);
+ MdmLink link = links.get(i);
+ link.setScore(score);
+ myMdmLinkDao.save(link);
+ }
+ }
+
+ @Override
+ public String getStringMetrics(MdmMetrics theMetrics) {
+ try {
+ return myObjectMapper.writeValueAsString(theMetrics);
+ } catch (JsonProcessingException ex) {
+ // we've failed anyway - we might as well display the exception
+ fail(ex);
+ return "NOT PARSEABLE!";
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImplIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImplIT.java
index 6433348881e..549f818f399 100644
--- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImplIT.java
+++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmLinkUpdaterSvcImplIT.java
@@ -41,7 +41,7 @@ class MdmLinkUpdaterSvcImplIT extends BaseMdmR4Test {
private IMdmLinkUpdaterSvc myMdmLinkUpdaterSvc;
@Autowired
- private MdmResourceDaoSvc myMdmResourceDaoSvc;
+ private MdmResourceDaoSvcImpl myMdmResourceDaoSvc;
@Autowired
private MessageHelper myMessageHelper;
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 1bd33081e2f..e51949689c4 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
@@ -7,13 +7,13 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.searchparam.extractor.ISearchParamExtractor;
+import ca.uhn.fhir.mdm.api.IMdmResourceDaoSvc;
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import org.hl7.fhir.instance.model.api.IAnyResource;
-import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.AfterEach;
@@ -21,7 +21,6 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
-import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -35,7 +34,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
private static final String TEST_EID = "TEST_EID";
@Autowired
- MdmResourceDaoSvc myResourceDaoSvc;
+ IMdmResourceDaoSvc myResourceDaoSvc;
@Autowired
private ISearchParamExtractor mySearchParamExtractor;
diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml
index 27c8d0a0379..0eb9cabc642 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml
index 3fe94ad2c5f..a2728494bf4 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml
index 972d0aca525..ed3cab96c80 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml
index 6fe814dfd00..2e00cf23d76 100644
--- a/hapi-fhir-jpaserver-test-dstu2/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml
index de5da25656a..f03dae46f3b 100644
--- a/hapi-fhir-jpaserver-test-dstu3/pom.xml
+++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml
index 74e8f394246..9253e66d122 100644
--- a/hapi-fhir-jpaserver-test-r4/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml
index ffe2b31be48..22ad4ef0907 100644
--- a/hapi-fhir-jpaserver-test-r4b/pom.xml
+++ b/hapi-fhir-jpaserver-test-r4b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml
index 2e85a2a2bd4..1a9b4c1527a 100644
--- a/hapi-fhir-jpaserver-test-r5/pom.xml
+++ b/hapi-fhir-jpaserver-test-r5/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml
index 0c810ee1268..c5a65a61dd0 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/IMdmMetricSvcTest.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/IMdmMetricSvcTest.java
new file mode 100644
index 00000000000..18b51d0bc28
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/IMdmMetricSvcTest.java
@@ -0,0 +1,177 @@
+package ca.uhn.fhir.jpa.mdm;
+
+import ca.uhn.fhir.jpa.mdm.models.GenerateMetricsTestParameters;
+import ca.uhn.fhir.jpa.mdm.models.LinkMetricTestParameters;
+import ca.uhn.fhir.jpa.mdm.models.LinkScoreMetricTestParams;
+import ca.uhn.fhir.jpa.mdm.models.ResourceMetricTestParams;
+import ca.uhn.fhir.jpa.mdm.util.MdmMetricSvcTestUtil;
+import ca.uhn.fhir.mdm.api.IMdmMetricSvc;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.api.params.GenerateMdmMetricsParameters;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+import ca.uhn.fhir.mdm.model.MdmResourceMetrics;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.Map;
+import java.util.function.Supplier;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * Tests the various metrics returned by IMdmMetricSvc
+ * Because of the way these metrics are broken down in 3 different ways,
+ * these results are tested separately, even though there is a single
+ * entry point.
+ */
+public interface IMdmMetricSvcTest {
+
+ IMdmMetricSvc getMetricsSvc();
+
+ void generateMdmMetricsSetup(GenerateMetricsTestParameters theParameters);
+
+ @Test
+ default void generateMdmMetrics_generalTest_happyPath() {
+ // setup
+ GenerateMetricsTestParameters testParameters = new GenerateMetricsTestParameters();
+ testParameters.setInitialState(MdmMetricSvcTestUtil.OUR_BASIC_STATE);
+ testParameters.setScores(Arrays.asList(0.1, 0.2, 0.3, 0.4));
+
+ generateMdmMetricsSetup(testParameters);
+
+ // test
+ GenerateMdmMetricsParameters parameters = new GenerateMdmMetricsParameters("Patient");
+ MdmMetrics results = getMetricsSvc().generateMdmMetrics(parameters);
+
+ // verify
+ assertNotNull(results);
+ assertEquals("Patient", results.getResourceType());
+ assertEquals(4, results.getGoldenResourcesCount());
+ assertEquals(4, results.getSourceResourcesCount());
+ assertEquals(0, results.getExcludedResources());
+
+ Map> map = results.getMatchTypeToLinkToCountMap();
+ // See OUR_BASIC_STATE
+ assertEquals(3, map.size());
+ for (MdmMatchResultEnum matchResult : new MdmMatchResultEnum[] {
+ MdmMatchResultEnum.MATCH, MdmMatchResultEnum.NO_MATCH, MdmMatchResultEnum.POSSIBLE_MATCH
+ }) {
+ assertTrue(map.containsKey(matchResult));
+ Map source2Count = map.get(matchResult);
+ assertNotNull(source2Count);
+ for (MdmLinkSourceEnum ls : MdmLinkSourceEnum.values()) {
+ assertNotNull(source2Count.get(ls));
+ }
+ }
+ }
+
+ void generateLinkMetricsSetup(LinkMetricTestParameters theParameters);
+
+ @ParameterizedTest
+ @MethodSource("ca.uhn.fhir.jpa.mdm.util.MdmMetricSvcTestUtil#linkMetricsParameters")
+ default void test_generateLinkMetrics_multipleInputs(LinkMetricTestParameters theParameters) {
+ // setup
+ generateLinkMetricsSetup(theParameters);
+
+ // all tests use Patient resource type
+ GenerateMdmMetricsParameters parameters = new GenerateMdmMetricsParameters("Patient");
+ for (MdmLinkSourceEnum linkSource : theParameters.getLinkSourceFilters()) {
+ parameters.addLinkSource(linkSource);
+ }
+ for (MdmMatchResultEnum matchResultEnum : theParameters.getMatchFilters()) {
+ parameters.addMatchResult(matchResultEnum);
+ }
+
+ // test
+ MdmMetrics metrics = getMetricsSvc().generateMdmMetrics(parameters);
+
+ // verify
+ assertNotNull(metrics);
+ assertEquals(metrics.getResourceType(), "Patient");
+
+ MdmMetrics expectedMetrics = theParameters.getExpectedMetrics();
+
+ Supplier err = () -> getComparingMetrics(metrics, expectedMetrics);
+
+ Map> actual = metrics.getMatchTypeToLinkToCountMap();
+ Map> expected = expectedMetrics.getMatchTypeToLinkToCountMap();
+ assertEquals(expected, actual, err.get());
+
+ for (MdmMatchResultEnum matchResult : MdmMatchResultEnum.values()) {
+ assertEquals(expected.containsKey(matchResult), actual.containsKey(matchResult), err.get());
+ if (actual.containsKey(matchResult)) {
+ Map actualMatch = actual.get(matchResult);
+ Map expectedMatch = expected.get(matchResult);
+ assertEquals(expectedMatch, actualMatch, err.get());
+ for (MdmLinkSourceEnum linkSource : MdmLinkSourceEnum.values()) {
+ assertEquals(expectedMatch.get(linkSource), actualMatch.get(linkSource), err.get());
+ }
+ }
+ }
+ }
+
+ void generateResourceMetricsSetup(ResourceMetricTestParams theParams);
+
+ @ParameterizedTest
+ @MethodSource("ca.uhn.fhir.jpa.mdm.util.MdmMetricSvcTestUtil#resourceMetricParameters")
+ default void test_generateResourceMetrics_multipleInputs(ResourceMetricTestParams theParams) {
+ // setup
+ generateResourceMetricsSetup(theParams);
+
+ // test
+ GenerateMdmMetricsParameters parameters = new GenerateMdmMetricsParameters("Patient");
+ MdmResourceMetrics results = getMetricsSvc().generateMdmMetrics(parameters);
+
+ // verify
+ assertNotNull(results);
+ assertEquals("Patient", results.getResourceType());
+ assertEquals(
+ theParams.getExpectedResourceCount(),
+ results.getSourceResourcesCount() + results.getGoldenResourcesCount());
+ assertEquals(theParams.getExpectedBlockedResourceCount(), results.getExcludedResources());
+ assertEquals(theParams.getExpectedGoldenResourceCount(), results.getGoldenResourcesCount());
+ }
+
+ void generateLinkScoreMetricsSetup(LinkScoreMetricTestParams theParams);
+
+ @ParameterizedTest
+ @MethodSource("ca.uhn.fhir.jpa.mdm.util.MdmMetricSvcTestUtil#linkScoreParameters")
+ default void test_generateLinkScoreMetrics_multipleInputs(LinkScoreMetricTestParams theParams) {
+ // setup
+ generateLinkScoreMetricsSetup(theParams);
+
+ GenerateMdmMetricsParameters scoreMetricsParameters = new GenerateMdmMetricsParameters("Patient");
+ for (MdmMatchResultEnum matchType : theParams.getMatchFilter()) {
+ scoreMetricsParameters.addMatchResult(matchType);
+ }
+
+ // test
+ MdmMetrics actualMetrics = getMetricsSvc().generateMdmMetrics(scoreMetricsParameters);
+
+ // verify
+ assertNotNull(actualMetrics);
+ assertEquals("Patient", actualMetrics.getResourceType());
+
+ MdmMetrics expectedMetrics = theParams.getExpectedMetrics();
+
+ Map actual = actualMetrics.getScoreCounts();
+ Map expected = expectedMetrics.getScoreCounts();
+ assertEquals(expected.size(), actual.size());
+ for (String score : expected.keySet()) {
+ assertTrue(actual.containsKey(score), String.format("Score of %s is not in results", score));
+ assertEquals(expected.get(score), actual.get(score), score);
+ }
+ }
+
+ private String getComparingMetrics(MdmMetrics theActual, MdmMetrics theExpected) {
+ return String.format(
+ "\nExpected: \n%s - \nActual: \n%s", getStringMetrics(theExpected), getStringMetrics(theActual));
+ }
+
+ String getStringMetrics(MdmMetrics theMetrics);
+}
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/GenerateMetricsTestParameters.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/GenerateMetricsTestParameters.java
new file mode 100644
index 00000000000..8afeb438902
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/GenerateMetricsTestParameters.java
@@ -0,0 +1,31 @@
+package ca.uhn.fhir.jpa.mdm.models;
+
+import java.util.List;
+
+public class GenerateMetricsTestParameters {
+
+ private String myInitialState;
+
+ /**
+ * The scores for each link.
+ * The order should match the order of the
+ * links listed in initial state.
+ */
+ private List myScores;
+
+ public String getInitialState() {
+ return myInitialState;
+ }
+
+ public void setInitialState(String theInitialState) {
+ myInitialState = theInitialState;
+ }
+
+ public List getScores() {
+ return myScores;
+ }
+
+ public void setScores(List theScores) {
+ myScores = theScores;
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkMetricTestParameters.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkMetricTestParameters.java
new file mode 100644
index 00000000000..95ba075b645
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkMetricTestParameters.java
@@ -0,0 +1,68 @@
+package ca.uhn.fhir.jpa.mdm.models;
+
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LinkMetricTestParameters {
+ /**
+ * The initial state (as to be fed into MdmLinkHelper)
+ */
+ private String myInitialState;
+
+ /**
+ * The filters for MatchResult
+ */
+ private List myMatchFilters;
+
+ /**
+ * The filters for LinkSource
+ */
+ private List myLinkSourceEnums;
+
+ /**
+ * The expected metrics to be returned
+ */
+ private MdmMetrics myExpectedMetrics;
+
+ public String getInitialState() {
+ return myInitialState;
+ }
+
+ public void setInitialState(String theInitialState) {
+ myInitialState = theInitialState;
+ }
+
+ public List getMatchFilters() {
+ if (myMatchFilters == null) {
+ myMatchFilters = new ArrayList<>();
+ }
+ return myMatchFilters;
+ }
+
+ public void setMatchFilters(List theMatchFilters) {
+ myMatchFilters = theMatchFilters;
+ }
+
+ public List getLinkSourceFilters() {
+ if (myLinkSourceEnums == null) {
+ myLinkSourceEnums = new ArrayList<>();
+ }
+ return myLinkSourceEnums;
+ }
+
+ public void setLinkSourceFilters(List theLinkSourceEnums) {
+ myLinkSourceEnums = theLinkSourceEnums;
+ }
+
+ public MdmMetrics getExpectedMetrics() {
+ return myExpectedMetrics;
+ }
+
+ public void setExpectedMetrics(MdmMetrics theExpectedMetrics) {
+ myExpectedMetrics = theExpectedMetrics;
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkScoreMetricTestParams.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkScoreMetricTestParams.java
new file mode 100644
index 00000000000..0434ccb69fb
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/LinkScoreMetricTestParams.java
@@ -0,0 +1,60 @@
+package ca.uhn.fhir.jpa.mdm.models;
+
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LinkScoreMetricTestParams {
+ private String myInitialState;
+
+ private List myMatchFilter;
+
+ private MdmMetrics myExpectedMetrics;
+
+ /**
+ * The scores for each link.
+ * The order should match the order of the
+ * links listed in initial state.
+ */
+ private List myScores;
+
+ public String getInitialState() {
+ return myInitialState;
+ }
+
+ public void setInitialState(String theInitialState) {
+ myInitialState = theInitialState;
+ }
+
+ public MdmMetrics getExpectedMetrics() {
+ return myExpectedMetrics;
+ }
+
+ public void setExpectedMetrics(MdmMetrics theExpectedMetrics) {
+ myExpectedMetrics = theExpectedMetrics;
+ }
+
+ public List getMatchFilter() {
+ if (myMatchFilter == null) {
+ myMatchFilter = new ArrayList<>();
+ }
+ return myMatchFilter;
+ }
+
+ public void addMatchType(MdmMatchResultEnum theResultEnum) {
+ getMatchFilter().add(theResultEnum);
+ }
+
+ public List getScores() {
+ if (myScores == null) {
+ myScores = new ArrayList<>();
+ }
+ return myScores;
+ }
+
+ public void setScores(List theScores) {
+ myScores = theScores;
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/ResourceMetricTestParams.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/ResourceMetricTestParams.java
new file mode 100644
index 00000000000..4ed1b52972c
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/models/ResourceMetricTestParams.java
@@ -0,0 +1,61 @@
+package ca.uhn.fhir.jpa.mdm.models;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ResourceMetricTestParams {
+ /**
+ * The initial state, as consumable by
+ * MdmLinkHelper.
+ */
+ private String myInitialState;
+
+ /**
+ * The list of Golden Resource Ids (in initial state) that should be
+ * saved as BlockedResources
+ */
+ private List myBlockedResourceGoldenResourceIds;
+
+ private long myExpectedResourceCount;
+
+ private long myExpectedGoldenResourceCount;
+
+ public String getInitialState() {
+ return myInitialState;
+ }
+
+ public void setInitialState(String theInitialState) {
+ myInitialState = theInitialState;
+ }
+
+ public List getBlockedResourceGoldenResourceIds() {
+ if (myBlockedResourceGoldenResourceIds == null) {
+ myBlockedResourceGoldenResourceIds = new ArrayList<>();
+ }
+ return myBlockedResourceGoldenResourceIds;
+ }
+
+ public void addBlockedResourceGoldenResources(String theBlockedResourceId) {
+ getBlockedResourceGoldenResourceIds().add(theBlockedResourceId);
+ }
+
+ public long getExpectedResourceCount() {
+ return myExpectedResourceCount;
+ }
+
+ public void setExpectedResourceCount(long theExpectedResourceCount) {
+ myExpectedResourceCount = theExpectedResourceCount;
+ }
+
+ public long getExpectedGoldenResourceCount() {
+ return myExpectedGoldenResourceCount;
+ }
+
+ public void setExpectedGoldenResourceCount(long theExpectedGoldenResourceCount) {
+ myExpectedGoldenResourceCount = theExpectedGoldenResourceCount;
+ }
+
+ public long getExpectedBlockedResourceCount() {
+ return getBlockedResourceGoldenResourceIds().size();
+ }
+}
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/package-info.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/package-info.java
new file mode 100644
index 00000000000..13da8304544
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * This package is for persistence-agnostic mdm tests.
+ * Even though the package is "jpaserver-test-utils", these
+ * classes are not dependent on jpa backed persistence.
+ */
+package ca.uhn.fhir.jpa.mdm;
diff --git a/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmMetricSvcTestUtil.java b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmMetricSvcTestUtil.java
new file mode 100644
index 00000000000..9e5a7503dcd
--- /dev/null
+++ b/hapi-fhir-jpaserver-test-utilities/src/main/java/ca/uhn/fhir/jpa/mdm/util/MdmMetricSvcTestUtil.java
@@ -0,0 +1,338 @@
+package ca.uhn.fhir.jpa.mdm.util;
+
+import ca.uhn.fhir.jpa.mdm.models.LinkMetricTestParameters;
+import ca.uhn.fhir.jpa.mdm.models.LinkScoreMetricTestParams;
+import ca.uhn.fhir.jpa.mdm.models.ResourceMetricTestParams;
+import ca.uhn.fhir.mdm.api.BaseMdmMetricSvc;
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.commons.lang3.StringUtils.isNotBlank;
+
+/**
+ * This provides parameter methods for the {@link ca.uhn.fhir.jpa.mdm.IMdmMetricSvcTest}.
+ */
+public class MdmMetricSvcTestUtil {
+
+ public static final String OUR_BASIC_STATE =
+ """
+ G1, AUTO, MATCH, P1
+ G2, AUTO, MATCH, P2,
+ G3, AUTO, POSSIBLE_MATCH, P3,
+ G4, MANUAL, MATCH, P4
+ G2, AUTO, NO_MATCH, P1
+ G1, MANUAL, NO_MATCH, P2
+ G1, MANUAL, POSSIBLE_MATCH, P3
+ """;
+
+ /**
+ * Parameters supplied to {@link ca.uhn.fhir.jpa.mdm.IMdmMetricSvcTest#test_generateLinkMetrics_multipleInputs(LinkMetricTestParameters)}
+ */
+ public static List linkMetricsParameters() {
+ List params = new ArrayList<>();
+
+ // 1
+ {
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState(OUR_BASIC_STATE);
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.AUTO, 2);
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ metrics.addMetric(MdmMatchResultEnum.NO_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ metrics.addMetric(MdmMatchResultEnum.NO_MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ metrics.addMetric(MdmMatchResultEnum.POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ metrics.addMetric(MdmMatchResultEnum.POSSIBLE_MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ // 2
+ {
+ // link source filter
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState(OUR_BASIC_STATE);
+ testParameters.setLinkSourceFilters(Arrays.asList(MdmLinkSourceEnum.AUTO));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.AUTO, 2);
+ metrics.addMetric(MdmMatchResultEnum.NO_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ metrics.addMetric(MdmMatchResultEnum.POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ // 3
+ {
+ // match result filter
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState(OUR_BASIC_STATE);
+ testParameters.setMatchFilters(Arrays.asList(MdmMatchResultEnum.MATCH, MdmMatchResultEnum.POSSIBLE_MATCH));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.AUTO, 2);
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ metrics.addMetric(MdmMatchResultEnum.POSSIBLE_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ metrics.addMetric(MdmMatchResultEnum.POSSIBLE_MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ // 4
+ {
+ // match result and link source filters
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState(OUR_BASIC_STATE);
+ testParameters.setMatchFilters(Arrays.asList(MdmMatchResultEnum.MATCH));
+ testParameters.setLinkSourceFilters(Arrays.asList(MdmLinkSourceEnum.MANUAL));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.addMetric(MdmMatchResultEnum.MATCH, MdmLinkSourceEnum.MANUAL, 1);
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ // 5
+ {
+ // no initial state
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState("");
+ MdmMetrics metrics = new MdmMetrics();
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ // 6
+ {
+ // initial state with filters to omit all values
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState("""
+ G1, AUTO, NO_MATCH, P1
+ G2, MANUAL, MATCH, P2
+ """);
+ testParameters.setMatchFilters(Arrays.asList(MdmMatchResultEnum.MATCH));
+ testParameters.setLinkSourceFilters(Arrays.asList(MdmLinkSourceEnum.AUTO));
+ testParameters.setExpectedMetrics(new MdmMetrics());
+ params.add(testParameters);
+ }
+
+ // 7
+ {
+ // initial state with filters to omit some values
+ LinkMetricTestParameters testParameters = new LinkMetricTestParameters();
+ testParameters.setInitialState("""
+ G1, AUTO, NO_MATCH, P1
+ G2, MANUAL, MATCH, P2
+ """);
+ testParameters.setMatchFilters(Arrays.asList(MdmMatchResultEnum.NO_MATCH));
+ testParameters.setLinkSourceFilters(Arrays.asList(MdmLinkSourceEnum.AUTO));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.addMetric(MdmMatchResultEnum.NO_MATCH, MdmLinkSourceEnum.AUTO, 1);
+ testParameters.setExpectedMetrics(metrics);
+ params.add(testParameters);
+ }
+
+ return params;
+ }
+
+ /**
+ * Parameters supplied to {@link ca.uhn.fhir.jpa.mdm.IMdmMetricSvcTest#test_generateResourceMetrics_multipleInputs(ResourceMetricTestParams)}
+ */
+ public static List resourceMetricParameters() {
+ List params = new ArrayList<>();
+
+ // 1
+ {
+ // a mix of golden, regular, and blocked resources
+ ResourceMetricTestParams p = new ResourceMetricTestParams();
+ p.setInitialState(
+ """
+ G1, AUTO, MATCH, P1
+ G2, AUTO, MATCH, P2
+ G2, AUTO, MATCH, P1,
+ G3, AUTO, MATCH, P3
+ """);
+ p.addBlockedResourceGoldenResources("G2");
+ p.addBlockedResourceGoldenResources("G3");
+ p.setExpectedResourceCount(6);
+ p.setExpectedGoldenResourceCount(3);
+ params.add(p);
+ }
+
+ // 2
+ {
+ // 2 non-golden, 1 golden
+ ResourceMetricTestParams p = new ResourceMetricTestParams();
+ p.setInitialState("""
+ G1, AUTO, MATCH, P1,
+ G1, MANUAL, MATCH, P2
+ """);
+ p.setExpectedResourceCount(3);
+ p.setExpectedGoldenResourceCount(1);
+ params.add(p);
+ }
+
+ // 3
+ {
+ // 2 golden, 1 non-golden
+ ResourceMetricTestParams p = new ResourceMetricTestParams();
+ p.setInitialState("""
+ G1, AUTO, MATCH, P1
+ G2, AUTO, POSSIBLE_DUPLICATE, G1
+ """);
+ p.setExpectedGoldenResourceCount(2);
+ p.setExpectedResourceCount(3);
+ params.add(p);
+ }
+
+ // 4
+ {
+ // 2 golden, 1 blocked, 0 non-golden
+ ResourceMetricTestParams p = new ResourceMetricTestParams();
+ p.setInitialState("""
+ G1, AUTO, POSSIBLE_DUPLICATE, G2
+ """);
+ p.addBlockedResourceGoldenResources("G1");
+ p.setExpectedResourceCount(2);
+ p.setExpectedGoldenResourceCount(2);
+ params.add(p);
+ }
+
+ // 5
+ {
+ // no resources
+ ResourceMetricTestParams p = new ResourceMetricTestParams();
+ p.setInitialState("");
+ params.add(p);
+ }
+
+ return params;
+ }
+
+ /**
+ * Parameters supplied to {@link ca.uhn.fhir.jpa.mdm.IMdmMetricSvcTest#generateLinkScoreMetricsSetup(LinkScoreMetricTestParams)}
+ */
+ public static List linkScoreParameters() {
+ List parameters = new ArrayList<>();
+
+ // 1
+ {
+ // score counts
+ LinkScoreMetricTestParams p = new LinkScoreMetricTestParams();
+ p.setInitialState(
+ """
+ G1, AUTO, MATCH, P1
+ G2, AUTO, POSSIBLE_MATCH, P2,
+ G3, AUTO, POSSIBLE_MATCH, P1
+ """);
+ p.setScores(Arrays.asList(.2D, .2D, .1D));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.setResourceType("Patient");
+ populateScoreIntoMetrics(p, metrics);
+ p.setExpectedMetrics(metrics);
+ parameters.add(p);
+ }
+
+ // 2
+ {
+ // a null score
+ LinkScoreMetricTestParams p = new LinkScoreMetricTestParams();
+ p.setInitialState("""
+ G1, AUTO, POSSIBLE_MATCH, P1,
+ G2, AUTO, POSSIBLE_MATCH, P2
+ """);
+ p.setScores(Arrays.asList(null, 0.02D));
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.setResourceType("Patient");
+ populateScoreIntoMetrics(p, metrics);
+ p.setExpectedMetrics(metrics);
+ parameters.add(p);
+ }
+
+ // 3
+ {
+ // match type filtering
+ LinkScoreMetricTestParams p = new LinkScoreMetricTestParams();
+ p.setInitialState(
+ """
+ G1, AUTO, POSSIBLE_MATCH, P1
+ G2, AUTO, MATCH, P2
+ G3, AUTO, POSSIBLE_MATCH, P3
+ G4, AUTO, MATCH, P4
+ """);
+ p.setScores(Arrays.asList(0.4D, 0.4D, 0.1D, 0.3D));
+ p.addMatchType(MdmMatchResultEnum.POSSIBLE_MATCH);
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.setResourceType("Patient");
+ populateScoreIntoMetrics(p, metrics);
+ p.setExpectedMetrics(metrics);
+ parameters.add(p);
+ }
+
+ // 4
+ {
+ // no links
+ LinkScoreMetricTestParams p = new LinkScoreMetricTestParams();
+ p.setInitialState("");
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.setResourceType("Patient");
+ p.setExpectedMetrics(metrics);
+ populateScoreIntoMetrics(p, metrics);
+ parameters.add(p);
+ }
+
+ return parameters;
+ }
+
+ private static void populateScoreIntoMetrics(LinkScoreMetricTestParams p, MdmMetrics metrics) {
+ String initialState = p.getInitialState();
+ Map indexToMatchResult = new HashMap<>();
+ if (isNotBlank(initialState)) {
+ String[] states = initialState.split("\n");
+ int len = states.length;
+ for (int i = 0; i < len; i++) {
+ String state = states[i];
+ String[] values = state.split(",");
+ indexToMatchResult.put(i, MdmMatchResultEnum.valueOf(values[2].trim()));
+ }
+ }
+
+ Map score2Count = new HashMap<>();
+ long nullCount = 0;
+ for (int i = 0; i < p.getScores().size(); i++) {
+ MdmMatchResultEnum matchResult = indexToMatchResult.get(i);
+ // if it's not a filtered value, add it to the expected metrics
+ if (p.getMatchFilter().isEmpty() || p.getMatchFilter().contains(matchResult)) {
+ Double d = p.getScores().get(i);
+ if (d == null) {
+ nullCount++;
+ } else {
+ if (!score2Count.containsKey(d)) {
+ score2Count.put(d, 0L);
+ }
+ score2Count.put(d, score2Count.get(d) + 1);
+ }
+ }
+ }
+ metrics.addScore(BaseMdmMetricSvc.NULL_VALUE, nullCount);
+ for (int i = 0; i < BaseMdmMetricSvc.BUCKETS; i++) {
+ double bucket = (double) Math.round((float) (100 * (i + 1)) / BaseMdmMetricSvc.BUCKETS) / 100;
+ long count = 0;
+ // TODO - do not add it if the corresponding link does not have
+ // the correct MATCH_RESULT value
+ if (score2Count.containsKey(bucket)) {
+ count = score2Count.get(bucket);
+ }
+ if (i == 0) {
+ metrics.addScore(String.format(BaseMdmMetricSvc.FIRST_BUCKET, bucket), count);
+ } else {
+ metrics.addScore(
+ String.format(BaseMdmMetricSvc.NTH_BUCKET, (float) i / BaseMdmMetricSvc.BUCKETS, bucket),
+ count);
+ }
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index 883d501d672..dbb6efb3f9c 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-server-cds-hooks/pom.xml b/hapi-fhir-server-cds-hooks/pom.xml
index feac29e26be..266e0577cf8 100644
--- a/hapi-fhir-server-cds-hooks/pom.xml
+++ b/hapi-fhir-server-cds-hooks/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml
index 03faeaa9b70..f01dc291872 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/BaseMdmMetricSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/BaseMdmMetricSvc.java
new file mode 100644
index 00000000000..a3a9f75f56d
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/BaseMdmMetricSvc.java
@@ -0,0 +1,94 @@
+package ca.uhn.fhir.mdm.api;
+
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.mdm.api.params.GenerateMdmMetricsParameters;
+import ca.uhn.fhir.mdm.model.MdmResourceMetrics;
+import ca.uhn.fhir.mdm.util.MdmSearchParamBuildingUtils;
+import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
+
+public abstract class BaseMdmMetricSvc implements IMdmMetricSvc {
+
+ /**
+ * Count of numbered buckets.
+ * There will also be a NULL bucket, so there will be a total
+ * of BUCKETS + 1 buckets.
+ */
+ public static final int BUCKETS = 100;
+
+ /**
+ * The NULL label
+ */
+ public static final String NULL_VALUE = "NULL";
+
+ /**
+ * The label for the first bucket
+ */
+ public static final String FIRST_BUCKET = "x_<_%.2f";
+
+ /**
+ * The label for the nth bucket (2... buckets)
+ */
+ public static final String NTH_BUCKET = "%.2f_<_x_<=_%.2f";
+
+ protected final DaoRegistry myDaoRegistry;
+
+ public BaseMdmMetricSvc(DaoRegistry theDaoRegistry) {
+ myDaoRegistry = theDaoRegistry;
+ }
+
+ protected double getBucket(int theBucketId) {
+ return (double) Math.round((float) (100 * theBucketId) / BUCKETS) / 100;
+ }
+
+ protected MdmResourceMetrics generateResourceMetrics(GenerateMdmMetricsParameters theParameters) {
+ String resourceType = theParameters.getResourceType();
+ @SuppressWarnings("rawtypes")
+ IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceType);
+
+ // TODO
+ /*
+ * We are using 3 different queries to count:
+ * * all resources
+ * * all golden resources
+ * * all blocked resources.
+ *
+ * This is inefficient and if we want, we can speed it up with
+ * a custom query in the future.
+ */
+ IBundleProvider outcome = null;
+ SearchParameterMap map = null;
+
+ MdmResourceMetrics metrics = new MdmResourceMetrics();
+ metrics.setResourceType(resourceType);
+
+ // find golden resources
+ map = MdmSearchParamBuildingUtils.buildBasicGoldenResourceSearchParameterMap(resourceType);
+ setCountOnly(map);
+ outcome = dao.search(map, new SystemRequestDetails());
+ metrics.setGoldenResourcesCount(outcome.size());
+
+ // find blocked resources
+ map = MdmSearchParamBuildingUtils.buildSearchParameterForBlockedResourceCount(resourceType);
+ setCountOnly(map);
+ outcome = dao.search(map, new SystemRequestDetails());
+ metrics.setExcludedResources(outcome.size());
+
+ // find all resources
+ map = new SearchParameterMap();
+ setCountOnly(map);
+ outcome = dao.search(map, new SystemRequestDetails());
+ metrics.setSourceResourcesCount(outcome.size() - metrics.getGoldenResourcesCount());
+
+ return metrics;
+ }
+
+ private void setCountOnly(SearchParameterMap theMap) {
+ theMap.setCount(0);
+ theMap.setLoadSynchronous(true);
+ theMap.setSearchTotalMode(SearchTotalModeEnum.ACCURATE);
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMetricSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMetricSvc.java
new file mode 100644
index 00000000000..451239bd243
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmMetricSvc.java
@@ -0,0 +1,19 @@
+package ca.uhn.fhir.mdm.api;
+
+import ca.uhn.fhir.mdm.api.params.GenerateMdmMetricsParameters;
+import ca.uhn.fhir.mdm.model.MdmMetrics;
+
+public interface IMdmMetricSvc {
+
+ /**
+ * Generates metrics on MDM Links.
+ * Metrics include:
+ * * breakdowns of counts of MATCH_RESULT types by LINK_SOURCE types.
+ * * counts of resources of each type
+ * * a histogram of score 'buckets' with the appropriate counts.
+ * @param theParameters - Parameters defining resource type of interest,
+ * as well as MatchResult and LinkSource filters.
+ * @return The metrics in a JSON format.
+ */
+ MdmMetrics generateMdmMetrics(GenerateMdmMetricsParameters theParameters);
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmResourceDaoSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmResourceDaoSvc.java
new file mode 100644
index 00000000000..7afe2aa388e
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmResourceDaoSvc.java
@@ -0,0 +1,27 @@
+package ca.uhn.fhir.mdm.api;
+
+import ca.uhn.fhir.interceptor.model.RequestPartitionId;
+import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
+import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
+import org.hl7.fhir.instance.model.api.IAnyResource;
+
+import java.util.Optional;
+
+public interface IMdmResourceDaoSvc {
+ DaoMethodOutcome upsertGoldenResource(IAnyResource theGoldenResource, String theResourceType);
+
+ /**
+ * Given a resource, remove its Golden Resource tag.
+ *
+ * @param theGoldenResource the {@link IAnyResource} to remove the tag from.
+ * @param theResourcetype the type of that resource
+ */
+ void removeGoldenResourceTag(IAnyResource theGoldenResource, String theResourcetype);
+
+ IAnyResource readGoldenResourceByPid(IResourcePersistentId theGoldenResourcePid, String theResourceType);
+
+ Optional searchGoldenResourceByEID(String theEid, String theResourceType);
+
+ Optional searchGoldenResourceByEID(
+ String theEid, String theResourceType, RequestPartitionId thePartitionId);
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmConstants.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmConstants.java
index 7d35442c202..0207577abd7 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmConstants.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/MdmConstants.java
@@ -34,6 +34,13 @@ public class MdmConstants {
"http://hapifhir.io/fhir/NamingSystem/mdm-golden-resource-enterprise-id";
public static final String ALL_RESOURCE_SEARCH_PARAM_TYPE = "*";
+ /**
+ * Blocked resource tag info
+ */
+ public static final String CODE_BLOCKED = "BLOCKED_RESOURCE";
+
+ public static final String CODE_BLOCKED_DISPLAY = "Source Resource is omitted from MDM matching.";
+
public static final String FIHR_STRUCTURE_DEF_MATCH_GRADE_URL_NAMESPACE =
"http://hl7.org/fhir/StructureDefinition/match-grade";
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmLinkMetricParameters.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmLinkMetricParameters.java
new file mode 100644
index 00000000000..b8f0c2bfcbc
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmLinkMetricParameters.java
@@ -0,0 +1,60 @@
+package ca.uhn.fhir.mdm.api.params;
+
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenerateMdmLinkMetricParameters {
+
+ /**
+ * The resource type of interest.
+ * Must be provided!
+ */
+ private final String myResourceType;
+
+ /**
+ * The MDM MatchResult types of interest.
+ * Specified MatchResults will be included.
+ * If none are specified, all will be included.
+ */
+ private List myMatchResultFilters;
+
+ /**
+ * The MDM Link values of interest.
+ * Specified LinkSources will be included.
+ * If none are specified, all are included.
+ */
+ private List myLinkSourceFilters;
+
+ public GenerateMdmLinkMetricParameters(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public List getMatchResultFilters() {
+ if (myMatchResultFilters == null) {
+ myMatchResultFilters = new ArrayList<>();
+ }
+ return myMatchResultFilters;
+ }
+
+ public void addMatchResultFilter(MdmMatchResultEnum theMdmMatchResultEnum) {
+ getMatchResultFilters().add(theMdmMatchResultEnum);
+ }
+
+ public List getLinkSourceFilters() {
+ if (myLinkSourceFilters == null) {
+ myLinkSourceFilters = new ArrayList<>();
+ }
+ return myLinkSourceFilters;
+ }
+
+ public void addLinkSourceFilter(MdmLinkSourceEnum theLinkSource) {
+ getLinkSourceFilters().add(theLinkSource);
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmMetricsParameters.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmMetricsParameters.java
new file mode 100644
index 00000000000..98dd96b8366
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmMetricsParameters.java
@@ -0,0 +1,69 @@
+package ca.uhn.fhir.mdm.api.params;
+
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenerateMdmMetricsParameters {
+
+ /**
+ * We only allow finding metrics by resource type
+ */
+ private final String myResourceType;
+
+ /**
+ * The MDM MatchResult types of interest.
+ * Specified MatchResults will be included.
+ * If none are specified, all will be included.
+ */
+ private List myMatchResultFilters;
+
+ /**
+ * The MDM Link values of interest.
+ * Specified LinkSources will be included.
+ * If none are specified, all are included.
+ */
+ private List myLinkSourceFilters;
+
+ public GenerateMdmMetricsParameters(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public List getMatchResultFilters() {
+ if (myMatchResultFilters == null) {
+ myMatchResultFilters = new ArrayList<>();
+ }
+ return myMatchResultFilters;
+ }
+
+ public void addMatchResult(MdmMatchResultEnum theMdmMatchResultEnum) {
+ getMatchResultFilters().add(theMdmMatchResultEnum);
+ }
+
+ public List getLinkSourceFilters() {
+ if (myLinkSourceFilters == null) {
+ myLinkSourceFilters = new ArrayList<>();
+ }
+ return myLinkSourceFilters;
+ }
+
+ public void addLinkSource(MdmLinkSourceEnum theLinkSource) {
+ getLinkSourceFilters().add(theLinkSource);
+ }
+
+ // public GenerateMdmLinkMetricParameters toLinkMetricParams() {
+ //
+ // }
+ //
+ // public GenerateMdmResourceMetricsParameters toResourceMetricParams() {
+ //
+ // }
+ //
+
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmResourceMetricsParameters.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmResourceMetricsParameters.java
new file mode 100644
index 00000000000..504f169604e
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateMdmResourceMetricsParameters.java
@@ -0,0 +1,17 @@
+package ca.uhn.fhir.mdm.api.params;
+
+public class GenerateMdmResourceMetricsParameters {
+
+ /**
+ * We only allow finding metrics by resource type
+ */
+ private final String myResourceType;
+
+ public GenerateMdmResourceMetricsParameters(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateScoreMetricsParameters.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateScoreMetricsParameters.java
new file mode 100644
index 00000000000..412703585de
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/params/GenerateScoreMetricsParameters.java
@@ -0,0 +1,39 @@
+package ca.uhn.fhir.mdm.api.params;
+
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class GenerateScoreMetricsParameters {
+ /**
+ * The resource type of interest.
+ */
+ private final String myResourceType;
+
+ /**
+ * MatchResult types to filter for.
+ * Specified MatchResults will be included.
+ * If none specified, all will be included.
+ */
+ private List myMatchTypeFilters;
+
+ public GenerateScoreMetricsParameters(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public List getMatchTypes() {
+ if (myMatchTypeFilters == null) {
+ myMatchTypeFilters = new ArrayList<>();
+ }
+ return myMatchTypeFilters;
+ }
+
+ public void addMatchType(MdmMatchResultEnum theMatchType) {
+ getMatchTypes().add(theMatchType);
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkMetrics.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkMetrics.java
new file mode 100644
index 00000000000..9d30b033030
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkMetrics.java
@@ -0,0 +1,52 @@
+package ca.uhn.fhir.mdm.model;
+
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+
+import java.util.HashMap;
+import java.util.Map;
+
+public class MdmLinkMetrics {
+ /**
+ * The resource type to which these metrics apply.
+ */
+ private String myResourceType;
+
+ /**
+ * A mapping of MatchType -> LinkSource -> count.
+ * Eg:
+ * MATCH
+ * AUTO - 2
+ * MANUAL - 1
+ * NO_MATCH
+ * AUTO - 1
+ * MANUAL - 3
+ */
+ private Map> myMatchTypeToLinkToCountMap;
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public void setResourceType(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public Map> getMatchTypeToLinkToCountMap() {
+ if (myMatchTypeToLinkToCountMap == null) {
+ myMatchTypeToLinkToCountMap = new HashMap<>();
+ }
+ return myMatchTypeToLinkToCountMap;
+ }
+
+ public void addMetric(
+ MdmMatchResultEnum theMdmMatchResultEnum, MdmLinkSourceEnum theLinkSourceEnum, long theCount) {
+ Map> map = getMatchTypeToLinkToCountMap();
+
+ if (!map.containsKey(theMdmMatchResultEnum)) {
+ map.put(theMdmMatchResultEnum, new HashMap<>());
+ }
+ Map lsToCountMap = map.get(theMdmMatchResultEnum);
+ lsToCountMap.put(theLinkSourceEnum, theCount);
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkScoreMetrics.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkScoreMetrics.java
new file mode 100644
index 00000000000..d5ea731ddea
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmLinkScoreMetrics.java
@@ -0,0 +1,35 @@
+package ca.uhn.fhir.mdm.model;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class MdmLinkScoreMetrics {
+
+ private String myResourceType;
+
+ /**
+ * Map of Score:Count
+ * Scores are typically Doubles. But we cast to string because
+ * Score is not a non-null field, and so "NULL" is a value.
+ */
+ private Map myScoreCounts;
+
+ public void setResourceType(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public Map getScoreCounts() {
+ if (myScoreCounts == null) {
+ myScoreCounts = new LinkedHashMap<>();
+ }
+ return myScoreCounts;
+ }
+
+ public void addScore(String theScore, Long theCount) {
+ getScoreCounts().put(theScore, theCount);
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmMetrics.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmMetrics.java
new file mode 100644
index 00000000000..aed9fbe9f76
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmMetrics.java
@@ -0,0 +1,132 @@
+package ca.uhn.fhir.mdm.model;
+
+import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
+import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
+import ca.uhn.fhir.model.api.IModelJson;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+public class MdmMetrics extends MdmResourceMetrics implements IModelJson {
+
+ @JsonProperty("resourceType")
+ private String myResourceType;
+
+ /**
+ * A mapping of MatchType -> LinkSource -> count.
+ * Eg:
+ * MATCH
+ * AUTO - 2
+ * MANUAL - 1
+ * NO_MATCH
+ * AUTO - 1
+ * MANUAL - 3
+ */
+ @JsonProperty("matchResult2linkSource2count")
+ private Map> myMatchTypeToLinkToCountMap;
+
+ /**
+ * Score buckets (in brackets of 0.01 size, and null) to counts.
+ */
+ @JsonProperty("scoreCounts")
+ private Map myScoreCounts;
+
+ /**
+ * The number of golden resources.
+ */
+ @JsonProperty("goldenResources")
+ private long myGoldenResourcesCount;
+
+ /**
+ * The number of source resources.
+ */
+ @JsonProperty("sourceResources")
+ private long mySourceResourcesCount;
+
+ /**
+ * The number of excluded resources.
+ * These are necessarily a subset of both
+ * GoldenResources and SourceResources
+ * (as each Blocked resource will still generate
+ * a GoldenResource)
+ */
+ @JsonProperty("excludedResources")
+ private long myExcludedResources;
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public Map> getMatchTypeToLinkToCountMap() {
+ if (myMatchTypeToLinkToCountMap == null) {
+ myMatchTypeToLinkToCountMap = new HashMap<>();
+ }
+ return myMatchTypeToLinkToCountMap;
+ }
+
+ public void addMetric(
+ MdmMatchResultEnum theMdmMatchResultEnum, MdmLinkSourceEnum theLinkSourceEnum, long theCount) {
+ Map> map = getMatchTypeToLinkToCountMap();
+
+ if (!map.containsKey(theMdmMatchResultEnum)) {
+ map.put(theMdmMatchResultEnum, new HashMap<>());
+ }
+ Map lsToCountMap = map.get(theMdmMatchResultEnum);
+ lsToCountMap.put(theLinkSourceEnum, theCount);
+ }
+
+ public void setResourceType(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public long getGoldenResourcesCount() {
+ return myGoldenResourcesCount;
+ }
+
+ public void setGoldenResourcesCount(long theGoldenResourcesCount) {
+ myGoldenResourcesCount = theGoldenResourcesCount;
+ }
+
+ public long getSourceResourcesCount() {
+ return mySourceResourcesCount;
+ }
+
+ public void setSourceResourcesCount(long theSourceResourcesCount) {
+ mySourceResourcesCount = theSourceResourcesCount;
+ }
+
+ public long getExcludedResources() {
+ return myExcludedResources;
+ }
+
+ public void setExcludedResources(long theExcludedResources) {
+ myExcludedResources = theExcludedResources;
+ }
+
+ public Map getScoreCounts() {
+ if (myScoreCounts == null) {
+ myScoreCounts = new LinkedHashMap<>();
+ }
+ return myScoreCounts;
+ }
+
+ public void addScore(String theScore, Long theCount) {
+ getScoreCounts().put(theScore, theCount);
+ }
+
+ public static MdmMetrics fromSeperableMetrics(
+ MdmResourceMetrics theMdmResourceMetrics,
+ MdmLinkMetrics theLinkMetrics,
+ MdmLinkScoreMetrics theLinkScoreMetrics) {
+ MdmMetrics metrics = new MdmMetrics();
+ metrics.setResourceType(theMdmResourceMetrics.getResourceType());
+ metrics.setExcludedResources(theMdmResourceMetrics.getExcludedResources());
+ metrics.setGoldenResourcesCount(theMdmResourceMetrics.getGoldenResourcesCount());
+ metrics.setSourceResourcesCount(theMdmResourceMetrics.getSourceResourcesCount());
+ metrics.myMatchTypeToLinkToCountMap = theLinkMetrics.getMatchTypeToLinkToCountMap();
+ metrics.myScoreCounts = theLinkScoreMetrics.getScoreCounts();
+ return metrics;
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmResourceMetrics.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmResourceMetrics.java
new file mode 100644
index 00000000000..49939a5fd27
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmResourceMetrics.java
@@ -0,0 +1,60 @@
+package ca.uhn.fhir.mdm.model;
+
+public class MdmResourceMetrics {
+
+ /**
+ * The resource type to which these metrics apply.
+ */
+ private String myResourceType;
+
+ /**
+ * The number of golden resources.
+ */
+ private long myGoldenResourcesCount;
+
+ /**
+ * The number of source resources.
+ */
+ private long mySourceResourcesCount;
+
+ /**
+ * The number of excluded resources.
+ * These are necessarily a subset of both
+ * GoldenResources and SourceResources
+ * (as each Blocked resource will still generate
+ * a GoldenResource)
+ */
+ private long myExcludedResources;
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public void setResourceType(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public long getGoldenResourcesCount() {
+ return myGoldenResourcesCount;
+ }
+
+ public void setGoldenResourcesCount(long theGoldenResourcesCount) {
+ myGoldenResourcesCount = theGoldenResourcesCount;
+ }
+
+ public long getSourceResourcesCount() {
+ return mySourceResourcesCount;
+ }
+
+ public void setSourceResourcesCount(long theSourceResourcesCount) {
+ mySourceResourcesCount = theSourceResourcesCount;
+ }
+
+ public long getExcludedResources() {
+ return myExcludedResources;
+ }
+
+ public void setExcludedResources(long theExcludedResources) {
+ myExcludedResources = theExcludedResources;
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmTransactionContext.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmTransactionContext.java
index a2ca1b94930..17613f59be8 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmTransactionContext.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/model/MdmTransactionContext.java
@@ -49,6 +49,12 @@ public class MdmTransactionContext {
private String myResourceType;
+ /**
+ * Whether or not the currently processed resource is a 'blocked resource'.
+ * This will only be set on matching.
+ */
+ private boolean myIsBlockedResource;
+
private List myMdmLinkEvents = new ArrayList<>();
public TransactionLogMessages getTransactionLogMessages() {
@@ -111,4 +117,12 @@ public class MdmTransactionContext {
public void setMdmLinks(List theMdmLinkEvents) {
myMdmLinkEvents = theMdmLinkEvents;
}
+
+ public void setIsBlocked(boolean theIsBlocked) {
+ myIsBlockedResource = theIsBlocked;
+ }
+
+ public boolean getIsBlocked() {
+ return myIsBlockedResource;
+ }
}
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 d133a7a9605..c7b46f4cd38 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
@@ -116,6 +116,14 @@ public class GoldenResourceHelper {
MdmResourceUtil.setMdmManaged(newGoldenResource);
MdmResourceUtil.setGoldenResource(newGoldenResource);
+ // TODO - on updating links, if resolving a link, this should go away?
+ // blocked resource's golden resource will be marked special
+ // they are not part of MDM matching algorithm (will not link to other resources)
+ // but other resources can link to them
+ if (theMdmTransactionContext.getIsBlocked()) {
+ MdmResourceUtil.setGoldenResourceAsBlockedResourceGoldenResource(newGoldenResource);
+ }
+
// add the partition id to the new resource
newGoldenResource.setUserData(
Constants.RESOURCE_PARTITION_ID,
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmResourceUtil.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmResourceUtil.java
index 44f34ea094f..4e7faf9d523 100644
--- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmResourceUtil.java
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmResourceUtil.java
@@ -132,6 +132,24 @@ public final class MdmResourceUtil {
MdmConstants.DISPLAY_GOLDEN_REDIRECT);
}
+ /**
+ * Adds the BLOCKED tag to the golden resource.
+ * Because this is called *before* a resource is saved,
+ * we must add a new system/code combo to it
+ * @param theBaseResource
+ * @return
+ */
+ public static IBaseResource setGoldenResourceAsBlockedResourceGoldenResource(IBaseResource theBaseResource) {
+ IBaseCoding tag = theBaseResource.getMeta().addTag();
+ tag.setSystem(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS);
+ tag.setCode(MdmConstants.CODE_BLOCKED);
+ tag.setDisplay(MdmConstants.CODE_BLOCKED_DISPLAY);
+ tag.setUserSelected(false);
+ tag.setVersion("1");
+
+ return theBaseResource;
+ }
+
/**
* WARNING: This code may _look_ like it replaces in place a code of a tag, but this DOES NOT ACTUALLY WORK!. In reality what will
* happen is a secondary tag will be created with the same system. the only way to actually remove a tag from a resource
diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmSearchParamBuildingUtils.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmSearchParamBuildingUtils.java
new file mode 100644
index 00000000000..d2085329296
--- /dev/null
+++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/util/MdmSearchParamBuildingUtils.java
@@ -0,0 +1,51 @@
+package ca.uhn.fhir.mdm.util;
+
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.mdm.api.MdmConstants;
+import ca.uhn.fhir.mdm.rules.json.MdmRulesJson;
+import ca.uhn.fhir.rest.param.TokenAndListParam;
+import ca.uhn.fhir.rest.param.TokenParam;
+
+public class MdmSearchParamBuildingUtils {
+
+ private static final String IDENTIFIER = "identifier";
+
+ private static final String TAG = "_tag";
+
+ /**
+ * Builds a search parameter map that can be used to find the
+ * golden resources associated with MDM blocked resources (ie, those
+ * resources that were omitted from MDM matching).
+ */
+ public static SearchParameterMap buildSearchParameterForBlockedResourceCount(String theResourceType) {
+ SearchParameterMap map = new SearchParameterMap();
+ map.setLoadSynchronous(true);
+ TokenAndListParam tagsToSearch = new TokenAndListParam();
+ tagsToSearch.addAnd(new TokenParam(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD));
+ tagsToSearch.addAnd(new TokenParam(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_BLOCKED));
+
+ map.add(TAG, tagsToSearch);
+ return map;
+ }
+
+ /**
+ * Creates a SearchParameterMap used for searching for golden resources
+ * by EID specifically.
+ */
+ public static SearchParameterMap buildEidSearchParameterMap(
+ String theEid, String theResourceType, MdmRulesJson theMdmRules) {
+ SearchParameterMap map = buildBasicGoldenResourceSearchParameterMap(theEid);
+ map.add(IDENTIFIER, new TokenParam(theMdmRules.getEnterpriseEIDSystemForResourceType(theResourceType), theEid));
+ return map;
+ }
+
+ /**
+ * Creates a SearchParameterMap that can be used to find golden resources.
+ */
+ public static SearchParameterMap buildBasicGoldenResourceSearchParameterMap(String theResourceType) {
+ SearchParameterMap map = new SearchParameterMap();
+ map.setLoadSynchronous(true);
+ map.add(TAG, new TokenParam(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD));
+ return map;
+ }
+}
diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/util/MdmResourceUtilTest.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/util/MdmResourceUtilTest.java
index 8b128896f1d..85671682cc0 100644
--- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/util/MdmResourceUtilTest.java
+++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/util/MdmResourceUtilTest.java
@@ -1,11 +1,21 @@
package ca.uhn.fhir.mdm.util;
+import ca.uhn.fhir.mdm.api.MdmConstants;
+import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.Organization;
+import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.Test;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
class MdmResourceUtilTest {
@@ -20,4 +30,28 @@ class MdmResourceUtilTest {
assertThat(hasGoldenRecordTag, is(equalTo(false)));
}
+
+ @Test
+ public void testSetGoldenAndBlockedResource() {
+ // setup
+ Patient patient = new Patient();
+ patient.setActive(true);
+
+ // test
+ Patient changed = (Patient) MdmResourceUtil.setGoldenResourceAsBlockedResourceGoldenResource(
+ MdmResourceUtil.setGoldenResource(patient)
+ );
+
+ // verify
+ assertNotNull(changed);
+ List tags = changed.getMeta().getTag();
+ Set codes = new HashSet<>();
+ codes.add(MdmConstants.CODE_BLOCKED);
+ codes.add(MdmConstants.CODE_GOLDEN_RECORD);
+ assertEquals(2, tags.size());
+ for (Coding code : tags) {
+ assertEquals(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, code.getSystem());
+ assertTrue(codes.contains(code.getCode()));
+ }
+ }
}
diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml
index 97a9d442082..c57d846a2d1 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml
index 05f1e323a7c..a52010ad2d0 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml
index 3d61960b0b0..7a91609e596 100644
--- a/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml
+++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-api/pom.xml
@@ -7,7 +7,7 @@
hapi-fhir-serviceloaders
ca.uhn.hapi.fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml
index b3446ed9a2a..a3b872bcbb6 100644
--- a/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml
+++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-caffeine/pom.xml
@@ -7,7 +7,7 @@
hapi-fhir-serviceloaders
ca.uhn.hapi.fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
@@ -21,7 +21,7 @@
ca.uhn.hapi.fhir
hapi-fhir-caching-api
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml
index ab639b80f69..31a240fdbb3 100644
--- a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml
+++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml
@@ -7,7 +7,7 @@
hapi-fhir-serviceloaders
ca.uhn.hapi.fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml
index bd046a5d4a5..119a3ced85c 100644
--- a/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml
+++ b/hapi-fhir-serviceloaders/hapi-fhir-caching-testing/pom.xml
@@ -7,7 +7,7 @@
hapi-fhir
ca.uhn.hapi.fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../../pom.xml
diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml
index c465731f954..4d50f71fa86 100644
--- a/hapi-fhir-serviceloaders/pom.xml
+++ b/hapi-fhir-serviceloaders/pom.xml
@@ -5,7 +5,7 @@
hapi-deployable-pom
ca.uhn.hapi.fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
index 3cd4f85ea30..148c5717fb5 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.9.8-SNAPSHOT
+ 6.9.9-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 36d820541cf..debccca5b4b 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.9.8-SNAPSHOT
+ 6.9.9-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 cdf05f46650..9b6ba0cdf17 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
index 27dc8f1ee62..05465b1fd32 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
index 7f01939e11a..8d89550158d 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
index 59b94d03c74..6a845cc9ffc 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml
index 465d0b784d3..16232047a4f 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml
index 50f71fb0834..f7ee91e88a1 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.9.8-SNAPSHOT
+ 6.9.9-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 da9f668f778..53aaee618a2 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-batch2-test-utilities/pom.xml b/hapi-fhir-storage-batch2-test-utilities/pom.xml
index 4b55a6d0612..259a89b3dbb 100644
--- a/hapi-fhir-storage-batch2-test-utilities/pom.xml
+++ b/hapi-fhir-storage-batch2-test-utilities/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml
index 1e2ba7f7e8c..791bfc09bbf 100644
--- a/hapi-fhir-storage-batch2/pom.xml
+++ b/hapi-fhir-storage-batch2/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml
index bceff64f591..6adae32a21c 100644
--- a/hapi-fhir-storage-cr/pom.xml
+++ b/hapi-fhir-storage-cr/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml
index b815a275b9f..0ba86977969 100644
--- a/hapi-fhir-storage-mdm/pom.xml
+++ b/hapi-fhir-storage-mdm/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml
index e665b690315..b12e654faf8 100644
--- a/hapi-fhir-storage-test-utilities/pom.xml
+++ b/hapi-fhir-storage-test-utilities/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml
index bb9a01ab472..8677b904bbe 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml
index 6f9ae35ffb8..23a3f4ccfd9 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index a9643757fc7..e3d347cc12c 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml
index cda18bff14a..1fb57ba2778 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.9.8-SNAPSHOT
+ 6.9.9-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 e0567ffd108..98b3407c903 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml
index e070a8fb9e7..db74917e705 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml
index 5b9471961cb..b31d930227f 100644
--- a/hapi-fhir-structures-r4b/pom.xml
+++ b/hapi-fhir-structures-r4b/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml
index c97208fe2e2..eab80fc01a3 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
index c8cdbf8062f..239efa1efea 100644
--- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
+++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/fhirpath/FhirPathR5.java
@@ -16,7 +16,7 @@ import org.hl7.fhir.r5.model.IdType;
import org.hl7.fhir.r5.model.TypeDetails;
import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.utils.FHIRPathEngine;
-import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses.FunctionDetails;
+import org.hl7.fhir.r5.utils.FHIRPathUtilityClasses;
import java.util.List;
import java.util.Optional;
@@ -108,7 +108,7 @@ public class FhirPathR5 implements IFhirPath {
}
@Override
- public FunctionDetails resolveFunction(String functionName) {
+ public FHIRPathUtilityClasses.FunctionDetails resolveFunction(String functionName) {
return null;
}
diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml
index f208de1b2f7..3c9b6e6c687 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index fb872aa9377..d1336006d52 100644
--- a/hapi-fhir-testpage-overlay/pom.xml
+++ b/hapi-fhir-testpage-overlay/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml
index 77f87de8553..82f33474782 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.9.8-SNAPSHOT
+ 6.9.9-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 0c33abe7f82..7ed3464e804 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.9.8-SNAPSHOT
+ 6.9.9-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 1d399034981..8ec6bcb529e 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.9.8-SNAPSHOT
+ 6.9.9-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 fb0365de8a7..961ea491248 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-r4b/pom.xml b/hapi-fhir-validation-resources-r4b/pom.xml
index 8d78cb03be9..1b4da7b170b 100644
--- a/hapi-fhir-validation-resources-r4b/pom.xml
+++ b/hapi-fhir-validation-resources-r4b/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 6.9.8-SNAPSHOT
+ 6.9.9-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 5018a5c0a0c..f44873e9e6a 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml
index f7c7a9fcfa1..d11066607d5 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml
index 2880a0397e4..0ec080fa1e6 100644
--- a/hapi-tinder-plugin/pom.xml
+++ b/hapi-tinder-plugin/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml
index 133b6269e46..01786c9d945 100644
--- a/hapi-tinder-test/pom.xml
+++ b/hapi-tinder-test/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../pom.xml
diff --git a/pom.xml b/pom.xml
index a9bf58d73ad..4c37982117a 100644
--- a/pom.xml
+++ b/pom.xml
@@ -9,7 +9,7 @@
ca.uhn.hapi.fhir
hapi-fhir
pom
- 6.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
HAPI-FHIR
An open-source implementation of the FHIR specification in Java.
diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
index 3d54ad5b0c4..95bb4d038b7 100644
--- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
+++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 6.9.8-SNAPSHOT
+ 6.9.9-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 11f932aa409..bd679c2e152 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.9.8-SNAPSHOT
+ 6.9.9-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 2bac2e98877..b5570d3c637 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.9.8-SNAPSHOT
+ 6.9.9-SNAPSHOT
../../pom.xml