001/*- 002 * #%L 003 * Smile CDR - CDR 004 * %% 005 * Copyright (C) 2016 - 2024 Smile CDR, Inc. 006 * %% 007 * All rights reserved. 008 * #L% 009 */ 010package ca.cdr.api.pub.hl7v2.out; 011 012import ca.cdr.api.util.PublicApiConstants; 013import ca.uhn.fhir.context.FhirContext; 014import jakarta.annotation.Nonnull; 015import jakarta.annotation.Nullable; 016import org.apache.commons.lang3.Validate; 017import org.hl7.fhir.instance.model.api.IBaseReference; 018import org.hl7.fhir.instance.model.api.IBaseResource; 019import org.hl7.fhir.instance.model.api.IIdType; 020 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024 025public class OutboundMappingInstructions { 026 027 public static final OutboundMappingInstructions DEFAULT = new OutboundMappingInstructions.Builder().build(); 028 private final Map<IIdType, Long> myUseSourceDataResourceVersions; 029 030 /** 031 * Constructor 032 */ 033 private OutboundMappingInstructions(Map<IIdType, Long> theUseSourceDataResourceVersions) { 034 myUseSourceDataResourceVersions = theUseSourceDataResourceVersions; 035 } 036 037 @Nullable 038 public Long getSourceDataResourceVersion(@Nonnull IIdType theId) { 039 IIdType storageId = theId.toUnqualifiedVersionless(); 040 return myUseSourceDataResourceVersions.get(storageId); 041 } 042 043 /** 044 * Factory class for {@link OutboundMappingInstructions} 045 */ 046 public static class Builder { 047 048 private Map<IIdType, Long> myUseSourceDataResourceVersions; 049 050 /** 051 * When resolving FHIR resources to use as source data for generating HL7 v2.x messages, this method can be 052 * used to specify that a specific version of a given resource should be used. This can be used to achieve 053 * point-in-time architecture with your messages. 054 * 055 * @param theId The complete ID, must include the resource type, resource ID, and version. 056 * @return Returns a reference to the builder for easy method chaining 057 */ 058 public Builder addSourceDataResourceVersion(@Nonnull IIdType theId) { 059 if (!theId.hasResourceType()) { 060 throw new IllegalArgumentException("ID does not have a resource type specified"); 061 } 062 if (!theId.hasIdPart()) { 063 throw new IllegalArgumentException("ID does not have an ID part specified"); 064 } 065 if (!theId.isVersionIdPartValidLong()) { 066 throw new IllegalArgumentException("ID does not have a numeric version specified"); 067 } 068 IIdType storageId = theId.toUnqualifiedVersionless(); 069 if (myUseSourceDataResourceVersions == null) { 070 myUseSourceDataResourceVersions = new HashMap<>(); 071 } 072 myUseSourceDataResourceVersions.put(storageId, theId.getVersionIdPartAsLong()); 073 return this; 074 } 075 076 public OutboundMappingInstructions build() { 077 if (myUseSourceDataResourceVersions == null) { 078 myUseSourceDataResourceVersions = Map.of(); 079 } 080 return new OutboundMappingInstructions(myUseSourceDataResourceVersions); 081 } 082 083 /** 084 * Examine a MessageHeader resource to extract the list of resources found in 085 * <code>MessageHeader.focus</code>, and for any versioned references apply 086 * them to {@link #addSourceDataResourceVersion(IIdType)}. 087 * 088 * @param theMessageHeader The MessageHeader to extract from 089 */ 090 public OutboundMappingInstructions.Builder addSourceDataResourceVersionsFromMessageHeaderFocus( 091 @Nonnull IBaseResource theMessageHeader) { 092 093 FhirContext ctx = FhirContext.forCached(theMessageHeader.getStructureFhirVersionEnum()); 094 String resourceType = ctx.getResourceType(theMessageHeader); 095 Validate.isTrue( 096 resourceType.equals("MessageHeader"), 097 "theMessageHeader must be a MessageHeader resource, found: %s", 098 resourceType); 099 100 List<IBaseReference> focalReferences = ctx.newTerser() 101 .getValues( 102 theMessageHeader, 103 PublicApiConstants.FHIRPATH_MESSAGEHEADER_FOCUS, 104 IBaseReference.class, 105 false); 106 for (IBaseReference next : focalReferences) { 107 IIdType referenceId = next.getReferenceElement(); 108 if (referenceId.hasResourceType() && referenceId.hasIdPart() && referenceId.hasVersionIdPart()) { 109 addSourceDataResourceVersion(referenceId); 110 } 111 } 112 113 return this; 114 } 115 } 116}