Added ability to create a resthook subscription without returning a payload using an HTTP POST for notification
This commit is contained in:
parent
502f58022e
commit
eb2d21ac4b
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -98,11 +98,7 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
|||
}
|
||||
|
||||
protected void validateChannelPayload(Subscription theResource) {
|
||||
if (isBlank(theResource.getChannel().getPayload())) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.payload must be populated for rest-hook subscriptions");
|
||||
}
|
||||
|
||||
if (EncodingEnum.forContentType(theResource.getChannel().getPayload()) == null) {
|
||||
if (!isBlank(theResource.getChannel().getPayload()) && EncodingEnum.forContentType(theResource.getChannel().getPayload()) == null) {
|
||||
throw new UnprocessableEntityException("Invalid value for Subscription.channel.payload: " + theResource.getChannel().getPayload());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,11 +99,7 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
|
|||
}
|
||||
|
||||
protected void validateChannelPayload(Subscription theResource) {
|
||||
if (isBlank(theResource.getChannel().getPayload())) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.payload must be populated for rest-hook subscriptions");
|
||||
}
|
||||
|
||||
if (EncodingEnum.forContentType(theResource.getChannel().getPayload()) == null) {
|
||||
if (!isBlank(theResource.getChannel().getPayload()) && EncodingEnum.forContentType(theResource.getChannel().getPayload()) == null) {
|
||||
throw new UnprocessableEntityException("Invalid value for Subscription.channel.payload: " + theResource.getChannel().getPayload());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,24 +20,26 @@ package ca.uhn.fhir.jpa.subscription.resthook;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.subscription.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.client.api.*;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -54,10 +56,38 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
|
|||
IClientExecutable<?, ?> 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<String, List<String>> params = new HashMap();
|
||||
List<Header> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Observation> 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
|
||||
|
|
Loading…
Reference in New Issue