Fix subscriptions

This commit is contained in:
James 2017-08-13 16:02:35 -04:00
parent be5c5ebecd
commit 04f16294aa
10 changed files with 268 additions and 299 deletions

View File

@ -1077,7 +1077,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType); RuntimeResourceDefinition resourceDef = getContext().getResourceDefinition(theResourceType);
SearchParameterMap paramMap = translateMatchUrl(this, myContext, theMatchUrl, resourceDef); SearchParameterMap paramMap = translateMatchUrl(this, myContext, theMatchUrl, resourceDef);
paramMap.setPersistResults(false); paramMap.setLoadSynchronous(true);
if (paramMap.isEmpty() && paramMap.getLastUpdated() == null) { if (paramMap.isEmpty() && paramMap.getLastUpdated() == null) {
throw new InvalidRequestException("Invalid match URL[" + theMatchUrl + "] - URL has no search parameters"); throw new InvalidRequestException("Invalid match URL[" + theMatchUrl + "] - URL has no search parameters");

View File

@ -20,21 +20,26 @@ package ca.uhn.fhir.jpa.interceptor;
* #L% * #L%
*/ */
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.context.RuntimeResourceDefinition; import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.*; import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter; import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import javax.annotation.PostConstruct;
import java.util.concurrent.*;
public abstract class BaseRestHookSubscriptionInterceptor extends ServerOperationInterceptorAdapter { public abstract class BaseRestHookSubscriptionInterceptor extends ServerOperationInterceptorAdapter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseRestHookSubscriptionInterceptor.class);
protected static final Integer MAX_SUBSCRIPTION_RESULTS = 10000; protected static final Integer MAX_SUBSCRIPTION_RESULTS = 10000;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseRestHookSubscriptionInterceptor.class);
protected ExecutorService myExecutor;
private int myExecutorThreadCount = 1;
protected abstract IFhirResourceDao<?> getSubscriptionDao(); protected abstract IFhirResourceDao<?> getSubscriptionDao();
@ -47,6 +52,18 @@ public abstract class BaseRestHookSubscriptionInterceptor extends ServerOperatio
} }
} }
@PostConstruct
public void postConstruct() {
try {
myExecutor = new ThreadPoolExecutor(myExecutorThreadCount, myExecutorThreadCount,
0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>(1000));
myExecutor = Executors.newFixedThreadPool(myExecutorThreadCount);
} catch (Exception e) {
throw new RuntimeException("Unable to get DAO from PROXY");
}
}
private IBundleProvider executeSubscriptionCriteria(String theCriteria, IIdType idType) { private IBundleProvider executeSubscriptionCriteria(String theCriteria, IIdType idType) {
String criteria = theCriteria; String criteria = theCriteria;

View File

@ -20,25 +20,6 @@ package ca.uhn.fhir.jpa.interceptor;
* #L% * #L%
*/ */
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
@ -49,24 +30,36 @@ import ca.uhn.fhir.model.dstu2.resource.Subscription;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum; import ca.uhn.fhir.model.dstu2.valueset.SubscriptionChannelTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum; import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscriptionInterceptor { public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscriptionInterceptor {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu2Interceptor.class); private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu2Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<>();
@Autowired @Autowired
private FhirContext myFhirContext; private FhirContext myFhirContext;
private boolean myNotifyOnDelete = false; private boolean myNotifyOnDelete = false;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired @Autowired
@Qualifier("mySubscriptionDaoDstu2") @Qualifier("mySubscriptionDaoDstu2")
private IFhirResourceDao<Subscription> mySubscriptionDao; private IFhirResourceDao<Subscription> mySubscriptionDao;
@ -117,14 +110,13 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement()); ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement());
HttpUriRequest request = createRequest(subscription, next, theOperation); HttpUriRequest request = createRequest(subscription, next, theOperation);
if (request != null) { if (request != null) {
executor.submit(new HttpRequestDstu2Job(request, subscription)); myExecutor.submit(new HttpRequestDstu2Job(request, subscription));
} }
} }
} }
} }
/** /**
* Creates an HTTP Post for a subscription * Creates an HTTP Post for a subscription
*/ */
@ -242,6 +234,10 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
return mySubscriptionDao; return mySubscriptionDao;
} }
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override @Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) { public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// check the subscription criteria to see if its valid before creating or updating a subscription // check the subscription criteria to see if its valid before creating or updating a subscription
@ -286,6 +282,10 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
return myNotifyOnDelete; return myNotifyOnDelete;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.myNotifyOnDelete = notifyOnDelete;
}
/** /**
* Subclasses may override * Subclasses may override
*/ */
@ -293,15 +293,6 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
return theCriteria; return theCriteria;
} }
@PostConstruct
public void postConstruct() {
try {
executor = Executors.newFixedThreadPool(MAX_THREADS);
} catch (Exception e) {
throw new RuntimeException("Unable to get DAO from PROXY");
}
}
/** /**
* Remove subscription from cache * Remove subscription from cache
* *
@ -345,14 +336,11 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
/** /**
* Check subscriptions to see if there is a matching subscription when there is delete * Check subscriptions to see if there is a matching subscription when there is delete
* *
* @param theRequest * @param theRequest A bean containing details about the request that is about to be processed, including details such as the
* A bean containing details about the request that is about to be processed, including details such as the
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
* pulled out of the {@link HttpServletRequest servlet request}. * pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest * @param theRequest The incoming request
* The incoming request * @param theResource The response. Note that interceptors may choose to provide a response (i.e. by calling
* @param theResource
* The response. Note that interceptors may choose to provide a response (i.e. by calling
* {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code> * {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code>
* to indicate that the server itself should not also provide a response. * to indicate that the server itself should not also provide a response.
*/ */
@ -401,12 +389,4 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
myFhirContext = theFhirContext; myFhirContext = theFhirContext;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.myNotifyOnDelete = notifyOnDelete;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
} }

View File

@ -1,4 +1,3 @@
package ca.uhn.fhir.jpa.interceptor; package ca.uhn.fhir.jpa.interceptor;
/*- /*-
@ -21,47 +20,42 @@ package ca.uhn.fhir.jpa.interceptor;
* #L% * #L%
*/ */
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.dstu3.model.Subscription;
import org.hl7.fhir.instance.model.api.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.thread.HttpRequestDstu3Job; import ca.uhn.fhir.jpa.thread.HttpRequestDstu3Job;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.dstu3.model.Subscription;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscriptionInterceptor { public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscriptionInterceptor {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu3Interceptor.class); private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu3Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired @Autowired
private FhirContext myFhirContext; private FhirContext myFhirContext;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired @Autowired
@Qualifier("mySubscriptionDaoDstu3") @Qualifier("mySubscriptionDaoDstu3")
private IFhirResourceDao<Subscription> mySubscriptionDao; private IFhirResourceDao<Subscription> mySubscriptionDao;
@ -114,7 +108,7 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement()); ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement());
HttpUriRequest request = createRequest(subscription, next, theOperation); HttpUriRequest request = createRequest(subscription, next, theOperation);
if (request != null) { if (request != null) {
executor.submit(new HttpRequestDstu3Job(request, subscription)); myExecutor.submit(new HttpRequestDstu3Job(request, subscription));
} }
} }
} }
@ -230,6 +224,10 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
return mySubscriptionDao; return mySubscriptionDao;
} }
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override @Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) { public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// check the subscription criteria to see if its valid before creating or updating a subscription // check the subscription criteria to see if its valid before creating or updating a subscription
@ -274,6 +272,10 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
return notifyOnDelete; return notifyOnDelete;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
/** /**
* Subclasses may override * Subclasses may override
*/ */
@ -281,15 +283,6 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
return theCriteria; return theCriteria;
} }
@PostConstruct
public void postConstruct() {
try {
executor = Executors.newFixedThreadPool(MAX_THREADS);
} catch (Exception e) {
throw new RuntimeException("Unable to get DAO from PROXY");
}
}
/** /**
* Remove subscription from cache * Remove subscription from cache
* *
@ -333,14 +326,11 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
/** /**
* Check subscriptions to see if there is a matching subscription when there is a delete * Check subscriptions to see if there is a matching subscription when there is a delete
* *
* @param theRequest * @param theRequest A bean containing details about the request that is about to be processed, including details such as the
* A bean containing details about the request that is about to be processed, including details such as the
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
* pulled out of the {@link HttpServletRequest servlet request}. * pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest * @param theRequest The incoming request
* The incoming request * @param theResource The response. Note that interceptors may choose to provide a response (i.e. by calling
* @param theResource
* The response. Note that interceptors may choose to provide a response (i.e. by calling
* {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code> * {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code>
* to indicate that the server itself should not also provide a response. * to indicate that the server itself should not also provide a response.
*/ */
@ -389,12 +379,4 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
myFhirContext = theFhirContext; myFhirContext = theFhirContext;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
} }

View File

@ -1,4 +1,3 @@
package ca.uhn.fhir.jpa.interceptor.r4; package ca.uhn.fhir.jpa.interceptor.r4;
/*- /*-
@ -21,48 +20,43 @@ package ca.uhn.fhir.jpa.interceptor.r4;
* #L% * #L%
*/ */
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.*;
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.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap; import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.interceptor.BaseRestHookSubscriptionInterceptor; import ca.uhn.fhir.jpa.interceptor.BaseRestHookSubscriptionInterceptor;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails; import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.thread.HttpRequestR4Job; import ca.uhn.fhir.jpa.thread.HttpRequestR4Job;
import ca.uhn.fhir.rest.api.*; import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.param.TokenParam;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
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.beans.factory.annotation.Qualifier;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionInterceptor { public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionInterceptor {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionR4Interceptor.class); private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionR4Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired @Autowired
private FhirContext myFhirContext; private FhirContext myFhirContext;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired @Autowired
@Qualifier("mySubscriptionDaoR4") @Qualifier("mySubscriptionDaoR4")
private IFhirResourceDao<Subscription> mySubscriptionDao; private IFhirResourceDao<Subscription> mySubscriptionDao;
@ -109,7 +103,7 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement()); ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement());
HttpUriRequest request = createRequest(subscription, next, theOperation); HttpUriRequest request = createRequest(subscription, next, theOperation);
if (request != null) { if (request != null) {
executor.submit(new HttpRequestR4Job(request, subscription)); myExecutor.submit(new HttpRequestR4Job(request, subscription));
} }
} }
} }
@ -225,6 +219,10 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
return mySubscriptionDao; return mySubscriptionDao;
} }
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override @Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) { public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// check the subscription criteria to see if its valid before creating or updating a subscription // check the subscription criteria to see if its valid before creating or updating a subscription
@ -269,6 +267,10 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
return notifyOnDelete; return notifyOnDelete;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
/** /**
* Subclasses may override * Subclasses may override
*/ */
@ -276,15 +278,6 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
return theCriteria; return theCriteria;
} }
@PostConstruct
public void postConstruct() {
try {
executor = Executors.newFixedThreadPool(MAX_THREADS);
} catch (Exception e) {
throw new RuntimeException("Unable to get DAO from PROXY");
}
}
/** /**
* Remove subscription from cache * Remove subscription from cache
* *
@ -328,14 +321,11 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
/** /**
* Check subscriptions to see if there is a matching subscription when there is a delete * Check subscriptions to see if there is a matching subscription when there is a delete
* *
* @param theRequest * @param theRequest A bean containing details about the request that is about to be processed, including details such as the
* A bean containing details about the request that is about to be processed, including details such as the
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been * resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
* pulled out of the {@link HttpServletRequest servlet request}. * pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest * @param theRequest The incoming request
* The incoming request * @param theResource The response. Note that interceptors may choose to provide a response (i.e. by calling
* @param theResource
* The response. Note that interceptors may choose to provide a response (i.e. by calling
* {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code> * {@link HttpServletResponse#getWriter()}) but in that case it is important to return <code>false</code>
* to indicate that the server itself should not also provide a response. * to indicate that the server itself should not also provide a response.
*/ */
@ -384,12 +374,4 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
myFhirContext = theFhirContext; myFhirContext = theFhirContext;
} }
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
} }

View File

@ -1,30 +1,10 @@
package ca.uhn.fhir.jpa.provider; package ca.uhn.fhir.jpa.provider;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.*;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import ca.uhn.fhir.jpa.config.WebsocketDstu2Config; import ca.uhn.fhir.jpa.config.WebsocketDstu2Config;
import ca.uhn.fhir.jpa.config.WebsocketDstu2DispatcherConfig; import ca.uhn.fhir.jpa.config.WebsocketDstu2DispatcherConfig;
import ca.uhn.fhir.jpa.dao.dstu2.BaseJpaDstu2Test; import ca.uhn.fhir.jpa.dao.dstu2.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.interceptor.RestHookSubscriptionDstu2Interceptor; import ca.uhn.fhir.jpa.interceptor.RestHookSubscriptionDstu2Interceptor;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.dstu2.resource.Bundle; import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry; import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.model.dstu2.resource.Patient;
@ -35,6 +15,27 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.springframework.web.context.ContextLoader;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static ca.uhn.fhir.jpa.testutil.RandomServerPortProvider.findFreePort;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test { public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test {
@ -65,7 +66,7 @@ public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test {
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
if (ourServer == null) { if (ourServer == null) {
ourPort = RandomServerPortProvider.findFreePort(); ourPort = findFreePort();
ourRestServer = new RestfulServer(myFhirCtx); ourRestServer = new RestfulServer(myFhirCtx);

View File

@ -5,6 +5,8 @@ import static org.junit.Assert.assertEquals;
import java.util.List; import java.util.List;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.util.BundleUtil;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler; import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder; import org.eclipse.jetty.servlet.ServletHolder;
@ -55,10 +57,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
public void afterUnregisterRestHookListener() { public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
ourLog.info("Deleting all subscriptions"); ourLog.info("Deleting all subscriptions");
ourClient.delete().resourceConditionalByUrl("Subscription?status=requested").execute();// TODO: this shouldn't be neccesary
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute(); ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
ourLog.info("Done deleting all subscriptions"); ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete()); myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor); myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
} }
@ -71,12 +73,18 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
public void beforeReset() { public void beforeReset() {
ourCreatedObservations.clear(); ourCreatedObservations.clear();
ourUpdatedObservations.clear(); ourUpdatedObservations.clear();
myDaoConfig.setAllowMultipleDelete(true);
for (IBaseResource next : BundleUtil.toListOfResources(myFhirCtx, ourClient.search().forResource("Subscription").returnBundle(Bundle.class).execute())) {
ourClient.delete().resource(next).execute();
}
ourClient.delete().resourceConditionalByUrl("Subscription?type=rest-hook").execute();
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
} }
private Subscription createSubscription(String criteria, String payload, String endpoint) { private Subscription createSubscription(String criteria, String payload, String endpoint) {
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(SubscriptionStatusEnum.ACTIVE); subscription.setStatus(SubscriptionStatusEnum.REQUESTED);
subscription.setCriteria(criteria); subscription.setCriteria(criteria);
Channel channel = new Channel(); Channel channel = new Channel();
@ -138,7 +146,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see two subscription notifications // Should see two subscription notifications
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
@ -147,7 +155,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -160,7 +168,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -174,7 +182,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -209,9 +217,9 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
Observation observation2 = sendObservation(code, "SNOMED-CT"); Observation observation2 = sendObservation(code, "SNOMED-CT");
// Should see two subscription notifications // Should see one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
@ -220,7 +228,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -233,7 +241,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -247,7 +255,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -46,10 +46,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
public void afterUnregisterRestHookListener() { public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
ourLog.info("Deleting all subscriptions"); ourLog.info("Deleting all subscriptions");
ourClient.delete().resourceConditionalByUrl("Subscription?status=requested").execute();// TODO: this shouldn't be neccesary
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute(); ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
ourLog.info("Done deleting all subscriptions"); ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete()); myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor); myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
} }
@ -67,7 +67,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
private Subscription createSubscription(String criteria, String payload, String endpoint) { private Subscription createSubscription(String criteria, String payload, String endpoint) {
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE); subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
subscription.setCriteria(criteria); subscription.setCriteria(criteria);
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent(); Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
@ -129,7 +129,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see two subscription notifications // Should see two subscription notifications
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -138,7 +138,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -151,7 +151,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -165,7 +165,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -202,7 +202,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see two subscription notifications // Should see two subscription notifications
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -211,7 +211,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -224,7 +224,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -238,7 +238,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -1,40 +1,39 @@
package ca.uhn.fhir.jpa.subscription.r4; package ca.uhn.fhir.jpa.subscription.r4;
import static org.junit.Assert.*;
import java.util.List;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.r4.model.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.*;
import com.google.common.collect.Lists;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test; import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider; import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
import ca.uhn.fhir.model.primitive.IdDt; import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.*; import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import com.google.common.collect.Lists;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.r4.model.*;
import org.junit.*;
import java.util.List;
import static org.junit.Assert.assertEquals;
/** /**
* Test the rest-hook subscriptions * Test the rest-hook subscriptions
*/ */
public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends BaseResourceProviderR4Test { public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends BaseResourceProviderR4Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
private static List<Observation> ourCreatedObservations = Lists.newArrayList(); private static List<Observation> ourCreatedObservations = Lists.newArrayList();
private static int ourListenerPort; private static int ourListenerPort;
private static RestfulServer ourListenerRestServer; private static RestfulServer ourListenerRestServer;
private static Server ourListenerServer; private static Server ourListenerServer;
private static String ourListenerServerBase; private static String ourListenerServerBase;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
private static List<Observation> ourUpdatedObservations = Lists.newArrayList(); private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
@Override @Override
@ -46,10 +45,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
public void afterUnregisterRestHookListener() { public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true); myDaoConfig.setAllowMultipleDelete(true);
ourLog.info("Deleting all subscriptions"); ourLog.info("Deleting all subscriptions");
ourClient.delete().resourceConditionalByUrl("Subscription?status=requested").execute();// TODO: this shouldn't be neccesary
ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute(); ourClient.delete().resourceConditionalByUrl("Subscription?status=active").execute();
ourLog.info("Done deleting all subscriptions"); ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete()); myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor); myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
} }
@ -67,7 +66,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
private Subscription createSubscription(String criteria, String payload, String endpoint) { private Subscription createSubscription(String criteria, String payload, String endpoint) {
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE); subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
subscription.setCriteria(criteria); subscription.setCriteria(criteria);
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent(); Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
@ -129,7 +128,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see two subscription notifications // Should see two subscription notifications
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -138,7 +137,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -151,7 +150,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -165,7 +164,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -202,7 +201,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see two subscription notifications // Should see two subscription notifications
Thread.sleep(500); Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size()); assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute(); ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -211,7 +210,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -224,7 +223,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see no subscription notification // Should see no subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size()); assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId()); Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -238,7 +237,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification // Should see only one subscription notification
Thread.sleep(500); Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size()); assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size()); assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId())); Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -6,7 +6,23 @@
<title>HAPI FHIR Changelog</title> <title>HAPI FHIR Changelog</title>
</properties> </properties>
<body> <body>
<release version="3.0" date="TBD"> <release version="3.0.0" date="TBD">
<action type="add">
<![CDATA[
<ul>
<li>AddProfileTagEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>IVersionSpecificBundleFactory moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>BundleInclusionRule moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>RestSearchParameterTypeEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>EncodingEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>Constants moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>IClientInterceptor moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>IGenericClient moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>IRestfulClient moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>ITestingUiClientFactory moved from package ca.uhn.fhir.util to package ca.uhn.fhir.rest.server.util</li>
</ul>
]]>
</action>
<action type="add"> <action type="add">
Bump the version of a few dependencies to the Bump the version of a few dependencies to the
latest versions (dependent HAPI modules listed in brackets): latest versions (dependent HAPI modules listed in brackets):
@ -46,22 +62,6 @@
FHIR DSTU2. The presence of these headers sometimes caused parsed resource instances FHIR DSTU2. The presence of these headers sometimes caused parsed resource instances
to contain duplicate tags to contain duplicate tags
</action> </action>
</release>
<release version="2.6" date="TBD">
<action type="add">
<ul>
<li>AddProfileTagEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>IVersionSpecificBundleFactory moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>BundleInclusionRule moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.context.api</li>
<li>RestSearchParameterTypeEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>EncodingEnum moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>Constants moved from package ca.uhn.fhir.rest.server to package ca.uhn.fhir.rest.api</li>
<li>IClientInterceptor moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>IGenericClient moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>IRestfulClient moved from package ca.uhn.fhir.rest.client to package ca.uhn.fhir.rest.client.api</li>
<li>ITestingUiClientFactory moved from package ca.uhn.fhir.util to package ca.uhn.fhir.rest.server.util</li>
</ul>
</action>
<action type="fix" issue="667"> <action type="fix" issue="667">
When using the AuthorizationInterceptor with the JPA server, when a client is updating a resource When using the AuthorizationInterceptor with the JPA server, when a client is updating a resource
from A to B, the user now needs to have write permission for both A and B. This is particularly from A to B, the user now needs to have write permission for both A and B. This is particularly
@ -254,7 +254,7 @@
<![CDATA[<code>Bundle.entry.response.outcome</code>]]> <![CDATA[<code>Bundle.entry.response.outcome</code>]]>
instead of the previous instead of the previous
<![CDATA[<code>Bundle.entry.resource</code>]]> <![CDATA[<code>Bundle.entry.resource</code>]]>
<action> </action>
<action type="fix" issue="696"> <action type="fix" issue="696">
An issue was corrected where search parameters containing negative numbers An issue was corrected where search parameters containing negative numbers
were sometimes treated as positive numbers when processing the search. Thanks were sometimes treated as positive numbers when processing the search. Thanks