From eb2d21ac4bff0c999fd3e55a4e26e753b793da85 Mon Sep 17 00:00:00 2001 From: Jeff Chung Date: Fri, 22 Dec 2017 17:14:45 -0800 Subject: [PATCH] Added ability to create a resthook subscription without returning a payload using an HTTP POST for notification --- .../fhir/rest/client/impl/GenericClient.java | 4 +- .../FhirResourceDaoSubscriptionDstu3.java | 6 +- .../dao/r4/FhirResourceDaoSubscriptionR4.java | 6 +- ...scriptionDeliveringRestHookSubscriber.java | 90 +++++++++++++++---- .../subscription/RestHookTestDstu3Test.java | 21 ++++- 5 files changed, 98 insertions(+), 29 deletions(-) diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java index 1432d8c5a00..733e3ac27b4 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java @@ -2105,14 +2105,14 @@ public class GenericClient extends BaseClient implements IGenericClient { @Override public IUpdateTyped resource(IBaseResource theResource) { - Validate.notNull(theResource, "Resource can not be null"); + //Validate.notNull(theResource, "Resource can not be null"); myResource = theResource; return this; } @Override public IUpdateTyped resource(String theResourceBody) { - Validate.notBlank(theResourceBody, "Body can not be null or blank"); + //Validate.notBlank(theResourceBody, "Body can not be null or blank"); myResourceBody = theResourceBody; return this; } diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSubscriptionDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSubscriptionDstu3.java index 1cd47153f03..d55f77978ce 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSubscriptionDstu3.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoSubscriptionDstu3.java @@ -98,11 +98,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3 operation; switch (theMsg.getOperationType()) { case CREATE: - operation = theClient.update().resource(payloadResource); + if (payloadResource == null || payloadResource.isEmpty()) { + if (thePayloadType != null ) { + operation = theClient.create().resource(payloadResource); + } else { + sendNotification(theMsg); + return; + } + } else { + if (thePayloadType != null ) { + operation = theClient.update().resource(payloadResource); + } else { + sendNotification(theMsg); + return; + } + } break; case UPDATE: - operation = theClient.update().resource(payloadResource); + if (payloadResource == null || payloadResource.isEmpty()) { + if (thePayloadType != null ) { + operation = theClient.create().resource(payloadResource); + } else { + sendNotification(theMsg); + return; + } + } else { + if (thePayloadType != null ) { + operation = theClient.update().resource(payloadResource); + } else { + sendNotification(theMsg); + return; + } + } break; case DELETE: operation = theClient.delete().resourceById(theMsg.getPayloadId(getContext())); @@ -67,11 +97,19 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe return; } - operation.encoded(thePayloadType); + if (thePayloadType != null) { + operation.encoded(thePayloadType); + } ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), payloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue()); - operation.execute(); + try { + operation.execute(); + } catch (ResourceNotFoundException e) { + ourLog.error("Cannot reach "+ theMsg.getSubscription().getEndpointUrl()); + e.printStackTrace(); + throw e; + } } @Override @@ -83,13 +121,14 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe // Grab the payload type (encoding mimetype) from the subscription String payloadString = subscription.getPayloadString(); - payloadString = StringUtils.defaultString(payloadString, Constants.CT_FHIR_XML_NEW); - if (payloadString.contains(";")) { - payloadString = payloadString.substring(0, payloadString.indexOf(';')); + EncodingEnum payloadType = null; + if(payloadString != null) { + if (payloadString.contains(";")) { + payloadString = payloadString.substring(0, payloadString.indexOf(';')); + } + payloadString = payloadString.trim(); + payloadType = EncodingEnum.forContentType(payloadString); } - payloadString = payloadString.trim(); - EncodingEnum payloadType = EncodingEnum.forContentType(payloadString); - payloadType = ObjectUtils.defaultIfNull(payloadType, EncodingEnum.XML); // Create the client request getContext().getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); @@ -109,4 +148,23 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe deliverPayload(theMessage, subscription, payloadType, client); } + /** + * Sends a POST notification without a payload + * @param theMsg + */ + protected void sendNotification(ResourceDeliveryMessage theMsg) { + FhirContext context= getContext(); + Map> params = new HashMap(); + List
headers = new ArrayList<>(); + StringBuilder url = new StringBuilder(theMsg.getSubscription().getEndpointUrl()); + IHttpClient client = context.getRestfulClientFactory().getHttpClient(url, params, "", RequestTypeEnum.POST, headers); + IHttpRequest request = client.createParamRequest(context, params, null); + try { + IHttpResponse response = request.execute(); + } catch (IOException e) { + ourLog.error("Error trying to reach "+ theMsg.getSubscription().getEndpointUrl()); + e.printStackTrace(); + throw new ResourceNotFoundException(e.getMessage()); + } + } } diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/RestHookTestDstu3Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/RestHookTestDstu3Test.java index f6c75c605b4..ee96aefb4f4 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/RestHookTestDstu3Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/RestHookTestDstu3Test.java @@ -34,7 +34,7 @@ import static org.junit.Assert.fail; */ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test { - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu2Test.class); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestDstu3Test.class); private static List ourCreatedObservations = Lists.newArrayList(); private static int ourListenerPort; private static RestfulServer ourListenerRestServer; @@ -311,6 +311,25 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test { assertEquals(Constants.CT_FHIR_XML_NEW, ourContentTypes.get(0)); } + @Test + public void testRestHookSubscriptionWithoutPayload() throws Exception { + String payload = ""; + + String code = "1000000050"; + String criteria1 = "Observation?code=SNOMED-CT|" + code; + String criteria2 = "Observation?code=SNOMED-CT|" + code + "111"; + + Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase); + Subscription subscription2 = createSubscription(criteria2, payload, ourListenerServerBase); + + Observation observation1 = sendObservation(code, "SNOMED-CT"); + + // Should see 1 subscription notification, but no payload + waitForQueueToDrain(); + waitForSize(0, ourCreatedObservations); + waitForSize(0, ourUpdatedObservations); + } + // TODO: Reenable this @Test @Ignore