
001/*- 002 * #%L 003 * HAPI FHIR - Master Data Management 004 * %% 005 * Copyright (C) 2014 - 2025 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.svc; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.mdm.api.IMdmLinkExpandSvc; 024import ca.uhn.fhir.mdm.api.IMdmSettings; 025import ca.uhn.fhir.mdm.api.MdmModeEnum; 026import ca.uhn.fhir.mdm.util.EIDHelper; 027 028/** 029 * Holder class that manages two different MDM expansion implementation approaches based on MdmSettings. 030 * <p> 031 * This class addresses the dependency injection challenge where MdmSettings may not be available when these 032 * service objects are created. It holds references to both implementation approaches and determines which ones 033 * to use based on the MdmSettings. setMdmSettings method should be called when MdmSettings is constructed or updated 034 * for proper functioning. 035 * <p> 036 * The two implementation approaches are: 037 * <p> 038 * <strong>1. Eid Match-Only Mode:</strong> A simplified approach where resources are matched based solely on 039 * Enterprise ID (EID) values without creating golden resources or MDM links. This mode is activated when 040 * MdmSettings specify MATCH_ONLY mode and EID systems are defined. 041 * <p> 042 * <strong>2. Full MDM Mode:</strong> The complete MDM solution that creates golden resources and manages 043 * MDM links between resources. 044 * <p> 045 * Each approach has two service implementations, one for mdm expansion for searches and the other for mdm expansion for group bulk export: 046 * <p> 047 * <strong>Eid Match-Only Mode implementations:</strong> 048 * - MdmEidMatchOnlyLinkExpandSvc 049 * - BulkExportMdmEidMatchOnlyResourceExpander 050 * <p> 051 * <strong>Full MDM Mode implementations:</strong> 052 * - MdmLinkExpandSvc 053 * - BulkExportMdmResourceExpander 054 * <p> 055 * 056 * This class holds references to these service objects rather than creating them by itself, because some of these service objects have Spring annotations 057 * like @Transactional, for those annotations to work the objects need to be created by Spring itself. 058 */ 059public class MdmExpandersHolder { 060 061 /** MDM configuration settings used to determine which implementation to use */ 062 private IMdmSettings myMdmSettings; 063 064 /** Cached instance of the selected link expand service */ 065 private IMdmLinkExpandSvc myLinkExpandSvcInstanceToUse; 066 067 /** Cached instance of the selected bulk export resource expander */ 068 private IBulkExportMdmResourceExpander myBulkExportMDMResourceExpanderInstanceToUse; 069 070 /** Full MDM link expand service implementation 071 * We have to use the interface as the type here instead of concrete implementing class MdmLinkExpandSvc 072 * because the class has Spring annotations like @Transactional which rely on a Proxy interface implementation and doesn't work if concrete classes are used as beans. */ 073 private final IMdmLinkExpandSvc myMdmLinkExpandSvc; 074 075 /** EID-only match expand service implementation */ 076 private final MdmEidMatchOnlyExpandSvc myMdmEidMatchOnlyExpandSvc; 077 078 /** Full MDM bulk export resource expander implementation */ 079 private final BulkExportMdmResourceExpander myBulkExportMDMResourceExpander; 080 081 /** EID-only match bulk export resource expander implementation */ 082 private final BulkExportMdmEidMatchOnlyResourceExpander myBulkExportMDMEidMatchOnlyResourceExpander; 083 084 private final FhirContext myFhirContext; 085 086 public MdmExpandersHolder( 087 FhirContext theFhirContext, 088 IMdmLinkExpandSvc theMdmLinkExpandSvc, 089 MdmEidMatchOnlyExpandSvc theMdmEidMatchOnlyLinkExpandSvc, 090 BulkExportMdmResourceExpander theBulkExportMDMResourceExpander, 091 BulkExportMdmEidMatchOnlyResourceExpander theBulkExportMDMEidMatchOnlyResourceExpander) { 092 093 myFhirContext = theFhirContext; 094 myMdmLinkExpandSvc = theMdmLinkExpandSvc; 095 myMdmEidMatchOnlyExpandSvc = theMdmEidMatchOnlyLinkExpandSvc; 096 myBulkExportMDMResourceExpander = theBulkExportMDMResourceExpander; 097 myBulkExportMDMEidMatchOnlyResourceExpander = theBulkExportMDMEidMatchOnlyResourceExpander; 098 } 099 100 /** 101 * Returns the appropriate expand service instance appropriate for the mdm settings 102 */ 103 public IMdmLinkExpandSvc getLinkExpandSvcInstance() { 104 if (myLinkExpandSvcInstanceToUse != null) { 105 // we already determined instance to use, just return it 106 return myLinkExpandSvcInstanceToUse; 107 } 108 109 myLinkExpandSvcInstanceToUse = determineExpandSvsInstanceToUse(); 110 111 return myLinkExpandSvcInstanceToUse; 112 } 113 114 /** 115 * Returns the appropriate bulk export resource expander instance appropriate for the mdm settings 116 */ 117 public IBulkExportMdmResourceExpander getBulkExportMDMResourceExpanderInstance() { 118 if (myBulkExportMDMResourceExpanderInstanceToUse != null) { 119 // we already determined instance to use, just return it 120 return myBulkExportMDMResourceExpanderInstanceToUse; 121 } 122 123 myBulkExportMDMResourceExpanderInstanceToUse = determineBulkExportMDMResourceExpanderInstanceToUse(); 124 125 return myBulkExportMDMResourceExpanderInstanceToUse; 126 } 127 128 /** 129 * Determines which bulk export resource expander to use based on MDM mode and EID configuration. 130 */ 131 public IBulkExportMdmResourceExpander determineBulkExportMDMResourceExpanderInstanceToUse() { 132 if (isMatchOnlyWithEidSystems()) { 133 return myBulkExportMDMEidMatchOnlyResourceExpander; 134 } else { 135 return myBulkExportMDMResourceExpander; 136 } 137 } 138 139 /** 140 * Determines if MDM is configured in MATCH_ONLY mode and EID systems are defined in the MDM rules. 141 */ 142 private boolean isMatchOnlyWithEidSystems() { 143 144 if (myMdmSettings == null) { 145 // if mdmSettings is not set yet, assume we are using the full mdm mode 146 // to not break existing code, because previously we were just using the 147 // full mdm implementation without checking the mdm settings. 148 // This would be called again when mdmSettings setter is called 149 return false; 150 } 151 boolean isMatchOnly = myMdmSettings.getMode() == MdmModeEnum.MATCH_ONLY; 152 boolean hasEidSystems = false; 153 if (myMdmSettings.getMdmRules() != null) { 154 hasEidSystems = myMdmSettings.getMdmRules().getEnterpriseEIDSystems() != null 155 && !myMdmSettings.getMdmRules().getEnterpriseEIDSystems().isEmpty(); 156 } 157 return isMatchOnly && hasEidSystems; 158 } 159 160 /** 161 * Determines which expand service to use and configures it if necessary. 162 */ 163 private IMdmLinkExpandSvc determineExpandSvsInstanceToUse() { 164 if (isMatchOnlyWithEidSystems()) { 165 myMdmEidMatchOnlyExpandSvc.setMyEidHelper(new EIDHelper(myFhirContext, myMdmSettings)); 166 return myMdmEidMatchOnlyExpandSvc; 167 } else { 168 return myMdmLinkExpandSvc; 169 } 170 } 171 172 /** 173 * Sets the MDM settings and immediately determines which service implementations to use. 174 * This method is called after MDM settings become available during application startup. 175 */ 176 public void setMdmSettings(IMdmSettings theMdmSettings) { 177 myMdmSettings = theMdmSettings; 178 myLinkExpandSvcInstanceToUse = determineExpandSvsInstanceToUse(); 179 myBulkExportMDMResourceExpanderInstanceToUse = determineBulkExportMDMResourceExpanderInstanceToUse(); 180 } 181}