diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index 2bb028adf117..e0e2da10efa6 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 76912044d5f9..b0ed5515c518 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index ceda17a4858a..e7fed5b63b1a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index 6a3c6420f683..86c78ed521a3 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT pom HAPI FHIR BOM @@ -12,7 +12,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 2ebfeaaedcae..8f8b2af5a655 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-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 6812535d1fb3..67624d468905 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.7.3-SNAPSHOT + 6.7.6-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 92f108eadc6f..90738fec4a31 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index e85812b3e1c2..634e7300b3eb 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index dc61facbf014..d8324ba8548a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 3bb88a8b7f49..152f24fd1b3e 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 69c428bc2c02..ac25f9925da3 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index 6d3fce4ee70e..16a8d4cf3ce2 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index 9644d93dce91..005ee26c1bfe 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/4917-refactoring-matchers.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/4917-refactoring-matchers.yaml new file mode 100644 index 000000000000..7d0fb27a49c8 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_8_0/4917-refactoring-matchers.yaml @@ -0,0 +1,7 @@ +--- +type: fix +issue: 4917 +title: "Matching algorithms have been refactored to allow + greater flexibility in setting and defining nicknames + as well as allowing bean injection into matcher classes. + " diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index bf2f22d8f203..82ee95419594 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index 94cf43c7abbe..a6625af0cf6d 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index 54cbd9050c2f..9de34ddf89d5 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMap.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameMap.java similarity index 72% rename from hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMap.java rename to hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameMap.java index fc5900e58164..a0d6632c6bc7 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMap.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameMap.java @@ -17,7 +17,7 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.jpa.searchparam.nickname; +package ca.uhn.fhir.jpa.nickname; import javax.annotation.Nonnull; import java.io.BufferedReader; @@ -33,19 +33,30 @@ class NicknameMap { private final Map> myFormalToNick = new HashMap<>(); private final Map> myNicknameToFormal = new HashMap<>(); + private final List myBadRows = new ArrayList<>(); + void load(Reader theReader) throws IOException { try (BufferedReader reader = new BufferedReader(theReader)) { String line; while ((line = reader.readLine()) != null) { String[] parts = line.split(","); - String key = parts[0]; - List values = new ArrayList<>(Arrays.asList(parts).subList(1, parts.length)); - add(key, values); + if (parts.length > 1) { + String key = parts[0]; + List values = new ArrayList<>(Arrays.asList(parts).subList(1, parts.length)); + add(key, values); + } else { + myBadRows.add(line); + } } } } - private void add(String theKey, List theValues) { + void clear() { + myFormalToNick.clear(); + myNicknameToFormal.clear(); + } + + void add(String theKey, List theValues) { myFormalToNick.put(theKey, theValues); for (String value : theValues) { myNicknameToFormal.putIfAbsent(value, new ArrayList<>()); @@ -57,14 +68,22 @@ int size() { return myFormalToNick.size(); } + boolean isEmpty() { + return size() == 0; + } + + List getBadRows() { + return myBadRows; + } + @Nonnull - List getNicknamesFromFormalName(String theName) { + public List getNicknamesFromFormalName(String theName) { List result = myFormalToNick.get(theName); return result == null ? new ArrayList<>() : result; } @Nonnull - List getFormalNamesFromNickname(String theNickname) { + public List getFormalNamesFromNickname(String theNickname) { List result = myNicknameToFormal.get(theNickname); return result == null ? new ArrayList<>() : result; } diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvc.java b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameSvc.java similarity index 53% rename from hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvc.java rename to hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameSvc.java index e500dcc8466a..c99c307f5fa2 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvc.java +++ b/hapi-fhir-jpa/src/main/java/ca/uhn/fhir/jpa/nickname/NicknameSvc.java @@ -17,8 +17,12 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.jpa.searchparam.nickname; +package ca.uhn.fhir.jpa.nickname; +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.i18n.Msg; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -32,22 +36,40 @@ import java.util.List; import java.util.Set; +/** + * Nickname service is used to load nicknames + * via a file that contains rows of comma separated names that are + * "similar" or nicknames of each other. + * - + * If no nickname resource is provided, nicknames/names.csv will be used instead. + * - + * If one is to be provided, it must be provided before nickname svc is invoked + */ public class NicknameSvc { - private final NicknameMap myNicknameMap = new NicknameMap(); + private static final Logger ourLog = LoggerFactory.getLogger(NicknameSvc.class); - public NicknameSvc() throws IOException { - Resource nicknameCsvResource = new ClassPathResource("/nickname/names.csv"); - try (InputStream inputStream = nicknameCsvResource.getInputStream()) { - try (Reader reader = new InputStreamReader(inputStream)) { - myNicknameMap.load(reader); - } - } + private NicknameMap myNicknameMap; + + private Resource myNicknameResource; + + public NicknameSvc() { + + } + + public void setNicknameResource(Resource theNicknameResource) { + myNicknameResource = theNicknameResource; } public int size() { + ensureMapInitialized(); return myNicknameMap.size(); } + public List getBadRows() { + ensureMapInitialized(); + return myNicknameMap.getBadRows(); + } + public Collection getEquivalentNames(String theName) { Set retval = new HashSet<>(getNicknamesFromFormalName(theName)); @@ -64,11 +86,34 @@ public Collection getEquivalentNames(String theName) { @Nonnull List getNicknamesFromFormalName(String theName) { + ensureMapInitialized(); return myNicknameMap.getNicknamesFromFormalName(theName); } @Nonnull List getFormalNamesFromNickname(String theNickname) { + ensureMapInitialized(); return myNicknameMap.getFormalNamesFromNickname(theNickname); } + + private void ensureMapInitialized() { + if (myNicknameResource == null) { + myNicknameResource = new ClassPathResource("/nickname/names.csv"); + } + + if (myNicknameMap == null) { + myNicknameMap = new NicknameMap(); + } + if (myNicknameMap.isEmpty()) { + try { + try (InputStream inputStream = myNicknameResource.getInputStream()) { + try (Reader reader = new InputStreamReader(inputStream)) { + myNicknameMap.load(reader); + } + } + } catch (IOException e) { + throw new ConfigurationException(Msg.code(2234) + "Unable to load nicknames", e); + } + } + } } diff --git a/hapi-fhir-jpa/src/main/resources/.gitkeep b/hapi-fhir-jpa/src/main/resources/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/License.txt b/hapi-fhir-jpa/src/main/resources/nickname/License.txt similarity index 100% rename from hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/License.txt rename to hapi-fhir-jpa/src/main/resources/nickname/License.txt diff --git a/hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/README.md b/hapi-fhir-jpa/src/main/resources/nickname/README.md similarity index 100% rename from hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/README.md rename to hapi-fhir-jpa/src/main/resources/nickname/README.md diff --git a/hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/README.txt b/hapi-fhir-jpa/src/main/resources/nickname/README.txt similarity index 100% rename from hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/README.txt rename to hapi-fhir-jpa/src/main/resources/nickname/README.txt diff --git a/hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/names.csv b/hapi-fhir-jpa/src/main/resources/nickname/names.csv similarity index 100% rename from hapi-fhir-jpaserver-searchparam/src/main/resources/nickname/names.csv rename to hapi-fhir-jpa/src/main/resources/nickname/names.csv diff --git a/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/.gitkeep b/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMapTest.java b/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameMapTest.java similarity index 95% rename from hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMapTest.java rename to hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameMapTest.java index 524142a9ccb2..9adf090d0b83 100644 --- a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameMapTest.java +++ b/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameMapTest.java @@ -1,4 +1,4 @@ -package ca.uhn.fhir.jpa.searchparam.nickname; +package ca.uhn.fhir.jpa.nickname; import org.junit.jupiter.api.Test; diff --git a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvcTest.java b/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameSvcTest.java similarity index 86% rename from hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvcTest.java rename to hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameSvcTest.java index 80d24b88559b..180f5a53ad82 100644 --- a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameSvcTest.java +++ b/hapi-fhir-jpa/src/test/java/ca/uhn/fhir/jpa/nickname/NicknameSvcTest.java @@ -1,4 +1,4 @@ -package ca.uhn.fhir.jpa.searchparam.nickname; +package ca.uhn.fhir.jpa.nickname; import org.junit.jupiter.api.Test; diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 983ab2708b53..6a3d9b0c2b89 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java index 2678c339d5b1..d3868db6f813 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/JpaConfig.java @@ -95,8 +95,8 @@ import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; import ca.uhn.fhir.jpa.partition.RequestPartitionHelperSvc; import ca.uhn.fhir.jpa.provider.DiffProvider; -import ca.uhn.fhir.jpa.provider.ProcessMessageProvider; import ca.uhn.fhir.jpa.provider.InstanceReindexProvider; +import ca.uhn.fhir.jpa.provider.ProcessMessageProvider; import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider; import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider; import ca.uhn.fhir.jpa.provider.ValueSetOperationProvider; @@ -149,7 +149,6 @@ import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.searchparam.config.SearchParamConfig; import ca.uhn.fhir.jpa.searchparam.extractor.IResourceLinkResolver; -import ca.uhn.fhir.jpa.searchparam.nickname.NicknameInterceptor; import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider; import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc; import ca.uhn.fhir.jpa.sp.SearchParamPresenceSvcImpl; @@ -198,7 +197,6 @@ import org.springframework.transaction.PlatformTransactionManager; import javax.annotation.Nullable; -import java.io.IOException; import java.util.Date; @Configuration @@ -772,12 +770,6 @@ public UnknownCodeSystemWarningValidationSupport unknownCodeSystemWarningValidat return new UnknownCodeSystemWarningValidationSupport(theFhirContext); } - @Lazy - @Bean - public NicknameInterceptor nicknameInterceptor() throws IOException { - return new NicknameInterceptor(); - } - @Bean public ISynchronousSearchSvc synchronousSearchSvc() { return new SynchronousSearchSvcImpl(); diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ResourceTableFKProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ResourceTableFKProvider.java index cfb343f9f418..e5b74026fe56 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ResourceTableFKProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/expunge/ResourceTableFKProvider.java @@ -20,13 +20,11 @@ package ca.uhn.fhir.jpa.dao.expunge; import ca.uhn.fhir.mdm.api.IMdmSettings; -import ca.uhn.fhir.mdm.rules.config.MdmSettings; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import javax.annotation.Nonnull; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; @Service diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index 346301900ec5..d984ff0c4f58 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-ips/pom.xml b/hapi-fhir-jpaserver-ips/pom.xml index ba78361f2893..66da1d4ba0d1 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index e45850b92995..553c35cfe732 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmCommonConfig.java b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmCommonConfig.java index 9f9d90aad92b..a39afe5c2ddd 100644 --- a/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmCommonConfig.java +++ b/hapi-fhir-jpaserver-mdm/src/main/java/ca/uhn/fhir/jpa/mdm/config/MdmCommonConfig.java @@ -20,14 +20,21 @@ package ca.uhn.fhir.jpa.mdm.config; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.jpa.searchparam.config.NicknameServiceConfig; +import ca.uhn.fhir.mdm.api.IMdmSettings; import ca.uhn.fhir.mdm.interceptor.MdmSearchExpandingInterceptor; import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator; +import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory; +import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherFactory; import ca.uhn.fhir.mdm.svc.MdmLinkDeleteSvc; import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; +@Import(NicknameServiceConfig.class) @Configuration public class MdmCommonConfig { @Bean @@ -44,4 +51,17 @@ public MdmSearchExpandingInterceptor mdmSearchExpandingInterceptor() { MdmLinkDeleteSvc mdmLinkDeleteSvc() { return new MdmLinkDeleteSvc(); } + + @Bean + public IMatcherFactory matcherFactory( + FhirContext theFhirContext, + IMdmSettings theSettings, + NicknameSvc theNicknameSvc + ) { + return new MdmMatcherFactory( + theFhirContext, + theSettings, + theNicknameSvc + ); + } } 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 4007b24ed7d1..1593d5c27a46 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 @@ -48,6 +48,7 @@ import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchCriteriaBuilderSvc; import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchSvc; import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmGoldenResourceFindingSvc; +import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory; import ca.uhn.fhir.mdm.util.MdmPartitionHelper; import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc; import ca.uhn.fhir.jpa.subscription.channel.api.IChannelFactory; @@ -205,8 +206,12 @@ MdmCandidateSearchCriteriaBuilderSvc mdmCriteriaBuilderSvc() { } @Bean - MdmResourceMatcherSvc mdmResourceComparatorSvc(FhirContext theFhirContext, IMdmSettings theMdmSettings) { - return new MdmResourceMatcherSvc(theFhirContext, theMdmSettings); + MdmResourceMatcherSvc mdmResourceComparatorSvc( + FhirContext theFhirContext, + IMatcherFactory theIMatcherFactory, + IMdmSettings theMdmSettings + ) { + return new MdmResourceMatcherSvc(theFhirContext, theIMatcherFactory, theMdmSettings); } @Bean 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 a20df1252a88..7ee9b49dd1f9 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 @@ -76,7 +76,12 @@ import static org.slf4j.LoggerFactory.getLogger; @ExtendWith(SpringExtension.class) -@ContextConfiguration(classes = {MdmSubmitterConfig.class, MdmConsumerConfig.class, TestMdmConfigR4.class, SubscriptionProcessorConfig.class}) +@ContextConfiguration(classes = { + MdmSubmitterConfig.class, + MdmConsumerConfig.class, + TestMdmConfigR4.class, + SubscriptionProcessorConfig.class +}) abstract public class BaseMdmR4Test extends BaseJpaR4Test { protected static final String PARTITION_1 = "PART-1"; diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java index 526ca53fb6d3..3b8cb72dc107 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/provider/BaseProviderR4Test.java @@ -7,6 +7,7 @@ import ca.uhn.fhir.mdm.provider.MdmControllerHelper; import ca.uhn.fhir.mdm.provider.MdmProviderDstu3Plus; import ca.uhn.fhir.mdm.rules.config.MdmSettings; +import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc; import ca.uhn.fhir.mdm.util.MessageHelper; import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; @@ -34,6 +35,8 @@ public abstract class BaseProviderR4Test extends BaseMdmR4Test { @Autowired protected MdmSettings myMdmSettings; @Autowired + protected MdmResourceMatcherSvc myMdmResourceMatcherSvc; + @Autowired private MdmControllerHelper myMdmHelper; @Autowired Batch2JobHelper myBatch2JobHelper; @@ -48,7 +51,7 @@ protected void setMdmRuleJson(String theString) throws IOException { String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8); myMdmSettings.setEnabled(true); myMdmSettings.setScriptText(json); - myMdmResourceMatcherSvc.setMdmSettings(myMdmSettings); + myMdmResourceMatcherSvc.setMdmRulesJson(myMdmSettings.getMdmRules()); } @BeforeEach @@ -62,7 +65,7 @@ public void before() throws Exception { public void after() throws IOException { super.after(); myMdmSettings.setScriptText(defaultScript); - myMdmResourceMatcherSvc.setMdmSettings(myMdmSettings); + myMdmResourceMatcherSvc.setMdmRulesJson(myMdmSettings.getMdmRules()); } protected void clearMdmLinks() { diff --git a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java index eb6dcfd6847c..8afd790406a5 100644 --- a/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java +++ b/hapi-fhir-jpaserver-mdm/src/test/java/ca/uhn/fhir/jpa/mdm/svc/MdmCandidateSearchSvcIT.java @@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test; import ca.uhn.fhir.jpa.mdm.svc.candidate.MdmCandidateSearchSvc; import ca.uhn.fhir.jpa.mdm.svc.candidate.TooManyCandidatesException; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.searchparam.nickname.NicknameInterceptor; @@ -18,7 +19,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; -import java.io.IOException; import java.util.Collection; import java.util.Collections; import java.util.Date; @@ -37,11 +37,15 @@ public class MdmCandidateSearchSvcIT extends BaseMdmR4Test { @Autowired MatchUrlService myMatchUrlService; + @Autowired + NicknameSvc myNicknameSvc; + private NicknameInterceptor myNicknameInterceptor; @BeforeEach - public void before() throws IOException { - myNicknameInterceptor = new NicknameInterceptor(); + public void before() throws Exception { + super.before(); + myNicknameInterceptor = new NicknameInterceptor(myNicknameSvc); myInterceptorRegistry.registerInterceptor(myNicknameInterceptor); } diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 5eba4315f39d..4fade2524a8f 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index df64ae24d8dd..2eab432dc3c9 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -165,8 +165,6 @@ test - - diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/NicknameServiceConfig.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/NicknameServiceConfig.java new file mode 100644 index 000000000000..cd4b41f78c30 --- /dev/null +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/NicknameServiceConfig.java @@ -0,0 +1,22 @@ +package ca.uhn.fhir.jpa.searchparam.config; + +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.jpa.searchparam.nickname.NicknameInterceptor; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; + +@Configuration +public class NicknameServiceConfig { + + @Lazy + @Bean + public NicknameInterceptor nicknameInterceptor(NicknameSvc theNicknameSvc) { + return new NicknameInterceptor(theNicknameSvc); + } + + @Bean + public NicknameSvc nicknameSvc() { + return new NicknameSvc(); + } +} diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/SearchParamConfig.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/SearchParamConfig.java index fa2b85d238f8..230311213809 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/SearchParamConfig.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/SearchParamConfig.java @@ -47,9 +47,13 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; +@Import({ + NicknameServiceConfig.class +}) @Configuration public class SearchParamConfig { diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptor.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptor.java index 3739c3f0d227..23d9e4b39ab3 100644 --- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptor.java +++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptor.java @@ -21,13 +21,13 @@ import ca.uhn.fhir.interceptor.api.Hook; import ca.uhn.fhir.interceptor.api.Pointcut; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.rest.param.StringParam; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -39,8 +39,8 @@ public class NicknameInterceptor { private final NicknameSvc myNicknameSvc; - public NicknameInterceptor() throws IOException { - myNicknameSvc = new NicknameSvc(); + public NicknameInterceptor(NicknameSvc theNicknameSvc) { + myNicknameSvc = theNicknameSvc; } @Hook(Pointcut.STORAGE_PRESEARCH_REGISTERED) diff --git a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptorTest.java b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptorTest.java index 862366ce6cca..877f6df833fc 100644 --- a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptorTest.java +++ b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/nickname/NicknameInterceptorTest.java @@ -1,5 +1,6 @@ package ca.uhn.fhir.jpa.searchparam.nickname; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.rest.param.StringParam; import org.junit.jupiter.api.Test; @@ -9,13 +10,18 @@ import static org.junit.jupiter.api.Assertions.assertEquals; class NicknameInterceptorTest { + + private NicknameInterceptor createNicknameInterceptor() { + return new NicknameInterceptor(new NicknameSvc()); + } + @Test public void testExpandForward() throws IOException { // setup String formalName = "kenneth"; SearchParameterMap sp = new SearchParameterMap(); sp.add("name", new StringParam(formalName).setNicknameExpand(true)); - NicknameInterceptor svc = new NicknameInterceptor(); + NicknameInterceptor svc = createNicknameInterceptor(); // execute svc.expandNicknames(sp); @@ -31,7 +37,7 @@ public void testExpandBackward() throws IOException { String nickname = "ken"; SearchParameterMap sp = new SearchParameterMap(); sp.add("name", new StringParam(nickname).setNicknameExpand(true)); - NicknameInterceptor svc = new NicknameInterceptor(); + NicknameInterceptor svc = createNicknameInterceptor(); // execute svc.expandNicknames(sp); @@ -47,7 +53,7 @@ public void testNothingToExpand() throws IOException { String unusualName = "X Æ A-12"; SearchParameterMap sp = new SearchParameterMap(); sp.add("name", new StringParam(unusualName).setNicknameExpand(true)); - NicknameInterceptor svc = new NicknameInterceptor(); + NicknameInterceptor svc = createNicknameInterceptor(); // execute svc.expandNicknames(sp); diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 8b80f14f0617..2700433c14d9 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.7.3-SNAPSHOT + 6.7.6-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 d0f879597d35..b33bfd197f07 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.7.3-SNAPSHOT + 6.7.6-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 fad857b6e698..7c14134a156f 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.7.3-SNAPSHOT + 6.7.6-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 9c67828dbcaf..5728236c9b9f 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.7.3-SNAPSHOT + 6.7.6-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 0c1e8ebbc6a2..fdb204010298 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.7.3-SNAPSHOT + 6.7.6-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 ab80ea617ce7..ebef7c7488e3 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.7.3-SNAPSHOT + 6.7.6-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 ad5915cc1db3..6cf333dc98d6 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index eff8ef8282cf..f4e7226865dc 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 481a0f3f52df..aa961a06121a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSettings.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSettings.java index 50d9ed78ad47..293594f5c8e3 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSettings.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/api/IMdmSettings.java @@ -19,7 +19,6 @@ */ package ca.uhn.fhir.mdm.api; -import ca.uhn.fhir.mdm.dao.IMdmLinkImplFactory; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; import java.util.stream.Collectors; diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java index ac3097cc8441..2849ae944084 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/provider/MdmControllerHelper.java @@ -139,7 +139,7 @@ public void validateIsMdmManaged(String theName, IAnyResource theResource) { public IBaseBundle getMatchesAndPossibleMatchesForResource(IAnyResource theResource, String theResourceType, RequestDetails theRequestDetails) { RequestPartitionId requestPartitionId; ReadPartitionIdRequestDetails details = ReadPartitionIdRequestDetails.forSearchType(theResourceType, null, null); - if (myMdmSettings.getSearchAllPartitionForMatch()){ + if (myMdmSettings.getSearchAllPartitionForMatch()) { requestPartitionId = RequestPartitionId.allPartitions(); } else { requestPartitionId = myRequestPartitionHelperSvc.determineReadPartitionForRequest(theRequestDetails, details); diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmFieldMatchJson.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmFieldMatchJson.java index 70059c9f37be..d809d0f122bf 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmFieldMatchJson.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmFieldMatchJson.java @@ -19,21 +19,16 @@ */ package ca.uhn.fhir.mdm.rules.json; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.mdm.api.MdmMatchEvaluation; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import ca.uhn.fhir.model.api.IModelJson; -import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import com.fasterxml.jackson.annotation.JsonProperty; -import org.hl7.fhir.instance.model.api.IBase; import javax.annotation.Nonnull; /** * Contains all business data for determining if a match exists on a particular field, given: *

- * 1. A {@link MdmMatcherEnum} which determines the actual similarity values. + * 1. A {@link MatchTypeEnum} which determines the actual similarity values. * 2. A given resource type (e.g. Patient) * 3. A given FHIRPath expression for finding the particular primitive to be used for comparison. (e.g. name.given) */ @@ -87,10 +82,6 @@ public MdmMatcherJson getMatcher() { return myMatcher; } - public boolean isMatcherSupportingEmptyFields() { - return (getMatcher() == null) ? false : getMatcher().isMatchingEmptyFields(); - } - public MdmFieldMatchJson setMatcher(MdmMatcherJson theMatcher) { myMatcher = theMatcher; return this; @@ -105,17 +96,6 @@ public MdmFieldMatchJson setSimilarity(MdmSimilarityJson theSimilarity) { return this; } - public MdmMatchEvaluation match(FhirContext theFhirContext, IBase theLeftValue, IBase theRightValue) { - if (myMatcher != null) { - boolean result = myMatcher.match(theFhirContext, theLeftValue, theRightValue); - return new MdmMatchEvaluation(result, result ? 1.0 : 0.0); - } - if (mySimilarity != null) { - return mySimilarity.match(theFhirContext, theLeftValue, theRightValue); - } - throw new InternalErrorException(Msg.code(1522) + "Field Match " + myName + " has neither a matcher nor a similarity."); - } - public String getFhirPath() { return myFhirPath; } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmMatcherJson.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmMatcherJson.java index 18332a2a1c45..e78824cbe9b6 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmMatcherJson.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/json/MdmMatcherJson.java @@ -19,15 +19,13 @@ */ package ca.uhn.fhir.mdm.rules.json; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import ca.uhn.fhir.model.api.IModelJson; import com.fasterxml.jackson.annotation.JsonProperty; -import org.hl7.fhir.instance.model.api.IBase; public class MdmMatcherJson implements IModelJson { @JsonProperty(value = "algorithm", required = true) - MdmMatcherEnum myAlgorithm; + MatchTypeEnum myAlgorithm; @JsonProperty(value = "identifierSystem", required = false) String myIdentifierSystem; @@ -38,11 +36,11 @@ public class MdmMatcherJson implements IModelJson { @JsonProperty(value = "exact") boolean myExact; - public MdmMatcherEnum getAlgorithm() { + public MatchTypeEnum getAlgorithm() { return myAlgorithm; } - public MdmMatcherJson setAlgorithm(MdmMatcherEnum theAlgorithm) { + public MdmMatcherJson setAlgorithm(MatchTypeEnum theAlgorithm) { myAlgorithm = theAlgorithm; return this; } @@ -64,12 +62,4 @@ public MdmMatcherJson setExact(boolean theExact) { myExact = theExact; return this; } - - public boolean isMatchingEmptyFields() { - return myAlgorithm.isMatchingEmptyFields(); - } - - public boolean match(FhirContext theFhirContext, IBase theLeftValue, IBase theRightValue) { - return myAlgorithm.match(theFhirContext, theLeftValue, theRightValue, myExact, myIdentifierSystem); - } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcher.java deleted file mode 100644 index 8c923f2c167c..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcher.java +++ /dev/null @@ -1,41 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.context.FhirContext; -import org.hl7.fhir.instance.model.api.IBase; - -public class HapiDateMatcher implements IMdmFieldMatcher { - private final HapiDateMatcherDstu3 myHapiDateMatcherDstu3 = new HapiDateMatcherDstu3(); - private final HapiDateMatcherR4 myHapiDateMatcherR4 = new HapiDateMatcherR4(); - - @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { - switch (theFhirContext.getVersion().getVersion()) { - case DSTU3: - return myHapiDateMatcherDstu3.match(theLeftBase, theRightBase); - case R4: - return myHapiDateMatcherR4.match(theLeftBase, theRightBase); - default: - throw new UnsupportedOperationException(Msg.code(1520) + "Version not supported: " + theFhirContext.getVersion().getVersion()); - } - } -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherDstu3.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherDstu3.java deleted file mode 100644 index 2682856f2916..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherDstu3.java +++ /dev/null @@ -1,59 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -import org.hl7.fhir.dstu3.model.BaseDateTimeType; -import org.hl7.fhir.dstu3.model.DateTimeType; -import org.hl7.fhir.dstu3.model.DateType; -import org.hl7.fhir.instance.model.api.IBase; - -public class HapiDateMatcherDstu3 { - // TODO KHS code duplication (tried generalizing it with generics, but it got too convoluted) - public boolean match(IBase theLeftBase, IBase theRightBase) { - if (theLeftBase instanceof BaseDateTimeType && theRightBase instanceof BaseDateTimeType) { - BaseDateTimeType leftDate = (BaseDateTimeType) theLeftBase; - BaseDateTimeType rightDate = (BaseDateTimeType) theRightBase; - int comparison = leftDate.getPrecision().compareTo(rightDate.getPrecision()); - if (comparison == 0) { - return leftDate.getValueAsString().equals(rightDate.getValueAsString()); - } - BaseDateTimeType leftPDate; - BaseDateTimeType rightPDate; - if (comparison > 0) { - leftPDate = leftDate; - if (rightDate instanceof DateType) { - rightPDate = new DateType(rightDate.getValue(), leftDate.getPrecision()); - } else { - rightPDate = new DateTimeType(rightDate.getValue(), leftDate.getPrecision()); - } - } else { - rightPDate = rightDate; - if (leftDate instanceof DateType) { - leftPDate = new DateType(leftDate.getValue(), rightDate.getPrecision()); - } else { - leftPDate = new DateTimeType(leftDate.getValue(), rightDate.getPrecision()); - } - } - return leftPDate.getValueAsString().equals(rightPDate.getValueAsString()); - } - - return false; - } -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherR4.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherR4.java deleted file mode 100644 index ade01e59c30e..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiDateMatcherR4.java +++ /dev/null @@ -1,61 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -import org.hl7.fhir.instance.model.api.IBase; -import org.hl7.fhir.r4.model.BaseDateTimeType; -import org.hl7.fhir.r4.model.DateTimeType; -import org.hl7.fhir.r4.model.DateType; - -public class HapiDateMatcherR4 { - // TODO KHS code duplication (tried generalizing it with generics, but it got too convoluted) - public boolean match(IBase theLeftBase, IBase theRightBase) { - if (theLeftBase instanceof BaseDateTimeType && theRightBase instanceof BaseDateTimeType) { - BaseDateTimeType leftDate = (BaseDateTimeType) theLeftBase; - BaseDateTimeType rightDate = (BaseDateTimeType) theRightBase; - int comparison = leftDate.getPrecision().compareTo(rightDate.getPrecision()); - if (comparison == 0) { - return leftDate.getValueAsString().equals(rightDate.getValueAsString()); - } - BaseDateTimeType leftPDate; - BaseDateTimeType rightPDate; - //Left date is coarser - if (comparison < 0) { - leftPDate = leftDate; - if (rightDate instanceof DateType) { - rightPDate = new DateType(rightDate.getValue(), leftDate.getPrecision()); - } else { - rightPDate = new DateTimeType(rightDate.getValue(), leftDate.getPrecision()); - } - //Right date is coarser - } else { - rightPDate = rightDate; - if (leftDate instanceof DateType) { - leftPDate = new DateType(leftDate.getValue(), rightDate.getPrecision()); - } else { - leftPDate = new DateTimeType(leftDate.getValue(), rightDate.getPrecision()); - } - } - return leftPDate.getValueAsString().equals(rightPDate.getValueAsString()); - } - - return false; - } -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMatcherFactory.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMatcherFactory.java new file mode 100644 index 000000000000..bb9ae94d9ded --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMatcherFactory.java @@ -0,0 +1,12 @@ +package ca.uhn.fhir.mdm.rules.matcher; + +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; + +public interface IMatcherFactory { + + /** + * Retrieves the field matcher for the given MatchTypeEnum + */ + IMdmFieldMatcher getFieldMatcherForMatchType(MatchTypeEnum theMdmMatcherEnum); +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmStringMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmStringMatcher.java deleted file mode 100644 index 638c2741d3cc..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmStringMatcher.java +++ /dev/null @@ -1,24 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -public interface IMdmStringMatcher { - boolean matches(String theLeftString, String theRightString); -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherEnum.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherEnum.java deleted file mode 100644 index 17e2dd1e7f43..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherEnum.java +++ /dev/null @@ -1,86 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum; -import org.hl7.fhir.instance.model.api.IBase; - -/** - * Enum for holding all the known FHIR Element matchers that we support in HAPI. The string matchers first - * encode the string using an Apache Encoder before comparing them. - * https://commons.apache.org/proper/commons-codec/userguide.html - */ -public enum MdmMatcherEnum { - - CAVERPHONE1(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE1))), - CAVERPHONE2(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE2))), - COLOGNE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.COLOGNE))), - DOUBLE_METAPHONE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.DOUBLE_METAPHONE))), - MATCH_RATING_APPROACH(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.MATCH_RATING_APPROACH))), - METAPHONE(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.METAPHONE))), - NYSIIS(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.NYSIIS))), - REFINED_SOUNDEX(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.REFINED_SOUNDEX))), - SOUNDEX(new HapiStringMatcher(new PhoneticEncoderMatcher(PhoneticEncoderEnum.SOUNDEX))), - NICKNAME(new HapiStringMatcher(new NicknameMatcher())), - - STRING(new HapiStringMatcher()), - SUBSTRING(new HapiStringMatcher(new SubstringStringMatcher())), - - DATE(new HapiDateMatcher()), - NAME_ANY_ORDER(new NameMatcher(MdmNameMatchModeEnum.ANY_ORDER)), - NAME_FIRST_AND_LAST(new NameMatcher(MdmNameMatchModeEnum.FIRST_AND_LAST)), - - IDENTIFIER(new IdentifierMatcher()), - - EMPTY_FIELD(new EmptyFieldMatcher()), - EXTENSION_ANY_ORDER(new ExtensionMatcher()), - NUMERIC(new HapiStringMatcher(new NumericMatcher())); - - private final IMdmFieldMatcher myMdmFieldMatcher; - - MdmMatcherEnum(IMdmFieldMatcher theMdmFieldMatcher) { - myMdmFieldMatcher = theMdmFieldMatcher; - } - - /** - * Determines whether two FHIR elements match according using the provided {@link IMdmFieldMatcher} - * - * @param theFhirContext - * @param theLeftBase left FHIR element to compare - * @param theRightBase right FHIR element to compare - * @param theExact used by String matchers. If "false" then the string is normalized (case, accents) before comparing. If "true" then an exact string comparison is performed. - * @param theIdentifierSystem used optionally by the IDENTIFIER matcher, when present, only matches the identifiers if they belong to this system. - * @return - */ - public boolean match(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { - return myMdmFieldMatcher.matches(theFhirContext, theLeftBase, theRightBase, theExact, theIdentifierSystem); - } - - /** - * Checks if this matcher supports checks on empty fields - * - * @return - * Returns true of this matcher supports empty fields and false otherwise - */ - public boolean isMatchingEmptyFields() { - return this == EMPTY_FIELD; - } -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherFactory.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherFactory.java new file mode 100644 index 000000000000..b5509dd506ba --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmMatcherFactory.java @@ -0,0 +1,96 @@ +package ca.uhn.fhir.mdm.rules.matcher; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.api.IMdmSettings; +import ca.uhn.fhir.mdm.log.Logs; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.EmptyFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.ExtensionMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.HapiDateMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.HapiStringMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.IdentifierMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.MdmNameMatchModeEnum; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.NameMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.NicknameMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.NumericMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.PhoneticEncoderMatcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.SubstringStringMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; +import org.slf4j.Logger; + +public class MdmMatcherFactory implements IMatcherFactory { + private static final Logger ourLog = Logs.getMdmTroubleshootingLog(); + + private final FhirContext myFhirContext; + private final IMdmSettings myMdmSettings; + + private final NicknameSvc myNicknameSvc; + + public MdmMatcherFactory( + FhirContext theFhirContext, + IMdmSettings theSettings, + NicknameSvc theNicknameSvc + ) { + myFhirContext = theFhirContext; + myMdmSettings = theSettings; + myNicknameSvc = theNicknameSvc; + } + + @Override + public IMdmFieldMatcher getFieldMatcherForMatchType(MatchTypeEnum theMdmMatcherEnum) { + String matchTypeName; + if (theMdmMatcherEnum != null) { + switch (theMdmMatcherEnum) { + case CAVERPHONE1: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE1); + case CAVERPHONE2: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.CAVERPHONE2); + case COLOGNE: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.COLOGNE); + case DOUBLE_METAPHONE: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.DOUBLE_METAPHONE); + case MATCH_RATING_APPROACH: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.MATCH_RATING_APPROACH); + case METAPHONE: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.METAPHONE); + case NYSIIS: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.NYSIIS); + case REFINED_SOUNDEX: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.REFINED_SOUNDEX); + case SOUNDEX: + return new PhoneticEncoderMatcher(PhoneticEncoderEnum.SOUNDEX); + case NICKNAME: + return new NicknameMatcher(myNicknameSvc); + case STRING: + return new HapiStringMatcher(); + case SUBSTRING: + return new SubstringStringMatcher(); + case DATE: + return new HapiDateMatcher(myFhirContext); + case NAME_ANY_ORDER: + return new NameMatcher(myFhirContext, MdmNameMatchModeEnum.ANY_ORDER); + case NAME_FIRST_AND_LAST: + return new NameMatcher(myFhirContext, MdmNameMatchModeEnum.FIRST_AND_LAST); + case IDENTIFIER: + return new IdentifierMatcher(); + case EXTENSION_ANY_ORDER: + return new ExtensionMatcher(); + case NUMERIC: + return new NumericMatcher(); + case EMPTY_FIELD: + return new EmptyFieldMatcher(); + default: + break; + } + matchTypeName = theMdmMatcherEnum.name(); + } else { + matchTypeName = "null"; + } + + // This is odd, but it's a valid code path + ourLog.warn("Unrecognized field type {}. Returning null", matchTypeName); + return null; + } +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/SubstringStringMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/SubstringStringMatcher.java deleted file mode 100644 index 28fc98f18b65..000000000000 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/SubstringStringMatcher.java +++ /dev/null @@ -1,27 +0,0 @@ -/*- - * #%L - * HAPI FHIR - Master Data Management - * %% - * Copyright (C) 2014 - 2023 Smile CDR, Inc. - * %% - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * #L% - */ -package ca.uhn.fhir.mdm.rules.matcher; - -public class SubstringStringMatcher implements IMdmStringMatcher { - @Override - public boolean matches(String theLeftString, String theRightString) { - return theLeftString.startsWith(theRightString) || theRightString.startsWith(theLeftString); - } -} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/DateTimeWrapper.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/DateTimeWrapper.java new file mode 100644 index 000000000000..a78a3800b68d --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/DateTimeWrapper.java @@ -0,0 +1,56 @@ +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.r4.model.DateTimeType; +import org.hl7.fhir.r4.model.DateType; + +/** + * A wrapper class for datetimes of ambiguous fhir version + */ +public class DateTimeWrapper { + + /** + * The precision of this datetime object + */ + private final TemporalPrecisionEnum myPrecision; + + /** + * The string value with current precision + */ + private final String myValueAsString; + + public DateTimeWrapper(FhirContext theFhirContext, IBase theDate) { + if (theDate instanceof org.hl7.fhir.dstu3.model.BaseDateTimeType) { + org.hl7.fhir.dstu3.model.BaseDateTimeType dstu3Date = (org.hl7.fhir.dstu3.model.BaseDateTimeType) theDate; + myPrecision = dstu3Date.getPrecision(); + myValueAsString = dstu3Date.getValueAsString(); + } else if (theDate instanceof org.hl7.fhir.r4.model.BaseDateTimeType) { + org.hl7.fhir.r4.model.BaseDateTimeType r4Date = (org.hl7.fhir.r4.model.BaseDateTimeType) theDate; + myPrecision = r4Date.getPrecision(); + myValueAsString = r4Date.getValueAsString(); + } else { + // we should consider changing this error so we don't need the fhir context at all + throw new UnsupportedOperationException(Msg.code(1520) + "Version not supported: " + theFhirContext.getVersion().getVersion()); + } + } + + public TemporalPrecisionEnum getPrecision() { + return myPrecision; + } + + public String getValueAsStringWithPrecision(TemporalPrecisionEnum thePrecision) { + // we are using an R4 DateTypes because all datetime strings are the same for all fhir versions + // (and so it won't matter here) + // we just want the string at a specific precision + DateTimeType dateTimeType = new DateTimeType(myValueAsString); + dateTimeType.setPrecision(thePrecision); + return dateTimeType.getValueAsString(); + } + + public String getValueAsString() { + return myValueAsString; + } +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/EmptyFieldMatcher.java similarity index 74% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/EmptyFieldMatcher.java index a3341ebf9fe5..02618e097d32 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/EmptyFieldMatcher.java @@ -17,9 +17,10 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; -import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; import org.hl7.fhir.instance.model.api.IBase; public class EmptyFieldMatcher implements IMdmFieldMatcher { @@ -28,7 +29,7 @@ public EmptyFieldMatcher() { } @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { for (IBase b : new IBase[] {theLeftBase, theRightBase}) { if (b != null && !b.isEmpty()) { return false; @@ -36,4 +37,9 @@ public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theR } return true; } + + @Override + public boolean isMatchingEmptyFields() { + return true; + } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/ExtensionMatcher.java similarity index 85% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/ExtensionMatcher.java index fea4d7314ebf..4b96a838bc60 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/ExtensionMatcher.java @@ -17,9 +17,10 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; -import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; import ca.uhn.fhir.util.ExtensionUtil; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseExtension; @@ -30,7 +31,7 @@ public class ExtensionMatcher implements IMdmFieldMatcher { @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { if (!(theLeftBase instanceof IBaseHasExtensions && theRightBase instanceof IBaseHasExtensions)) { return false; } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiDateMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiDateMatcher.java new file mode 100644 index 000000000000..8504120433e9 --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiDateMatcher.java @@ -0,0 +1,65 @@ +/*- + * #%L + * HAPI FHIR - Master Data Management + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import org.hl7.fhir.instance.model.api.IBase; + +public class HapiDateMatcher implements IMdmFieldMatcher { + + private final FhirContext myFhirContext; + + public HapiDateMatcher(FhirContext theFhirContext) { + myFhirContext = theFhirContext; + } + + @Override + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + DateTimeWrapper left = new DateTimeWrapper(myFhirContext, theLeftBase); + DateTimeWrapper right = new DateTimeWrapper(myFhirContext, theRightBase); + + /* + * we use the precision to determine how we should equate. + * We should use the same precision (the precision of the less + * precise date) + */ + int comparison = left.getPrecision().compareTo(right.getPrecision()); + + String leftString; + String rightString; + if (comparison == 0) { + // same precision + leftString = left.getValueAsString(); + rightString = right.getValueAsString(); + } else if (comparison > 0) { + // left date is more precise than right date + leftString = left.getValueAsStringWithPrecision(right.getPrecision()); + rightString = right.getValueAsString(); + } else { + // right date is more precise than left date + rightString = right.getValueAsStringWithPrecision(left.getPrecision()); + leftString = left.getValueAsString(); + } + + return leftString.equals(rightString); + } +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiStringMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiStringMatcher.java similarity index 57% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiStringMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiStringMatcher.java index 9d5b9d6b6747..4168051754b5 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/HapiStringMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/HapiStringMatcher.java @@ -17,33 +17,26 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; -import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IPrimitiveType; /** * Similarity measure for two IBase fields whose similarity can be measured by their String representations. */ -public class HapiStringMatcher extends BaseHapiStringMetric implements IMdmFieldMatcher { - private final IMdmStringMatcher myStringMatcher; - - public HapiStringMatcher(IMdmStringMatcher theStringMatcher) { - myStringMatcher = theStringMatcher; - } - - public HapiStringMatcher() { - myStringMatcher = String::equals; - } +public class HapiStringMatcher implements IMdmFieldMatcher { @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theExtraMatchParams) { if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) { - String leftString = extractString((IPrimitiveType) theLeftBase, theExact); - String rightString = extractString((IPrimitiveType) theRightBase, theExact); + String leftString = StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theExtraMatchParams.getExact()); + String rightString = StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theExtraMatchParams.getExact()); - return myStringMatcher.matches(leftString, rightString); + return leftString.equals(rightString); } return false; } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/IdentifierMatcher.java similarity index 80% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/IdentifierMatcher.java index 94662737cbcb..a3f82ae7c190 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/IdentifierMatcher.java @@ -17,25 +17,34 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.util.CanonicalIdentifier; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; import ca.uhn.fhir.mdm.util.IdentifierUtil; import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.util.CanonicalIdentifier; import org.hl7.fhir.instance.model.api.IBase; public class IdentifierMatcher implements IMdmFieldMatcher { + + private boolean isEmpty(StringDt theValue) { + if (theValue == null) { + return true; + } + return theValue.isEmpty(); + } + /** * @return true if the two fhir identifiers are the same. If @param theIdentifierSystem is not null, then the * matcher only returns true if the identifier systems also match this system. * @throws UnsupportedOperationException if either Base is not an Identifier instance */ @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { CanonicalIdentifier left = IdentifierUtil.identifierDtFromIdentifier(theLeftBase); - if (theIdentifierSystem != null) { - if (!theIdentifierSystem.equals(left.getSystemElement().getValueAsString())) { + if (theParams.getIdentifierSystem() != null) { + if (!theParams.getIdentifierSystem().equals(left.getSystemElement().getValueAsString())) { return false; } } @@ -45,11 +54,4 @@ public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theR } return left.equals(right); } - - private boolean isEmpty(StringDt theValue) { - if (theValue == null) { - return true; - } - return theValue.isEmpty(); - } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmNameMatchModeEnum.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/MdmNameMatchModeEnum.java similarity index 93% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmNameMatchModeEnum.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/MdmNameMatchModeEnum.java index aff7121d24b0..1f62d634b2b3 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/MdmNameMatchModeEnum.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/MdmNameMatchModeEnum.java @@ -17,7 +17,7 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; public enum MdmNameMatchModeEnum { ANY_ORDER, diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NameMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NameMatcher.java similarity index 72% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NameMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NameMatcher.java index c87a47c52469..15cafbdabbcd 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NameMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NameMatcher.java @@ -17,9 +17,11 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; import ca.uhn.fhir.mdm.util.NameUtil; import ca.uhn.fhir.util.StringUtil; import org.apache.commons.lang3.StringUtils; @@ -35,24 +37,27 @@ public class NameMatcher implements IMdmFieldMatcher { private final MdmNameMatchModeEnum myMatchMode; - public NameMatcher(MdmNameMatchModeEnum theMatchMode) { + private final FhirContext myFhirContext; + + public NameMatcher(FhirContext theFhirContext, MdmNameMatchModeEnum theMatchMode) { myMatchMode = theMatchMode; + myFhirContext = theFhirContext; } @Override - public boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem) { - String leftFamilyName = NameUtil.extractFamilyName(theFhirContext, theLeftBase); - String rightFamilyName = NameUtil.extractFamilyName(theFhirContext, theRightBase); + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + String leftFamilyName = NameUtil.extractFamilyName(myFhirContext, theLeftBase); + String rightFamilyName = NameUtil.extractFamilyName(myFhirContext, theRightBase); if (StringUtils.isEmpty(leftFamilyName) || StringUtils.isEmpty(rightFamilyName)) { return false; } boolean match = false; - List leftGivenNames = NameUtil.extractGivenNames(theFhirContext, theLeftBase); - List rightGivenNames = NameUtil.extractGivenNames(theFhirContext, theRightBase); + List leftGivenNames = NameUtil.extractGivenNames(myFhirContext, theLeftBase); + List rightGivenNames = NameUtil.extractGivenNames(myFhirContext, theRightBase); - if (!theExact) { + if (!theParams.getExact()) { leftFamilyName = StringUtil.normalizeStringForSearchIndexing(leftFamilyName); rightFamilyName = StringUtil.normalizeStringForSearchIndexing(rightFamilyName); leftGivenNames = leftGivenNames.stream().map(StringUtil::normalizeStringForSearchIndexing).collect(Collectors.toList()); diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NicknameMatcher.java similarity index 55% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NicknameMatcher.java index 335acdc56365..f95e94127df5 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NicknameMatcher.java @@ -17,28 +17,25 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; -import ca.uhn.fhir.context.ConfigurationException; -import ca.uhn.fhir.i18n.Msg; -import ca.uhn.fhir.jpa.searchparam.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IPrimitiveType; -import java.io.IOException; import java.util.Collection; import java.util.Locale; -public class NicknameMatcher implements IMdmStringMatcher { +public class NicknameMatcher implements IMdmFieldMatcher { private final NicknameSvc myNicknameSvc; - public NicknameMatcher() { - try { - myNicknameSvc = new NicknameSvc(); - } catch (IOException e) { - throw new ConfigurationException(Msg.code(2234) + "Unable to load nicknames", e); - } + public NicknameMatcher(NicknameSvc theNicknameSvc) { + myNicknameSvc = theNicknameSvc; } - @Override public boolean matches(String theLeftString, String theRightString) { String leftString = theLeftString.toLowerCase(Locale.ROOT); String rightString = theRightString.toLowerCase(Locale.ROOT); @@ -51,4 +48,15 @@ public boolean matches(String theLeftString, String theRightString) { Collection rightNames = myNicknameSvc.getEquivalentNames(rightString); return rightNames.contains(leftString); } + + @Override + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) { + String leftString = StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theParams.getExact()); + String rightString = StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theParams.getExact()); + + return matches(leftString, rightString); + } + return false; + } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NumericMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NumericMatcher.java similarity index 53% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NumericMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NumericMatcher.java index d7ece7966d48..c9a3777f6ddb 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/NumericMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/NumericMatcher.java @@ -17,19 +17,27 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; import ca.uhn.fhir.context.phonetic.NumericEncoder; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IPrimitiveType; // Useful for numerical identifiers like phone numbers, address parts etc. // This should not be used where decimals are important. A new "quantity matcher" should be added to handle cases like that. -public class NumericMatcher implements IMdmStringMatcher { +public class NumericMatcher implements IMdmFieldMatcher { private final NumericEncoder encoder = new NumericEncoder(); @Override - public boolean matches(String theLeftString, String theRightString) { - String left = encoder.encode(theLeftString); - String right = encoder.encode(theRightString); - return left.equals(right); + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) { + String left = encoder.encode(StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theParams.getExact())); + String right = encoder.encode(StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theParams.getExact())); + return left.equals(right); + } + return false; } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/PhoneticEncoderMatcher.java similarity index 64% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/PhoneticEncoderMatcher.java index cd158a443d72..efbb3372e1fd 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/PhoneticEncoderMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/PhoneticEncoderMatcher.java @@ -17,15 +17,20 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; import ca.uhn.fhir.context.phonetic.IPhoneticEncoder; import ca.uhn.fhir.context.phonetic.PhoneticEncoderEnum; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; import ca.uhn.fhir.util.PhoneticEncoderUtil; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IPrimitiveType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class PhoneticEncoderMatcher implements IMdmStringMatcher { +public class PhoneticEncoderMatcher implements IMdmFieldMatcher { private static final Logger ourLog = LoggerFactory.getLogger(PhoneticEncoderMatcher.class); private final IPhoneticEncoder myStringEncoder; @@ -34,8 +39,16 @@ public PhoneticEncoderMatcher(PhoneticEncoderEnum thePhoneticEnum) { myStringEncoder = PhoneticEncoderUtil.getEncoder(thePhoneticEnum.name()); } - @Override public boolean matches(String theLeftString, String theRightString) { return myStringEncoder.encode(theLeftString).equals(myStringEncoder.encode(theRightString)); } + + @Override + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + String leftString = StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theParams.getExact()); + String rightString = StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theParams.getExact()); + + return matches(leftString, rightString); + } + } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/SubstringStringMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/SubstringStringMatcher.java new file mode 100644 index 000000000000..dc72b446b03e --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/fieldmatchers/SubstringStringMatcher.java @@ -0,0 +1,39 @@ +/*- + * #%L + * HAPI FHIR - Master Data Management + * %% + * Copyright (C) 2014 - 2023 Smile CDR, Inc. + * %% + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ +package ca.uhn.fhir.mdm.rules.matcher.fieldmatchers; + +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +public class SubstringStringMatcher implements IMdmFieldMatcher { + + @Override + public boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams) { + if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) { + String left = StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theParams.getExact()); + String right = StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theParams.getExact()); + return left.startsWith(right) || right.startsWith(left); + } + return false; + } +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmFieldMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/IMdmFieldMatcher.java similarity index 64% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmFieldMatcher.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/IMdmFieldMatcher.java index c9603d9b224d..745a9df85f33 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/IMdmFieldMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/IMdmFieldMatcher.java @@ -17,14 +17,27 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.models; -import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import org.hl7.fhir.instance.model.api.IBase; /** * Measure how similar two IBase (resource fields) are to one another. 1.0 means identical. 0.0 means completely different. */ public interface IMdmFieldMatcher { - boolean matches(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact, String theIdentifierSystem); + /** + * Checks if theLeftBase and theRightBase match, returning true if they do + * and false otherwise. + */ + boolean matches(IBase theLeftBase, IBase theRightBase, MdmMatcherJson theParams); + + /** + * True if matcher can/will match empty (null) fields, + * false otherwise. + */ + default boolean isMatchingEmptyFields() { + // false because most people are overriding this + return false; + } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/BaseHapiStringMetric.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/MatchTypeEnum.java similarity index 53% rename from hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/BaseHapiStringMetric.java rename to hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/MatchTypeEnum.java index e4485019ade3..7f721c20822e 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/BaseHapiStringMetric.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/models/MatchTypeEnum.java @@ -17,17 +17,37 @@ * limitations under the License. * #L% */ -package ca.uhn.fhir.mdm.rules.matcher; +package ca.uhn.fhir.mdm.rules.matcher.models; -import ca.uhn.fhir.util.StringUtil; -import org.hl7.fhir.instance.model.api.IPrimitiveType; +/** + * Enum for holding all the known FHIR Element matchers that we support in HAPI. The string matchers first + * encode the string using an Apache Encoder before comparing them. + * https://commons.apache.org/proper/commons-codec/userguide.html + */ +public enum MatchTypeEnum { + + CAVERPHONE1, + CAVERPHONE2, + COLOGNE, + DOUBLE_METAPHONE, + MATCH_RATING_APPROACH, + METAPHONE, + NYSIIS, + REFINED_SOUNDEX, + SOUNDEX, + NICKNAME, + + STRING, + SUBSTRING, + + DATE, + NAME_ANY_ORDER, + NAME_FIRST_AND_LAST, + + IDENTIFIER, + + EMPTY_FIELD, + EXTENSION_ANY_ORDER, + NUMERIC; -public abstract class BaseHapiStringMetric { - protected String extractString(IPrimitiveType thePrimitive, boolean theExact) { - String theString = thePrimitive.getValueAsString(); - if (theExact) { - return theString; - } - return StringUtil.normalizeStringForSearchIndexing(theString); - } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/util/StringMatcherUtils.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/util/StringMatcherUtils.java new file mode 100644 index 000000000000..3924745f1288 --- /dev/null +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/matcher/util/StringMatcherUtils.java @@ -0,0 +1,14 @@ +package ca.uhn.fhir.mdm.rules.matcher.util; + +import ca.uhn.fhir.util.StringUtil; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +public class StringMatcherUtils { + public static String extractString(IPrimitiveType thePrimitive, boolean theExact) { + String theString = thePrimitive.getValueAsString(); + if (theExact) { + return theString; + } + return StringUtil.normalizeStringForSearchIndexing(theString); + } +} diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/similarity/HapiStringSimilarity.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/similarity/HapiStringSimilarity.java index d2e7d894a6b1..c5e50effeaec 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/similarity/HapiStringSimilarity.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/similarity/HapiStringSimilarity.java @@ -20,7 +20,7 @@ package ca.uhn.fhir.mdm.rules.similarity; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.mdm.rules.matcher.BaseHapiStringMetric; +import ca.uhn.fhir.mdm.rules.matcher.util.StringMatcherUtils; import info.debatty.java.stringsimilarity.interfaces.NormalizedStringSimilarity; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IPrimitiveType; @@ -28,7 +28,7 @@ /** * Similarity measure for two IBase fields whose similarity can be measured by their String representations. */ -public class HapiStringSimilarity extends BaseHapiStringMetric implements IMdmFieldSimilarity { +public class HapiStringSimilarity implements IMdmFieldSimilarity { private final NormalizedStringSimilarity myStringSimilarity; public HapiStringSimilarity(NormalizedStringSimilarity theStringSimilarity) { @@ -38,8 +38,8 @@ public HapiStringSimilarity(NormalizedStringSimilarity theStringSimilarity) { @Override public double similarity(FhirContext theFhirContext, IBase theLeftBase, IBase theRightBase, boolean theExact) { if (theLeftBase instanceof IPrimitiveType && theRightBase instanceof IPrimitiveType) { - String leftString = extractString((IPrimitiveType) theLeftBase, theExact); - String rightString = extractString((IPrimitiveType) theRightBase, theExact); + String leftString = StringMatcherUtils.extractString((IPrimitiveType) theLeftBase, theExact); + String rightString = StringMatcherUtils.extractString((IPrimitiveType) theRightBase, theExact); return myStringSimilarity.similarity(leftString, rightString); } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcher.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcher.java index 55c125d1bc48..9dd3fda09ec3 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcher.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcher.java @@ -21,9 +21,16 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.fhirpath.IFhirPath; +import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.mdm.api.MdmMatchEvaluation; import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; +import ca.uhn.fhir.mdm.rules.json.MdmSimilarityJson; +import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.util.FhirTerser; import org.apache.commons.lang3.Validate; import org.hl7.fhir.instance.model.api.IBase; @@ -48,7 +55,16 @@ public class MdmResourceFieldMatcher { private final String myName; private final boolean myIsFhirPathExpression; - public MdmResourceFieldMatcher(FhirContext theFhirContext, MdmFieldMatchJson theMdmFieldMatchJson, MdmRulesJson theMdmRulesJson) { + private final IMatcherFactory myIMatcherFactory; + + public MdmResourceFieldMatcher( + FhirContext theFhirContext, + IMatcherFactory theIMatcherFactory, + MdmFieldMatchJson theMdmFieldMatchJson, + MdmRulesJson theMdmRulesJson + ) { + myIMatcherFactory = theIMatcherFactory; + myFhirContext = theFhirContext; myMdmFieldMatchJson = theMdmFieldMatchJson; myResourceType = theMdmFieldMatchJson.getResourceType(); @@ -70,7 +86,6 @@ public MdmResourceFieldMatcher(FhirContext theFhirContext, MdmFieldMatchJson the * @param theRightResource the second {@link IBaseResource} * @return A boolean indicating whether they match. */ - @SuppressWarnings("rawtypes") public MdmMatchEvaluation match(IBaseResource theLeftResource, IBaseResource theRightResource) { validate(theLeftResource); validate(theRightResource); @@ -90,12 +105,12 @@ public MdmMatchEvaluation match(IBaseResource theLeftResource, IBaseResource the return match(leftValues, rightValues); } - @SuppressWarnings("rawtypes") private MdmMatchEvaluation match(List theLeftValues, List theRightValues) { MdmMatchEvaluation retval = new MdmMatchEvaluation(false, 0.0); boolean isMatchingEmptyFieldValues = (theLeftValues.isEmpty() && theRightValues.isEmpty()); - if (isMatchingEmptyFieldValues && myMdmFieldMatchJson.isMatcherSupportingEmptyFields()) { + IMdmFieldMatcher matcher = getFieldMatcher(); + if (isMatchingEmptyFieldValues && (matcher != null && matcher.isMatchingEmptyFields())) { return match((IBase) null, (IBase) null); } @@ -110,7 +125,18 @@ private MdmMatchEvaluation match(List theLeftValues, List theRight } private MdmMatchEvaluation match(IBase theLeftValue, IBase theRightValue) { - return myMdmFieldMatchJson.match(myFhirContext, theLeftValue, theRightValue); + IMdmFieldMatcher matcher = getFieldMatcher(); + if (matcher != null) { + boolean isMatches = matcher.matches(theLeftValue, theRightValue, myMdmFieldMatchJson.getMatcher()); + return new MdmMatchEvaluation(isMatches, isMatches ? 1.0 : 0.0); + } + + MdmSimilarityJson similarity = myMdmFieldMatchJson.getSimilarity(); + if (similarity != null) { + return similarity.match(myFhirContext, theLeftValue, theRightValue); + } + + throw new InternalErrorException(Msg.code(1522) + "Field Match " + myName + " has neither a matcher nor a similarity."); } private void validate(IBaseResource theResource) { @@ -136,4 +162,17 @@ public String getResourcePath() { public String getName() { return myName; } + + private IMdmFieldMatcher getFieldMatcher() { + MdmMatcherJson matcherJson = myMdmFieldMatchJson.getMatcher(); + MatchTypeEnum matchTypeEnum = null; + if (matcherJson != null) { + matchTypeEnum = matcherJson.getAlgorithm(); + } + if (matchTypeEnum == null) { + return null; + } + + return myIMatcherFactory.getFieldMatcherForMatchType(matchTypeEnum); + } } diff --git a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvc.java b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvc.java index 5dc9e46fbf4b..418849cb3630 100644 --- a/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvc.java +++ b/hapi-fhir-server-mdm/src/main/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvc.java @@ -30,6 +30,8 @@ import ca.uhn.fhir.mdm.log.Logs; import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; +import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory; +import com.google.common.annotations.VisibleForTesting; import org.hl7.fhir.instance.model.api.IBaseResource; import org.slf4j.Logger; import org.springframework.stereotype.Service; @@ -48,16 +50,18 @@ public class MdmResourceMatcherSvc { private static final Logger ourLog = Logs.getMdmTroubleshootingLog(); private final FhirContext myFhirContext; - private MdmRulesJson myMdmRulesJson; + private final IMatcherFactory myMatcherFactory; private final List myFieldMatchers = new ArrayList<>(); - public MdmResourceMatcherSvc(FhirContext theFhirContext, IMdmSettings theMdmSettings) { - myFhirContext = theFhirContext; - - setMdmSettings(theMdmSettings); - } + private MdmRulesJson myMdmRulesJson; - public void setMdmSettings(IMdmSettings theMdmSettings) { + public MdmResourceMatcherSvc( + FhirContext theFhirContext, + IMatcherFactory theIMatcherFactory, + IMdmSettings theMdmSettings + ) { + myFhirContext = theFhirContext; + myMatcherFactory = theIMatcherFactory; myMdmRulesJson = theMdmSettings.getMdmRules(); addFieldMatchers(); @@ -69,7 +73,7 @@ private void addFieldMatchers() { } myFieldMatchers.clear(); for (MdmFieldMatchJson matchFieldJson : myMdmRulesJson.getMatchFields()) { - myFieldMatchers.add(new MdmResourceFieldMatcher( myFhirContext, matchFieldJson, myMdmRulesJson)); + myFieldMatchers.add(new MdmResourceFieldMatcher(myFhirContext, myMatcherFactory, matchFieldJson, myMdmRulesJson)); } } @@ -77,9 +81,8 @@ private void addFieldMatchers() { * Given two {@link IBaseResource}s, perform all comparisons on them to determine an {@link MdmMatchResultEnum}, indicating * to what level the two resources are considered to be matching. * - * @param theLeftResource The first {@link IBaseResource}. + * @param theLeftResource The first {@link IBaseResource}. * @param theRightResource The second {@link IBaseResource} - * * @return an {@link MdmMatchResultEnum} indicating the result of the comparison. */ public MdmMatchOutcome getMatchResult(IBaseResource theLeftResource, IBaseResource theRightResource) { @@ -91,8 +94,8 @@ MdmMatchOutcome match(IBaseResource theLeftResource, IBaseResource theRightResou MdmMatchResultEnum matchResultEnum = myMdmRulesJson.getMatchResult(matchResult.getVector()); matchResult.setMatchResultEnum(matchResultEnum); if (ourLog.isDebugEnabled()) { - ourLog.debug("{} {}: {}", matchResult.getMatchResultEnum(), theRightResource.getIdElement().toUnqualifiedVersionless(), matchResult); - if (ourLog.isTraceEnabled()) { + ourLog.debug("{} {}: {}", matchResult.getMatchResultEnum(), theRightResource.getIdElement().toUnqualifiedVersionless(), matchResult); + if (ourLog.isTraceEnabled()) { ourLog.trace("Field matcher results:\n{}", myMdmRulesJson.getDetailedFieldMatchResultWithSuccessInformation(matchResult.getVector())); } } @@ -105,11 +108,11 @@ MdmMatchOutcome match(IBaseResource theLeftResource, IBaseResource theRightResou * start with a binary representation of the value 0 for long: 0000 * first_name matches, so the value `1` is bitwise-ORed to the current value (0) in right-most position. * `0001` - * + *

* Next, we look at the second field comparator, and see if it matches. If it does, we left-shift 1 by the index * of the comparator, in this case also 1. * `0010` - * + *

* Then, we bitwise-or it with the current retval: * 0001|0010 = 0011 * The binary string is now `0011`, which when you return it as a long becomes `3`. @@ -146,11 +149,16 @@ private MdmMatchOutcome getMatchOutcome(IBaseResource theLeftResource, IBaseReso return retVal; } - - private boolean isValidResourceType(String theResourceType, String theFieldComparatorType) { + private boolean isValidResourceType(String theResourceType, String theFieldComparatorType) { return ( theFieldComparatorType.equalsIgnoreCase(MdmConstants.ALL_RESOURCE_SEARCH_PARAM_TYPE) - || theFieldComparatorType.equalsIgnoreCase(theResourceType) + || theFieldComparatorType.equalsIgnoreCase(theResourceType) ); } + + @VisibleForTesting + public void setMdmRulesJson(MdmRulesJson theMdmRulesJson) { + myMdmRulesJson = theMdmRulesJson; + addFieldMatchers(); + } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/BaseR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/BaseR4Test.java index 494cd93992d3..c4e506656747 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/BaseR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/BaseR4Test.java @@ -1,14 +1,19 @@ package ca.uhn.fhir.mdm; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.api.IMdmSettings; import ca.uhn.fhir.mdm.api.MdmMatchOutcome; import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; import ca.uhn.fhir.mdm.rules.config.MdmRuleValidator; import ca.uhn.fhir.mdm.rules.config.MdmSettings; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; +import ca.uhn.fhir.mdm.rules.matcher.IMatcherFactory; +import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherFactory; import ca.uhn.fhir.mdm.rules.svc.MdmResourceMatcherSvc; import ca.uhn.fhir.rest.server.util.ISearchParamRegistry; import org.hl7.fhir.r4.model.Patient; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.junit.jupiter.MockitoExtension; @@ -20,6 +25,20 @@ public abstract class BaseR4Test { protected static final FhirContext ourFhirContext = FhirContext.forR4(); protected ISearchParamRegistry mySearchParamRetriever = mock(ISearchParamRegistry.class); + protected IMatcherFactory myIMatcherFactory; + + protected IMdmSettings myMdmSettings; + + @BeforeEach + public void before() { + myMdmSettings = mock(IMdmSettings.class); + myIMatcherFactory = new MdmMatcherFactory( + ourFhirContext, + myMdmSettings, + new NicknameSvc() + ); + } + protected Patient buildJohn() { Patient patient = new Patient(); patient.addName().addGiven("John"); @@ -35,7 +54,10 @@ protected Patient buildJohny() { } protected MdmResourceMatcherSvc buildMatcher(MdmRulesJson theMdmRulesJson) { - return new MdmResourceMatcherSvc(ourFhirContext, new MdmSettings(new MdmRuleValidator(ourFhirContext, mySearchParamRetriever)).setMdmRules(theMdmRulesJson)); + return new MdmResourceMatcherSvc(ourFhirContext, + myIMatcherFactory, + new MdmSettings(new MdmRuleValidator(ourFhirContext, mySearchParamRetriever)).setMdmRules(theMdmRulesJson) + ); } protected void assertMatch(MdmMatchResultEnum theExpectedMatchEnum, MdmMatchOutcome theMatchResult) { diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/json/VectorMatchResultMapTest.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/json/VectorMatchResultMapTest.java index e129cf2f8356..19d105e6cd46 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/json/VectorMatchResultMapTest.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/json/VectorMatchResultMapTest.java @@ -1,7 +1,7 @@ package ca.uhn.fhir.mdm.rules.json; import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -27,7 +27,7 @@ public void splitFieldMatchNames() { @Test public void testMatchBeforePossibleMatch() { MdmRulesJson mdmRulesJson = new MdmRulesJson(); - MdmMatcherJson matcherJson = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.STRING); + MdmMatcherJson matcherJson = new MdmMatcherJson().setAlgorithm(MatchTypeEnum.STRING); mdmRulesJson.addMatchField(new MdmFieldMatchJson().setName("given").setResourceType("Patient").setResourcePath("name.given").setMatcher(matcherJson)); mdmRulesJson.addMatchField(new MdmFieldMatchJson().setName("family").setResourceType("Patient").setResourcePath("name.family").setMatcher(matcherJson)); mdmRulesJson.addMatchField(new MdmFieldMatchJson().setName("prefix").setResourceType("Patient").setResourcePath("name.prefix").setMatcher(matcherJson)); diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/BaseMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/BaseMatcherR4Test.java index f6243442212d..5a19e8956be7 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/BaseMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/BaseMatcherR4Test.java @@ -1,7 +1,16 @@ package ca.uhn.fhir.mdm.rules.matcher; import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import org.junit.jupiter.api.BeforeEach; public abstract class BaseMatcherR4Test { protected static final FhirContext ourFhirContext = FhirContext.forR4(); + + protected MdmMatcherJson myMdmMatcherJson; + + @BeforeEach + public void before() { + myMdmMatcherJson = new MdmMatcherJson(); + } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/DateMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/DateMatcherR4Test.java index 113c8ba6a842..9b79f81a578f 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/DateMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/DateMatcherR4Test.java @@ -1,8 +1,10 @@ package ca.uhn.fhir.mdm.rules.matcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.HapiDateMatcher; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import org.hl7.fhir.r4.model.DateTimeType; import org.hl7.fhir.r4.model.DateType; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.util.Calendar; @@ -14,6 +16,14 @@ public class DateMatcherR4Test extends BaseMatcherR4Test { + private HapiDateMatcher myDateMatcher; + + @BeforeEach + public void before() { + super.before(); + myDateMatcher = new HapiDateMatcher(ourFhirContext); + } + @Test public void testExactDatePrecision() { Calendar cal = new GregorianCalendar(2020, 6, 15); @@ -43,7 +53,8 @@ public void testExactDatePrecision() { } private boolean dateMatch(Date theDate, Date theSameMonth, TemporalPrecisionEnum theTheDay) { - return MdmMatcherEnum.DATE.match(ourFhirContext, new DateType(theDate, theTheDay), new DateType(theSameMonth, theTheDay), true, null); + myMdmMatcherJson.setExact(true); + return myDateMatcher.matches(new DateType(theDate, theTheDay), new DateType(theSameMonth, theTheDay), myMdmMatcherJson); } @Test @@ -87,12 +98,11 @@ public void testExactDateTimePrecision() { } private boolean dateTimeMatch(Date theDate, Date theSecondDate, TemporalPrecisionEnum thePrecision, TemporalPrecisionEnum theSecondPrecision) { - return MdmMatcherEnum.DATE.match( - ourFhirContext, + myMdmMatcherJson.setExact(true); + return myDateMatcher.matches( new DateTimeType(theDate, thePrecision), new DateTimeType(theSecondDate, theSecondPrecision), - true, - null + myMdmMatcherJson ); } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcherTest.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcherTest.java index f1ef1982b22b..67ba92324272 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcherTest.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/EmptyFieldMatcherTest.java @@ -2,6 +2,8 @@ import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.EmptyFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import ca.uhn.fhir.model.primitive.StringDt; import org.junit.jupiter.api.Test; @@ -16,16 +18,16 @@ public void testEmptyFieldMatch() { StringDt leftEmpty = new StringDt(""); StringDt rightEmpty = new StringDt(""); StringDt right = new StringDt("a value"); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.EMPTY_FIELD); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); - - assertTrue(fieldMatch.match(ourFhirContext, null, null).match); - assertTrue(fieldMatch.match(ourFhirContext, null, rightEmpty).match); - assertTrue(fieldMatch.match(ourFhirContext, leftEmpty, null).match); - assertTrue(fieldMatch.match(ourFhirContext, leftEmpty, rightEmpty).match); - assertFalse(fieldMatch.match(ourFhirContext, null, right).match); - assertFalse(fieldMatch.match(ourFhirContext, left, null).match); - assertFalse(fieldMatch.match(ourFhirContext, left, right).match); + + EmptyFieldMatcher fieldMatch = new EmptyFieldMatcher(); + + assertTrue(fieldMatch.matches(null, null, null)); + assertTrue(fieldMatch.matches(null, rightEmpty, null)); + assertTrue(fieldMatch.matches(leftEmpty, null, null)); + assertTrue(fieldMatch.matches(leftEmpty, rightEmpty, null)); + assertFalse(fieldMatch.matches(null, right, null)); + assertFalse(fieldMatch.matches(left, null, null)); + assertFalse(fieldMatch.matches(left, right, null)); } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcherR4Test.java index c5252b1e0160..569e1b133fef 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/ExtensionMatcherR4Test.java @@ -1,16 +1,28 @@ package ca.uhn.fhir.mdm.rules.matcher; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.ExtensionMatcher; +import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.r4.model.IntegerType; -import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.StringType; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; public class ExtensionMatcherR4Test extends BaseMatcherR4Test { + + private ExtensionMatcher myExtensionMatcher; + + @BeforeEach + public void before() { + super.before(); + + myExtensionMatcher = new ExtensionMatcher(); + } + @Test public void testPatientWithMatchingExtension(){ Patient patient1 = new Patient(); @@ -19,7 +31,7 @@ public void testPatientWithMatchingExtension(){ patient1.addExtension("asd",new StringType("Patient1")); patient2.addExtension("asd",new StringType("Patient1")); - assertTrue(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertTrue(match(patient1, patient2)); } @Test @@ -30,7 +42,7 @@ public void testPatientWithoutMatchingExtension(){ patient1.addExtension("asd",new StringType("Patient1")); patient2.addExtension("asd",new StringType("Patient2")); - assertFalse(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertFalse(match(patient1, patient2)); } @Test @@ -41,7 +53,7 @@ public void testPatientSameValueDifferentUrl(){ patient1.addExtension("asd",new StringType("Patient1")); patient2.addExtension("asd1",new StringType("Patient1")); - assertFalse(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertFalse(match(patient1, patient2)); } @Test @@ -54,7 +66,7 @@ public void testPatientWithMultipleExtensionOneMatching(){ patient2.addExtension("asd",new StringType("Patient1")); patient2.addExtension("asdasd", new StringType("some value")); - assertTrue(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertTrue(match(patient1, patient2)); } @Test @@ -65,7 +77,7 @@ public void testPatientWithoutIntExtension(){ patient1.addExtension("asd", new IntegerType(123)); patient2.addExtension("asd", new IntegerType(123)); - assertTrue(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertTrue(match(patient1, patient2)); } @Test @@ -73,7 +85,10 @@ public void testPatientWithNoExtension(){ Patient patient1 = new Patient(); Patient patient2 = new Patient(); - assertFalse(MdmMatcherEnum.EXTENSION_ANY_ORDER.match(ourFhirContext, patient1, patient2, false, null)); + assertFalse(match(patient1, patient2)); } + private boolean match(IBase theFirst, IBase theSecond) { + return myExtensionMatcher.matches(theFirst, theSecond, myMdmMatcherJson); + } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcherR4Test.java index 66666446f8a6..221eb0d87566 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/IdentifierMatcherR4Test.java @@ -1,8 +1,9 @@ package ca.uhn.fhir.mdm.rules.matcher; -import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; -import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.IdentifierMatcher; +import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.r4.model.Identifier; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertFalse; @@ -14,15 +15,20 @@ public class IdentifierMatcherR4Test extends BaseMatcherR4Test { private static final String MATCHING_VALUE = "matchme"; private static final String OTHER_VALUE = "strange"; + private IdentifierMatcher myIdentifierMatcher; + + @BeforeEach + public void before() { + super.before(); + myIdentifierMatcher = new IdentifierMatcher(); + } + @Test public void testIdentifierMatch() { Identifier left = new Identifier().setSystem(MATCHING_SYSTEM).setValue(MATCHING_VALUE); Identifier right = new Identifier().setSystem(MATCHING_SYSTEM).setValue(MATCHING_VALUE); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.IDENTIFIER); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); - - assertTrue(fieldMatch.match(ourFhirContext, left, right).match); + assertTrue(match(left, right)); } @Test @@ -33,17 +39,15 @@ public void testIdentifierNoMatch() { Identifier rightNoSystem = new Identifier().setValue(MATCHING_VALUE); Identifier rightNoValue = new Identifier().setSystem(MATCHING_SYSTEM); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.IDENTIFIER); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); - - assertFalse(fieldMatch.match(ourFhirContext, left, rightWrongSystem).match); - assertFalse(fieldMatch.match(ourFhirContext, left, rightWrongValue).match); - assertFalse(fieldMatch.match(ourFhirContext, left, rightNoSystem).match); - assertFalse(fieldMatch.match(ourFhirContext, left, rightNoValue).match); - assertFalse(fieldMatch.match(ourFhirContext, rightWrongSystem, left).match); - assertFalse(fieldMatch.match(ourFhirContext, rightWrongValue, left).match); - assertFalse(fieldMatch.match(ourFhirContext, rightNoSystem, left).match); - assertFalse(fieldMatch.match(ourFhirContext, rightNoValue, left).match); + + assertFalse(match(left, rightWrongSystem)); + assertFalse(match(left, rightWrongValue)); + assertFalse(match(left, rightNoSystem)); + assertFalse(match(left, rightNoValue)); + assertFalse(match(rightWrongSystem, left)); + assertFalse(match(rightWrongValue, left)); + assertFalse(match(rightNoSystem, left)); + assertFalse(match(rightNoValue, left)); } @Test @@ -51,10 +55,9 @@ public void testIdentifierMatchWithNoValues() { Identifier left = new Identifier().setSystem(MATCHING_SYSTEM); Identifier right = new Identifier().setSystem(MATCHING_SYSTEM); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.IDENTIFIER).setIdentifierSystem(MATCHING_SYSTEM); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); + myMdmMatcherJson.setIdentifierSystem(MATCHING_SYSTEM); - assertFalse(fieldMatch.match(ourFhirContext, left, right).match); + assertFalse(match(left, right)); } @Test @@ -62,10 +65,9 @@ public void testIdentifierNamedSystemMatch() { Identifier left = new Identifier().setSystem(MATCHING_SYSTEM).setValue(MATCHING_VALUE); Identifier right = new Identifier().setSystem(MATCHING_SYSTEM).setValue(MATCHING_VALUE); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.IDENTIFIER).setIdentifierSystem(MATCHING_SYSTEM); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); + myMdmMatcherJson.setIdentifierSystem(MATCHING_SYSTEM); - assertTrue(fieldMatch.match(ourFhirContext, left, right).match); + assertTrue(match(left, right)); } @Test @@ -73,9 +75,12 @@ public void testIdentifierSystemNoMatch() { Identifier left = new Identifier().setSystem(OTHER_SYSTEM).setValue(MATCHING_VALUE); Identifier right = new Identifier().setSystem(OTHER_SYSTEM).setValue(MATCHING_VALUE); - MdmMatcherJson matcher = new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.IDENTIFIER).setIdentifierSystem(MATCHING_SYSTEM); - MdmFieldMatchJson fieldMatch = new MdmFieldMatchJson().setMatcher(matcher); + myMdmMatcherJson.setIdentifierSystem(MATCHING_SYSTEM); + + assertFalse(match(left, right)); + } - assertFalse(fieldMatch.match(ourFhirContext, left, right).match); + private boolean match(IBase theFirst, IBase theSecond) { + return myIdentifierMatcher.matches(theFirst, theSecond, myMdmMatcherJson); } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcherTest.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcherTest.java index f1ed249a21f5..d59a76312c25 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcherTest.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/NicknameMatcherTest.java @@ -1,31 +1,48 @@ package ca.uhn.fhir.mdm.rules.matcher; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.NicknameMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import org.hl7.fhir.r4.model.StringType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; - class NicknameMatcherTest { - IMdmStringMatcher matcher = new NicknameMatcher(); + IMdmFieldMatcher matcher; + + NicknameSvc myNicknameSvc = new NicknameSvc(); + + @BeforeEach + public void begin() { + matcher = new NicknameMatcher(myNicknameSvc); + } @Test public void testMatches() { - assertTrue(matcher.matches("Ken", "ken")); - assertTrue(matcher.matches("ken", "Ken")); - assertTrue(matcher.matches("Ken", "Ken")); - assertTrue(matcher.matches("Kenneth", "Ken")); - assertTrue(matcher.matches("Kenneth", "Kenny")); - assertTrue(matcher.matches("Ken", "Kenneth")); - assertTrue(matcher.matches("Kenny", "Kenneth")); - assertTrue(matcher.matches("Jim", "Jimmy")); - assertTrue(matcher.matches("Jimmy", "Jim")); - assertTrue(matcher.matches("Jim", "James")); - assertTrue(matcher.matches("Jimmy", "James")); - assertTrue(matcher.matches("James", "Jimmy")); - assertTrue(matcher.matches("James", "Jim")); + Assertions.assertTrue(match("Ken", "ken")); + Assertions.assertTrue(match("ken", "Ken")); + Assertions.assertTrue(match("Ken", "Ken")); + Assertions.assertTrue(match("Kenneth", "Ken")); + Assertions.assertTrue(match("Kenneth", "Kenny")); + Assertions.assertTrue(match("Ken", "Kenneth")); + Assertions.assertTrue(match("Kenny", "Kenneth")); + Assertions.assertTrue(match("Jim", "Jimmy")); + Assertions.assertTrue(match("Jimmy", "Jim")); + Assertions.assertTrue(match("Jim", "James")); + Assertions.assertTrue(match("Jimmy", "James")); + Assertions.assertTrue(match("James", "Jimmy")); + Assertions.assertTrue(match("James", "Jim")); - assertFalse(matcher.matches("Ken", "Bob")); + Assertions.assertFalse(match("Ken", "Bob")); // These aren't nickname matches. If you want matches like these use a phonetic matcher - assertFalse(matcher.matches("Allen", "Allan")); + Assertions.assertFalse(match("Allen", "Allan")); + } + + private boolean match(String theFirst, String theSecond) { + MdmMatcherJson json = new MdmMatcherJson(); + json.setExact(true); + return matcher.matches(new StringType(theFirst), new StringType(theSecond), json); } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/StringMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/StringMatcherR4Test.java index 73aafb7aebed..646641f8966b 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/StringMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/matcher/StringMatcherR4Test.java @@ -1,106 +1,140 @@ package ca.uhn.fhir.mdm.rules.matcher; +import ca.uhn.fhir.jpa.nickname.NicknameSvc; +import ca.uhn.fhir.mdm.api.IMdmSettings; +import ca.uhn.fhir.mdm.rules.matcher.models.IMdmFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.DateType; import org.hl7.fhir.r4.model.Enumeration; import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.StringType; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import javax.annotation.Nonnull; + import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; public class StringMatcherR4Test extends BaseMatcherR4Test { private static final Logger ourLog = LoggerFactory.getLogger(StringMatcherR4Test.class); public static final String LEFT_NAME = "namadega"; public static final String RIGHT_NAME = "namaedga"; + private IMatcherFactory myIMatcherFactory; + + private IMdmSettings myMdmSettings; + + @BeforeEach + public void before() { + super.before(); + + myMdmSettings = mock(IMdmSettings.class); + + myIMatcherFactory = new MdmMatcherFactory( + ourFhirContext, + myMdmSettings, + new NicknameSvc() + ); + } + + private @Nonnull IMdmFieldMatcher getFieldMatcher(MatchTypeEnum theMatchTypeEnum) { + return myIMatcherFactory.getFieldMatcherForMatchType(theMatchTypeEnum); + } + @Test public void testNamadega() { String left = LEFT_NAME; String right = RIGHT_NAME; - assertTrue(match(MdmMatcherEnum.COLOGNE, left, right)); - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, left, right)); - assertTrue(match(MdmMatcherEnum.MATCH_RATING_APPROACH, left, right)); - assertTrue(match(MdmMatcherEnum.METAPHONE, left, right)); - assertTrue(match(MdmMatcherEnum.SOUNDEX, left, right)); - assertTrue(match(MdmMatcherEnum.METAPHONE, left, right)); - - assertFalse(match(MdmMatcherEnum.CAVERPHONE1, left, right)); - assertFalse(match(MdmMatcherEnum.CAVERPHONE2, left, right)); - assertFalse(match(MdmMatcherEnum.NYSIIS, left, right)); - assertFalse(match(MdmMatcherEnum.REFINED_SOUNDEX, left, right)); - assertFalse(match(MdmMatcherEnum.STRING, left, right)); - assertFalse(match(MdmMatcherEnum.SUBSTRING, left, right)); + assertTrue(match(MatchTypeEnum.COLOGNE, left, right)); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, left, right)); + assertTrue(match(MatchTypeEnum.MATCH_RATING_APPROACH, left, right)); + assertTrue(match(MatchTypeEnum.METAPHONE, left, right)); + assertTrue(match(MatchTypeEnum.SOUNDEX, left, right)); + + assertFalse(match(MatchTypeEnum.CAVERPHONE1, left, right)); + assertFalse(match(MatchTypeEnum.CAVERPHONE2, left, right)); + assertFalse(match(MatchTypeEnum.NYSIIS, left, right)); + assertFalse(match(MatchTypeEnum.REFINED_SOUNDEX, left, right)); + assertFalse(match(MatchTypeEnum.STRING, left, right)); + assertFalse(match(MatchTypeEnum.SUBSTRING, left, right)); } @Test public void testNumeric() { - assertTrue(match(MdmMatcherEnum.NUMERIC, "4169671111", "(416) 967-1111")); - assertFalse(match(MdmMatcherEnum.NUMERIC, "5169671111", "(416) 967-1111")); - assertFalse(match(MdmMatcherEnum.NUMERIC, "4169671111", "(416) 967-1111x123")); + assertTrue(match(MatchTypeEnum.NUMERIC, "4169671111", "(416) 967-1111")); + assertFalse(match(MatchTypeEnum.NUMERIC, "5169671111", "(416) 967-1111")); + assertFalse(match(MatchTypeEnum.NUMERIC, "4169671111", "(416) 967-1111x123")); } @Test public void testMetaphone() { - assertTrue(match(MdmMatcherEnum.METAPHONE, "Durie", "dury")); - assertTrue(match(MdmMatcherEnum.METAPHONE, "Balo", "ballo")); - assertTrue(match(MdmMatcherEnum.METAPHONE, "Hans Peter", "Hanspeter")); - assertTrue(match(MdmMatcherEnum.METAPHONE, "Lawson", "Law son")); - - assertFalse(match(MdmMatcherEnum.METAPHONE, "Allsop", "Allsob")); - assertFalse(match(MdmMatcherEnum.METAPHONE, "Gevne", "Geve")); - assertFalse(match(MdmMatcherEnum.METAPHONE, "Bruce", "Bruch")); - assertFalse(match(MdmMatcherEnum.METAPHONE, "Smith", "Schmidt")); - assertFalse(match(MdmMatcherEnum.METAPHONE, "Jyothi", "Jyoti")); + assertTrue(match(MatchTypeEnum.METAPHONE, "Durie", "dury")); + assertTrue(match(MatchTypeEnum.METAPHONE, "Balo", "ballo")); + assertTrue(match(MatchTypeEnum.METAPHONE, "Hans Peter", "Hanspeter")); + assertTrue(match(MatchTypeEnum.METAPHONE, "Lawson", "Law son")); + + assertFalse(match(MatchTypeEnum.METAPHONE, "Allsop", "Allsob")); + assertFalse(match(MatchTypeEnum.METAPHONE, "Gevne", "Geve")); + assertFalse(match(MatchTypeEnum.METAPHONE, "Bruce", "Bruch")); + assertFalse(match(MatchTypeEnum.METAPHONE, "Smith", "Schmidt")); + assertFalse(match(MatchTypeEnum.METAPHONE, "Jyothi", "Jyoti")); } @Test public void testDoubleMetaphone() { - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Durie", "dury")); - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Balo", "ballo")); - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Hans Peter", "Hanspeter")); - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Lawson", "Law son")); - assertTrue(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Allsop", "Allsob")); - - assertFalse(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Gevne", "Geve")); - assertFalse(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Bruce", "Bruch")); - assertFalse(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Smith", "Schmidt")); - assertFalse(match(MdmMatcherEnum.DOUBLE_METAPHONE, "Jyothi", "Jyoti")); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, "Durie", "dury")); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, "Balo", "ballo")); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, "Hans Peter", "Hanspeter")); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, "Lawson", "Law son")); + assertTrue(match(MatchTypeEnum.DOUBLE_METAPHONE, "Allsop", "Allsob")); + + assertFalse(match(MatchTypeEnum.DOUBLE_METAPHONE, "Gevne", "Geve")); + assertFalse(match(MatchTypeEnum.DOUBLE_METAPHONE, "Bruce", "Bruch")); + assertFalse(match(MatchTypeEnum.DOUBLE_METAPHONE, "Smith", "Schmidt")); + assertFalse(match(MatchTypeEnum.DOUBLE_METAPHONE, "Jyothi", "Jyoti")); } @Test public void testNormalizeCase() { - assertTrue(match(MdmMatcherEnum.STRING, "joe", "JoE")); - assertTrue(match(MdmMatcherEnum.STRING, "MCTAVISH", "McTavish")); + assertTrue(match(MatchTypeEnum.STRING, "joe", "JoE")); + assertTrue(match(MatchTypeEnum.STRING, "MCTAVISH", "McTavish")); - assertFalse(match(MdmMatcherEnum.STRING, "joey", "joe")); - assertFalse(match(MdmMatcherEnum.STRING, "joe", "joey")); + assertFalse(match(MatchTypeEnum.STRING, "joey", "joe")); + assertFalse(match(MatchTypeEnum.STRING, "joe", "joey")); } @Test public void testExactString() { - assertTrue(MdmMatcherEnum.STRING.match(ourFhirContext, new StringType("Jilly"), new StringType("Jilly"), true, null)); + myMdmMatcherJson.setExact(true); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, new StringType("MCTAVISH"), new StringType("McTavish"), true, null)); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, new StringType("Durie"), new StringType("dury"), true, null)); + assertTrue(getFieldMatcher(MatchTypeEnum.STRING).matches(new StringType("Jilly"), new StringType("Jilly"), myMdmMatcherJson)); + + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(new StringType("MCTAVISH"), new StringType("McTavish"), myMdmMatcherJson)); + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(new StringType("Durie"), new StringType("dury"), myMdmMatcherJson)); } @Test public void testExactBoolean() { - assertTrue(MdmMatcherEnum.STRING.match(ourFhirContext, new BooleanType(true), new BooleanType(true), true, null)); + myMdmMatcherJson.setExact(true); + + assertTrue(getFieldMatcher(MatchTypeEnum.STRING).matches(new BooleanType(true), new BooleanType(true), myMdmMatcherJson)); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, new BooleanType(true), new BooleanType(false), true, null)); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, new BooleanType(false), new BooleanType(true), true, null)); + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(new BooleanType(true), new BooleanType(false), myMdmMatcherJson)); + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(new BooleanType(false), new BooleanType(true), myMdmMatcherJson)); } @Test public void testExactDateString() { - assertTrue(MdmMatcherEnum.STRING.match(ourFhirContext, new DateType("1965-08-09"), new DateType("1965-08-09"), true, null)); + myMdmMatcherJson.setExact(true); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, new DateType("1965-08-09"), new DateType("1965-09-08"), true, null)); + assertTrue(getFieldMatcher(MatchTypeEnum.STRING).matches(new DateType("1965-08-09"), new DateType("1965-08-09"), myMdmMatcherJson)); + + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(new DateType("1965-08-09"), new DateType("1965-09-08"), myMdmMatcherJson)); } @@ -112,52 +146,55 @@ public void testExactGender() { Enumeration female = new Enumeration(new Enumerations.AdministrativeGenderEnumFactory()); female.setValue(Enumerations.AdministrativeGender.FEMALE); - assertTrue(MdmMatcherEnum.STRING.match(ourFhirContext, male, male, true, null)); + myMdmMatcherJson.setExact(true); + + assertTrue(getFieldMatcher(MatchTypeEnum.STRING).matches(male, male, myMdmMatcherJson)); - assertFalse(MdmMatcherEnum.STRING.match(ourFhirContext, male, female, true, null)); + assertFalse(getFieldMatcher(MatchTypeEnum.STRING).matches(male, female, myMdmMatcherJson)); } @Test public void testSoundex() { - assertTrue(match(MdmMatcherEnum.SOUNDEX, "Gail", "Gale")); - assertTrue(match(MdmMatcherEnum.SOUNDEX, "John", "Jon")); - assertTrue(match(MdmMatcherEnum.SOUNDEX, "Thom", "Tom")); + assertTrue(match(MatchTypeEnum.SOUNDEX, "Gail", "Gale")); + assertTrue(match(MatchTypeEnum.SOUNDEX, "John", "Jon")); + assertTrue(match(MatchTypeEnum.SOUNDEX, "Thom", "Tom")); - assertFalse(match(MdmMatcherEnum.SOUNDEX, "Fred", "Frank")); - assertFalse(match(MdmMatcherEnum.SOUNDEX, "Thomas", "Tom")); + assertFalse(match(MatchTypeEnum.SOUNDEX, "Fred", "Frank")); + assertFalse(match(MatchTypeEnum.SOUNDEX, "Thomas", "Tom")); } @Test public void testCaverphone1() { - assertTrue(match(MdmMatcherEnum.CAVERPHONE1, "Gail", "Gael")); - assertTrue(match(MdmMatcherEnum.CAVERPHONE1, "John", "Jon")); + assertTrue(match(MatchTypeEnum.CAVERPHONE1, "Gail", "Gael")); + assertTrue(match(MatchTypeEnum.CAVERPHONE1, "John", "Jon")); - assertFalse(match(MdmMatcherEnum.CAVERPHONE1, "Gail", "Gale")); - assertFalse(match(MdmMatcherEnum.CAVERPHONE1, "Fred", "Frank")); - assertFalse(match(MdmMatcherEnum.CAVERPHONE1, "Thomas", "Tom")); + assertFalse(match(MatchTypeEnum.CAVERPHONE1, "Gail", "Gale")); + assertFalse(match(MatchTypeEnum.CAVERPHONE1, "Fred", "Frank")); + assertFalse(match(MatchTypeEnum.CAVERPHONE1, "Thomas", "Tom")); } @Test public void testCaverphone2() { - assertTrue(match(MdmMatcherEnum.CAVERPHONE2, "Gail", "Gael")); - assertTrue(match(MdmMatcherEnum.CAVERPHONE2, "John", "Jon")); - assertTrue(match(MdmMatcherEnum.CAVERPHONE2, "Gail", "Gale")); + assertTrue(match(MatchTypeEnum.CAVERPHONE2, "Gail", "Gael")); + assertTrue(match(MatchTypeEnum.CAVERPHONE2, "John", "Jon")); + assertTrue(match(MatchTypeEnum.CAVERPHONE2, "Gail", "Gale")); - assertFalse(match(MdmMatcherEnum.CAVERPHONE2, "Fred", "Frank")); - assertFalse(match(MdmMatcherEnum.CAVERPHONE2, "Thomas", "Tom")); + assertFalse(match(MatchTypeEnum.CAVERPHONE2, "Fred", "Frank")); + assertFalse(match(MatchTypeEnum.CAVERPHONE2, "Thomas", "Tom")); } @Test public void testNormalizeSubstring() { - assertTrue(match(MdmMatcherEnum.SUBSTRING, "BILLY", "Bill")); - assertTrue(match(MdmMatcherEnum.SUBSTRING, "Bill", "Billy")); - assertTrue(match(MdmMatcherEnum.SUBSTRING, "FRED", "Frederik")); + assertTrue(match(MatchTypeEnum.SUBSTRING, "BILLY", "Bill")); + assertTrue(match(MatchTypeEnum.SUBSTRING, "Bill", "Billy")); + assertTrue(match(MatchTypeEnum.SUBSTRING, "FRED", "Frederik")); - assertFalse(match(MdmMatcherEnum.SUBSTRING, "Fred", "Friederik")); + assertFalse(match(MatchTypeEnum.SUBSTRING, "Fred", "Friederik")); } - private boolean match(MdmMatcherEnum theMatcher, String theLeft, String theRight) { - return theMatcher.match(ourFhirContext, new StringType(theLeft), new StringType(theRight), false, null); + private boolean match(MatchTypeEnum theMatcher, String theLeft, String theRight) { + return getFieldMatcher(theMatcher) + .matches(new StringType(theLeft), new StringType(theRight), myMdmMatcherJson); } } diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/BaseMdmRulesR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/BaseMdmRulesR4Test.java index ce8721b97eb3..4ef383b97677 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/BaseMdmRulesR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/BaseMdmRulesR4Test.java @@ -29,6 +29,7 @@ public abstract class BaseMdmRulesR4Test extends BaseR4Test { @BeforeEach public void before() { + super.before(); myMdmRulesJson = new MdmRulesJson(); ArrayList myLegalMdmTypes = new ArrayList<>(); diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/CustomResourceMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/CustomResourceMatcherR4Test.java index 7232394673e8..d46e225119ff 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/CustomResourceMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/CustomResourceMatcherR4Test.java @@ -6,7 +6,7 @@ import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.hl7.fhir.r4.model.HumanName; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeAll; @@ -20,7 +20,7 @@ public class CustomResourceMatcherR4Test extends BaseR4Test { - public static final String FIELD_EXACT_MATCH_NAME = MdmMatcherEnum.NAME_ANY_ORDER.name(); + public static final String FIELD_EXACT_MATCH_NAME = MatchTypeEnum.NAME_ANY_ORDER.name(); private static Patient ourJohnHenry; private static Patient ourJohnHENRY; private static Patient ourJaneHenry; @@ -32,6 +32,7 @@ public class CustomResourceMatcherR4Test extends BaseR4Test { @BeforeEach public void before() { + super.before(); when(mySearchParamRetriever.getActiveSearchParam("Patient", "identifier")).thenReturn(mock(RuntimeSearchParam.class)); when(mySearchParamRetriever.getActiveSearchParam("Practitioner", "identifier")).thenReturn(mock(RuntimeSearchParam.class)); when(mySearchParamRetriever.getActiveSearchParam("Medication", "identifier")).thenReturn(mock(RuntimeSearchParam.class)); @@ -40,7 +41,8 @@ public void before() { @Test public void testExactNameAnyOrder() { - MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MdmMatcherEnum.NAME_ANY_ORDER, true)); + MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MatchTypeEnum.NAME_ANY_ORDER, true)); + assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourJohnHenry)); assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJohn)); assertMatch(MdmMatchResultEnum.NO_MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJOHN)); @@ -53,7 +55,8 @@ public void testExactNameAnyOrder() { @Test public void testNormalizedNameAnyOrder() { - MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MdmMatcherEnum.NAME_ANY_ORDER, false)); + MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MatchTypeEnum.NAME_ANY_ORDER, false)); + assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourJohnHenry)); assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJohn)); assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJOHN)); @@ -66,7 +69,8 @@ public void testNormalizedNameAnyOrder() { @Test public void testExactNameFirstAndLast() { - MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MdmMatcherEnum.NAME_FIRST_AND_LAST, true)); + MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MatchTypeEnum.NAME_FIRST_AND_LAST, true)); + assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourJohnHenry)); assertMatchResult(MdmMatchResultEnum.MATCH, 1L, 1.0, false, false, nameAnyOrderMatcher.match(ourJohnHenry, ourJohnHenry)); assertMatch(MdmMatchResultEnum.NO_MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJohn)); @@ -80,7 +84,8 @@ public void testExactNameFirstAndLast() { @Test public void testNormalizedNameFirstAndLast() { - MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MdmMatcherEnum.NAME_FIRST_AND_LAST, false)); + MdmResourceMatcherSvc nameAnyOrderMatcher = buildMatcher(buildNameRules(MatchTypeEnum.NAME_FIRST_AND_LAST, false)); + assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourJohnHenry)); assertMatch(MdmMatchResultEnum.NO_MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJohn)); assertMatch(MdmMatchResultEnum.NO_MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourHenryJOHN)); @@ -91,7 +96,7 @@ public void testNormalizedNameFirstAndLast() { assertMatch(MdmMatchResultEnum.MATCH, nameAnyOrderMatcher.match(ourJohnHenry, ourBillyJohnHenry)); } - private MdmRulesJson buildNameRules(MdmMatcherEnum theAlgorithm, boolean theExact) { + private MdmRulesJson buildNameRules(MatchTypeEnum theAlgorithm, boolean theExact) { MdmMatcherJson matcherJson = new MdmMatcherJson().setAlgorithm(theAlgorithm).setExact(theExact); MdmFieldMatchJson nameAnyOrderFieldMatch = new MdmFieldMatchJson() .setName(FIELD_EXACT_MATCH_NAME) diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/FhirPathResourceMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/FhirPathResourceMatcherR4Test.java index b482fcd71caa..d46a0d067767 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/FhirPathResourceMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/FhirPathResourceMatcherR4Test.java @@ -6,7 +6,7 @@ import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.hl7.fhir.r4.model.HumanName; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; @@ -46,10 +46,9 @@ public void before() { } } - @Test public void testFhirPathOrderedMatches() { - MdmResourceMatcherSvc matcherSvc = buildMatcher(buildOrderedGivenNameRules(MdmMatcherEnum.STRING)); + MdmResourceMatcherSvc matcherSvc = buildMatcher(buildOrderedGivenNameRules(MatchTypeEnum.STRING)); myLeft = new Patient(); HumanName name = myLeft.addName(); @@ -63,6 +62,7 @@ public void testFhirPathOrderedMatches() { name2.addGiven("Gary"); myRight.setId("Patient/2"); + // test MdmMatchOutcome result = matcherSvc.match(myLeft, myRight); assertMatchResult(MdmMatchResultEnum.NO_MATCH, 0L, 0.0, false, false, result); @@ -85,12 +85,12 @@ public void testFhirPathOrderedMatches() { @Test public void testStringMatchResult() { - MdmResourceMatcherSvc matcherSvc = buildMatcher(buildOrderedGivenNameRules(MdmMatcherEnum.STRING)); + MdmResourceMatcherSvc matcherSvc = buildMatcher(buildOrderedGivenNameRules(MatchTypeEnum.STRING)); MdmMatchOutcome result = matcherSvc.match(myLeft, myRight); assertMatchResult(MdmMatchResultEnum.NO_MATCH, 0L, 0.0, false, false, result); } - protected MdmRulesJson buildOrderedGivenNameRules(MdmMatcherEnum theMatcherEnum) { + protected MdmRulesJson buildOrderedGivenNameRules(MatchTypeEnum theMatcherEnum) { MdmFieldMatchJson firstGivenNameMatchField = new MdmFieldMatchJson() .setName(PATIENT_GIVEN_FIRST) .setResourceType("Patient") diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcherR4Test.java index c00841ca7083..c47be74ba27e 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceFieldMatcherR4Test.java @@ -3,10 +3,8 @@ import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; -import ca.uhn.fhir.mdm.rules.json.MdmSimilarityJson; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; -import ca.uhn.fhir.mdm.rules.similarity.MdmSimilarityEnum; -import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.mdm.rules.matcher.fieldmatchers.EmptyFieldMatcher; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.hl7.fhir.r4.model.Encounter; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; @@ -14,12 +12,12 @@ import java.util.Arrays; -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.core.StringStartsWith.startsWith; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.when; public class MdmResourceFieldMatcherR4Test extends BaseMdmRulesR4Test { protected MdmResourceFieldMatcher myComparator; @@ -30,7 +28,13 @@ public class MdmResourceFieldMatcherR4Test extends BaseMdmRulesR4Test { @BeforeEach public void before() { super.before(); - myComparator = new MdmResourceFieldMatcher(ourFhirContext, myGivenNameMatchField, myMdmRulesJson); + + myComparator = new MdmResourceFieldMatcher( + ourFhirContext, + myIMatcherFactory, + myGivenNameMatchField, + myMdmRulesJson + ); myJohn = buildJohn(); myJohny = buildJohny(); } @@ -44,8 +48,13 @@ public void testEmptyPath() { .setName("empty-given") .setResourceType("Patient") .setResourcePath("name.given") - .setMatcher(new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.EMPTY_FIELD)); - myComparator = new MdmResourceFieldMatcher(ourFhirContext, myGivenNameMatchField, myMdmRulesJson); + .setMatcher(new MdmMatcherJson().setAlgorithm(MatchTypeEnum.EMPTY_FIELD)); + myComparator = new MdmResourceFieldMatcher( + ourFhirContext, + myIMatcherFactory, + myGivenNameMatchField, + myMdmRulesJson + ); assertFalse(myComparator.match(myJohn, myJohny).match); @@ -90,6 +99,9 @@ public void testBadType() { } } + // TODO - what is this supposed to test? + // it relies on matcher being null (is this a reasonable assumption?) + // and falls through to similarity check @Test public void testMatch() { assertTrue(myComparator.match(myJohn, myJohny).match); diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvcR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvcR4Test.java index 912348f59808..61045b37671c 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvcR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/MdmResourceMatcherSvcR4Test.java @@ -36,7 +36,6 @@ public void before() { public void testCompareFirstNameMatch() { MdmMatchOutcome result = myMdmResourceMatcherSvc.match(myJohn, myJohny); assertMatchResult(MdmMatchResultEnum.POSSIBLE_MATCH, 1L, 0.816, false, false, result); - } @Test diff --git a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/ResourceMatcherR4Test.java b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/ResourceMatcherR4Test.java index 8a2342c93980..8fa816bc5f11 100644 --- a/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/ResourceMatcherR4Test.java +++ b/hapi-fhir-server-mdm/src/test/java/ca/uhn/fhir/mdm/rules/svc/ResourceMatcherR4Test.java @@ -6,7 +6,7 @@ import ca.uhn.fhir.mdm.rules.json.MdmFieldMatchJson; import ca.uhn.fhir.mdm.rules.json.MdmMatcherJson; import ca.uhn.fhir.mdm.rules.json.MdmRulesJson; -import ca.uhn.fhir.mdm.rules.matcher.MdmMatcherEnum; +import ca.uhn.fhir.mdm.rules.matcher.models.MatchTypeEnum; import org.hl7.fhir.r4.model.HumanName; import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; @@ -55,19 +55,21 @@ public void before() { @Test public void testMetaphoneMatchResult() { - MdmResourceMatcherSvc matcherSvc = buildMatcher(buildNamePhoneRules(MdmMatcherEnum.METAPHONE)); - MdmMatchOutcome result = matcherSvc.match(myLeft, myRight); - assertMatchResult(MdmMatchResultEnum.MATCH, 7L, 3.0, false, false, result); + MdmResourceMatcherSvc matcherSvc = buildMatcher(buildNamePhoneRules(MatchTypeEnum.METAPHONE)); + + MdmMatchOutcome result = matcherSvc.match(myLeft, myRight); + assertMatchResult(MdmMatchResultEnum.MATCH, 7L, 3.0, false, false, result); } @Test public void testStringMatchResult() { - MdmResourceMatcherSvc matcherSvc = buildMatcher(buildNamePhoneRules(MdmMatcherEnum.STRING)); + MdmResourceMatcherSvc matcherSvc = buildMatcher(buildNamePhoneRules(MatchTypeEnum.STRING)); + MdmMatchOutcome result = matcherSvc.match(myLeft, myRight); assertMatchResult(MdmMatchResultEnum.NO_MATCH, 5L, 2.0, false, false, result); } - protected MdmRulesJson buildNamePhoneRules(MdmMatcherEnum theMatcherEnum) { + protected MdmRulesJson buildNamePhoneRules(MatchTypeEnum theMatcherEnum) { MdmFieldMatchJson lastNameMatchField = new MdmFieldMatchJson() .setName(PATIENT_FAMILY) .setResourceType("Patient") @@ -84,7 +86,7 @@ protected MdmRulesJson buildNamePhoneRules(MdmMatcherEnum theMatcherEnum) { .setName(PATIENT_PHONE) .setResourceType("Patient") .setResourcePath("telecom.value") - .setMatcher(new MdmMatcherJson().setAlgorithm(MdmMatcherEnum.STRING)); + .setMatcher(new MdmMatcherJson().setAlgorithm(MatchTypeEnum.STRING)); MdmRulesJson retval = new MdmRulesJson(); retval.setVersion("test version"); diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index f84a86302a15..0ed640c27aee 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index b30a941fc9c9..77ff5e85d8c1 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.7.3-SNAPSHOT + 6.7.6-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 70d41bc55aad..4131a72db783 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.7.3-SNAPSHOT + 6.7.6-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 5ba003ee8c69..18bb22d455ec 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml @@ -21,7 +21,7 @@ ca.uhn.hapi.fhir hapi-fhir-caching-api - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT diff --git a/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml b/hapi-fhir-serviceloaders/hapi-fhir-caching-guava/pom.xml index bbce9743293b..181f50506b73 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.7.3-SNAPSHOT + 6.7.6-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 4e213837c38d..09bd53681888 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../../pom.xml diff --git a/hapi-fhir-serviceloaders/pom.xml b/hapi-fhir-serviceloaders/pom.xml index 336f2807cd3d..2b208f2a4c83 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.7.3-SNAPSHOT + 6.7.6-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 74e6524c6d37..2eadb3aacf0a 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.7.3-SNAPSHOT + 6.7.6-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 ef7ce4e2eb2b..68729f911045 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.7.3-SNAPSHOT + 6.7.6-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 bbce2275e644..911ef458004d 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.7.3-SNAPSHOT + 6.7.6-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 f22a1b77e9f4..053dae392132 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.7.3-SNAPSHOT + 6.7.6-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 3b40f5b70766..c3eb384e2d29 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.7.3-SNAPSHOT + 6.7.6-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 6cbac82b2130..e04106d945d0 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index 2fb0f60836ae..67f1758a05e5 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index ffc7c6d92eac..41aee3a6ef1e 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.7.3-SNAPSHOT + 6.7.6-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 b5254c05b8ea..2c0d483fb576 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.7.3-SNAPSHOT + 6.7.6-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 f6e4d2c5da42..3db7d7909f2d 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml @@ -55,11 +55,6 @@ junit-jupiter-params compile - - org.hamcrest - hamcrest - compile - org.mockito mockito-core diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 75dde80756ec..e2943e16547c 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-cr/pom.xml b/hapi-fhir-storage-cr/pom.xml index 622754f0120b..ce757764d18a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index b5afd30d2fa5..41683f2c5d40 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.7.3-SNAPSHOT + 6.7.6-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 470892e5168d..e7cafc21ef9a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index ff63e862464d..c72de5445b21 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.7.3-SNAPSHOT + 6.7.6-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 d8eca92c3795..d4a6a4844537 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index eac2f1a2d764..f920fdb6a50e 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index e28f1911df13..ebb9ff22aca4 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.7.3-SNAPSHOT + 6.7.6-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 3038ea589039..9278f52c527a 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 80afda1d51f5..394367d5c853 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index 7c63abd158ea..d177f89fc084 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index 05e2adef8ee5..4c11c9587612 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 96a0bcf9f20c..8a6521ad8fe4 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index a618f4af12c1..7c9d233c8508 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index c8a5ebb5d143..a1a323051833 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.7.3-SNAPSHOT + 6.7.6-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 660a8568519a..7017285ebb01 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.7.3-SNAPSHOT + 6.7.6-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 c07f70601b4d..b1be1ffeddba 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.7.3-SNAPSHOT + 6.7.6-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 1bff9aa5ac9b..a7ae0bf600d5 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.7.3-SNAPSHOT + 6.7.6-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 83fbb803661b..820dcfca45c8 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.7.3-SNAPSHOT + 6.7.6-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 070f9931a4c0..643beeae9f92 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index 26d4c89c42f0..f5e16d515b5b 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 627d86b0b6e3..702abdb1b300 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index 828b6abf7dd7..ee21d7e99080 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 7370c9e2bafd..0dbdabd1b237 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 6.7.3-SNAPSHOT + 6.7.6-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 91037292edc5..f6e04cc5db08 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.7.3-SNAPSHOT + 6.7.6-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 11de060de8a2..535894c9cc03 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.7.3-SNAPSHOT + 6.7.6-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 cc858f7f0afb..bde81d287541 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.7.3-SNAPSHOT + 6.7.6-SNAPSHOT ../../pom.xml