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);
SearchParameterMap paramMap = translateMatchUrl(this, myContext, theMatchUrl, resourceDef);
paramMap.setPersistResults(false);
paramMap.setLoadSynchronous(true);
if (paramMap.isEmpty() && paramMap.getLastUpdated() == null) {
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%
*/
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.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.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
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 {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseRestHookSubscriptionInterceptor.class);
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();
@ -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) {
String criteria = theCriteria;
@ -64,7 +81,7 @@ public abstract class BaseRestHookSubscriptionInterceptor extends ServerOperatio
/**
* Search based on a query criteria
*
*
* @param theCheckOnly Is this just a test that the search works
*/
protected IBundleProvider getBundleProvider(String theCriteria, boolean theCheckOnly) {
@ -75,13 +92,13 @@ public abstract class BaseRestHookSubscriptionInterceptor extends ServerOperatio
req.setSubRequest(true);
IFhirResourceDao<? extends IBaseResource> responseDao = getSubscriptionDao().getDao(responseResourceDef.getImplementingClass());
if (theCheckOnly) {
responseCriteriaUrl.setLoadSynchronousUpTo(1);
} else {
responseCriteriaUrl.setLoadSynchronousUpTo(MAX_SUBSCRIPTION_RESULTS);
}
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
return responseResults;
}

View File

@ -20,25 +20,6 @@ package ca.uhn.fhir.jpa.interceptor;
* #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.jpa.dao.IFhirResourceDao;
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.SubscriptionStatusEnum;
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.RequestDetails;
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 {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu2Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<>();
@Autowired
private FhirContext myFhirContext;
private boolean myNotifyOnDelete = false;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired
@Qualifier("mySubscriptionDaoDstu2")
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());
HttpUriRequest request = createRequest(subscription, next, theOperation);
if (request != null) {
executor.submit(new HttpRequestDstu2Job(request, subscription));
myExecutor.submit(new HttpRequestDstu2Job(request, subscription));
}
}
}
}
/**
* Creates an HTTP Post for a subscription
*/
@ -242,6 +234,10 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
return mySubscriptionDao;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// 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;
}
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.myNotifyOnDelete = notifyOnDelete;
}
/**
* Subclasses may override
*/
@ -293,15 +293,6 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
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
*
@ -330,8 +321,8 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
if (theResource instanceof Subscription) {
Subscription subscription = (Subscription) theResource;
if (subscription.getChannel() != null
&& subscription.getChannel().getTypeElement().getValueAsEnum() == SubscriptionChannelTypeEnum.REST_HOOK
&& subscription.getStatusElement().getValueAsEnum() == SubscriptionStatusEnum.REQUESTED) {
&& subscription.getChannel().getTypeElement().getValueAsEnum() == SubscriptionChannelTypeEnum.REST_HOOK
&& subscription.getStatusElement().getValueAsEnum() == SubscriptionStatusEnum.REQUESTED) {
removeLocalSubscription(subscription.getIdElement().getIdPart());
subscription.setStatus(SubscriptionStatusEnum.ACTIVE);
myRestHookSubscriptions.add(subscription);
@ -345,16 +336,13 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
/**
* Check subscriptions to see if there is a matching subscription when there is delete
*
* @param theRequest
* 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest
* The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
* @param theRequest 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
*/
@Override
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
@ -401,12 +389,4 @@ public class RestHookSubscriptionDstu2Interceptor extends BaseRestHookSubscripti
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;
/*-
@ -21,47 +20,42 @@ package ca.uhn.fhir.jpa.interceptor;
* #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.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
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.RequestDetails;
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 {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionDstu3Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired
private FhirContext myFhirContext;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired
@Qualifier("mySubscriptionDaoDstu3")
private IFhirResourceDao<Subscription> mySubscriptionDao;
@ -78,7 +72,7 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
private void checkSubscriptions(IIdType idType, String resourceType, RestOperationTypeEnum theOperation) {
//avoid a ConcurrentModificationException by copying to an array
for (Object object : myRestHookSubscriptions.toArray()) {
//for (Subscription subscription : myRestHookSubscriptions) {
//for (Subscription subscription : myRestHookSubscriptions) {
if (object == null) {
continue;
}
@ -114,7 +108,7 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
ourLog.info("Found match: queueing rest-hook notification for resource: {}", next.getIdElement());
HttpUriRequest request = createRequest(subscription, next, theOperation);
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;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// 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;
}
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
/**
* Subclasses may override
*/
@ -281,15 +283,6 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
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
*
@ -318,8 +311,8 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
if (theResource instanceof Subscription) {
Subscription subscription = (Subscription) theResource;
if (subscription.getChannel() != null
&& subscription.getChannel().getType() == Subscription.SubscriptionChannelType.RESTHOOK
&& subscription.getStatus() == Subscription.SubscriptionStatus.REQUESTED) {
&& subscription.getChannel().getType() == Subscription.SubscriptionChannelType.RESTHOOK
&& subscription.getStatus() == Subscription.SubscriptionStatus.REQUESTED) {
removeLocalSubscription(subscription.getIdElement().getIdPart());
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
myRestHookSubscriptions.add(subscription);
@ -333,16 +326,13 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
/**
* Check subscriptions to see if there is a matching subscription when there is a delete
*
* @param theRequest
* 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest
* The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
* @param theRequest 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
*/
@Override
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
@ -389,12 +379,4 @@ public class RestHookSubscriptionDstu3Interceptor extends BaseRestHookSubscripti
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;
/*-
@ -21,48 +20,43 @@ package ca.uhn.fhir.jpa.interceptor.r4;
* #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.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.interceptor.BaseRestHookSubscriptionInterceptor;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
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.RequestDetails;
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 {
private static volatile ExecutorService executor;
private final static int MAX_THREADS = 1;
private static final Logger ourLog = LoggerFactory.getLogger(RestHookSubscriptionR4Interceptor.class);
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired
private FhirContext myFhirContext;
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
@Autowired
@Qualifier("mySubscriptionDaoR4")
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());
HttpUriRequest request = createRequest(subscription, next, theOperation);
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;
}
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
mySubscriptionDao = theSubscriptionDao;
}
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
// 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;
}
public void setNotifyOnDelete(boolean notifyOnDelete) {
this.notifyOnDelete = notifyOnDelete;
}
/**
* Subclasses may override
*/
@ -276,15 +278,6 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
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
*
@ -313,8 +306,8 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
if (theResource instanceof Subscription) {
Subscription subscription = (Subscription) theResource;
if (subscription.getChannel() != null
&& subscription.getChannel().getType() == Subscription.SubscriptionChannelType.RESTHOOK
&& subscription.getStatus() == Subscription.SubscriptionStatus.REQUESTED) {
&& subscription.getChannel().getType() == Subscription.SubscriptionChannelType.RESTHOOK
&& subscription.getStatus() == Subscription.SubscriptionStatus.REQUESTED) {
removeLocalSubscription(subscription.getIdElement().getIdPart());
myRestHookSubscriptions.add(subscription);
subscription.setStatus(Subscription.SubscriptionStatus.ACTIVE);
@ -328,16 +321,13 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
/**
* Check subscriptions to see if there is a matching subscription when there is a delete
*
* @param theRequest
* 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest
* The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
* @param theRequest 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
* pulled out of the {@link HttpServletRequest servlet request}.
* @param theRequest The incoming request
* @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>
* to indicate that the server itself should not also provide a response.
*/
@Override
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
@ -384,12 +374,4 @@ public class RestHookSubscriptionR4Interceptor extends BaseRestHookSubscriptionI
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;
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.WebsocketDstu2DispatcherConfig;
import ca.uhn.fhir.jpa.dao.dstu2.BaseJpaDstu2Test;
import ca.uhn.fhir.jpa.interceptor.RestHookSubscriptionDstu2Interceptor;
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.Entry;
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.server.RestfulServer;
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 {
@ -58,74 +59,74 @@ public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
@SuppressWarnings({"unchecked", "rawtypes"})
@Before
public void before() throws Exception {
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
if (ourServer == null) {
ourPort = RandomServerPortProvider.findFreePort();
ourPort = findFreePort();
ourRestServer = new RestfulServer(myFhirCtx);
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
ourRestServer.setResourceProviders((List)myResourceProviders);
ourRestServer.setResourceProviders((List) myResourceProviders);
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
ourRestServer.setPlainProviders(mySystemProvider);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(ourRestServer, mySystemDao, myDaoConfig);
confProvider.setImplementationDescription("THIS IS THE DESC");
ourRestServer.setServerConformanceProvider(confProvider);
ourPagingProvider = myAppCtx.getBean(DatabaseBackedPagingProvider.class);
ourRestServer.setPagingProvider(ourPagingProvider);
Server server = new Server(ourPort);
ServletContextHandler proxyHandler = new ServletContextHandler();
proxyHandler.setContextPath("/");
ServletHolder servletHolder = new ServletHolder();
servletHolder.setServlet(ourRestServer);
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
ourWebApplicationContext = new GenericWebApplicationContext();
ourWebApplicationContext.setParent(myAppCtx);
ourWebApplicationContext.refresh();
ourRestHookSubscriptionInterceptor = ourWebApplicationContext.getBean(RestHookSubscriptionDstu2Interceptor.class);
proxyHandler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ourWebApplicationContext);
proxyHandler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ourWebApplicationContext);
DispatcherServlet dispatcherServlet = new DispatcherServlet();
dispatcherServlet.setContextClass(AnnotationConfigWebApplicationContext.class);
ServletHolder subsServletHolder = new ServletHolder();
subsServletHolder.setServlet(dispatcherServlet);
subsServletHolder.setInitParameter(
ContextLoader.CONFIG_LOCATION_PARAM,
WebsocketDstu2Config.class.getName() + "\n" +
ContextLoader.CONFIG_LOCATION_PARAM,
WebsocketDstu2Config.class.getName() + "\n" +
WebsocketDstu2DispatcherConfig.class.getName());
proxyHandler.addServlet(subsServletHolder, "/*");
server.setHandler(proxyHandler);
server.start();
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor());
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
builder.setConnectionManager(connectionManager);
ourHttpClient = builder.build();
ourServer = server;
}
ourRestServer.setPagingProvider(ourPagingProvider);
}

View File

@ -5,6 +5,8 @@ import static org.junit.Assert.assertEquals;
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.servlet.ServletContextHandler;
import org.eclipse.jetty.servlet.ServletHolder;
@ -55,10 +57,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true);
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();
ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
}
@ -71,12 +73,18 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
public void beforeReset() {
ourCreatedObservations.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) {
Subscription subscription = new Subscription();
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);
Channel channel = new Channel();
@ -138,7 +146,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see two subscription notifications
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
@ -147,7 +155,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -160,7 +168,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -174,7 +182,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -209,9 +217,9 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
Observation observation2 = sendObservation(code, "SNOMED-CT");
// Should see two subscription notifications
// Should see one subscription notification
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription/"+ subscription2.getId())).execute();
@ -220,7 +228,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -233,7 +241,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -247,7 +255,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -46,10 +46,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true);
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();
ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
}
@ -67,7 +67,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
private Subscription createSubscription(String criteria, String payload, String endpoint) {
Subscription subscription = new Subscription();
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.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
@ -129,7 +129,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see two subscription notifications
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -138,7 +138,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -151,7 +151,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -165,7 +165,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -202,7 +202,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see two subscription notifications
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
@ -211,7 +211,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -224,7 +224,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -238,7 +238,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu3Test extends B
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -1,40 +1,39 @@
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.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
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.server.IResourceProvider;
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
*/
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 int ourListenerPort;
private static RestfulServer ourListenerRestServer;
private static Server ourListenerServer;
private static String ourListenerServerBase;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RestHookTestWithInterceptorRegisteredToDaoConfigR4Test.class);
private static List<Observation> ourUpdatedObservations = Lists.newArrayList();
@Override
@ -46,10 +45,10 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
public void afterUnregisterRestHookListener() {
myDaoConfig.setAllowMultipleDelete(true);
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();
ourLog.info("Done deleting all subscriptions");
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.getInterceptors().remove(ourRestHookSubscriptionInterceptor);
}
@ -67,7 +66,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
private Subscription createSubscription(String criteria, String payload, String endpoint) {
Subscription subscription = new Subscription();
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.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
@ -117,7 +116,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
Thread.sleep(500);
assertEquals(1, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
Assert.assertNotNull(subscriptionTemp);
@ -129,16 +128,16 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see two subscription notifications
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -151,7 +150,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -165,7 +164,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
@ -190,7 +189,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
Thread.sleep(500);
assertEquals(1, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Subscription subscriptionTemp = ourClient.read(Subscription.class, subscription2.getId());
Assert.assertNotNull(subscriptionTemp);
@ -202,16 +201,16 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see two subscription notifications
Thread.sleep(500);
assertEquals(3, ourCreatedObservations.size());
assertEquals(2, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
ourClient.delete().resourceById(new IdDt("Subscription", subscription2.getId())).execute();
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
@ -224,7 +223,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see no subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(0, ourUpdatedObservations.size());
Observation observation3a = ourClient.read(Observation.class, observationTemp3.getId());
@ -238,7 +237,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
// Should see only one subscription notification
Thread.sleep(500);
assertEquals(4, ourCreatedObservations.size());
assertEquals(3, ourCreatedObservations.size());
assertEquals(1, ourUpdatedObservations.size());
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));

View File

@ -6,7 +6,23 @@
<title>HAPI FHIR Changelog</title>
</properties>
<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">
Bump the version of a few dependencies to the
latest versions (dependent HAPI modules listed in brackets):
@ -46,22 +62,6 @@
FHIR DSTU2. The presence of these headers sometimes caused parsed resource instances
to contain duplicate tags
</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">
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
@ -254,7 +254,7 @@
<![CDATA[<code>Bundle.entry.response.outcome</code>]]>
instead of the previous
<![CDATA[<code>Bundle.entry.resource</code>]]>
<action>
</action>
<action type="fix" issue="696">
An issue was corrected where search parameters containing negative numbers
were sometimes treated as positive numbers when processing the search. Thanks