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.util; 021 022import ca.uhn.fhir.mdm.api.MdmConstants; 023import jakarta.annotation.Nonnull; 024import org.hl7.fhir.instance.model.api.IBaseCoding; 025import org.hl7.fhir.instance.model.api.IBaseResource; 026 027import java.util.Optional; 028 029public final class MdmResourceUtil { 030 031 private MdmResourceUtil() {} 032 033 /** 034 * If the resource is tagged as not managed by MDM, return false. Otherwise true. 035 * 036 * @param theBaseResource The FHIR resource that is potentially managed by MDM. 037 * @return A boolean indicating whether MDM can manage this resource. 038 */ 039 public static boolean isMdmAllowed(IBaseResource theBaseResource) { 040 return theBaseResource.getMeta().getTag(MdmConstants.SYSTEM_MDM_MANAGED, MdmConstants.CODE_NO_MDM_MANAGED) 041 == null; 042 } 043 044 /** 045 * Checks for the presence of the MDM-managed tag, indicating the MDM system has ownership 046 * of this golden resource's links. 047 * 048 * @param theBaseResource the resource to check. 049 * @return a boolean indicating whether or not MDM manages this FHIR resource. 050 */ 051 public static boolean isMdmManaged(IBaseResource theBaseResource) { 052 return resourceHasTag(theBaseResource, MdmConstants.SYSTEM_MDM_MANAGED, MdmConstants.CODE_HAPI_MDM_MANAGED); 053 } 054 055 public static boolean isGoldenRecord(IBaseResource theBaseResource) { 056 return resourceHasTag( 057 theBaseResource, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD); 058 } 059 060 public static boolean hasGoldenRecordSystemTag(IBaseResource theIBaseResource) { 061 return resourceHasTagWithSystem(theIBaseResource, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS); 062 } 063 064 public static boolean containsTagWithSystem(IBaseResource theBaseResource) { 065 return resourceHasTagWithSystem(theBaseResource, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS); 066 } 067 068 public static boolean isGoldenRecordRedirected(IBaseResource theBaseResource) { 069 return resourceHasTag( 070 theBaseResource, MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, MdmConstants.CODE_GOLDEN_RECORD_REDIRECTED); 071 } 072 073 private static boolean resourceHasTag(IBaseResource theBaseResource, String theSystem, String theCode) { 074 if (theBaseResource == null) { 075 return false; 076 } 077 return theBaseResource.getMeta().getTag(theSystem, theCode) != null; 078 } 079 080 private static boolean resourceHasTagWithSystem(IBaseResource theBaseResource, @Nonnull String theSystem) { 081 if (theBaseResource == null) { 082 return false; 083 } 084 return theBaseResource.getMeta().getTag().stream().anyMatch(tag -> theSystem.equalsIgnoreCase(tag.getSystem())); 085 } 086 087 private static Optional<? extends IBaseCoding> getTagWithSystem( 088 IBaseResource theResource, @Nonnull String theSystem) { 089 return theResource.getMeta().getTag().stream() 090 .filter(tag -> theSystem.equalsIgnoreCase(tag.getSystem())) 091 .findFirst(); 092 } 093 094 public static void removeTagWithSystem(IBaseResource theResource, @Nonnull String theSystem) { 095 theResource.getMeta().getTag().removeIf(tag -> theSystem.equalsIgnoreCase(tag.getSystem())); 096 } 097 098 /** 099 * Sets the MDM-managed tag, indicating the MDM system has ownership of this 100 * Resource. No changes are made if resource is already managed by MDM. 101 * 102 * @param theBaseResource resource to set the tag for 103 * @return Returns resource with the tag set. 104 */ 105 public static IBaseResource setMdmManaged(IBaseResource theBaseResource) { 106 return setTagOnResource( 107 theBaseResource, 108 MdmConstants.SYSTEM_MDM_MANAGED, 109 MdmConstants.CODE_HAPI_MDM_MANAGED, 110 MdmConstants.DISPLAY_HAPI_MDM_MANAGED); 111 } 112 113 public static IBaseResource setGoldenResource(IBaseResource theBaseResource) { 114 return setTagOnResource( 115 theBaseResource, 116 MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, 117 MdmConstants.CODE_GOLDEN_RECORD, 118 MdmConstants.DISPLAY_GOLDEN_RECORD); 119 } 120 121 /** 122 * Sets the provided resource as 'redirected' golden resource. 123 * This is done when a Golden Resource has been deprecated 124 * and is no longer the primary golden resource (for example, 125 * after a merge of 2 golden resources). 126 */ 127 public static IBaseResource setGoldenResourceRedirected(IBaseResource theBaseResource) { 128 return setTagOnResource( 129 theBaseResource, 130 MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS, 131 MdmConstants.CODE_GOLDEN_RECORD_REDIRECTED, 132 MdmConstants.DISPLAY_GOLDEN_REDIRECT); 133 } 134 135 /** 136 * Adds the BLOCKED tag to the golden resource. 137 * Because this is called *before* a resource is saved, 138 * we must add a new system/code combo to it 139 * @param theBaseResource 140 * @return 141 */ 142 public static IBaseResource setGoldenResourceAsBlockedResourceGoldenResource(IBaseResource theBaseResource) { 143 IBaseCoding tag = theBaseResource.getMeta().addTag(); 144 tag.setSystem(MdmConstants.SYSTEM_GOLDEN_RECORD_STATUS); 145 tag.setCode(MdmConstants.CODE_BLOCKED); 146 tag.setDisplay(MdmConstants.CODE_BLOCKED_DISPLAY); 147 tag.setUserSelected(false); 148 tag.setVersion("1"); 149 150 return theBaseResource; 151 } 152 153 /** 154 * WARNING: This code may _look_ like it replaces in place a code of a tag, but this DOES NOT ACTUALLY WORK!. In reality what will 155 * happen is a secondary tag will be created with the same system. the only way to actually remove a tag from a resource 156 * is by calling dao.removeTag(). This logic here is for the case where our representation of the resource still happens to contain 157 * a reference to a tag, to make sure it isn't double-added. 158 */ 159 @Nonnull 160 private static IBaseResource setTagOnResource( 161 IBaseResource theGoldenResource, String theSystem, String theCode, String theDisplay) { 162 Optional<? extends IBaseCoding> tagWithSystem = getTagWithSystem(theGoldenResource, theSystem); 163 if (tagWithSystem.isPresent()) { 164 tagWithSystem.get().setCode(theCode); 165 tagWithSystem.get().setDisplay(theDisplay); 166 } else { 167 IBaseCoding tag = theGoldenResource.getMeta().addTag(); 168 tag.setSystem(theSystem); 169 tag.setCode(theCode); 170 tag.setDisplay(theDisplay); 171 tag.setUserSelected(false); 172 tag.setVersion("1"); 173 } 174 return theGoldenResource; 175 } 176}