001/*- 002 * #%L 003 * HAPI FHIR - Master Data Management 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.mdm.rules.json; 021 022import ca.uhn.fhir.context.ConfigurationException; 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.mdm.api.MdmMatchResultEnum; 025import jakarta.annotation.Nonnull; 026 027import java.util.HashMap; 028import java.util.HashSet; 029import java.util.Map; 030import java.util.Set; 031 032public class VectorMatchResultMap { 033 private final MdmRulesJson myMdmRulesJson; 034 private Map<Long, MdmMatchResultEnum> myVectorToMatchResultMap = new HashMap<>(); 035 private Set<Long> myMatchVectors = new HashSet<>(); 036 private Set<Long> myPossibleMatchVectors = new HashSet<>(); 037 private Map<Long, String> myVectorToFieldMatchNamesMap = new HashMap<>(); 038 039 VectorMatchResultMap(MdmRulesJson theMdmRulesJson) { 040 myMdmRulesJson = theMdmRulesJson; 041 // no reason to hold the entire mdmRulesJson here 042 initMap(); 043 } 044 045 private void initMap() { 046 for (Map.Entry<String, MdmMatchResultEnum> entry : 047 myMdmRulesJson.getMatchResultMap().entrySet()) { 048 put(entry.getKey(), entry.getValue()); 049 } 050 } 051 052 @Nonnull 053 public MdmMatchResultEnum get(Long theMatchVector) { 054 return myVectorToMatchResultMap.computeIfAbsent(theMatchVector, this::computeMatchResult); 055 } 056 057 private MdmMatchResultEnum computeMatchResult(Long theVector) { 058 if (myMatchVectors.stream().anyMatch(v -> (v & theVector) == v)) { 059 return MdmMatchResultEnum.MATCH; 060 } 061 if (myPossibleMatchVectors.stream().anyMatch(v -> (v & theVector) == v)) { 062 return MdmMatchResultEnum.POSSIBLE_MATCH; 063 } 064 return MdmMatchResultEnum.NO_MATCH; 065 } 066 067 private void put(String theFieldMatchNames, MdmMatchResultEnum theMatchResult) { 068 long vector = getVector(theFieldMatchNames); 069 myVectorToFieldMatchNamesMap.put(vector, theFieldMatchNames); 070 myVectorToMatchResultMap.put(vector, theMatchResult); 071 if (theMatchResult == MdmMatchResultEnum.MATCH) { 072 myMatchVectors.add(vector); 073 } else if (theMatchResult == MdmMatchResultEnum.POSSIBLE_MATCH) { 074 myPossibleMatchVectors.add(vector); 075 } 076 } 077 078 public long getVector(String theFieldMatchNames) { 079 long retval = 0; 080 for (String fieldMatchName : splitFieldMatchNames(theFieldMatchNames)) { 081 int index = getFieldMatchIndex(fieldMatchName); 082 if (index == -1) { 083 throw new ConfigurationException(Msg.code(1523) + "There is no matchField with name " + fieldMatchName); 084 } 085 retval |= (1 << index); 086 } 087 return retval; 088 } 089 090 @Nonnull 091 static String[] splitFieldMatchNames(String theFieldMatchNames) { 092 return theFieldMatchNames.split(",\\s*"); 093 } 094 095 private int getFieldMatchIndex(final String theFieldMatchName) { 096 for (int i = 0; i < myMdmRulesJson.size(); ++i) { 097 if (myMdmRulesJson.get(i).getName().equals(theFieldMatchName)) { 098 return i; 099 } 100 } 101 return -1; 102 } 103 104 public String getFieldMatchNames(long theVector) { 105 return myVectorToFieldMatchNamesMap.get(theVector); 106 } 107}