
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.i18n.Msg; 023import ca.uhn.fhir.interceptor.model.RequestPartitionId; 024import ca.uhn.fhir.jpa.api.dao.DaoRegistry; 025import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; 026import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; 027import ca.uhn.fhir.mdm.api.IMdmLinkExpandSvc; 028import ca.uhn.fhir.mdm.model.CanonicalEID; 029import ca.uhn.fhir.mdm.util.EIDHelper; 030import ca.uhn.fhir.rest.api.server.SystemRequestDetails; 031import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId; 032import ca.uhn.fhir.rest.param.TokenOrListParam; 033import ca.uhn.fhir.rest.param.TokenParam; 034import org.hl7.fhir.instance.model.api.IBaseResource; 035import org.hl7.fhir.instance.model.api.IIdType; 036 037import java.util.*; 038 039/** 040 * MDM link expansion service that is used when MDM mode is Match-Only and eid systems are defined in Mdm rules. 041 * Expands resources by finding other resources with the same eids. 042 */ 043public class MdmEidMatchOnlyExpandSvc implements IMdmLinkExpandSvc { 044 045 private final DaoRegistry myDaoRegistry; 046 047 private EIDHelper myEidHelper; 048 049 public MdmEidMatchOnlyExpandSvc(DaoRegistry theDaoRegistry) { 050 myDaoRegistry = theDaoRegistry; 051 } 052 053 public void setMyEidHelper(EIDHelper theEidHelper) { 054 myEidHelper = theEidHelper; 055 } 056 057 /** 058 * MDM expands the resource with the given id by finding all resources with the same eids. 059 * @param theRequestPartitionId the partition to search in 060 * @param theId the resource ID to expand 061 * @return set of resource IDs with matching EIDs 062 */ 063 @Override 064 public Set<String> expandMdmBySourceResourceId(RequestPartitionId theRequestPartitionId, IIdType theId) { 065 Set<String> result = new HashSet<>(); 066 // 1. Resolve resource 067 String resourceType = theId.getResourceType(); 068 SystemRequestDetails srd = SystemRequestDetails.forRequestPartitionId(theRequestPartitionId); 069 IFhirResourceDao<IBaseResource> resourceDao = myDaoRegistry.getResourceDao(resourceType); 070 IBaseResource resource = resourceDao.read(theId, srd); 071 // 2. Extract EIDs from resource using EIDHelper 072 List<CanonicalEID> eids = myEidHelper.getExternalEid(resource); 073 if (!eids.isEmpty()) { 074 // 3. Search for resources of same type with the same eid 075 var map = new SearchParameterMap(); 076 final TokenOrListParam tokenOrListParam = new TokenOrListParam(); 077 eids.forEach(eid -> tokenOrListParam.addOr(new TokenParam(eid.getSystem(), eid.getValue()))); 078 map.add("identifier", tokenOrListParam); 079 List<IIdType> ids = resourceDao.searchForResourceIds(map, srd); 080 for (IIdType id : ids) { 081 result.add(id.toUnqualifiedVersionless().getValue()); 082 } 083 } 084 return result; 085 } 086 087 @Override 088 public Set<String> expandMdmBySourceResource(RequestPartitionId theRequestPartitionId, IBaseResource theResource) { 089 return expandMdmBySourceResourceId(theRequestPartitionId, theResource.getIdElement()); 090 } 091 092 @Override 093 public Set<String> expandMdmBySourceResourcePid( 094 RequestPartitionId theRequestPartitionId, IResourcePersistentId<?> theSourceResourcePid) { 095 throw new UnsupportedOperationException( 096 Msg.code(2809) + "This operation is not implemented when using MDM in MATCH_ONLY mode."); 097 } 098 099 @Override 100 public Set<String> expandMdmByGoldenResourceId( 101 RequestPartitionId theRequestPartitionId, IResourcePersistentId<?> theGoldenResourcePid) { 102 // This operation is not applicable when using MDM in MATCH_ONLY mode, 103 // return an emtpy set to rather than an exception to not affect existing code 104 return Collections.emptySet(); 105 } 106 107 @Override 108 public Set<String> expandMdmByGoldenResourcePid( 109 RequestPartitionId theRequestPartitionId, IResourcePersistentId<?> theGoldenResourcePid) { 110 // This operation is not applicable when using MDM in MATCH_ONLY mode, 111 // return an emtpy set to rather than an exception to not affect existing code 112 return Collections.emptySet(); 113 } 114 115 @Override 116 public Set<String> expandMdmByGoldenResourceId(RequestPartitionId theRequestPartitionId, IIdType theId) { 117 // This operation is not applicable when using MDM in MATCH_ONLY mode, 118 // return an emtpy set to rather than an exception to not affect existing code 119 return Collections.emptySet(); 120 } 121}