
001/*- 002 * #%L 003 * HAPI FHIR - Converter 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.hapi.converters.canonical; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.subscription.SubscriptionConstants; 025import org.hl7.fhir.convertors.factory.VersionConvertorFactory_43_50; 026import org.hl7.fhir.instance.model.api.IBaseResource; 027import org.hl7.fhir.r4.model.Basic; 028import org.hl7.fhir.r4.model.Extension; 029import org.hl7.fhir.r5.model.DateTimeType; 030import org.hl7.fhir.r5.model.Enumerations.PublicationStatus; 031import org.hl7.fhir.r5.model.SubscriptionTopic; 032import org.hl7.fhir.r5.model.SubscriptionTopic.InteractionTrigger; 033import org.hl7.fhir.r5.model.SubscriptionTopic.SubscriptionTopicCanFilterByComponent; 034import org.hl7.fhir.r5.model.SubscriptionTopic.SubscriptionTopicNotificationShapeComponent; 035import org.hl7.fhir.r5.model.SubscriptionTopic.SubscriptionTopicResourceTriggerComponent; 036 037public final class SubscriptionTopicCanonicalizer { 038 private SubscriptionTopicCanonicalizer() {} 039 040 public static SubscriptionTopic canonicalizeTopic(FhirContext theFhirContext, IBaseResource theSubscriptionTopic) { 041 switch (theFhirContext.getVersion().getVersion()) { 042 case R4: 043 if (theSubscriptionTopic instanceof Basic) { 044 return canonicalizeR4BasicTopic((Basic) theSubscriptionTopic); 045 } 046 throw new UnsupportedOperationException( 047 Msg.code(2337) + "Unsupported R4 resource type for subscription topic: " 048 + theSubscriptionTopic.getClass().getSimpleName()); 049 case R4B: 050 return (SubscriptionTopic) VersionConvertorFactory_43_50.convertResource( 051 (org.hl7.fhir.r4b.model.SubscriptionTopic) theSubscriptionTopic); 052 case R5: 053 return (SubscriptionTopic) theSubscriptionTopic; 054 default: 055 throw new UnsupportedOperationException( 056 Msg.code(2651) + "Subscription topics are not supported in FHIR version " 057 + theFhirContext.getVersion().getVersion()); 058 } 059 } 060 061 private static SubscriptionTopic canonicalizeR4BasicTopic(Basic theBasicTopic) { 062 SubscriptionTopic retVal = new SubscriptionTopic(); 063 064 // Basic properties 065 retVal.setId(theBasicTopic.getIdElement().getIdPart()); 066 067 // Extract regular extensions 068 for (Extension extension : theBasicTopic.getExtension()) { 069 String url = extension.getUrl(); 070 071 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_URL.equals(url)) { 072 retVal.setUrl(extension.getValue().primitiveValue()); 073 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_VERSION.equals(url)) { 074 retVal.setVersion(extension.getValue().primitiveValue()); 075 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_NAME.equals(url)) { 076 retVal.setName(extension.getValue().primitiveValue()); 077 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_TITLE.equals(url)) { 078 retVal.setTitle(extension.getValue().primitiveValue()); 079 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_DATE.equals(url)) { 080 retVal.setDateElement(new DateTimeType(extension.getValue().primitiveValue())); 081 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_DESCRIPTION.equals(url)) { 082 retVal.setDescription(extension.getValue().primitiveValue()); 083 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_RESOURCE_TRIGGER.equals(url)) { 084 processResourceTrigger(extension, retVal); 085 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_CAN_FILTER_BY.equals(url)) { 086 processCanFilterBy(extension, retVal); 087 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_NOTIFICATION_SHAPE.equals(url)) { 088 processNotificationShape(extension, retVal); 089 } 090 } 091 092 // Extract modifier extensions (e.g., status) 093 for (Extension extension : theBasicTopic.getModifierExtension()) { 094 String url = extension.getUrl(); 095 096 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_TOPIC_STATUS.equals(url)) { 097 String statusCode = extension.getValue().primitiveValue(); 098 retVal.setStatus(PublicationStatus.fromCode(statusCode)); 099 } 100 } 101 102 return retVal; 103 } 104 105 private static void processResourceTrigger(Extension theExtension, SubscriptionTopic theTopic) { 106 SubscriptionTopicResourceTriggerComponent trigger = new SubscriptionTopicResourceTriggerComponent(); 107 108 for (Extension ext : theExtension.getExtension()) { 109 String url = ext.getUrl(); 110 111 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_DESCRIPTION.equals(url)) { 112 trigger.setDescription(ext.getValue().primitiveValue()); 113 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_RESOURCE.equals(url)) { 114 trigger.setResource(ext.getValue().primitiveValue()); 115 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_SUPPORTED_INTERACTION.equals(url)) { 116 trigger.addSupportedInteraction( 117 InteractionTrigger.fromCode(ext.getValue().primitiveValue())); 118 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_FHIRPATH_CRITERIA.equals(url)) { 119 trigger.setFhirPathCriteria(ext.getValue().primitiveValue()); 120 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_QUERY_CRITERIA.equals(url)) { 121 // Process the queryCriteria extension 122 processQueryCriteria(ext, trigger); 123 } 124 } 125 126 theTopic.addResourceTrigger(trigger); 127 } 128 129 private static void processQueryCriteria( 130 Extension theQueryCriteriaExtension, SubscriptionTopicResourceTriggerComponent theTrigger) { 131 // Create a queryCriteria backbone component for the ResourceTrigger 132 SubscriptionTopic.SubscriptionTopicResourceTriggerQueryCriteriaComponent queryCriteria = 133 new SubscriptionTopic.SubscriptionTopicResourceTriggerQueryCriteriaComponent(); 134 135 // Process each nested extension within the queryCriteria extension 136 for (Extension ext : theQueryCriteriaExtension.getExtension()) { 137 String url = ext.getUrl(); 138 139 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_QUERY_CRITERIA_PREVIOUS.equals(url)) { 140 queryCriteria.setPrevious(ext.getValue().primitiveValue()); 141 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_QUERY_CRITERIA_CURRENT.equals(url)) { 142 queryCriteria.setCurrent(ext.getValue().primitiveValue()); 143 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_QUERY_CRITERIA_REQUIRE_BOTH.equals(url)) { 144 queryCriteria.setRequireBoth(Boolean.parseBoolean(ext.getValue().primitiveValue())); 145 } 146 } 147 148 // Set the queryCriteria component on the trigger 149 theTrigger.setQueryCriteria(queryCriteria); 150 } 151 152 private static void processCanFilterBy(Extension theExtension, SubscriptionTopic theTopic) { 153 SubscriptionTopicCanFilterByComponent filterBy = new SubscriptionTopicCanFilterByComponent(); 154 155 for (Extension ext : theExtension.getExtension()) { 156 String url = ext.getUrl(); 157 158 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_DESCRIPTION.equals(url)) { 159 filterBy.setDescription(ext.getValue().primitiveValue()); 160 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_RESOURCE.equals(url)) { 161 filterBy.setResource(ext.getValue().primitiveValue()); 162 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_FILTER_PARAMETER.equals(url)) { 163 filterBy.setFilterParameter(ext.getValue().primitiveValue()); 164 } 165 } 166 167 theTopic.addCanFilterBy(filterBy); 168 } 169 170 private static void processNotificationShape(Extension theExtension, SubscriptionTopic theTopic) { 171 SubscriptionTopicNotificationShapeComponent shape = new SubscriptionTopicNotificationShapeComponent(); 172 173 for (Extension ext : theExtension.getExtension()) { 174 String url = ext.getUrl(); 175 176 if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_RESOURCE.equals(url)) { 177 shape.setResource(ext.getValue().primitiveValue()); 178 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_INCLUDE.equals(url)) { 179 shape.addInclude(ext.getValue().primitiveValue()); 180 } else if (SubscriptionConstants.SUBSCRIPTION_TOPIC_R4_EXT_REVINCLUDE.equals(url)) { 181 shape.addRevInclude(ext.getValue().primitiveValue()); 182 } 183 } 184 185 theTopic.addNotificationShape(shape); 186 } 187}