diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingInterceptor.java index be42fcfc369..19b6e3ba1c1 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingInterceptor.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/subscription/SubscriptionActivatingInterceptor.java @@ -30,7 +30,7 @@ import ca.uhn.fhir.jpa.search.warm.CacheWarmingSvcImpl; import ca.uhn.fhir.jpa.searchparam.MatchUrlService; import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription; import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage; -import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCannonicalizer; +import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer; import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry; import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum; import ca.uhn.fhir.rest.api.server.RequestDetails; @@ -87,7 +87,7 @@ public class SubscriptionActivatingInterceptor extends ServerOperationIntercepto @Autowired private FhirContext myFhirContext; @Autowired - private SubscriptionCannonicalizer mySubscriptionCannonicalizer; + private SubscriptionCanonicalizer mySubscriptionCanonicalizer; @Autowired private MatchUrlService myMatchUrlService; @Autowired @@ -220,7 +220,7 @@ public class SubscriptionActivatingInterceptor extends ServerOperationIntercepto } public void validateCriteria(final IBaseResource theResource) { - CanonicalSubscription subscription = mySubscriptionCannonicalizer.canonicalize(theResource); + CanonicalSubscription subscription = mySubscriptionCanonicalizer.canonicalize(theResource); String criteria = subscription.getCriteriaString(); try { RuntimeResourceDefinition resourceDef = CacheWarmingSvcImpl.parseUrlResourceType(myFhirContext, criteria); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/CanonicalSubscription.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/CanonicalSubscription.java index 03f0401395d..854f20e1acf 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/CanonicalSubscription.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/CanonicalSubscription.java @@ -32,8 +32,7 @@ import org.hl7.fhir.r4.model.EventDefinition; import org.hl7.fhir.r4.model.Subscription; import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; +import java.util.*; import static org.apache.commons.lang3.StringUtils.isNotBlank; @@ -63,6 +62,8 @@ public class CanonicalSubscription implements Serializable { private EmailDetails myEmailDetails; @JsonProperty("restHookDetails") private RestHookDetails myRestHookDetails; + @JsonProperty("extensions") + private Map myChannelExtensions; /** * For now we're using the R4 TriggerDefinition, but this @@ -105,7 +106,7 @@ public class CanonicalSubscription implements Serializable { } public List getHeaders() { - return myHeaders; + return Collections.unmodifiableList(myHeaders); } public void setHeaders(List> theHeader) { @@ -124,6 +125,19 @@ public class CanonicalSubscription implements Serializable { } } + public Map getChannelExtensions() { + return Collections.unmodifiableMap(myChannelExtensions); + } + + public void setChannelExtensions(Map theChannelExtensions) { + myChannelExtensions = new HashMap<>(); + for (String url: theChannelExtensions.keySet()) { + if (isNotBlank(url) && isNotBlank(theChannelExtensions.get(url))) { + myChannelExtensions.put(url, theChannelExtensions.get(url)); + } + } + } + public IIdType getIdElement(FhirContext theContext) { IIdType retVal = null; if (isNotBlank(myIdElement)) { diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCannonicalizer.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCanonicalizer.java similarity index 67% rename from hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCannonicalizer.java rename to hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCanonicalizer.java index b04e2521d02..d8661af2127 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCannonicalizer.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionCanonicalizer.java @@ -9,9 +9,9 @@ package ca.uhn.fhir.jpa.subscription.module.cache; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -24,20 +24,29 @@ import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription; import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscriptionChannelType; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.api.IPrimitiveDatatype; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.instance.model.api.IBaseReference; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Extension; -import org.hl7.fhir.r4.model.Subscription; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import static org.apache.commons.lang3.StringUtils.isNotBlank; @Service -public class SubscriptionCannonicalizer { +public class SubscriptionCanonicalizer { + private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionCanonicalizer.class); + @Autowired FhirContext myFhirContext; @@ -64,6 +73,7 @@ public class SubscriptionCannonicalizer { retVal.setCriteriaString(subscription.getCriteria()); retVal.setEndpointUrl(subscription.getChannel().getEndpoint()); retVal.setHeaders(subscription.getChannel().getHeader()); + retVal.setChannelExtensions(convertChannelExtensionsDstu2(subscription)); retVal.setIdElement(subscription.getIdElement()); retVal.setPayloadString(subscription.getChannel().getPayload()); } catch (FHIRException theE) { @@ -82,6 +92,7 @@ public class SubscriptionCannonicalizer { retVal.setCriteriaString(subscription.getCriteria()); retVal.setEndpointUrl(subscription.getChannel().getEndpoint()); retVal.setHeaders(subscription.getChannel().getHeader()); + retVal.setChannelExtensions(convertChannelExtensionsDstu3(subscription)); retVal.setIdElement(subscription.getIdElement()); retVal.setPayloadString(subscription.getChannel().getPayload()); @@ -118,6 +129,87 @@ public class SubscriptionCannonicalizer { return retVal; } + private Map convertChannelExtensionsDstu2(ca.uhn.fhir.model.dstu2.resource.Subscription theSubscription) { + Map retval = new HashMap<>(); + for (ExtensionDt extension : theSubscription.getChannel().getUndeclaredExtensions()) { + String url = extension.getUrl(); + if (isNotBlank(url)) { + String value = extractExtension(theSubscription, url); + if (isNotBlank(value)) { + retval.put(url, value); + } + } + } + return retval; + } + + private Map convertChannelExtensionsDstu3(org.hl7.fhir.dstu3.model.Subscription theSubscription) { + Map retval = new HashMap<>(); + for (org.hl7.fhir.dstu3.model.Extension extension : theSubscription.getChannel().getExtension()) { + String url = extension.getUrl(); + if (isNotBlank(url)) { + String value = extractExtension(theSubscription, url); + if (isNotBlank(value)) { + retval.put(url, value); + } + } + } + return retval; + } + + private Map convertChannelExtensionsR4(org.hl7.fhir.r4.model.Subscription theSubscription) { + Map retval = new HashMap<>(); + for (org.hl7.fhir.r4.model.Extension extension : theSubscription.getChannel().getExtension()) { + String url = extension.getUrl(); + if (isNotBlank(url)) { + String value = extractExtension(theSubscription, url); + if (isNotBlank(value)) { + retval.put(url, value); + } + } + } + return retval; + } + + + private String extractExtension(IBaseResource theSubscription, String theUrl) { + try { + switch (theSubscription.getStructureFhirVersionEnum()) { + case DSTU2: { + ca.uhn.fhir.model.dstu2.resource.Subscription subscription = (ca.uhn.fhir.model.dstu2.resource.Subscription) theSubscription; + List extensions = subscription.getChannel().getUndeclaredExtensionsByUrl(theUrl); + if (extensions.size() == 0) { + return null; + } + if (extensions.size() > 1) { + throw new FHIRException("Multiple matching extensions found"); + } + if (!(extensions.get(0).getValue() instanceof IPrimitiveDatatype)) { + throw new FHIRException("Extension could not be converted to a string"); + } + return ((IPrimitiveDatatype) extensions.get(0).getValue()).getValueAsString(); + } + case DSTU3: { + org.hl7.fhir.dstu3.model.Subscription subscription = (org.hl7.fhir.dstu3.model.Subscription) theSubscription; + return subscription.getChannel().getExtensionString(theUrl); + } + case R4: { + org.hl7.fhir.r4.model.Subscription subscription = (org.hl7.fhir.r4.model.Subscription) theSubscription; + return subscription.getChannel().getExtensionString(theUrl); + } + case DSTU2_HL7ORG: + case DSTU2_1: + default: { + ourLog.error("Failed to extract extension with URL {} from subscription {}", theUrl, theSubscription.getIdElement().toUnqualified().getValue()); + break; + } + } + } catch (FHIRException theE) { + ourLog.error("Failed to extract extension with URL {} from subscription {}", theUrl, theSubscription.getIdElement().toUnqualified().getValue(), theE); + } + return null; + } + protected CanonicalSubscription canonicalizeR4(IBaseResource theSubscription) { org.hl7.fhir.r4.model.Subscription subscription = (org.hl7.fhir.r4.model.Subscription) theSubscription; @@ -127,6 +219,7 @@ public class SubscriptionCannonicalizer { retVal.setCriteriaString(subscription.getCriteria()); retVal.setEndpointUrl(subscription.getChannel().getEndpoint()); retVal.setHeaders(subscription.getChannel().getHeader()); + retVal.setChannelExtensions(convertChannelExtensionsR4(subscription)); retVal.setIdElement(subscription.getIdElement()); retVal.setPayloadString(subscription.getChannel().getPayload()); diff --git a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionRegistry.java b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionRegistry.java index 93ee15737bb..8c55ad2d924 100644 --- a/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionRegistry.java +++ b/hapi-fhir-jpaserver-subscription/src/main/java/ca/uhn/fhir/jpa/subscription/module/cache/SubscriptionRegistry.java @@ -47,7 +47,7 @@ public class SubscriptionRegistry { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionRegistry.class); @Autowired - SubscriptionCannonicalizer mySubscriptionCanonicalizer; + SubscriptionCanonicalizer mySubscriptionCanonicalizer; @Autowired SubscriptionDeliveryHandlerFactory mySubscriptionDeliveryHandlerFactory; @Autowired