Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
da962b8c10
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -78,8 +79,9 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
return FhirServerConfigCommon.loggingInterceptor();
|
return FhirServerConfigCommon.loggingInterceptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
|
||||||
import org.springframework.core.env.Environment;
|
import org.springframework.core.env.Environment;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||||
|
@ -101,8 +100,9 @@ public class FhirServerConfigCommon {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public static IServerInterceptor loggingInterceptor() {
|
public static LoggingInterceptor loggingInterceptor() {
|
||||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||||
retVal.setLoggerName("fhirtest.access");
|
retVal.setLoggerName("fhirtest.access");
|
||||||
retVal.setMessageFormat(
|
retVal.setMessageFormat(
|
||||||
|
|
|
@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.demo;
|
||||||
import javax.persistence.EntityManagerFactory;
|
import javax.persistence.EntityManagerFactory;
|
||||||
import javax.sql.DataSource;
|
import javax.sql.DataSource;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -82,8 +83,9 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
return FhirServerConfigCommon.loggingInterceptor();
|
return FhirServerConfigCommon.loggingInterceptor();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
@ -61,8 +62,8 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
ResourceProviderFactory beans = myAppCtx.getBean(resourceProviderBeanName, ResourceProviderFactory.class);
|
||||||
setResourceProviders(beans);
|
registerProviders(beans.createProviders());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The system provider implements non-resource-type methods, such as
|
* The system provider implements non-resource-type methods, such as
|
||||||
|
@ -76,7 +77,7 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
setPlainProviders(systemProvider);
|
registerProviders(systemProvider);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The conformance provider exports the supported resources, search parameters, etc for
|
* The conformance provider exports the supported resources, search parameters, etc for
|
||||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
@ -61,8 +62,8 @@ public class JpaServerDemoDstu2 extends RestfulServer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
ResourceProviderFactory beans = myAppCtx.getBean(resourceProviderBeanName, ResourceProviderFactory.class);
|
||||||
setResourceProviders(beans);
|
registerProviders(beans.createProviders());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The system provider implements non-resource-type methods, such as
|
* The system provider implements non-resource-type methods, such as
|
||||||
|
@ -76,7 +77,7 @@ public class JpaServerDemoDstu2 extends RestfulServer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
setPlainProviders(systemProvider);
|
registerProvider(systemProvider);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The conformance provider exports the supported resources, search parameters, etc for
|
* The conformance provider exports the supported resources, search parameters, etc for
|
||||||
|
|
|
@ -7,7 +7,6 @@ import javax.sql.DataSource;
|
||||||
|
|
||||||
import org.apache.commons.dbcp2.BasicDataSource;
|
import org.apache.commons.dbcp2.BasicDataSource;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -94,8 +93,9 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||||
retVal.setLoggerName("fhirtest.access");
|
retVal.setLoggerName("fhirtest.access");
|
||||||
retVal.setMessageFormat(
|
retVal.setMessageFormat(
|
||||||
|
|
|
@ -8,6 +8,7 @@ import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||||
|
@ -47,14 +48,14 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
|
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
|
||||||
* contains bean definitions for a resource provider for each resource type
|
* contains bean definitions for a resource provider for each resource type
|
||||||
*/
|
*/
|
||||||
List<IResourceProvider> beans = myAppCtx.getBean("myResourceProvidersDstu3", List.class);
|
ResourceProviderFactory beans = myAppCtx.getBean("myResourceProvidersDstu3", ResourceProviderFactory.class);
|
||||||
setResourceProviders(beans);
|
registerProviders(beans.createProviders());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The system provider implements non-resource-type methods, such as
|
* The system provider implements non-resource-type methods, such as
|
||||||
* transaction, and global history.
|
* transaction, and global history.
|
||||||
*/
|
*/
|
||||||
setPlainProviders(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
registerProviders(myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The conformance provider exports the supported resources, search parameters, etc for
|
* The conformance provider exports the supported resources, search parameters, etc for
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package example;
|
package example;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||||
|
@ -13,6 +16,7 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.*;
|
import ca.uhn.fhir.rest.server.interceptor.auth.*;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
|
@ -101,7 +105,8 @@ public class AuthorizationInterceptors {
|
||||||
@IdParam IdDt theId,
|
@IdParam IdDt theId,
|
||||||
@ResourceParam Patient theResource,
|
@ResourceParam Patient theResource,
|
||||||
@ConditionalUrlParam String theConditionalUrl,
|
@ConditionalUrlParam String theConditionalUrl,
|
||||||
RequestDetails theRequestDetails) {
|
ServletRequestDetails theRequestDetails,
|
||||||
|
IInterceptorBroadcaster theInterceptorBroadcaster) {
|
||||||
|
|
||||||
// If we're processing a conditional URL...
|
// If we're processing a conditional URL...
|
||||||
if (isNotBlank(theConditionalUrl)) {
|
if (isNotBlank(theConditionalUrl)) {
|
||||||
|
@ -111,20 +116,25 @@ public class AuthorizationInterceptors {
|
||||||
// and supply the actual ID that's being updated
|
// and supply the actual ID that's being updated
|
||||||
IdDt actual = new IdDt("Patient", "1123");
|
IdDt actual = new IdDt("Patient", "1123");
|
||||||
|
|
||||||
// There are a number of possible constructors for ActionRequestDetails.
|
|
||||||
// You should supply as much detail about the sub-operation as possible
|
|
||||||
IServerInterceptor.ActionRequestDetails subRequest =
|
|
||||||
new IServerInterceptor.ActionRequestDetails(theRequestDetails, actual);
|
|
||||||
|
|
||||||
// Notify the interceptors
|
|
||||||
subRequest.notifyIncomingRequestPreHandled(RestOperationTypeEnum.UPDATE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In a real server, perhaps we would process the conditional
|
// In a real server, perhaps we would process the conditional
|
||||||
// request differently and follow a separate path. Either way,
|
// request differently and follow a separate path. Either way,
|
||||||
// let's pretend there is some storage code here.
|
// let's pretend there is some storage code here.
|
||||||
|
|
||||||
theResource.setId(theId.withVersion("2"));
|
theResource.setId(theId.withVersion("2"));
|
||||||
|
|
||||||
|
// Notify the interceptor framework when we're about to perform an update. This is
|
||||||
|
// useful as the authorization interceptor will pick this event up and use it
|
||||||
|
// to factor into a decision about whether the operation should be allowed to proceed.
|
||||||
|
IBaseResource previousContents = theResource;
|
||||||
|
IBaseResource newContents = theResource;
|
||||||
|
HookParams params = new HookParams()
|
||||||
|
.add(IBaseResource.class, previousContents)
|
||||||
|
.add(IBaseResource.class, newContents)
|
||||||
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
|
.add(ServletRequestDetails.class, theRequestDetails);
|
||||||
|
theInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, params);
|
||||||
|
|
||||||
MethodOutcome retVal = new MethodOutcome();
|
MethodOutcome retVal = new MethodOutcome();
|
||||||
retVal.setCreated(true);
|
retVal.setCreated(true);
|
||||||
retVal.setResource(theResource);
|
retVal.setResource(theResource);
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
package example;
|
||||||
|
|
||||||
|
public class NewInterceptors {
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package example.interceptor;
|
package example.interceptor;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -27,12 +27,8 @@ import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This annotation should be placed on
|
* This annotation should be placed on
|
||||||
* {@link Interceptor Subscription Interceptor}
|
* {@link Interceptor}
|
||||||
* bean methods.
|
* bean methods.
|
||||||
* <p>
|
|
||||||
* Methods with this annotation are invoked immediately before a REST HOOK
|
|
||||||
* subscription delivery
|
|
||||||
* </p>
|
|
||||||
*
|
*
|
||||||
* @see Interceptor
|
* @see Interceptor
|
||||||
*/
|
*/
|
||||||
|
@ -43,6 +39,15 @@ public @interface Hook {
|
||||||
/**
|
/**
|
||||||
* Provides the specific point where this method should be invoked
|
* Provides the specific point where this method should be invoked
|
||||||
*/
|
*/
|
||||||
Pointcut[] value();
|
Pointcut value();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order that interceptors should be called in. Lower numbers happen before higher numbers. Default is 0
|
||||||
|
* and allowable values can be positive or negative or 0.
|
||||||
|
* <p>
|
||||||
|
* If no order is specified, or the order is set to <code>0</code> (the default order),
|
||||||
|
* the order specified at the interceptor type level will take precedence.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
int order() default Interceptor.DEFAULT_ORDER;
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -25,6 +25,7 @@ import com.google.common.collect.ListMultimap;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -51,22 +52,23 @@ public class HookParams {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
private <T> void add(T theNext) {
|
public <T> HookParams add(@Nonnull T theNext) {
|
||||||
Class<T> nextClass = (Class<T>) theNext.getClass();
|
Class<T> nextClass = (Class<T>) theNext.getClass();
|
||||||
add(nextClass, theNext);
|
add(nextClass, theNext);
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> HookParams add(Class<T> theType, T theParam) {
|
public <T> HookParams add(Class<T> theType, T theParam) {
|
||||||
return doAdd(theType, theParam);
|
return doAdd(theType, theParam);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
// /**
|
||||||
* This is useful for providing a lazy-loaded (generally expensive to create)
|
// * This is useful for providing a lazy-loaded (generally expensive to create)
|
||||||
* parameters
|
// * parameters
|
||||||
*/
|
// */
|
||||||
public <T> HookParams addSupplier(Class<T> theType, Supplier<T> theParam) {
|
// public <T> HookParams addSupplier(Class<T> theType, Supplier<T> theParam) {
|
||||||
return doAdd(theType, theParam);
|
// return doAdd(theType, theParam);
|
||||||
}
|
// }
|
||||||
|
|
||||||
private <T> HookParams doAdd(Class<T> theType, Object theParam) {
|
private <T> HookParams doAdd(Class<T> theType, Object theParam) {
|
||||||
Validate.isTrue(theType.equals(Supplier.class) == false, "Can not add parameters of type Supplier");
|
Validate.isTrue(theType.equals(Supplier.class) == false, "Can not add parameters of type Supplier");
|
||||||
|
@ -78,7 +80,7 @@ public class HookParams {
|
||||||
return get(theParamType, 0);
|
return get(theParamType, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public <T> T get(Class<T> theParamType, int theIndex) {
|
public <T> T get(Class<T> theParamType, int theIndex) {
|
||||||
List<Object> objects = myParams.get(theParamType);
|
List<Object> objects = myParams.get(theParamType);
|
||||||
Object retVal = null;
|
Object retVal = null;
|
||||||
|
@ -115,4 +117,19 @@ public class HookParams {
|
||||||
.map(t -> unwrapValue(t))
|
.map(t -> unwrapValue(t))
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <T> HookParams addIfMatchesType(Class<T> theType, Object theParam) {
|
||||||
|
if (theParam == null) {
|
||||||
|
add(theType, null);
|
||||||
|
} else {
|
||||||
|
if (theType.isAssignableFrom(theParam.getClass())) {
|
||||||
|
T param = (T) theParam;
|
||||||
|
add(theType, param);
|
||||||
|
} else {
|
||||||
|
add(theType, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -23,13 +23,20 @@ package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||||
public interface IInterceptorBroadcaster {
|
public interface IInterceptorBroadcaster {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke the interceptor methods
|
* Invoke registered interceptor hook methods for the given Pointcut.
|
||||||
|
*
|
||||||
|
* @return Returns <code>false</code> if any of the invoked hook methods returned
|
||||||
|
* <code>false</code>, and returns <code>true</code> otherwise.
|
||||||
*/
|
*/
|
||||||
boolean callHooks(Pointcut thePointcut, HookParams theParams);
|
boolean callHooks(Pointcut thePointcut, HookParams theParams);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Invoke the interceptor methods
|
* Invoke registered interceptor hook methods for the given Pointcut. This method
|
||||||
|
* should only be called for pointcuts that return a type other than
|
||||||
|
* <code>void</code> or <code>boolean</code>
|
||||||
|
*
|
||||||
|
* @return Returns the object returned by the first hook method that did not return <code>null</code>
|
||||||
*/
|
*/
|
||||||
boolean callHooks(Pointcut thePointcut, Object... theParams);
|
Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -20,14 +20,11 @@ package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public interface IInterceptorRegistry {
|
public interface IInterceptorService extends IInterceptorBroadcaster {
|
||||||
|
|
||||||
int DEFAULT_ORDER = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register an interceptor that will be used in a {@link ThreadLocal} context.
|
* Register an interceptor that will be used in a {@link ThreadLocal} context.
|
||||||
|
@ -35,10 +32,15 @@ public interface IInterceptorRegistry {
|
||||||
* they were fired from the current thread.
|
* they were fired from the current thread.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that it is almost always desirable to call this method with a
|
* Note that it is almost always desirable to call this method with a
|
||||||
* try-finally statment that removes the interceptor afterwards, since
|
* try-finally statement that removes the interceptor afterwards, since
|
||||||
* this can lead to memory leakage, poor performance due to ever-increasing
|
* this can lead to memory leakage, poor performance due to ever-increasing
|
||||||
* numbers of interceptors, etc.
|
* numbers of interceptors, etc.
|
||||||
* </p>
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Note that most methods such as {@link #getAllRegisteredInterceptors()} and
|
||||||
|
* {@link #unregisterAllInterceptors()} do not affect thread local interceptors
|
||||||
|
* as they are kept in a separate list.
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param theInterceptor The interceptor
|
* @param theInterceptor The interceptor
|
||||||
* @return Returns <code>true</code> if at least one valid hook method was found on this interceptor
|
* @return Returns <code>true</code> if at least one valid hook method was found on this interceptor
|
||||||
|
@ -68,24 +70,23 @@ public interface IInterceptorRegistry {
|
||||||
*/
|
*/
|
||||||
void unregisterInterceptor(Object theInterceptor);
|
void unregisterInterceptor(Object theInterceptor);
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated to be removed
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
boolean registerGlobalInterceptor(Object theInterceptor);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @deprecated to be removed
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
void unregisterGlobalInterceptor(Object theInterceptor);
|
|
||||||
|
|
||||||
void registerAnonymousInterceptor(Pointcut thePointcut, IAnonymousInterceptor theInterceptor);
|
void registerAnonymousInterceptor(Pointcut thePointcut, IAnonymousInterceptor theInterceptor);
|
||||||
|
|
||||||
void registerAnonymousInterceptor(Pointcut thePointcut, int theOrder, IAnonymousInterceptor theInterceptor);
|
void registerAnonymousInterceptor(Pointcut thePointcut, int theOrder, IAnonymousInterceptor theInterceptor);
|
||||||
|
|
||||||
@VisibleForTesting
|
/**
|
||||||
void clearAnonymousHookForUnitTest();
|
* Returns all currently registered interceptors (excluding any thread local interceptors).
|
||||||
|
*/
|
||||||
|
List<Object> getAllRegisteredInterceptors();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters all registered interceptors. Note that this method does not unregister
|
||||||
|
* any {@link #registerThreadLocalInterceptor(Object) thread local interceptors}.
|
||||||
|
*/
|
||||||
|
void unregisterAllInterceptors();
|
||||||
|
|
||||||
void unregisterInterceptors(@Nullable Collection<?> theInterceptors);
|
void unregisterInterceptors(@Nullable Collection<?> theInterceptors);
|
||||||
|
|
||||||
|
void registerInterceptors(@Nullable Collection<?> theInterceptors);
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
package ca.uhn.fhir.interceptor.api;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -33,9 +33,13 @@ import java.lang.annotation.Target;
|
||||||
public @interface Interceptor {
|
public @interface Interceptor {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Declares that an interceptor should be manually registered with the registry,
|
* @see #order()
|
||||||
* and should not auto-register using Spring autowiring.
|
|
||||||
*/
|
*/
|
||||||
boolean manualRegistration() default false;
|
int DEFAULT_ORDER = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The order that interceptors should be called in. Lower numbers happen before higher numbers. Default is 0
|
||||||
|
* and allowable values can be positive or negative or 0.
|
||||||
|
*/
|
||||||
|
int order() default DEFAULT_ORDER;
|
||||||
}
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.model.interceptor.executor;
|
package ca.uhn.fhir.interceptor.executor;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR Model
|
* HAPI FHIR - Core Library
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2019 University Health Network
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
* %%
|
* %%
|
||||||
|
@ -20,26 +20,31 @@ package ca.uhn.fhir.jpa.model.interceptor.executor;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.*;
|
import ca.uhn.fhir.interceptor.api.*;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.ArrayListMultimap;
|
import com.google.common.collect.ArrayListMultimap;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
import com.google.common.collect.Multimaps;
|
import com.google.common.collect.Multimaps;
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.springframework.core.annotation.Order;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import org.apache.commons.lang3.reflect.MethodUtils;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import java.lang.annotation.Annotation;
|
||||||
|
import java.lang.reflect.AnnotatedElement;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
public class InterceptorService implements IInterceptorRegistry, IInterceptorBroadcaster {
|
public class InterceptorService implements IInterceptorService, IInterceptorBroadcaster {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(InterceptorService.class);
|
||||||
private final List<Object> myInterceptors = new ArrayList<>();
|
private final List<Object> myInterceptors = new ArrayList<>();
|
||||||
private final ListMultimap<Pointcut, BaseInvoker> myGlobalInvokers = ArrayListMultimap.create();
|
private final ListMultimap<Pointcut, BaseInvoker> myGlobalInvokers = ArrayListMultimap.create();
|
||||||
private final ListMultimap<Pointcut, BaseInvoker> myAnonymousInvokers = ArrayListMultimap.create();
|
private final ListMultimap<Pointcut, BaseInvoker> myAnonymousInvokers = ArrayListMultimap.create();
|
||||||
|
@ -84,11 +89,10 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
return myInterceptors;
|
return myInterceptors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void registerAnonymousInterceptor(Pointcut thePointcut, IAnonymousInterceptor theInterceptor) {
|
public void registerAnonymousInterceptor(Pointcut thePointcut, IAnonymousInterceptor theInterceptor) {
|
||||||
registerAnonymousInterceptor(thePointcut, DEFAULT_ORDER, theInterceptor);
|
registerAnonymousInterceptor(thePointcut, Interceptor.DEFAULT_ORDER, theInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setName(String theName) {
|
public void setName(String theName) {
|
||||||
|
@ -100,15 +104,30 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
Validate.notNull(thePointcut);
|
Validate.notNull(thePointcut);
|
||||||
Validate.notNull(theInterceptor);
|
Validate.notNull(theInterceptor);
|
||||||
synchronized (myRegistryMutex) {
|
synchronized (myRegistryMutex) {
|
||||||
|
|
||||||
myAnonymousInvokers.put(thePointcut, new AnonymousLambdaInvoker(thePointcut, theInterceptor, theOrder));
|
myAnonymousInvokers.put(thePointcut, new AnonymousLambdaInvoker(thePointcut, theInterceptor, theOrder));
|
||||||
|
if (!isInterceptorAlreadyRegistered(theInterceptor)) {
|
||||||
|
myInterceptors.add(theInterceptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Object> getAllRegisteredInterceptors() {
|
||||||
|
synchronized (myRegistryMutex) {
|
||||||
|
List<Object> retVal = new ArrayList<>();
|
||||||
|
retVal.addAll(myInterceptors);
|
||||||
|
return Collections.unmodifiableList(retVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void clearAnonymousHookForUnitTest() {
|
public void unregisterAllInterceptors() {
|
||||||
synchronized (myRegistryMutex) {
|
synchronized (myRegistryMutex) {
|
||||||
myAnonymousInvokers.clear();
|
myAnonymousInvokers.clear();
|
||||||
|
myGlobalInvokers.clear();
|
||||||
|
myInterceptors.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -119,6 +138,13 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerInterceptors(@Nullable Collection<?> theInterceptors) {
|
||||||
|
if (theInterceptors != null) {
|
||||||
|
theInterceptors.forEach(t -> registerInterceptor(t));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean registerThreadLocalInterceptor(Object theInterceptor) {
|
public boolean registerThreadLocalInterceptor(Object theInterceptor) {
|
||||||
if (!myThreadlocalInvokersEnabled) {
|
if (!myThreadlocalInvokersEnabled) {
|
||||||
|
@ -160,6 +186,7 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
|
|
||||||
List<HookInvoker> addedInvokers = scanInterceptorAndAddToInvokerMultimap(theInterceptor, myGlobalInvokers);
|
List<HookInvoker> addedInvokers = scanInterceptorAndAddToInvokerMultimap(theInterceptor, myGlobalInvokers);
|
||||||
if (addedInvokers.isEmpty()) {
|
if (addedInvokers.isEmpty()) {
|
||||||
|
ourLog.warn("Interceptor registered with no valid hooks - Type was: {}", theInterceptor.getClass().getName());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -189,21 +216,11 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean registerGlobalInterceptor(Object theInterceptor) {
|
|
||||||
return registerInterceptor(theInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void unregisterGlobalInterceptor(Object theInterceptor) {
|
|
||||||
unregisterInterceptor(theInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void sortByOrderAnnotation(List<Object> theObjects) {
|
private void sortByOrderAnnotation(List<Object> theObjects) {
|
||||||
IdentityHashMap<Object, Integer> interceptorToOrder = new IdentityHashMap<>();
|
IdentityHashMap<Object, Integer> interceptorToOrder = new IdentityHashMap<>();
|
||||||
for (Object next : theObjects) {
|
for (Object next : theObjects) {
|
||||||
Order orderAnnotation = next.getClass().getAnnotation(Order.class);
|
Interceptor orderAnnotation = next.getClass().getAnnotation(Interceptor.class);
|
||||||
int order = orderAnnotation != null ? orderAnnotation.value() : 0;
|
int order = orderAnnotation != null ? orderAnnotation.order() : 0;
|
||||||
interceptorToOrder.put(next, order);
|
interceptorToOrder.put(next, order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -215,27 +232,47 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean callHooks(Pointcut thePointcut, Object... theParams) {
|
public Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams) {
|
||||||
return callHooks(thePointcut, new HookParams(theParams));
|
assert haveAppropriateParams(thePointcut, theParams);
|
||||||
|
assert thePointcut.getReturnType() != void.class && thePointcut.getReturnType() != boolean.class;
|
||||||
|
|
||||||
|
Object retVal = doCallHooks(thePointcut, theParams, null);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
||||||
assert haveAppropriateParams(thePointcut, theParams);
|
assert haveAppropriateParams(thePointcut, theParams);
|
||||||
|
assert thePointcut.getReturnType() == void.class || thePointcut.getReturnType() == boolean.class;
|
||||||
|
|
||||||
|
Object retValObj = doCallHooks(thePointcut, theParams, true);
|
||||||
|
return (Boolean) retValObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object doCallHooks(Pointcut thePointcut, HookParams theParams, Object theRetVal) {
|
||||||
List<BaseInvoker> invokers = getInvokersForPointcut(thePointcut);
|
List<BaseInvoker> invokers = getInvokersForPointcut(thePointcut);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Call each hook in order
|
* Call each hook in order
|
||||||
*/
|
*/
|
||||||
for (BaseInvoker nextInvoker : invokers) {
|
for (BaseInvoker nextInvoker : invokers) {
|
||||||
boolean shouldContinue = nextInvoker.invoke(theParams);
|
Object nextOutcome = nextInvoker.invoke(theParams);
|
||||||
if (!shouldContinue) {
|
if (thePointcut.getReturnType() == boolean.class) {
|
||||||
return false;
|
Boolean nextOutcomeAsBoolean = (Boolean) nextOutcome;
|
||||||
|
if (Boolean.FALSE.equals(nextOutcomeAsBoolean)) {
|
||||||
|
ourLog.trace("callHooks({}) for invoker({}) returned false", thePointcut, nextInvoker);
|
||||||
|
theRetVal = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (thePointcut.getReturnType() != void.class) {
|
||||||
|
if (nextOutcome != null) {
|
||||||
|
theRetVal = nextOutcome;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return theRetVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
@ -272,7 +309,8 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
/**
|
/**
|
||||||
* First argument must be the global invoker list!!
|
* First argument must be the global invoker list!!
|
||||||
*/
|
*/
|
||||||
private List<BaseInvoker> union(List<BaseInvoker>... theInvokersLists) {
|
@SafeVarargs
|
||||||
|
private final List<BaseInvoker> union(List<BaseInvoker>... theInvokersLists) {
|
||||||
List<BaseInvoker> haveOne = null;
|
List<BaseInvoker> haveOne = null;
|
||||||
boolean haveMultiple = false;
|
boolean haveMultiple = false;
|
||||||
for (List<BaseInvoker> nextInvokerList : theInvokersLists) {
|
for (List<BaseInvoker> nextInvokerList : theInvokersLists) {
|
||||||
|
@ -322,7 +360,7 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
* Only call this when assertions are enabled, it's expensive
|
* Only call this when assertions are enabled, it's expensive
|
||||||
*/
|
*/
|
||||||
boolean haveAppropriateParams(Pointcut thePointcut, HookParams theParams) {
|
boolean haveAppropriateParams(Pointcut thePointcut, HookParams theParams) {
|
||||||
Validate.isTrue(theParams.getParamsForType().values().size() == thePointcut.getParameterTypes().size(), "Wrong number of params for pointcut %s - Wanted %s but found %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), theParams.getParamsForType().values().stream().map(t -> t.getClass().getSimpleName()).sorted().collect(Collectors.toList()));
|
Validate.isTrue(theParams.getParamsForType().values().size() == thePointcut.getParameterTypes().size(), "Wrong number of params for pointcut %s - Wanted %s but found %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), theParams.getParamsForType().values().stream().map(t -> t != null ? t.getClass().getSimpleName() : "null").sorted().collect(Collectors.toList()));
|
||||||
|
|
||||||
List<String> wantedTypes = new ArrayList<>(thePointcut.getParameterTypes());
|
List<String> wantedTypes = new ArrayList<>(thePointcut.getParameterTypes());
|
||||||
|
|
||||||
|
@ -330,8 +368,8 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
for (Class<?> nextTypeClass : givenTypes.keySet()) {
|
for (Class<?> nextTypeClass : givenTypes.keySet()) {
|
||||||
String nextTypeName = nextTypeClass.getName();
|
String nextTypeName = nextTypeClass.getName();
|
||||||
for (Object nextParamValue : givenTypes.get(nextTypeClass)) {
|
for (Object nextParamValue : givenTypes.get(nextTypeClass)) {
|
||||||
Validate.isTrue(nextTypeClass.isAssignableFrom(nextParamValue.getClass()), "Invalid params for pointcut %s - %s is not of type %s", thePointcut.name(), nextParamValue.getClass(), nextTypeClass);
|
Validate.isTrue(nextParamValue == null || nextTypeClass.isAssignableFrom(nextParamValue.getClass()), "Invalid params for pointcut %s - %s is not of type %s", thePointcut.name(), nextParamValue != null ? nextParamValue.getClass() : "null", nextTypeClass);
|
||||||
Validate.isTrue(wantedTypes.remove(nextTypeName), "Invalid params for pointcut %s - Wanted %s but missing %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), nextTypeName);
|
Validate.isTrue(wantedTypes.remove(nextTypeName), "Invalid params for pointcut %s - Wanted %s but found %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), nextTypeName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,7 +387,7 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
boolean invoke(HookParams theParams) {
|
Object invoke(HookParams theParams) {
|
||||||
myHook.invoke(myPointcut, theParams);
|
myHook.invoke(myPointcut, theParams);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -369,7 +407,7 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
return myInterceptor;
|
return myInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract boolean invoke(HookParams theParams);
|
abstract Object invoke(HookParams theParams);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int compareTo(BaseInvoker theInvoker) {
|
public int compareTo(BaseInvoker theInvoker) {
|
||||||
|
@ -379,27 +417,27 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
|
|
||||||
private static class HookInvoker extends BaseInvoker {
|
private static class HookInvoker extends BaseInvoker {
|
||||||
|
|
||||||
private final boolean myReturnsBoolean;
|
|
||||||
private final Method myMethod;
|
private final Method myMethod;
|
||||||
private final Class<?>[] myParameterTypes;
|
private final Class<?>[] myParameterTypes;
|
||||||
private final int[] myParameterIndexes;
|
private final int[] myParameterIndexes;
|
||||||
private final Set<Pointcut> myPointcuts;
|
private final Pointcut myPointcut;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
private HookInvoker(Hook theHook, @Nonnull Object theInterceptor, @Nonnull Method theHookMethod, int theOrder) {
|
private HookInvoker(Hook theHook, @Nonnull Object theInterceptor, @Nonnull Method theHookMethod, int theOrder) {
|
||||||
super(theInterceptor, theOrder);
|
super(theInterceptor, theOrder);
|
||||||
myPointcuts = Collections.unmodifiableSet(Sets.newHashSet(theHook.value()));
|
myPointcut = theHook.value();
|
||||||
myParameterTypes = theHookMethod.getParameterTypes();
|
myParameterTypes = theHookMethod.getParameterTypes();
|
||||||
myMethod = theHookMethod;
|
myMethod = theHookMethod;
|
||||||
|
|
||||||
Class<?> returnType = theHookMethod.getReturnType();
|
Class<?> returnType = theHookMethod.getReturnType();
|
||||||
if (returnType.equals(boolean.class)) {
|
if (myPointcut.getReturnType().equals(boolean.class)) {
|
||||||
myReturnsBoolean = true;
|
Validate.isTrue(boolean.class.equals(returnType) || void.class.equals(returnType), "Method does not return boolean or void: %s", theHookMethod);
|
||||||
|
} else if (myPointcut.getReturnType().equals(void.class)) {
|
||||||
|
Validate.isTrue(void.class.equals(returnType), "Method does not return void: %s", theHookMethod);
|
||||||
} else {
|
} else {
|
||||||
Validate.isTrue(void.class.equals(returnType), "Method does not return boolean or void: %s", theHookMethod);
|
Validate.isTrue(myPointcut.getReturnType().isAssignableFrom(returnType) || void.class.equals(returnType), "Method does not return %s or void: %s", myPointcut.getReturnType(), theHookMethod);
|
||||||
myReturnsBoolean = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
myParameterIndexes = new int[myParameterTypes.length];
|
myParameterIndexes = new int[myParameterTypes.length];
|
||||||
|
@ -408,17 +446,26 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
AtomicInteger counter = typeToCount.computeIfAbsent(myParameterTypes[i], t -> new AtomicInteger(0));
|
AtomicInteger counter = typeToCount.computeIfAbsent(myParameterTypes[i], t -> new AtomicInteger(0));
|
||||||
myParameterIndexes[i] = counter.getAndIncrement();
|
myParameterIndexes[i] = counter.getAndIncrement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myMethod.setAccessible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<Pointcut> getPointcuts() {
|
@Override
|
||||||
return myPointcuts;
|
public String toString() {
|
||||||
|
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||||
|
.append("method", myMethod)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Pointcut getPointcut() {
|
||||||
|
return myPointcut;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Returns true/false if the hook method returns a boolean, returns true otherwise
|
* @return Returns true/false if the hook method returns a boolean, returns true otherwise
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
boolean invoke(HookParams theParams) {
|
Object invoke(HookParams theParams) {
|
||||||
|
|
||||||
Object[] args = new Object[myParameterTypes.length];
|
Object[] args = new Object[myParameterTypes.length];
|
||||||
for (int i = 0; i < myParameterTypes.length; i++) {
|
for (int i = 0; i < myParameterTypes.length; i++) {
|
||||||
|
@ -430,18 +477,18 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
|
|
||||||
// Invoke the method
|
// Invoke the method
|
||||||
try {
|
try {
|
||||||
Object returnValue = myMethod.invoke(getInterceptor(), args);
|
return myMethod.invoke(getInterceptor(), args);
|
||||||
if (myReturnsBoolean) {
|
|
||||||
return (boolean) returnValue;
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} catch (InvocationTargetException e) {
|
} catch (InvocationTargetException e) {
|
||||||
Throwable targetException = e.getTargetException();
|
Throwable targetException = e.getTargetException();
|
||||||
|
if (myPointcut.isShouldLogAndSwallowException(targetException)) {
|
||||||
|
ourLog.error("Exception thrown by interceptor: " + targetException.toString(), targetException);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (targetException instanceof RuntimeException) {
|
if (targetException instanceof RuntimeException) {
|
||||||
throw ((RuntimeException) targetException);
|
throw ((RuntimeException) targetException);
|
||||||
} else {
|
} else {
|
||||||
throw new InternalErrorException("Failure invoking interceptor for pointcut(s) " + getPointcuts(), targetException);
|
throw new InternalErrorException("Failure invoking interceptor for pointcut(s) " + getPointcut(), targetException);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
|
@ -459,17 +506,16 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
|
|
||||||
// Invoke the REGISTERED pointcut for any added hooks
|
// Invoke the REGISTERED pointcut for any added hooks
|
||||||
addedInvokers.stream()
|
addedInvokers.stream()
|
||||||
.filter(t -> t.getPointcuts().contains(Pointcut.REGISTERED))
|
.filter(t -> Pointcut.INTERCEPTOR_REGISTERED.equals(t.getPointcut()))
|
||||||
.forEach(t -> t.invoke(new HookParams()));
|
.forEach(t -> t.invoke(new HookParams()));
|
||||||
|
|
||||||
// Register the interceptor and its various hooks
|
// Register the interceptor and its various hooks
|
||||||
for (HookInvoker nextAddedHook : addedInvokers) {
|
for (HookInvoker nextAddedHook : addedInvokers) {
|
||||||
for (Pointcut nextPointcut : nextAddedHook.getPointcuts()) {
|
Pointcut nextPointcut = nextAddedHook.getPointcut();
|
||||||
if (nextPointcut.equals(Pointcut.REGISTERED)) {
|
if (nextPointcut.equals(Pointcut.INTERCEPTOR_REGISTERED)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
|
||||||
theInvokers.put(nextPointcut, nextAddedHook);
|
|
||||||
}
|
}
|
||||||
|
theInvokers.put(nextPointcut, nextAddedHook);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure we're always sorted according to the order declared in
|
// Make sure we're always sorted according to the order declared in
|
||||||
|
@ -488,27 +534,37 @@ public class InterceptorService implements IInterceptorRegistry, IInterceptorBro
|
||||||
private static List<HookInvoker> scanInterceptorForHookMethods(Object theInterceptor, int theTypeOrder) {
|
private static List<HookInvoker> scanInterceptorForHookMethods(Object theInterceptor, int theTypeOrder) {
|
||||||
ArrayList<HookInvoker> retVal = new ArrayList<>();
|
ArrayList<HookInvoker> retVal = new ArrayList<>();
|
||||||
for (Method nextMethod : theInterceptor.getClass().getMethods()) {
|
for (Method nextMethod : theInterceptor.getClass().getMethods()) {
|
||||||
Hook hook = AnnotationUtils.findAnnotation(nextMethod, Hook.class);
|
Optional<Hook> hook = findAnnotation(nextMethod, Hook.class);
|
||||||
|
|
||||||
if (hook != null) {
|
if (hook.isPresent()) {
|
||||||
int methodOrder = theTypeOrder;
|
int methodOrder = theTypeOrder;
|
||||||
Order methodOrderAnnotation = AnnotationUtils.findAnnotation(nextMethod, Order.class);
|
int methodOrderAnnotation = hook.get().order();
|
||||||
if (methodOrderAnnotation != null) {
|
if (methodOrderAnnotation != Interceptor.DEFAULT_ORDER) {
|
||||||
methodOrder = methodOrderAnnotation.value();
|
methodOrder = methodOrderAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
retVal.add(new HookInvoker(hook, theInterceptor, nextMethod, methodOrder));
|
retVal.add(new HookInvoker(hook.get(), theInterceptor, nextMethod, methodOrder));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static <T extends Annotation> Optional<T> findAnnotation(AnnotatedElement theObject, Class<T> theHookClass) {
|
||||||
|
T annotation;
|
||||||
|
if (theObject instanceof Method) {
|
||||||
|
annotation = MethodUtils.getAnnotation((Method) theObject, theHookClass, true, true);
|
||||||
|
} else {
|
||||||
|
annotation = theObject.getAnnotation(theHookClass);
|
||||||
|
}
|
||||||
|
return Optional.ofNullable(annotation);
|
||||||
|
}
|
||||||
|
|
||||||
private static int determineOrder(Class<?> theInterceptorClass) {
|
private static int determineOrder(Class<?> theInterceptorClass) {
|
||||||
int typeOrder = DEFAULT_ORDER;
|
int typeOrder = Interceptor.DEFAULT_ORDER;
|
||||||
Order typeOrderAnnotation = AnnotationUtils.findAnnotation(theInterceptorClass, Order.class);
|
Optional<Interceptor> typeOrderAnnotation = findAnnotation(theInterceptorClass, Interceptor.class);
|
||||||
if (typeOrderAnnotation != null) {
|
if (typeOrderAnnotation.isPresent()) {
|
||||||
typeOrder = typeOrderAnnotation.value();
|
typeOrder = typeOrderAnnotation.get().order();
|
||||||
}
|
}
|
||||||
return typeOrder;
|
return typeOrder;
|
||||||
}
|
}
|
|
@ -20,6 +20,9 @@ package ca.uhn.fhir.rest.client.api;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,11 +38,13 @@ public interface IClientInterceptor {
|
||||||
/**
|
/**
|
||||||
* Fired by the client just before invoking the HTTP client request
|
* Fired by the client just before invoking the HTTP client request
|
||||||
*/
|
*/
|
||||||
|
@Hook(Pointcut.CLIENT_REQUEST)
|
||||||
void interceptRequest(IHttpRequest theRequest);
|
void interceptRequest(IHttpRequest theRequest);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired by the client upon receiving an HTTP response, prior to processing that response
|
* Fired by the client upon receiving an HTTP response, prior to processing that response
|
||||||
*/
|
*/
|
||||||
|
@Hook(Pointcut.CLIENT_RESPONSE)
|
||||||
void interceptResponse(IHttpResponse theResponse) throws IOException;
|
void interceptResponse(IHttpResponse theResponse) throws IOException;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
package ca.uhn.fhir.rest.client.api;
|
package ca.uhn.fhir.rest.client.api;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum;
|
import ca.uhn.fhir.rest.api.RequestFormatParamStyleEnum;
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
import ca.uhn.fhir.rest.api.SummaryEnum;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import java.util.List;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -30,6 +31,20 @@ import java.util.List;
|
||||||
|
|
||||||
public interface IRestfulClient {
|
public interface IRestfulClient {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the interfceptor service used by this client
|
||||||
|
*
|
||||||
|
* @since 3.8.0
|
||||||
|
*/
|
||||||
|
IInterceptorService getInterceptorService();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the interfceptor service used by this client
|
||||||
|
*
|
||||||
|
* @since 3.8.0
|
||||||
|
*/
|
||||||
|
void setInterceptorService(@Nonnull IInterceptorService theInterceptorService);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the contents at the given URL and parse them as a resource. This
|
* Retrieve the contents at the given URL and parse them as a resource. This
|
||||||
* method could be used as a low level implementation of a read/vread/search
|
* method could be used as a low level implementation of a read/vread/search
|
||||||
|
@ -69,11 +84,6 @@ public interface IRestfulClient {
|
||||||
*/
|
*/
|
||||||
IHttpClient getHttpClient();
|
IHttpClient getHttpClient();
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the client interceptors that have been registered with this client
|
|
||||||
*/
|
|
||||||
List<IClientInterceptor> getInterceptors();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base URL for the server, with no trailing "/"
|
* Base URL for the server, with no trailing "/"
|
||||||
*/
|
*/
|
||||||
|
@ -82,7 +92,10 @@ public interface IRestfulClient {
|
||||||
/**
|
/**
|
||||||
* Register a new interceptor for this client. An interceptor can be used to add additional
|
* Register a new interceptor for this client. An interceptor can be used to add additional
|
||||||
* logging, or add security headers, or pre-process responses, etc.
|
* logging, or add security headers, or pre-process responses, etc.
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void registerInterceptor(IClientInterceptor theInterceptor);
|
void registerInterceptor(IClientInterceptor theInterceptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -102,7 +115,10 @@ public interface IRestfulClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
|
* Remove an intercaptor that was previously registered using {@link IRestfulClient#registerInterceptor(IClientInterceptor)}
|
||||||
|
*
|
||||||
|
* @deprecated Use {@link #getInterceptorService()} to access the list of inteerceptors, register them, and unregister them
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
void unregisterInterceptor(IClientInterceptor theInterceptor);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -150,16 +150,6 @@ public class PortUtil {
|
||||||
int nextCandidatePort = myCurrentControlSocketPort + myCurrentOffset;
|
int nextCandidatePort = myCurrentControlSocketPort + myCurrentOffset;
|
||||||
|
|
||||||
// Try to open a port on this socket and use it
|
// Try to open a port on this socket and use it
|
||||||
// try (ServerSocket server = new ServerSocket()) {
|
|
||||||
// server.setReuseAddress(true);
|
|
||||||
// server.bind(new InetSocketAddress("localhost", nextCandidatePort));
|
|
||||||
// try (Socket client = new Socket()) {
|
|
||||||
// client.setReuseAddress(true);
|
|
||||||
// client.connect(new InetSocketAddress("localhost", nextCandidatePort));
|
|
||||||
// }
|
|
||||||
// } catch (IOException e) {
|
|
||||||
// continue;
|
|
||||||
// }
|
|
||||||
if (!isAvailable(nextCandidatePort)) {
|
if (!isAvailable(nextCandidatePort)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -172,27 +162,6 @@ public class PortUtil {
|
||||||
.orElse(stackTraceElements[2]);
|
.orElse(stackTraceElements[2]);
|
||||||
ourLog.info("Returned available port {} for: {}", nextCandidatePort, previousElement.toString());
|
ourLog.info("Returned available port {} for: {}", nextCandidatePort, previousElement.toString());
|
||||||
|
|
||||||
// /*
|
|
||||||
// * This is an attempt to make sure the port is actually
|
|
||||||
// * free before releasing it. For whatever reason on Linux
|
|
||||||
// * it seems like even after we close the ServerSocket there
|
|
||||||
// * is a short while where it is not possible to bind the
|
|
||||||
// * port, even though it should be released by then.
|
|
||||||
// *
|
|
||||||
// * I don't have any solid evidence that this is a good
|
|
||||||
// * way to do this, but it seems to help...
|
|
||||||
// */
|
|
||||||
// for (int i = 0; i < 10; i++) {
|
|
||||||
// try (Socket client = new Socket()) {
|
|
||||||
// client.setReuseAddress(true);
|
|
||||||
// client.connect(new InetSocketAddress(nextCandidatePort), 1000);
|
|
||||||
// ourLog.info("Socket still seems open");
|
|
||||||
// Thread.sleep(250);
|
|
||||||
// } catch (Exception e) {
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
try {
|
try {
|
||||||
Thread.sleep(ourPortDelay);
|
Thread.sleep(ourPortDelay);
|
||||||
} catch (InterruptedException theE) {
|
} catch (InterruptedException theE) {
|
||||||
|
@ -216,22 +185,37 @@ public class PortUtil {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isAvailable(int port) {
|
/**
|
||||||
ourLog.info("Testing a bind on port {}", port);
|
* This method checks if we are able to bind a given port to both
|
||||||
try (ServerSocket ss = new ServerSocket(port)) {
|
* 0.0.0.0 and localhost in order to be sure it's truly available.
|
||||||
|
*/
|
||||||
|
private static boolean isAvailable(int thePort) {
|
||||||
|
ourLog.info("Testing a bind on thePort {}", thePort);
|
||||||
|
try (ServerSocket ss = new ServerSocket()) {
|
||||||
ss.setReuseAddress(true);
|
ss.setReuseAddress(true);
|
||||||
try (DatagramSocket ds = new DatagramSocket(port)) {
|
ss.bind(new InetSocketAddress("0.0.0.0", thePort));
|
||||||
|
try (DatagramSocket ds = new DatagramSocket()) {
|
||||||
ds.setReuseAddress(true);
|
ds.setReuseAddress(true);
|
||||||
ourLog.info("Successfully bound port {}", port);
|
ds.connect(new InetSocketAddress("127.0.0.1", thePort));
|
||||||
return true;
|
ourLog.info("Successfully bound thePort {}", thePort);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ourLog.info("Failed to bind port {}: {}", port, e.toString());
|
ourLog.info("Failed to bind thePort {}: {}", thePort, e.toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
ourLog.info("Failed to bind port {}: {}", port, e.toString());
|
ourLog.info("Failed to bind thePort {}: {}", thePort, e.toString());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try (ServerSocket ss = new ServerSocket()) {
|
||||||
|
ss.setReuseAddress(true);
|
||||||
|
ss.bind(new InetSocketAddress("localhost", thePort));
|
||||||
|
} catch (IOException e) {
|
||||||
|
ourLog.info("Failed to bind thePort {}: {}", thePort, e.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,588 @@
|
||||||
|
package ca.uhn.fhir.interceptor.executor;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.contains;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
public class InterceptorServiceTest {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(InterceptorServiceTest.class);
|
||||||
|
private List<String> myInvocations = new ArrayList<>();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInterceptorWithAnnotationDefinedOnInterface() {
|
||||||
|
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
TestInterceptorWithAnnotationDefinedOnInterface_Class interceptor = new TestInterceptorWithAnnotationDefinedOnInterface_Class();
|
||||||
|
svc.registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
assertEquals(1, interceptor.getRegisterCount());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInterceptorThrowsException() {
|
||||||
|
|
||||||
|
class InterceptorThrowingException {
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void test(String theValue) {
|
||||||
|
throw new AuthenticationException(theValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
svc.registerInterceptor(new InterceptorThrowingException());
|
||||||
|
|
||||||
|
try {
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, new HookParams("A MESSAGE", "B"));
|
||||||
|
fail();
|
||||||
|
} catch (AuthenticationException e) {
|
||||||
|
assertEquals("A MESSAGE", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInterceptorReturnsClass() {
|
||||||
|
|
||||||
|
class InterceptorReturningClass {
|
||||||
|
|
||||||
|
private BaseServerResponseException myNextResponse;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RO)
|
||||||
|
public BaseServerResponseException hook() {
|
||||||
|
return myNextResponse;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
InterceptorReturningClass interceptor0 = new InterceptorReturningClass();
|
||||||
|
InterceptorReturningClass interceptor1 = new InterceptorReturningClass();
|
||||||
|
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
|
||||||
|
interceptor0.myNextResponse = new InvalidRequestException("0");
|
||||||
|
interceptor1.myNextResponse = new InvalidRequestException("1");
|
||||||
|
Object response = svc.callHooksAndReturnObject(Pointcut.TEST_RO, new HookParams("", ""));
|
||||||
|
assertEquals("0", ((InvalidRequestException) response).getMessage());
|
||||||
|
|
||||||
|
interceptor0.myNextResponse = null;
|
||||||
|
response = svc.callHooksAndReturnObject(Pointcut.TEST_RO, new HookParams("", ""));
|
||||||
|
assertEquals("1", ((InvalidRequestException) response).getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testRegisterHookFails() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
int initialSize = svc.getGlobalInterceptorsForUnitTest().size();
|
||||||
|
|
||||||
|
try {
|
||||||
|
svc.registerInterceptor(new InterceptorThatFailsOnRegister());
|
||||||
|
fail();
|
||||||
|
} catch (InternalErrorException e) {
|
||||||
|
// good
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(initialSize, svc.getGlobalInterceptorsForUnitTest().size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testManuallyRegisterInterceptor() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
// Registered in opposite order to verify that the order on the annotation is used
|
||||||
|
MyTestInterceptorTwo interceptor1 = new MyTestInterceptorTwo();
|
||||||
|
MyTestInterceptorOne interceptor0 = new MyTestInterceptorOne();
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
|
||||||
|
// Register the manual interceptor (has Order right in the middle)
|
||||||
|
MyTestInterceptorManual myInterceptorManual = new MyTestInterceptorManual();
|
||||||
|
svc.registerInterceptor(myInterceptorManual);
|
||||||
|
List<Object> globalInterceptors = svc.getGlobalInterceptorsForUnitTest();
|
||||||
|
assertEquals(3, globalInterceptors.size());
|
||||||
|
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||||
|
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorManual);
|
||||||
|
assertTrue(globalInterceptors.get(2).getClass().toString(), globalInterceptors.get(2) instanceof MyTestInterceptorTwo);
|
||||||
|
|
||||||
|
// Try to register again (should have no effect
|
||||||
|
svc.registerInterceptor(myInterceptorManual);
|
||||||
|
globalInterceptors = svc.getGlobalInterceptorsForUnitTest();
|
||||||
|
assertEquals(3, globalInterceptors.size());
|
||||||
|
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||||
|
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorManual);
|
||||||
|
assertTrue(globalInterceptors.get(2).getClass().toString(), globalInterceptors.get(2) instanceof MyTestInterceptorTwo);
|
||||||
|
|
||||||
|
// Make sure we have the right invokers in the right order
|
||||||
|
List<Object> invokers = svc.getInterceptorsWithInvokersForPointcut(Pointcut.TEST_RB);
|
||||||
|
assertSame(interceptor0, invokers.get(0));
|
||||||
|
assertSame(myInterceptorManual, invokers.get(1));
|
||||||
|
assertSame(interceptor1, invokers.get(2));
|
||||||
|
|
||||||
|
// Finally, unregister it
|
||||||
|
svc.unregisterInterceptor(myInterceptorManual);
|
||||||
|
globalInterceptors = svc.getGlobalInterceptorsForUnitTest();
|
||||||
|
assertEquals(2, globalInterceptors.size());
|
||||||
|
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||||
|
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorTwo);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvokeGlobalInterceptorMethods() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
// Registered in opposite order to verify that the order on the annotation is used
|
||||||
|
MyTestInterceptorTwo interceptor1 = new MyTestInterceptorTwo();
|
||||||
|
MyTestInterceptorOne interceptor0 = new MyTestInterceptorOne();
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
|
||||||
|
boolean outcome = svc.callHooks(Pointcut.TEST_RB, new HookParams("A", "B"));
|
||||||
|
assertTrue(outcome);
|
||||||
|
|
||||||
|
assertThat(myInvocations, contains("MyTestInterceptorOne.testRb", "MyTestInterceptorTwo.testRb"));
|
||||||
|
assertSame("A", interceptor0.myLastString0);
|
||||||
|
assertSame("A", interceptor1.myLastString0);
|
||||||
|
assertSame("B", interceptor1.myLastString1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvokeUsingSupplierArg() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
MyTestInterceptorOne interceptor0 = new MyTestInterceptorOne();
|
||||||
|
MyTestInterceptorTwo interceptor1 = new MyTestInterceptorTwo();
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
|
||||||
|
boolean outcome = svc.callHooks(Pointcut.TEST_RB, new HookParams("A", "B"));
|
||||||
|
assertTrue(outcome);
|
||||||
|
|
||||||
|
assertThat(myInvocations, contains("MyTestInterceptorOne.testRb", "MyTestInterceptorTwo.testRb"));
|
||||||
|
assertSame("A", interceptor0.myLastString0);
|
||||||
|
assertSame("A", interceptor1.myLastString0);
|
||||||
|
assertSame("B", interceptor1.myLastString1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testInvokeGlobalInterceptorMethods_MethodAbortsProcessing() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
MyTestInterceptorOne interceptor0 = new MyTestInterceptorOne();
|
||||||
|
MyTestInterceptorTwo interceptor1 = new MyTestInterceptorTwo();
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
|
||||||
|
interceptor0.myNextReturn = false;
|
||||||
|
|
||||||
|
boolean outcome = svc.callHooks(Pointcut.TEST_RB, new HookParams("A", "B"));
|
||||||
|
assertFalse(outcome);
|
||||||
|
|
||||||
|
assertThat(myInvocations, contains("MyTestInterceptorOne.testRb"));
|
||||||
|
assertSame("A", interceptor0.myLastString0);
|
||||||
|
assertSame(null, interceptor1.myLastString0);
|
||||||
|
assertSame(null, interceptor1.myLastString1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallHooksInvokedWithNullParameters() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
class NullParameterInterceptor {
|
||||||
|
private String myValue0 = "";
|
||||||
|
private String myValue1 = "";
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void hook(String theValue0, String theValue1) {
|
||||||
|
myValue0 = theValue0;
|
||||||
|
myValue1 = theValue1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
NullParameterInterceptor interceptor;
|
||||||
|
HookParams params;
|
||||||
|
|
||||||
|
// Both null
|
||||||
|
interceptor = new NullParameterInterceptor();
|
||||||
|
svc.registerInterceptor(interceptor);
|
||||||
|
params = new HookParams()
|
||||||
|
.add(String.class, null)
|
||||||
|
.add(String.class, null);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
assertEquals(null, interceptor.myValue0);
|
||||||
|
assertEquals(null, interceptor.myValue1);
|
||||||
|
svc.unregisterAllInterceptors();
|
||||||
|
|
||||||
|
// First null
|
||||||
|
interceptor = new NullParameterInterceptor();
|
||||||
|
svc.registerInterceptor(interceptor);
|
||||||
|
params = new HookParams()
|
||||||
|
.add(String.class, null)
|
||||||
|
.add(String.class, "A");
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
assertEquals(null, interceptor.myValue0);
|
||||||
|
assertEquals("A", interceptor.myValue1);
|
||||||
|
svc.unregisterAllInterceptors();
|
||||||
|
|
||||||
|
// Second null
|
||||||
|
interceptor = new NullParameterInterceptor();
|
||||||
|
svc.registerInterceptor(interceptor);
|
||||||
|
params = new HookParams()
|
||||||
|
.add(String.class, "A")
|
||||||
|
.add(String.class, null);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
assertEquals("A", interceptor.myValue0);
|
||||||
|
assertEquals(null, interceptor.myValue1);
|
||||||
|
svc.unregisterAllInterceptors();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallHooksLogAndSwallowException() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
class LogAndSwallowInterceptor0 {
|
||||||
|
private boolean myHit;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void hook(String theValue0, String theValue1) {
|
||||||
|
myHit = true;
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogAndSwallowInterceptor0 interceptor0 = new LogAndSwallowInterceptor0();
|
||||||
|
svc.registerInterceptor(interceptor0);
|
||||||
|
|
||||||
|
class LogAndSwallowInterceptor1 {
|
||||||
|
private boolean myHit;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void hook(String theValue0, String theValue1) {
|
||||||
|
myHit = true;
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogAndSwallowInterceptor1 interceptor1 = new LogAndSwallowInterceptor1();
|
||||||
|
svc.registerInterceptor(interceptor1);
|
||||||
|
|
||||||
|
class LogAndSwallowInterceptor2 {
|
||||||
|
private boolean myHit;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void hook(String theValue0, String theValue1) {
|
||||||
|
myHit = true;
|
||||||
|
throw new NullPointerException("AAA");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LogAndSwallowInterceptor2 interceptor2 = new LogAndSwallowInterceptor2();
|
||||||
|
svc.registerInterceptor(interceptor2);
|
||||||
|
|
||||||
|
HookParams params = new HookParams()
|
||||||
|
.add(String.class, null)
|
||||||
|
.add(String.class, null);
|
||||||
|
|
||||||
|
try {
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
fail();
|
||||||
|
} catch (NullPointerException e) {
|
||||||
|
assertEquals("AAA", e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals(true, interceptor0.myHit);
|
||||||
|
assertEquals(true, interceptor1.myHit);
|
||||||
|
assertEquals(true, interceptor2.myHit);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCallHooksInvokedWithWrongParameters() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
Integer msg = 123;
|
||||||
|
CanonicalSubscription subs = new CanonicalSubscription();
|
||||||
|
HookParams params = new HookParams(msg, subs);
|
||||||
|
try {
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertThat(e.getMessage(), containsString("Invalid params for pointcut " + Pointcut.TEST_RB + " - Wanted java.lang.String,java.lang.String but found "));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateParamTypes() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
HookParams params = new HookParams();
|
||||||
|
params.add(String.class, "A");
|
||||||
|
params.add(String.class, "B");
|
||||||
|
boolean validated = svc.haveAppropriateParams(Pointcut.TEST_RB, params);
|
||||||
|
assertTrue(validated);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateParamTypesMissingParam() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
HookParams params = new HookParams();
|
||||||
|
params.add(String.class, "A");
|
||||||
|
try {
|
||||||
|
svc.haveAppropriateParams(Pointcut.TEST_RB, params);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals("Wrong number of params for pointcut " + Pointcut.TEST_RB + " - Wanted java.lang.String,java.lang.String but found [String]", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateParamTypesExtraParam() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
HookParams params = new HookParams();
|
||||||
|
params.add(String.class, "A");
|
||||||
|
params.add(String.class, "B");
|
||||||
|
params.add(String.class, "C");
|
||||||
|
params.add(String.class, "D");
|
||||||
|
params.add(String.class, "E");
|
||||||
|
try {
|
||||||
|
svc.haveAppropriateParams(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals("Wrong number of params for pointcut " + Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED + " - Wanted ca.uhn.fhir.rest.api.server.RequestDetails,ca.uhn.fhir.rest.server.servlet.ServletRequestDetails,org.hl7.fhir.instance.model.api.IBaseResource,org.hl7.fhir.instance.model.api.IBaseResource but found [String, String, String, String, String]", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
@Test
|
||||||
|
public void testValidateParamTypesWrongParam() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
|
||||||
|
HookParams params = new HookParams();
|
||||||
|
params.add((Class) String.class, 1);
|
||||||
|
params.add((Class) String.class, 2);
|
||||||
|
params.add((Class) String.class, 3);
|
||||||
|
params.add((Class) String.class, 4);
|
||||||
|
try {
|
||||||
|
svc.haveAppropriateParams(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||||
|
fail();
|
||||||
|
} catch (IllegalArgumentException e) {
|
||||||
|
assertEquals("Invalid params for pointcut " + Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED + " - class java.lang.Integer is not of type class java.lang.String", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testThreadLocalHookInterceptor() {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
svc.setThreadlocalInvokersEnabled(true);
|
||||||
|
|
||||||
|
HookParams params = new HookParams().add("A").add("B");
|
||||||
|
|
||||||
|
@Interceptor(order = 100)
|
||||||
|
class LocalInterceptor {
|
||||||
|
|
||||||
|
private int myCount = 0;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public boolean testRb(String theString0, String theString1) {
|
||||||
|
myCount++;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
LocalInterceptor interceptor = new LocalInterceptor();
|
||||||
|
svc.registerThreadLocalInterceptor(interceptor);
|
||||||
|
try {
|
||||||
|
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
assertEquals(5, interceptor.myCount);
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
svc.unregisterThreadLocalInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call some more - The interceptor is removed so the count shouldn't change
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
assertEquals(5, interceptor.myCount);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <pre>
|
||||||
|
* JA 20190321 On my MBP 2018
|
||||||
|
* ThreadLocalEnabled=true - Performed 500000 loops in 8383.0ms - 0.017ms / loop
|
||||||
|
* ThreadLocalEnabled=false - Performed 500000 loops in 3743.0ms - 0.007ms / loop
|
||||||
|
* ThreadLocalEnabled=true - Performed 500000 loops in 6163.0ms - 0.012ms / loop
|
||||||
|
* ThreadLocalEnabled=false - Performed 500000 loops in 3487.0ms - 0.007ms / loop
|
||||||
|
* ThreadLocalEnabled=true - Performed 1000000 loops in 00:00:12.458 - 0.012ms / loop
|
||||||
|
* ThreadLocalEnabled=false - Performed 1000000 loops in 7046.0ms - 0.007ms / loop
|
||||||
|
* </pre>
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
@Ignore("Performance test - Not needed normally")
|
||||||
|
public void testThreadLocalHookInterceptorMicroBenchmark() {
|
||||||
|
threadLocalMicroBenchmark(true, 500000);
|
||||||
|
threadLocalMicroBenchmark(false, 500000);
|
||||||
|
threadLocalMicroBenchmark(true, 500000);
|
||||||
|
threadLocalMicroBenchmark(false, 500000);
|
||||||
|
threadLocalMicroBenchmark(true, 500000);
|
||||||
|
threadLocalMicroBenchmark(false, 500000);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void threadLocalMicroBenchmark(boolean theThreadlocalInvokersEnabled, int theCount) {
|
||||||
|
InterceptorService svc = new InterceptorService();
|
||||||
|
svc.setThreadlocalInvokersEnabled(theThreadlocalInvokersEnabled);
|
||||||
|
|
||||||
|
HookParams params = new HookParams().add("A").add("B");
|
||||||
|
|
||||||
|
@Interceptor(order = 100)
|
||||||
|
class LocalInterceptor {
|
||||||
|
|
||||||
|
private int myCount = 0;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void testRb(String theString0, String theString1) {
|
||||||
|
myCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalInterceptor interceptor = new LocalInterceptor();
|
||||||
|
StopWatch sw = new StopWatch();
|
||||||
|
for (int i = 0; i < theCount; i++) {
|
||||||
|
|
||||||
|
svc.registerThreadLocalInterceptor(interceptor);
|
||||||
|
try {
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
svc.callHooks(Pointcut.TEST_RB, params);
|
||||||
|
} finally {
|
||||||
|
svc.unregisterThreadLocalInterceptor(interceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLog.info("ThreadLocalEnabled={} - Performed {} loops in {} - {} / loop - Outcomne: {}", theThreadlocalInvokersEnabled, theCount, sw.toString(), sw.formatMillisPerOperation(theCount), interceptor.myCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
myInvocations.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
interface TestInterceptorWithAnnotationDefinedOnInterface_Interface {
|
||||||
|
|
||||||
|
@Hook(Pointcut.INTERCEPTOR_REGISTERED)
|
||||||
|
void registered();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Interceptor(order = 100)
|
||||||
|
public class MyTestInterceptorOne {
|
||||||
|
|
||||||
|
private String myLastString0;
|
||||||
|
private boolean myNextReturn = true;
|
||||||
|
|
||||||
|
public MyTestInterceptorOne() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public boolean testRb(String theString0) {
|
||||||
|
myLastString0 = theString0;
|
||||||
|
myInvocations.add("MyTestInterceptorOne.testRb");
|
||||||
|
return myNextReturn;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Interceptor(order = 300)
|
||||||
|
public class MyTestInterceptorTwo {
|
||||||
|
private String myLastString0;
|
||||||
|
private String myLastString1;
|
||||||
|
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public boolean testRb(String theString0, String theString1) {
|
||||||
|
myLastString0 = theString0;
|
||||||
|
myLastString1 = theString1;
|
||||||
|
myInvocations.add("MyTestInterceptorTwo.testRb");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Interceptor(order = 200)
|
||||||
|
public class MyTestInterceptorManual {
|
||||||
|
@Hook(Pointcut.TEST_RB)
|
||||||
|
public void testRb() {
|
||||||
|
myInvocations.add("MyTestInterceptorManual.testRb");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class TestInterceptorWithAnnotationDefinedOnInterface_Class implements TestInterceptorWithAnnotationDefinedOnInterface_Interface {
|
||||||
|
|
||||||
|
private int myRegisterCount = 0;
|
||||||
|
|
||||||
|
public int getRegisterCount() {
|
||||||
|
return myRegisterCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registered() {
|
||||||
|
myRegisterCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just a make-believe version of this class for the unit test
|
||||||
|
*/
|
||||||
|
private static class CanonicalSubscription {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Just a make-believe version of this class for the unit test
|
||||||
|
*/
|
||||||
|
private static class ResourceDeliveryMessage {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Interceptor()
|
||||||
|
public static class InterceptorThatFailsOnRegister {
|
||||||
|
|
||||||
|
@Hook(Pointcut.INTERCEPTOR_REGISTERED)
|
||||||
|
public void start() throws Exception {
|
||||||
|
throw new Exception("InterceptorThatFailsOnRegister FAILED!");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -9,7 +9,8 @@ import java.util.Date;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
public class StopWatchTest {
|
public class StopWatchTest {
|
||||||
|
|
||||||
|
@ -99,7 +100,7 @@ public class StopWatchTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFormatMillis() {
|
public void testFormatMillis() {
|
||||||
assertEquals("0.134ms", StopWatch.formatMillis(0.1339d));
|
assertEquals("0.134ms", StopWatch.formatMillis(0.1339d).replace(',', '.'));
|
||||||
assertEquals("1000ms", StopWatch.formatMillis(DateUtils.MILLIS_PER_SECOND));
|
assertEquals("1000ms", StopWatch.formatMillis(DateUtils.MILLIS_PER_SECOND));
|
||||||
assertEquals("00:01:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE));
|
assertEquals("00:01:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE));
|
||||||
assertEquals("00:01:01", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE + DateUtils.MILLIS_PER_SECOND));
|
assertEquals("00:01:01", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE + DateUtils.MILLIS_PER_SECOND));
|
||||||
|
|
|
@ -7,7 +7,6 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
@ -59,8 +58,9 @@ public class FhirServerConfig extends BaseJavaConfigDstu2 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||||
retVal.setLoggerName("fhirtest.access");
|
retVal.setLoggerName("fhirtest.access");
|
||||||
retVal.setMessageFormat(
|
retVal.setMessageFormat(
|
||||||
|
|
|
@ -8,12 +8,9 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.springframework.beans.BeansException;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.context.ApplicationContext;
|
|
||||||
import org.springframework.context.ApplicationContextAware;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
|
@ -73,8 +70,9 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||||
retVal.setLoggerName("fhirtest.access");
|
retVal.setLoggerName("fhirtest.access");
|
||||||
retVal.setMessageFormat(
|
retVal.setMessageFormat(
|
||||||
|
|
|
@ -64,8 +64,9 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
* Do some fancy logging to create a nice access log that has details about each incoming request.
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
public IServerInterceptor loggingInterceptor() {
|
public LoggingInterceptor loggingInterceptor() {
|
||||||
LoggingInterceptor retVal = new LoggingInterceptor();
|
LoggingInterceptor retVal = new LoggingInterceptor();
|
||||||
retVal.setLoggerName("fhirtest.access");
|
retVal.setLoggerName("fhirtest.access");
|
||||||
retVal.setMessageFormat(
|
retVal.setMessageFormat(
|
||||||
|
|
|
@ -13,6 +13,7 @@ import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||||
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||||
|
@ -66,8 +67,8 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
|
ResourceProviderFactory beans = myAppCtx.getBean(resourceProviderBeanName, ResourceProviderFactory.class);
|
||||||
setResourceProviders(beans);
|
registerProviders(beans.createProviders());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The system provider implements non-resource-type methods, such as
|
* The system provider implements non-resource-type methods, such as
|
||||||
|
@ -85,7 +86,7 @@ public class JpaServerDemo extends RestfulServer {
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalStateException();
|
throw new IllegalStateException();
|
||||||
}
|
}
|
||||||
setPlainProviders(systemProvider);
|
registerProvider(systemProvider);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The conformance provider exports the supported resources, search parameters, etc for
|
* The conformance provider exports the supported resources, search parameters, etc for
|
||||||
|
|
|
@ -21,6 +21,10 @@ package ca.uhn.fhir.rest.client.impl;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.*;
|
import ca.uhn.fhir.context.*;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
|
@ -43,7 +47,11 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
|
||||||
import java.io.*;
|
import javax.annotation.Nonnull;
|
||||||
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.Reader;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
@ -65,13 +73,13 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
private final String myUrlBase;
|
private final String myUrlBase;
|
||||||
private boolean myDontValidateConformance;
|
private boolean myDontValidateConformance;
|
||||||
private EncodingEnum myEncoding = null; // default unspecified (will be XML)
|
private EncodingEnum myEncoding = null; // default unspecified (will be XML)
|
||||||
private List<IClientInterceptor> myInterceptors = new ArrayList<IClientInterceptor>();
|
|
||||||
private boolean myKeepResponses = false;
|
private boolean myKeepResponses = false;
|
||||||
private IHttpResponse myLastResponse;
|
private IHttpResponse myLastResponse;
|
||||||
private String myLastResponseBody;
|
private String myLastResponseBody;
|
||||||
private Boolean myPrettyPrint = false;
|
private Boolean myPrettyPrint = false;
|
||||||
private SummaryEnum mySummary;
|
private SummaryEnum mySummary;
|
||||||
private RequestFormatParamStyleEnum myRequestFormatParamStyle = RequestFormatParamStyleEnum.SHORT;
|
private RequestFormatParamStyleEnum myRequestFormatParamStyle = RequestFormatParamStyleEnum.SHORT;
|
||||||
|
private IInterceptorService myInterceptorService;
|
||||||
|
|
||||||
BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) {
|
BaseClient(IHttpClient theClient, String theUrlBase, RestfulClientFactory theFactory) {
|
||||||
super();
|
super();
|
||||||
|
@ -92,6 +100,18 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
myEncoding = EncodingEnum.JSON;
|
myEncoding = EncodingEnum.JSON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setInterceptorService(new InterceptorService());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IInterceptorService getInterceptorService() {
|
||||||
|
return myInterceptorService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setInterceptorService(@Nonnull IInterceptorService theInterceptorService) {
|
||||||
|
Validate.notNull(theInterceptorService, "theInterceptorService must not be null");
|
||||||
|
myInterceptorService = theInterceptorService;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected Map<String, List<String>> createExtraParams(String theCustomAcceptHeader) {
|
protected Map<String, List<String>> createExtraParams(String theCustomAcceptHeader) {
|
||||||
|
@ -149,14 +169,6 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
return myClient;
|
return myClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public List<IClientInterceptor> getInterceptors() {
|
|
||||||
return Collections.unmodifiableList(myInterceptors);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
|
* For now, this is a part of the internal API of HAPI - Use with caution as this method may change!
|
||||||
*/
|
*/
|
||||||
|
@ -276,15 +288,16 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IClientInterceptor nextInterceptor : myInterceptors) {
|
HookParams requestParams = new HookParams();
|
||||||
nextInterceptor.interceptRequest(httpRequest);
|
requestParams.add(IHttpRequest.class, httpRequest);
|
||||||
}
|
getInterceptorService().callHooks(Pointcut.CLIENT_REQUEST, requestParams);
|
||||||
|
|
||||||
response = httpRequest.execute();
|
response = httpRequest.execute();
|
||||||
|
|
||||||
for (IClientInterceptor nextInterceptor : myInterceptors) {
|
HookParams responseParams = new HookParams();
|
||||||
nextInterceptor.interceptResponse(response);
|
responseParams.add(IHttpRequest.class, httpRequest);
|
||||||
}
|
responseParams.add(IHttpResponse.class, response);
|
||||||
|
getInterceptorService().callHooks(Pointcut.CLIENT_RESPONSE, responseParams);
|
||||||
|
|
||||||
String mimeType;
|
String mimeType;
|
||||||
if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatus()) {
|
if (Constants.STATUS_HTTP_204_NO_CONTENT == response.getStatus()) {
|
||||||
|
@ -446,7 +459,7 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
@Override
|
@Override
|
||||||
public void registerInterceptor(IClientInterceptor theInterceptor) {
|
public void registerInterceptor(IClientInterceptor theInterceptor) {
|
||||||
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
||||||
myInterceptors.add(theInterceptor);
|
getInterceptorService().registerInterceptor(theInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -461,7 +474,7 @@ public abstract class BaseClient implements IRestfulClient {
|
||||||
@Override
|
@Override
|
||||||
public void unregisterInterceptor(IClientInterceptor theInterceptor) {
|
public void unregisterInterceptor(IClientInterceptor theInterceptor) {
|
||||||
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
||||||
myInterceptors.remove(theInterceptor);
|
getInterceptorService().unregisterInterceptor(theInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected final class ResourceOrBinaryResponseHandler extends ResourceResponseHandler<IBaseResource> {
|
protected final class ResourceOrBinaryResponseHandler extends ResourceResponseHandler<IBaseResource> {
|
||||||
|
|
|
@ -272,10 +272,9 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
||||||
@Override
|
@Override
|
||||||
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, IRestfulClient theClient) {
|
public void validateServerBase(String theServerBase, IHttpClient theHttpClient, IRestfulClient theClient) {
|
||||||
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);
|
GenericClient client = new GenericClient(myContext, theHttpClient, theServerBase, this);
|
||||||
|
|
||||||
|
client.setInterceptorService(theClient.getInterceptorService());
|
||||||
client.setEncoding(theClient.getEncoding());
|
client.setEncoding(theClient.getEncoding());
|
||||||
for (IClientInterceptor interceptor : theClient.getInterceptors()) {
|
|
||||||
client.registerInterceptor(interceptor);
|
|
||||||
}
|
|
||||||
client.setDontValidateConformance(true);
|
client.setDontValidateConformance(true);
|
||||||
|
|
||||||
IBaseResource conformance;
|
IBaseResource conformance;
|
||||||
|
|
|
@ -156,10 +156,10 @@ public abstract class AbstractJaxRsBundleProvider extends AbstractJaxRsProvider
|
||||||
/**
|
/**
|
||||||
* Default: an empty list of interceptors
|
* Default: an empty list of interceptors
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.rest.server.IRestfulServer#getInterceptors()
|
* @see ca.uhn.fhir.rest.server.IRestfulServerDefaults#getInterceptors_()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<IServerInterceptor> getInterceptors() {
|
public List<IServerInterceptor> getInterceptors_() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,6 +33,7 @@ import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
|
@ -25,6 +25,7 @@ import java.util.Map.Entry;
|
||||||
|
|
||||||
import javax.ws.rs.core.*;
|
import javax.ws.rs.core.*;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
@ -74,6 +75,11 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
CTX = ctx;
|
CTX = ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IInterceptorService getInterceptorService() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DEFAULT = AddProfileTagEnum.NEVER
|
* DEFAULT = AddProfileTagEnum.NEVER
|
||||||
*/
|
*/
|
||||||
|
@ -145,10 +151,10 @@ public abstract class AbstractJaxRsProvider implements IRestfulServerDefaults {
|
||||||
* Default: an empty list of interceptors (Interceptors are not yet supported
|
* Default: an empty list of interceptors (Interceptors are not yet supported
|
||||||
* in the JAX-RS server). Please get in touch if you'd like to help!
|
* in the JAX-RS server). Please get in touch if you'd like to help!
|
||||||
*
|
*
|
||||||
* @see ca.uhn.fhir.rest.server.IRestfulServer#getInterceptors()
|
* @see ca.uhn.fhir.rest.server.IRestfulServerDefaults#getInterceptors_()
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<IServerInterceptor> getInterceptors() {
|
public List<IServerInterceptor> getInterceptors_() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import javax.ws.rs.*;
|
||||||
import javax.ws.rs.core.MediaType;
|
import javax.ws.rs.core.MediaType;
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
@ -102,7 +103,7 @@ implements IRestfulServer<JaxRsRequest>, IResourceProvider {
|
||||||
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
theBindings = JaxRsMethodBindings.getMethodBindings(this, theProviderClass);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base for request for a resource provider has the following form:</br>
|
* The base for request for a resource provider has the following form:</br>
|
||||||
* {@link AbstractJaxRsResourceProvider#getBaseForServer()
|
* {@link AbstractJaxRsResourceProvider#getBaseForServer()
|
||||||
* getBaseForServer()} + "/" +
|
* getBaseForServer()} + "/" +
|
||||||
|
|
|
@ -67,6 +67,7 @@ public class JaxRsRequest extends RequestDetails {
|
||||||
*/
|
*/
|
||||||
public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType,
|
public JaxRsRequest(AbstractJaxRsProvider server, String resourceString, RequestTypeEnum requestType,
|
||||||
RestOperationTypeEnum restOperation) {
|
RestOperationTypeEnum restOperation) {
|
||||||
|
super(server.getInterceptorService());
|
||||||
this.myHeaders = server.getHeaders();
|
this.myHeaders = server.getHeaders();
|
||||||
this.myResourceString = resourceString;
|
this.myResourceString = resourceString;
|
||||||
this.setRestOperationType(restOperation);
|
this.setRestOperationType(restOperation);
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.jaxrs.server.test;
|
package ca.uhn.fhir.jaxrs.server.test;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
import org.hl7.fhir.dstu3.model.Patient;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
@ -18,4 +19,5 @@ public class TestJaxRsDummyPatientProviderDstu3 extends AbstractJaxRsResourcePro
|
||||||
public Class<Patient> getResourceType() {
|
public Class<Patient> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -127,7 +127,7 @@ public class JaxRsPatientRestProvider extends AbstractJaxRsResourceProvider<Pati
|
||||||
/** THE DEFAULTS */
|
/** THE DEFAULTS */
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IServerInterceptor> getInterceptors() {
|
public List<IServerInterceptor> getInterceptors_() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -128,7 +128,7 @@ public class JaxRsPatientRestProviderDstu3 extends AbstractJaxRsResourceProvider
|
||||||
/** THE DEFAULTS */
|
/** THE DEFAULTS */
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IServerInterceptor> getInterceptors() {
|
public List<IServerInterceptor> getInterceptors_() {
|
||||||
return Collections.emptyList();
|
return Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,8 +2,8 @@ package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.i18n.HapiLocalizer;
|
import ca.uhn.fhir.i18n.HapiLocalizer;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.executor.InterceptorService;
|
|
||||||
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
|
@ -16,6 +16,7 @@ import ca.uhn.fhir.jpa.subscription.module.cache.ISubscribableChannelFactory;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.LinkedBlockingQueueSubscribableChannelFactory;
|
import ca.uhn.fhir.jpa.subscription.module.cache.LinkedBlockingQueueSubscribableChannelFactory;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.matcher.ISubscriptionMatcher;
|
import ca.uhn.fhir.jpa.subscription.module.matcher.ISubscriptionMatcher;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.matcher.InMemorySubscriptionMatcher;
|
import ca.uhn.fhir.jpa.subscription.module.matcher.InMemorySubscriptionMatcher;
|
||||||
|
import ca.uhn.fhir.jpa.util.JpaInterceptorService;
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
import org.hibernate.jpa.HibernatePersistenceProvider;
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
@ -177,15 +178,15 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public InterceptorService interceptorRegistry() {
|
public IInterceptorService jpaInterceptorService() {
|
||||||
return new InterceptorService("hapi-fhir-jpa");
|
return new JpaInterceptorService();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses may override
|
* Subclasses may override
|
||||||
*/
|
*/
|
||||||
protected boolean isSupported(String theResourceType) {
|
protected boolean isSupported(String theResourceType) {
|
||||||
return daoRegistry().getResourceDao(theResourceType) != null;
|
return daoRegistry().getResourceDaoIfExists(theResourceType) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void configureEntityManagerFactory(LocalContainerEntityManagerFactoryBean theFactory, FhirContext theCtx) {
|
public static void configureEntityManagerFactory(LocalContainerEntityManagerFactoryBean theFactory, FhirContext theCtx) {
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.*;
|
import ca.uhn.fhir.context.*;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.dao.data.*;
|
import ca.uhn.fhir.jpa.dao.data.*;
|
||||||
import ca.uhn.fhir.jpa.dao.index.DaoSearchParamSynchronizer;
|
import ca.uhn.fhir.jpa.dao.index.DaoSearchParamSynchronizer;
|
||||||
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
|
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
|
@ -131,8 +131,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IdHelperService myIdHelperService;
|
protected IdHelperService myIdHelperService;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
|
||||||
@Autowired
|
|
||||||
protected IForcedIdDao myForcedIdDao;
|
protected IForcedIdDao myForcedIdDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ISearchResultDao mySearchResultDao;
|
protected ISearchResultDao mySearchResultDao;
|
||||||
|
@ -193,6 +191,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
private SearchBuilderFactory mySearchBuilderFactory;
|
private SearchBuilderFactory mySearchBuilderFactory;
|
||||||
|
|
||||||
private ApplicationContext myApplicationContext;
|
private ApplicationContext myApplicationContext;
|
||||||
|
@Autowired
|
||||||
|
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the newly created forced ID. If the entity already had a forced ID, or if
|
* Returns the newly created forced ID. If the entity already had a forced ID, or if
|
||||||
|
@ -225,7 +225,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (theExpungeOptions.getLimit() < 1) {
|
if (theExpungeOptions.getLimit() < 1) {
|
||||||
throw new InvalidRequestException("Expunge limit may not be less than 1. Received expunge limit "+theExpungeOptions.getLimit() + ".");
|
throw new InvalidRequestException("Expunge limit may not be less than 1. Received expunge limit " + theExpungeOptions.getLimit() + ".");
|
||||||
}
|
}
|
||||||
|
|
||||||
AtomicInteger remainingCount = new AtomicInteger(theExpungeOptions.getLimit());
|
AtomicInteger remainingCount = new AtomicInteger(theExpungeOptions.getLimit());
|
||||||
|
@ -624,10 +624,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
return myDaoRegistry.getResourceDaoIfExists(theType);
|
return myDaoRegistry.getResourceDaoIfExists(theType);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IBaseResource> theClass) {
|
|
||||||
return myDaoRegistry.getDaoOrThrowException(theClass);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected TagDefinition getTagOrNull(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
protected TagDefinition getTagOrNull(TagTypeEnum theTagType, String theScheme, String theTerm, String theLabel) {
|
||||||
if (isBlank(theScheme) && isBlank(theTerm) && isBlank(theLabel)) {
|
if (isBlank(theScheme) && isBlank(theTerm) && isBlank(theLabel)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -784,10 +780,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
if (theRequestDetails.getUserData().get(PROCESSING_SUB_REQUEST) == Boolean.TRUE) {
|
if (theRequestDetails.getUserData().get(PROCESSING_SUB_REQUEST) == Boolean.TRUE) {
|
||||||
theRequestDetails.notifyIncomingRequestPreHandled(theOperationType);
|
theRequestDetails.notifyIncomingRequestPreHandled(theOperationType);
|
||||||
}
|
}
|
||||||
List<IServerInterceptor> interceptors = getConfig().getInterceptors();
|
|
||||||
for (IServerInterceptor next : interceptors) {
|
|
||||||
next.incomingRequestPreHandled(theOperationType, theRequestDetails);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1439,6 +1431,11 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
|
|
||||||
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
||||||
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
||||||
|
|
||||||
|
// We'll update the resource ID with the correct version later but for
|
||||||
|
// now at least set it to something useful for the interceptors
|
||||||
|
theResource.setId(theEntity.getIdDt());
|
||||||
|
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
ActionRequestDetails requestDetails;
|
ActionRequestDetails requestDetails;
|
||||||
if (theRequestDetails != null) {
|
if (theRequestDetails != null) {
|
||||||
|
@ -1447,18 +1444,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify IServerOperationInterceptors about pre-action call
|
// Notify IServerOperationInterceptors about pre-action call
|
||||||
if (theRequestDetails != null) {
|
|
||||||
theRequestDetails.getRequestOperationCallback().resourcePreUpdate(theOldResource, theResource);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, theOldResource, theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, theOldResource)
|
.add(IBaseResource.class, theOldResource)
|
||||||
.add(IBaseResource.class, theResource);
|
.add(IBaseResource.class, theResource)
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED, hookParams);
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, hookParams);
|
||||||
|
|
||||||
// Perform update
|
// Perform update
|
||||||
ResourceTable savedEntity = updateEntity(theRequestDetails, theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
ResourceTable savedEntity = updateEntity(theRequestDetails, theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||||
|
@ -1480,23 +1471,15 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
|
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
if (!savedEntity.isUnchangedInCurrentOperation()) {
|
if (!savedEntity.isUnchangedInCurrentOperation()) {
|
||||||
if (theRequestDetails != null) {
|
|
||||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(theResource);
|
|
||||||
theRequestDetails.getRequestOperationCallback().resourceUpdated(theOldResource, theResource);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theResource);
|
|
||||||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theOldResource, theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, theOldResource)
|
.add(IBaseResource.class, theOldResource)
|
||||||
.add(IBaseResource.class, theResource);
|
.add(IBaseResource.class, theResource)
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, hookParams);
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, hookParams);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,10 +24,10 @@ import ca.uhn.fhir.context.ConfigurationException;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
|
@ -52,6 +52,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
|
import ca.uhn.fhir.rest.server.method.SearchMethodBinding;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.*;
|
import ca.uhn.fhir.util.*;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
@ -71,6 +72,7 @@ import javax.annotation.PostConstruct;
|
||||||
import javax.persistence.NoResultException;
|
import javax.persistence.NoResultException;
|
||||||
import javax.persistence.TypedQuery;
|
import javax.persistence.TypedQuery;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
@ -218,14 +220,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
T resourceToDelete = toResource(myResourceType, entity, null, false);
|
T resourceToDelete = toResource(myResourceType, entity, null, false);
|
||||||
|
|
||||||
// Notify IServerOperationInterceptors about pre-action call
|
// Notify IServerOperationInterceptors about pre-action call
|
||||||
if (theRequest != null) {
|
HookParams hook = new HookParams()
|
||||||
theRequest.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
}
|
.add(RequestDetails.class, theRequest)
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_DELETED, hook);
|
||||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequest, resourceToDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validateOkToDelete(theDeleteConflicts, entity, false);
|
validateOkToDelete(theDeleteConflicts, entity, false);
|
||||||
|
|
||||||
|
@ -242,25 +241,18 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
resourceToDelete.setId(entity.getIdDt());
|
resourceToDelete.setId(entity.getIdDt());
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
if (theRequest != null) {
|
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), theId.getResourceType(), theId);
|
|
||||||
theRequest.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourceDeleted(theRequest, resourceToDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, resourceToDelete);
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, resourceToDelete).setCreated(true);
|
DaoMethodOutcome outcome = toMethodOutcome(theRequest, savedEntity, resourceToDelete).setCreated(true);
|
||||||
|
|
||||||
IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
|
IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(getContext());
|
||||||
String message = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulDeletes", 1, w.getMillis());
|
String message = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "successfulDeletes", 1, w.getMillis());
|
||||||
|
@ -308,14 +300,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
T resourceToDelete = toResource(myResourceType, entity, null, false);
|
T resourceToDelete = toResource(myResourceType, entity, null, false);
|
||||||
|
|
||||||
// Notify IServerOperationInterceptors about pre-action call
|
// Notify IServerOperationInterceptors about pre-action call
|
||||||
if (theRequest != null) {
|
HookParams hooks = new HookParams()
|
||||||
theRequest.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
}
|
.add(RequestDetails.class, theRequest)
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_DELETED, hooks);
|
||||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequest, resourceToDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
validateOkToDelete(deleteConflicts, entity, false);
|
validateOkToDelete(deleteConflicts, entity, false);
|
||||||
|
|
||||||
|
@ -332,21 +321,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
resourceToDelete.setId(entity.getIdDt());
|
resourceToDelete.setId(entity.getIdDt());
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
if (theRequest != null) {
|
|
||||||
theRequest.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, idToDelete.getResourceType(), idToDelete);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourceDeleted(theRequest, resourceToDelete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||||
@Override
|
@Override
|
||||||
public void beforeCommit(boolean readOnly) {
|
public void beforeCommit(boolean readOnly) {
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, resourceToDelete);
|
.add(IBaseResource.class, resourceToDelete)
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -410,7 +392,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
entity = myEntityManager.find(ResourceTable.class, pid);
|
entity = myEntityManager.find(ResourceTable.class, pid);
|
||||||
IBaseResource resource = toResource(entity, false);
|
IBaseResource resource = toResource(entity, false);
|
||||||
theResource.setId(resource.getIdElement().getValue());
|
theResource.setId(resource.getIdElement().getValue());
|
||||||
return toMethodOutcome(entity, resource).setCreated(false);
|
return toMethodOutcome(theRequest, entity, resource).setCreated(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,17 +425,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
if (theRequest != null) {
|
|
||||||
theRequest.getRequestOperationCallback().resourcePreCreate(theResource);
|
|
||||||
}
|
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
|
||||||
((IServerOperationInterceptor) next).resourcePreCreate(theRequest, theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
HookParams hookParams = new HookParams()
|
HookParams hookParams = new HookParams()
|
||||||
.add(IBaseResource.class, theResource);
|
.add(IBaseResource.class, theResource)
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED, hookParams);
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, hookParams);
|
||||||
|
|
||||||
// Perform actual DB update
|
// Perform actual DB update
|
||||||
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||||
|
@ -488,25 +464,19 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
if (!updatedEntity.isUnchangedInCurrentOperation()) {
|
if (!updatedEntity.isUnchangedInCurrentOperation()) {
|
||||||
if (theRequest != null) {
|
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||||
theRequest.getRequestOperationCallback().resourceCreated(theResource);
|
@Override
|
||||||
}
|
public void beforeCommit(boolean readOnly) {
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
HookParams hookParams = new HookParams()
|
||||||
if (next instanceof IServerOperationInterceptor) {
|
.add(IBaseResource.class, theResource)
|
||||||
((IServerOperationInterceptor) next).resourceCreated(theRequest, theResource);
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, hookParams);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}
|
}
|
||||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
|
||||||
@Override
|
|
||||||
public void beforeCommit(boolean readOnly) {
|
|
||||||
HookParams hookParams = new HookParams()
|
|
||||||
.add(IBaseResource.class, theResource);
|
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, hookParams);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(true);
|
DaoMethodOutcome outcome = toMethodOutcome(theRequest, entity, theResource).setCreated(true);
|
||||||
if (!thePerformIndexing) {
|
if (!thePerformIndexing) {
|
||||||
outcome.setId(theResource.getIdElement());
|
outcome.setId(theResource.getIdElement());
|
||||||
}
|
}
|
||||||
|
@ -947,8 +917,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interceptor broadcast: RESOURCE_MAY_BE_RETURNED
|
// Interceptor broadcast: RESOURCE_MAY_BE_RETURNED
|
||||||
HookParams params = new HookParams().add(IBaseResource.class, retVal);
|
HookParams params = new HookParams()
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.RESOURCE_MAY_BE_RETURNED, params);
|
.add(IBaseResource.class, retVal)
|
||||||
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCE, params);
|
||||||
|
|
||||||
ourLog.debug("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
ourLog.debug("Processed read on {} in {}ms", theId.getValue(), w.getMillisAndRestart());
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -1140,9 +1113,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
String uuid = UUID.randomUUID().toString();
|
String uuid = UUID.randomUUID().toString();
|
||||||
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(uuid);
|
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(uuid);
|
||||||
|
|
||||||
Iterator<Long> iter = builder.createQuery(theParams, searchRuntimeDetails);
|
try (IResultIterator iter = builder.createQuery(theParams, searchRuntimeDetails)) {
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
retVal.add(iter.next());
|
retVal.add(iter.next());
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ourLog.error("IO failure during database access", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -1183,7 +1159,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private DaoMethodOutcome toMethodOutcome(@Nonnull final ResourceTable theEntity, @Nonnull IBaseResource theResource) {
|
private DaoMethodOutcome toMethodOutcome(RequestDetails theRequest, @Nonnull final ResourceTable theEntity, @Nonnull IBaseResource theResource) {
|
||||||
DaoMethodOutcome outcome = new DaoMethodOutcome();
|
DaoMethodOutcome outcome = new DaoMethodOutcome();
|
||||||
|
|
||||||
IIdType id = null;
|
IIdType id = null;
|
||||||
|
@ -1201,9 +1177,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
outcome.setResource(theResource);
|
outcome.setResource(theResource);
|
||||||
outcome.setEntity(theEntity);
|
outcome.setEntity(theEntity);
|
||||||
|
|
||||||
// Interceptor broadcast: RESOURCE_MAY_BE_RETURNED
|
// Interceptor broadcast
|
||||||
HookParams params = new HookParams().add(IBaseResource.class, theResource);
|
HookParams params = new HookParams()
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.RESOURCE_MAY_BE_RETURNED, params);
|
.add(IBaseResource.class, theResource)
|
||||||
|
.add(RequestDetails.class, theRequest)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCE, params);
|
||||||
|
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
@ -1347,7 +1326,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
*/
|
*/
|
||||||
if (!thePerformIndexing) {
|
if (!thePerformIndexing) {
|
||||||
theResource.setId(entity.getIdDt().getValue());
|
theResource.setId(entity.getIdDt().getValue());
|
||||||
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(false);
|
DaoMethodOutcome outcome = toMethodOutcome(theRequestDetails, entity, theResource).setCreated(false);
|
||||||
outcome.setPreviousResource(oldResource);
|
outcome.setPreviousResource(oldResource);
|
||||||
return outcome;
|
return outcome;
|
||||||
}
|
}
|
||||||
|
@ -1356,7 +1335,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
* Otherwise, we're not in a transaction
|
* Otherwise, we're not in a transaction
|
||||||
*/
|
*/
|
||||||
ResourceTable savedEntity = updateInternal(theRequestDetails, theResource, thePerformIndexing, theForceUpdateVersion, entity, resourceId, oldResource);
|
ResourceTable savedEntity = updateInternal(theRequestDetails, theResource, thePerformIndexing, theForceUpdateVersion, entity, resourceId, oldResource);
|
||||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
DaoMethodOutcome outcome = toMethodOutcome(theRequestDetails, savedEntity, theResource).setCreated(false);
|
||||||
|
|
||||||
if (!thePerformIndexing) {
|
if (!thePerformIndexing) {
|
||||||
outcome.setId(theResource.getIdElement());
|
outcome.setId(theResource.getIdElement());
|
||||||
|
|
|
@ -114,7 +114,6 @@ public class DaoConfig {
|
||||||
* update setter javadoc if default changes
|
* update setter javadoc if default changes
|
||||||
*/
|
*/
|
||||||
private boolean myIndexContainedResources = true;
|
private boolean myIndexContainedResources = true;
|
||||||
private List<IServerInterceptor> myInterceptors = new ArrayList<>();
|
|
||||||
/**
|
/**
|
||||||
* update setter javadoc if default changes
|
* update setter javadoc if default changes
|
||||||
*/
|
*/
|
||||||
|
@ -527,47 +526,6 @@ public class DaoConfig {
|
||||||
myIndexMissingFieldsEnabled = theIndexMissingFields;
|
myIndexMissingFieldsEnabled = theIndexMissingFields;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the interceptors which will be notified of operations.
|
|
||||||
*
|
|
||||||
* @see #setInterceptors(List)
|
|
||||||
* @deprecated Marked as deprecated as of HAPI 3.7.0. Use {@link #registerInterceptor} or {@link #unregisterInterceptor}instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Deprecated
|
|
||||||
public List<IServerInterceptor> getInterceptors() {
|
|
||||||
return myInterceptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
|
||||||
*/
|
|
||||||
public void setInterceptors(List<IServerInterceptor> theInterceptors) {
|
|
||||||
myInterceptors = theInterceptors;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This may be used to optionally register server interceptors directly against the DAOs.
|
|
||||||
*/
|
|
||||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
|
||||||
setInterceptors(new ArrayList<>());
|
|
||||||
if (theInterceptor != null && theInterceptor.length != 0) {
|
|
||||||
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void registerInterceptor(IServerInterceptor theInterceptor) {
|
|
||||||
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
|
||||||
if (!myInterceptors.contains(theInterceptor)) {
|
|
||||||
myInterceptors.add(theInterceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void unregisterInterceptor(IServerInterceptor theInterceptor) {
|
|
||||||
Validate.notNull(theInterceptor, "Interceptor can not be null");
|
|
||||||
myInterceptors.remove(theInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See {@link #setMaximumExpansionSize(int)}
|
* See {@link #setMaximumExpansionSize(int)}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -77,6 +77,9 @@ public class DaoRegistry implements ApplicationContextAware {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidRequestException If the given resource type is not supported
|
||||||
|
*/
|
||||||
public IFhirResourceDao getResourceDao(String theResourceName) {
|
public IFhirResourceDao getResourceDao(String theResourceName) {
|
||||||
init();
|
init();
|
||||||
IFhirResourceDao retVal = myResourceNameToResourceDao.get(theResourceName);
|
IFhirResourceDao retVal = myResourceNameToResourceDao.get(theResourceName);
|
||||||
|
@ -99,7 +102,19 @@ public class DaoRegistry implements ApplicationContextAware {
|
||||||
|
|
||||||
public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoIfExists(Class<T> theResourceType) {
|
public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoIfExists(Class<T> theResourceType) {
|
||||||
String resourceName = myContext.getResourceDefinition(theResourceType).getName();
|
String resourceName = myContext.getResourceDefinition(theResourceType).getName();
|
||||||
return (IFhirResourceDao<T>) getResourceDao(resourceName);
|
try {
|
||||||
|
return (IFhirResourceDao<T>) getResourceDao(resourceName);
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoIfExists(String theResourceType) {
|
||||||
|
try {
|
||||||
|
return (IFhirResourceDao<T>) getResourceDao(theResourceType);
|
||||||
|
} catch (InvalidRequestException e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void init() {
|
private void init() {
|
||||||
|
|
|
@ -20,9 +20,10 @@ package ca.uhn.fhir.jpa.dao;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public interface IResultIterator extends Iterator<Long> {
|
public interface IResultIterator extends Iterator<Long>, Closeable {
|
||||||
|
|
||||||
int getSkippedCount();
|
int getSkippedCount();
|
||||||
|
|
||||||
|
|
|
@ -29,9 +29,9 @@ import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
||||||
import ca.uhn.fhir.jpa.entity.ResourceSearchView;
|
import ca.uhn.fhir.jpa.entity.ResourceSearchView;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.model.util.StringNormalizer;
|
import ca.uhn.fhir.jpa.model.util.StringNormalizer;
|
||||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||||
|
@ -52,11 +52,13 @@ import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -76,6 +78,7 @@ import org.hibernate.query.criteria.internal.predicate.BooleanStaticAssertionPre
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Scope;
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
@ -675,22 +678,14 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
value = value.substring(1);
|
value = value.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
IdDt valueAsId = new IdDt(value);
|
IdType valueAsId = new IdType(value);
|
||||||
if (isNotBlank(value)) {
|
if (isNotBlank(value)) {
|
||||||
if (valueAsId.isIdPartValidLong()) {
|
try {
|
||||||
orPids.add(valueAsId.getIdPartAsLong());
|
Long pid = myIdHelperService.translateForcedIdToPid(myResourceName, valueAsId.getIdPart());
|
||||||
} else {
|
orPids.add(pid);
|
||||||
try {
|
} catch (ResourceNotFoundException e) {
|
||||||
BaseHasResource entity = myCallingDao.readEntity(valueAsId);
|
// This is not an error in a search, it just results in no matchesFhirResourceDaoR4InterceptorTest
|
||||||
if (entity.getDeleted() == null) {
|
ourLog.debug("Resource ID {} was requested but does not exist", valueAsId.getIdPart());
|
||||||
orPids.add(entity.getId());
|
|
||||||
}
|
|
||||||
} catch (ResourceNotFoundException e) {
|
|
||||||
/*
|
|
||||||
* This isn't an error, just means no result found
|
|
||||||
* that matches the ID the client provided
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1892,8 +1887,11 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Interceptor broadcast: RESOURCE_MAY_BE_RETURNED
|
// Interceptor broadcast: RESOURCE_MAY_BE_RETURNED
|
||||||
HookParams params = new HookParams().add(IBaseResource.class, resource);
|
HookParams params = new HookParams()
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.RESOURCE_MAY_BE_RETURNED, params);
|
.add(IBaseResource.class, resource)
|
||||||
|
.add(RequestDetails.class, null)
|
||||||
|
.add(ServletRequestDetails.class, null);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCE, params);
|
||||||
|
|
||||||
theResourceListToPopulate.set(index, resource);
|
theResourceListToPopulate.set(index, resource);
|
||||||
}
|
}
|
||||||
|
@ -2489,7 +2487,7 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
private IncludesIterator myIncludesIterator;
|
private IncludesIterator myIncludesIterator;
|
||||||
private Long myNext;
|
private Long myNext;
|
||||||
private Iterator<Long> myPreResultsIterator;
|
private Iterator<Long> myPreResultsIterator;
|
||||||
private Iterator<Long> myResultsIterator;
|
private ScrollableResultsIterator<Long> myResultsIterator;
|
||||||
private SortSpec mySort;
|
private SortSpec mySort;
|
||||||
private boolean myStillNeedToFetchIncludes;
|
private boolean myStillNeedToFetchIncludes;
|
||||||
private int mySkipCount = 0;
|
private int mySkipCount = 0;
|
||||||
|
@ -2581,12 +2579,16 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
mySearchRuntimeDetails.setFoundMatchesCount(myPidSet.size());
|
mySearchRuntimeDetails.setFoundMatchesCount(myPidSet.size());
|
||||||
|
|
||||||
if (myFirst) {
|
if (myFirst) {
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_SEARCH_FIRST_RESULT_LOADED, mySearchRuntimeDetails);
|
HookParams params = new HookParams();
|
||||||
|
params.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED, params);
|
||||||
myFirst = false;
|
myFirst = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NO_MORE.equals(myNext)) {
|
if (NO_MORE.equals(myNext)) {
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_SEARCH_SELECT_COMPLETE, mySearchRuntimeDetails);
|
HookParams params = new HookParams();
|
||||||
|
params.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2613,6 +2615,12 @@ public class SearchBuilder implements ISearchBuilder {
|
||||||
return mySkipCount;
|
return mySkipCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (myResultsIterator != null) {
|
||||||
|
myResultsIterator.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ import com.google.common.collect.ArrayListMultimap;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.http.NameValuePair;
|
import org.apache.http.NameValuePair;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.exception.ConstraintViolationException;
|
|
||||||
import org.hibernate.internal.SessionImpl;
|
import org.hibernate.internal.SessionImpl;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.exceptions.FHIRException;
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
|
|
|
@ -20,12 +20,13 @@ package ca.uhn.fhir.jpa.dao.index;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
import ca.uhn.fhir.jpa.dao.data.IForcedIdDao;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
import ca.uhn.fhir.jpa.model.entity.ForcedId;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.model.search.PerformanceMessage;
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import com.google.common.collect.ListMultimap;
|
import com.google.common.collect.ListMultimap;
|
||||||
|
@ -35,6 +36,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
@ -52,6 +54,10 @@ public class IdHelperService {
|
||||||
myForcedIdDao.delete(forcedId);
|
myForcedIdDao.delete(forcedId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws ResourceNotFoundException If the ID can not be found
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
public Long translateForcedIdToPid(String theResourceName, String theResourceId) throws ResourceNotFoundException {
|
public Long translateForcedIdToPid(String theResourceName, String theResourceId) throws ResourceNotFoundException {
|
||||||
// We only pass 1 input in so only 0..1 will come back
|
// We only pass 1 input in so only 0..1 will come back
|
||||||
IdDt id = new IdDt(theResourceName, theResourceId);
|
IdDt id = new IdDt(theResourceName, theResourceId);
|
||||||
|
@ -94,9 +100,11 @@ public class IdHelperService {
|
||||||
Collection<String> nextIds = nextEntry.getValue();
|
Collection<String> nextIds = nextEntry.getValue();
|
||||||
if (isBlank(nextResourceType)) {
|
if (isBlank(nextResourceType)) {
|
||||||
|
|
||||||
PerformanceMessage msg = new PerformanceMessage()
|
StorageProcessingMessage msg = new StorageProcessingMessage()
|
||||||
.setMessage("This search uses unqualified resource IDs (an ID without a resource type). This is less efficient than using a qualified type.");
|
.setMessage("This search uses unqualified resource IDs (an ID without a resource type). This is less efficient than using a qualified type.");
|
||||||
theInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_MESSAGE, msg);
|
HookParams params = new HookParams()
|
||||||
|
.add(StorageProcessingMessage.class, msg);
|
||||||
|
theInterceptorBroadcaster.callHooks(Pointcut.STORAGE_PROCESSING_MESSAGE, params);
|
||||||
|
|
||||||
retVal.addAll(theForcedIdDao.findByForcedId(nextIds));
|
retVal.addAll(theForcedIdDao.findByForcedId(nextIds));
|
||||||
|
|
||||||
|
|
|
@ -20,16 +20,16 @@ package ca.uhn.fhir.jpa.interceptor;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.util.LogUtil;
|
import ca.uhn.fhir.util.LogUtil;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.slf4j.event.Level;
|
import org.slf4j.event.Level;
|
||||||
|
|
||||||
@Interceptor(manualRegistration = true)
|
@Interceptor()
|
||||||
public class PerformanceTracingLoggingInterceptor {
|
public class PerformanceTracingLoggingInterceptor {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(PerformanceTracingLoggingInterceptor.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(PerformanceTracingLoggingInterceptor.class);
|
||||||
private final Logger myLog;
|
private final Logger myLog;
|
||||||
|
@ -50,27 +50,27 @@ public class PerformanceTracingLoggingInterceptor {
|
||||||
myLevel = theLevel;
|
myLevel = theLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.PERFTRACE_SEARCH_FIRST_RESULT_LOADED)
|
@Hook(value = Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED)
|
||||||
public void searchFirstResultLoaded(SearchRuntimeDetails theOutcome) {
|
public void searchFirstResultLoaded(SearchRuntimeDetails theOutcome) {
|
||||||
log("Initial query result returned in {} for query {}", theOutcome.getQueryStopwatch(), theOutcome.getSearchUuid());
|
log("Initial query result returned in {} for query {}", theOutcome.getQueryStopwatch(), theOutcome.getSearchUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.PERFTRACE_SEARCH_SELECT_COMPLETE)
|
@Hook(value = Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE)
|
||||||
public void searchSelectComplete(SearchRuntimeDetails theOutcome) {
|
public void searchSelectComplete(SearchRuntimeDetails theOutcome) {
|
||||||
log("Query found {} matches in {} for query {}", theOutcome.getFoundMatchesCount(), theOutcome.getQueryStopwatch(), theOutcome.getSearchUuid());
|
log("Query found {} matches in {} for query {}", theOutcome.getFoundMatchesCount(), theOutcome.getQueryStopwatch(), theOutcome.getSearchUuid());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.PERFTRACE_SEARCH_COMPLETE)
|
@Hook(value = Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE)
|
||||||
public void searchComplete(SearchRuntimeDetails theOutcome) {
|
public void searchComplete(SearchRuntimeDetails theOutcome) {
|
||||||
log("Query {} is complete in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
log("Query {} is complete in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.PERFTRACE_SEARCH_PASS_COMPLETE)
|
@Hook(value = Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE)
|
||||||
public void searchPassComplete(SearchRuntimeDetails theOutcome) {
|
public void searchPassComplete(SearchRuntimeDetails theOutcome) {
|
||||||
log("Query {} pass complete and set to status {} in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getSearchStatus(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
log("Query {} pass complete and set to status {} in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getSearchStatus(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(value = Pointcut.PERFTRACE_SEARCH_FAILED)
|
@Hook(value = Pointcut.JPA_PERFTRACE_SEARCH_FAILED)
|
||||||
public void searchFailed(SearchRuntimeDetails theOutcome) {
|
public void searchFailed(SearchRuntimeDetails theOutcome) {
|
||||||
log("Query {} failed in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
log("Query {} failed in {} - Found {} matches", theOutcome.getSearchUuid(), theOutcome.getQueryStopwatch(), theOutcome.getFoundMatchesCount());
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
|
||||||
* @param theRequestDetails The parent request details
|
* @param theRequestDetails The parent request details
|
||||||
*/
|
*/
|
||||||
public ServletSubRequestDetails(ServletRequestDetails theRequestDetails) {
|
public ServletSubRequestDetails(ServletRequestDetails theRequestDetails) {
|
||||||
|
super(theRequestDetails.getInterceptorBroadcaster());
|
||||||
if (theRequestDetails != null) {
|
if (theRequestDetails != null) {
|
||||||
Map<String, List<String>> headers = theRequestDetails.getHeaders();
|
Map<String, List<String>> headers = theRequestDetails.getHeaders();
|
||||||
for (Map.Entry<String, List<String>> next : headers.entrySet()) {
|
for (Map.Entry<String, List<String>> next : headers.entrySet()) {
|
||||||
|
|
|
@ -21,14 +21,15 @@ package ca.uhn.fhir.jpa.search;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
import ca.uhn.fhir.jpa.dao.*;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchIncludeDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
|
||||||
import ca.uhn.fhir.jpa.entity.*;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
@ -72,6 +73,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.*;
|
import java.util.concurrent.*;
|
||||||
|
@ -308,15 +310,19 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
// Load the results synchronously
|
// Load the results synchronously
|
||||||
final List<Long> pids = new ArrayList<>();
|
final List<Long> pids = new ArrayList<>();
|
||||||
|
|
||||||
Iterator<Long> resultIter = sb.createQuery(theParams, searchRuntimeDetails);
|
try (IResultIterator resultIter = sb.createQuery(theParams, searchRuntimeDetails)) {
|
||||||
while (resultIter.hasNext()) {
|
while (resultIter.hasNext()) {
|
||||||
pids.add(resultIter.next());
|
pids.add(resultIter.next());
|
||||||
if (loadSynchronousUpTo != null && pids.size() >= loadSynchronousUpTo) {
|
if (loadSynchronousUpTo != null && pids.size() >= loadSynchronousUpTo) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
|
if (theParams.getLoadSynchronousUpTo() != null && pids.size() >= theParams.getLoadSynchronousUpTo()) {
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
ourLog.error("IO failure during database access", e);
|
||||||
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -717,9 +723,11 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
|
|
||||||
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
||||||
if (mySearch.getStatus() == SearchStatusEnum.FINISHED) {
|
if (mySearch.getStatus() == SearchStatusEnum.FINISHED) {
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_SEARCH_COMPLETE, mySearchRuntimeDetails);
|
HookParams params = new HookParams().add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE, params);
|
||||||
} else {
|
} else {
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_SEARCH_PASS_COMPLETE, mySearchRuntimeDetails);
|
HookParams params = new HookParams().add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE, params);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Have completed search for [{}{}] and found {} resources in {}ms - Status is {}", mySearch.getResourceType(), mySearch.getSearchQueryString(), mySyncedPids.size(), sw.getMillis(), mySearch.getStatus());
|
ourLog.info("Have completed search for [{}{}] and found {} resources in {}ms - Status is {}", mySearch.getResourceType(), mySearch.getSearchQueryString(), mySyncedPids.size(), sw.getMillis(), mySearch.getStatus());
|
||||||
|
@ -760,7 +768,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
mySearch.setStatus(SearchStatusEnum.FAILED);
|
mySearch.setStatus(SearchStatusEnum.FAILED);
|
||||||
|
|
||||||
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
||||||
myInterceptorBroadcaster.callHooks(Pointcut.PERFTRACE_SEARCH_FAILED, mySearchRuntimeDetails);
|
HookParams params = new HookParams().add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||||
|
myInterceptorBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_FAILED, params);
|
||||||
|
|
||||||
saveSearch();
|
saveSearch();
|
||||||
|
|
||||||
|
@ -891,51 +900,56 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
|
||||||
/*
|
/*
|
||||||
* Construct the SQL query we'll be sending to the database
|
* Construct the SQL query we'll be sending to the database
|
||||||
*/
|
*/
|
||||||
IResultIterator resultIterator = sb.createQuery(myParams, mySearchRuntimeDetails);
|
try (IResultIterator resultIterator = sb.createQuery(myParams, mySearchRuntimeDetails)) {
|
||||||
assert (resultIterator != null);
|
assert (resultIterator != null);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The following loop actually loads the PIDs of the resources
|
* The following loop actually loads the PIDs of the resources
|
||||||
* matching the search off of the disk and into memory. After
|
* matching the search off of the disk and into memory. After
|
||||||
* every X results, we commit to the HFJ_SEARCH table.
|
* every X results, we commit to the HFJ_SEARCH table.
|
||||||
*/
|
*/
|
||||||
int syncSize = mySyncSize;
|
int syncSize = mySyncSize;
|
||||||
while (resultIterator.hasNext()) {
|
while (resultIterator.hasNext()) {
|
||||||
myUnsyncedPids.add(resultIterator.next());
|
myUnsyncedPids.add(resultIterator.next());
|
||||||
|
|
||||||
boolean shouldSync = myUnsyncedPids.size() >= syncSize;
|
boolean shouldSync = myUnsyncedPids.size() >= syncSize;
|
||||||
|
|
||||||
if (myDaoConfig.getCountSearchResultsUpTo() != null &&
|
if (myDaoConfig.getCountSearchResultsUpTo() != null &&
|
||||||
myDaoConfig.getCountSearchResultsUpTo() > 0 &&
|
myDaoConfig.getCountSearchResultsUpTo() > 0 &&
|
||||||
myDaoConfig.getCountSearchResultsUpTo() < myUnsyncedPids.size()) {
|
myDaoConfig.getCountSearchResultsUpTo() < myUnsyncedPids.size()) {
|
||||||
shouldSync = false;
|
shouldSync = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (myUnsyncedPids.size() > 50000) {
|
||||||
|
shouldSync = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no abort was requested, bail out
|
||||||
|
Validate.isTrue(isNotAborted(), "Abort has been requested");
|
||||||
|
|
||||||
|
if (shouldSync) {
|
||||||
|
saveUnsynced(resultIterator);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myLoadingThrottleForUnitTests != null) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(myLoadingThrottleForUnitTests);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (myUnsyncedPids.size() > 50000) {
|
|
||||||
shouldSync = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no abort was requested, bail out
|
// If no abort was requested, bail out
|
||||||
Validate.isTrue(isNotAborted(), "Abort has been requested");
|
Validate.isTrue(isNotAborted(), "Abort has been requested");
|
||||||
|
|
||||||
if (shouldSync) {
|
saveUnsynced(resultIterator);
|
||||||
saveUnsynced(resultIterator);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myLoadingThrottleForUnitTests != null) {
|
|
||||||
try {
|
|
||||||
Thread.sleep(myLoadingThrottleForUnitTests);
|
|
||||||
} catch (InterruptedException e) {
|
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} catch (IOException e) {
|
||||||
|
ourLog.error("IO failure during database access", e);
|
||||||
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If no abort was requested, bail out
|
|
||||||
Validate.isTrue(isNotAborted(), "Abort has been requested");
|
|
||||||
|
|
||||||
saveUnsynced(resultIterator);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,9 +26,9 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
|
||||||
|
@ -69,7 +69,7 @@ import java.util.concurrent.TimeUnit;
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
@Lazy
|
@Lazy
|
||||||
@Interceptor(manualRegistration = true)
|
@Interceptor()
|
||||||
public class SubscriptionActivatingInterceptor {
|
public class SubscriptionActivatingInterceptor {
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingInterceptor.class);
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingInterceptor.class);
|
||||||
|
|
||||||
|
@ -179,14 +179,14 @@ public class SubscriptionActivatingInterceptor {
|
||||||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED)
|
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
||||||
public void addStrategyTagCreated(IBaseResource theResource) {
|
public void addStrategyTagCreated(IBaseResource theResource) {
|
||||||
if (isSubscription(theResource)) {
|
if (isSubscription(theResource)) {
|
||||||
validateCriteriaAndAddStrategy(theResource);
|
validateCriteriaAndAddStrategy(theResource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED)
|
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
|
||||||
public void addStrategyTagUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void addStrategyTagUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
if (isSubscription(theNewResource)) {
|
if (isSubscription(theNewResource)) {
|
||||||
validateCriteriaAndAddStrategy(theNewResource);
|
validateCriteriaAndAddStrategy(theNewResource);
|
||||||
|
@ -204,17 +204,17 @@ public class SubscriptionActivatingInterceptor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED)
|
||||||
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED)
|
||||||
public void resourceCreated(IBaseResource theResource) {
|
public void resourceCreated(IBaseResource theResource) {
|
||||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED)
|
||||||
public void resourceDeleted(IBaseResource theResource) {
|
public void resourceDeleted(IBaseResource theResource) {
|
||||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,7 +21,7 @@ package ca.uhn.fhir.jpa.subscription;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -47,9 +47,9 @@ public class SubscriptionInterceptorLoader {
|
||||||
@Autowired
|
@Autowired
|
||||||
private SubscriptionRegistry mySubscriptionRegistry;
|
private SubscriptionRegistry mySubscriptionRegistry;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ApplicationContext myAppicationContext;
|
private ApplicationContext myApplicationContext;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IInterceptorRegistry myInterceptorRegistry;
|
private IInterceptorService myInterceptorRegistry;
|
||||||
|
|
||||||
public void registerInterceptors() {
|
public void registerInterceptors() {
|
||||||
Set<Subscription.SubscriptionChannelType> supportedSubscriptionTypes = myDaoConfig.getSupportedSubscriptionTypes();
|
Set<Subscription.SubscriptionChannelType> supportedSubscriptionTypes = myDaoConfig.getSupportedSubscriptionTypes();
|
||||||
|
@ -69,7 +69,7 @@ public class SubscriptionInterceptorLoader {
|
||||||
private void loadSubscriptions() {
|
private void loadSubscriptions() {
|
||||||
ourLog.info("Loading subscriptions into the SubscriptionRegistry...");
|
ourLog.info("Loading subscriptions into the SubscriptionRegistry...");
|
||||||
// Activate scheduled subscription loads into the SubscriptionRegistry
|
// Activate scheduled subscription loads into the SubscriptionRegistry
|
||||||
myAppicationContext.getBean(SubscriptionLoader.class);
|
myApplicationContext.getBean(SubscriptionLoader.class);
|
||||||
ourLog.info("...{} subscriptions loaded", mySubscriptionRegistry.size());
|
ourLog.info("...{} subscriptions loaded", mySubscriptionRegistry.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,5 +77,6 @@ public class SubscriptionInterceptorLoader {
|
||||||
void unregisterInterceptorsForUnitTest() {
|
void unregisterInterceptorsForUnitTest() {
|
||||||
myInterceptorRegistry.unregisterInterceptor(mySubscriptionActivatingInterceptor);
|
myInterceptorRegistry.unregisterInterceptor(mySubscriptionActivatingInterceptor);
|
||||||
myInterceptorRegistry.unregisterInterceptor(mySubscriptionMatcherInterceptor);
|
myInterceptorRegistry.unregisterInterceptor(mySubscriptionMatcherInterceptor);
|
||||||
|
mySubscriptionMatcherInterceptor.preDestroy();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,7 @@
|
||||||
package ca.uhn.fhir.jpa.subscription;
|
package ca.uhn.fhir.jpa.subscription;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.*;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.subscription.module.LinkedBlockingQueueSubscribableChannel;
|
import ca.uhn.fhir.jpa.subscription.module.LinkedBlockingQueueSubscribableChannel;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionChannelFactory;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionChannelFactory;
|
||||||
|
@ -46,19 +43,19 @@ import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@Lazy
|
@Lazy
|
||||||
@Interceptor(manualRegistration = true)
|
@Interceptor()
|
||||||
public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer {
|
public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer {
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatcherInterceptor.class);
|
|
||||||
|
|
||||||
public static final String SUBSCRIPTION_MATCHING_CHANNEL_NAME = "subscription-matching";
|
public static final String SUBSCRIPTION_MATCHING_CHANNEL_NAME = "subscription-matching";
|
||||||
protected SubscribableChannel myMatchingChannel;
|
protected SubscribableChannel myMatchingChannel;
|
||||||
|
@Autowired
|
||||||
|
protected SubscriptionChannelFactory mySubscriptionChannelFactory;
|
||||||
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatcherInterceptor.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
@Autowired
|
@Autowired
|
||||||
private SubscriptionMatchingSubscriber mySubscriptionMatchingSubscriber;
|
private SubscriptionMatchingSubscriber mySubscriptionMatchingSubscriber;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected SubscriptionChannelFactory mySubscriptionChannelFactory;
|
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -85,28 +82,27 @@ public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED)
|
||||||
public void resourceCreated(IBaseResource theResource) {
|
public void resourceCreated(IBaseResource theResource) {
|
||||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED)
|
||||||
public void resourceDeleted(IBaseResource theResource) {
|
public void resourceDeleted(IBaseResource theResource) {
|
||||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED)
|
@Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED)
|
||||||
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
|
||||||
|
|
||||||
private void submitResourceModified(IBaseResource theNewResource, ResourceModifiedMessage.OperationTypeEnum theOperationType) {
|
private void submitResourceModified(IBaseResource theNewResource, ResourceModifiedMessage.OperationTypeEnum theOperationType) {
|
||||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theNewResource, theOperationType);
|
ResourceModifiedMessage msg = new ResourceModifiedMessage(myFhirContext, theNewResource, theOperationType);
|
||||||
// Interceptor call: SUBSCRIPTION_RESOURCE_MODIFIED
|
// Interceptor call: SUBSCRIPTION_RESOURCE_MODIFIED
|
||||||
if (!myInterceptorBroadcaster.callHooks(Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED, msg)) {
|
HookParams params = new HookParams()
|
||||||
|
.add(ResourceModifiedMessage.class, msg);
|
||||||
|
if (!myInterceptorBroadcaster.callHooks(Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED, params)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1399,10 +1399,12 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
org.hibernate.query.Query<TermConceptMapGroupElementTarget> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElementTarget>) typedQuery;
|
org.hibernate.query.Query<TermConceptMapGroupElementTarget> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElementTarget>) typedQuery;
|
||||||
hibernateQuery.setFetchSize(myFetchSize);
|
hibernateQuery.setFetchSize(myFetchSize);
|
||||||
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
Iterator<TermConceptMapGroupElementTarget> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults);
|
try (ScrollableResultsIterator<TermConceptMapGroupElementTarget> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) {
|
||||||
|
|
||||||
|
while (scrollableResultsIterator.hasNext()) {
|
||||||
|
targets.add(scrollableResultsIterator.next());
|
||||||
|
}
|
||||||
|
|
||||||
while (scrollableResultsIterator.hasNext()) {
|
|
||||||
targets.add(scrollableResultsIterator.next());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLastResultsFromTranslationCache = false; // For testing.
|
ourLastResultsFromTranslationCache = false; // For testing.
|
||||||
|
@ -1484,27 +1486,29 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
org.hibernate.query.Query<TermConceptMapGroupElement> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElement>) typedQuery;
|
org.hibernate.query.Query<TermConceptMapGroupElement> hibernateQuery = (org.hibernate.query.Query<TermConceptMapGroupElement>) typedQuery;
|
||||||
hibernateQuery.setFetchSize(myFetchSize);
|
hibernateQuery.setFetchSize(myFetchSize);
|
||||||
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
ScrollableResults scrollableResults = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
|
||||||
Iterator<TermConceptMapGroupElement> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults);
|
try (ScrollableResultsIterator<TermConceptMapGroupElement> scrollableResultsIterator = new ScrollableResultsIterator<>(scrollableResults)) {
|
||||||
|
|
||||||
while (scrollableResultsIterator.hasNext()) {
|
while (scrollableResultsIterator.hasNext()) {
|
||||||
TermConceptMapGroupElement nextElement = scrollableResultsIterator.next();
|
TermConceptMapGroupElement nextElement = scrollableResultsIterator.next();
|
||||||
nextElement.getConceptMapGroupElementTargets().size();
|
nextElement.getConceptMapGroupElementTargets().size();
|
||||||
myEntityManager.detach(nextElement);
|
myEntityManager.detach(nextElement);
|
||||||
|
|
||||||
if (isNotBlank(targetCode) && isNotBlank(targetCodeSystem)) {
|
if (isNotBlank(targetCode) && isNotBlank(targetCodeSystem)) {
|
||||||
for (Iterator<TermConceptMapGroupElementTarget> iter = nextElement.getConceptMapGroupElementTargets().iterator(); iter.hasNext(); ) {
|
for (Iterator<TermConceptMapGroupElementTarget> iter = nextElement.getConceptMapGroupElementTargets().iterator(); iter.hasNext(); ) {
|
||||||
TermConceptMapGroupElementTarget next = iter.next();
|
TermConceptMapGroupElementTarget next = iter.next();
|
||||||
if (targetCodeSystem.equals(next.getSystem())) {
|
if (targetCodeSystem.equals(next.getSystem())) {
|
||||||
if (targetCode.equals(next.getCode())) {
|
if (targetCode.equals(next.getCode())) {
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
iter.remove();
|
iter.remove();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
elements.add(nextElement);
|
||||||
}
|
}
|
||||||
|
|
||||||
elements.add(nextElement);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLastResultsFromTranslationWithReverseCache = false; // For testing.
|
ourLastResultsFromTranslationWithReverseCache = false; // For testing.
|
||||||
|
|
|
@ -28,6 +28,11 @@ public class JpaConstants {
|
||||||
*/
|
*/
|
||||||
public static final String OPERATION_EXPUNGE = "$expunge";
|
public static final String OPERATION_EXPUNGE = "$expunge";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation name for the $match operation
|
||||||
|
*/
|
||||||
|
public static final String OPERATION_MATCH = "$match";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Replace with {@link #OPERATION_EXPUNGE}
|
* @deprecated Replace with {@link #OPERATION_EXPUNGE}
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.*;
|
||||||
|
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The JPA server has two interceptor services (aka two registries of interceptors). One that lives
|
||||||
|
* in the JPA module and is created via Spring, and one that lives in the RestfulServer. We do this
|
||||||
|
* so that interceptors can be registered at the JPA level via Spring (which is convenient for
|
||||||
|
* lots of reasons) and also via the RestfulServer (which is how other interceptors work outside the
|
||||||
|
* JPA context)
|
||||||
|
* <p>
|
||||||
|
* This class is basically a composite broadcaster that broadcasts events to the internal registry but
|
||||||
|
* also to
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class JpaInterceptorService implements IInterceptorService {
|
||||||
|
|
||||||
|
private IInterceptorService myInterceptorBroadcaster = new InterceptorService("hapi-fhir-jpa");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
||||||
|
if (!myInterceptorBroadcaster.callHooks(thePointcut, theParams)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
RequestDetails requestDetails = theParams.get(RequestDetails.class);
|
||||||
|
if (requestDetails != null) {
|
||||||
|
requestDetails.getInterceptorBroadcaster().callHooks(thePointcut, theParams);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams) {
|
||||||
|
Object retVal = myInterceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams);
|
||||||
|
if (retVal == null) {
|
||||||
|
RequestDetails requestDetails = theParams.get(RequestDetails.class);
|
||||||
|
if (requestDetails != null) {
|
||||||
|
retVal = requestDetails.getInterceptorBroadcaster().callHooksAndReturnObject(thePointcut, theParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean registerThreadLocalInterceptor(Object theInterceptor) {
|
||||||
|
return myInterceptorBroadcaster.registerThreadLocalInterceptor(theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterThreadLocalInterceptor(Object theInterceptor) {
|
||||||
|
myInterceptorBroadcaster.unregisterThreadLocalInterceptor(theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean registerInterceptor(Object theInterceptor) {
|
||||||
|
return myInterceptorBroadcaster.registerInterceptor(theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterInterceptor(Object theInterceptor) {
|
||||||
|
myInterceptorBroadcaster.unregisterInterceptor(theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAnonymousInterceptor(Pointcut thePointcut, IAnonymousInterceptor theInterceptor) {
|
||||||
|
myInterceptorBroadcaster.registerAnonymousInterceptor(thePointcut, theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerAnonymousInterceptor(Pointcut thePointcut, int theOrder, IAnonymousInterceptor theInterceptor) {
|
||||||
|
myInterceptorBroadcaster.registerAnonymousInterceptor(thePointcut, theOrder, theInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Object> getAllRegisteredInterceptors() {
|
||||||
|
return myInterceptorBroadcaster.getAllRegisteredInterceptors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterAllInterceptors() {
|
||||||
|
myInterceptorBroadcaster.unregisterAllInterceptors();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unregisterInterceptors(@Nullable Collection<?> theInterceptors) {
|
||||||
|
myInterceptorBroadcaster.unregisterInterceptors(theInterceptors);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerInterceptors(@Nullable Collection<?> theInterceptors) {
|
||||||
|
myInterceptorBroadcaster.registerInterceptors(theInterceptors);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Server
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
|
public class ResourceProviderFactory {
|
||||||
|
|
||||||
|
private List<Supplier<Object>> mySuppliers = new ArrayList<>();
|
||||||
|
|
||||||
|
public void addSupplier(@Nonnull Supplier<Object> theSupplier) {
|
||||||
|
mySuppliers.add(theSupplier);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Object> createProviders() {
|
||||||
|
List<Object> retVal = new ArrayList<>();
|
||||||
|
for (Supplier<Object> next : mySuppliers) {
|
||||||
|
Object nextRp = next.get();
|
||||||
|
if (nextRp != null) {
|
||||||
|
retVal.add(nextRp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -23,9 +23,10 @@ package ca.uhn.fhir.jpa.util;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hibernate.ScrollableResults;
|
import org.hibernate.ScrollableResults;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
|
||||||
public class ScrollableResultsIterator<T extends Object> extends BaseIterator<T> implements Iterator<T> {
|
public class ScrollableResultsIterator<T extends Object> extends BaseIterator<T> implements Iterator<T>, Closeable {
|
||||||
private boolean hasNext;
|
private boolean hasNext;
|
||||||
private T myNext;
|
private T myNext;
|
||||||
private ScrollableResults myScroll;
|
private ScrollableResults myScroll;
|
||||||
|
@ -60,4 +61,14 @@ public class ScrollableResultsIterator<T extends Object> extends BaseIterator<T>
|
||||||
myNext = null;
|
myNext = null;
|
||||||
return next;
|
return next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
if (myScroll != null) {
|
||||||
|
myScroll.close();
|
||||||
|
myScroll = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
|
||||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||||
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
||||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
extraProperties.put("hibernate.search.default.directory_provider", "local-heap");
|
||||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||||
return extraProperties;
|
return extraProperties;
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,7 +92,6 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
* starvation
|
* starvation
|
||||||
*/
|
*/
|
||||||
int maxThreads = (int) (Math.random() * 6.0) + 1;
|
int maxThreads = (int) (Math.random() * 6.0) + 1;
|
||||||
maxThreads = 1;
|
|
||||||
retVal.setMaxTotal(maxThreads);
|
retVal.setMaxTotal(maxThreads);
|
||||||
|
|
||||||
return retVal;
|
return retVal;
|
||||||
|
@ -139,7 +138,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
|
||||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||||
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
||||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
extraProperties.put("hibernate.search.default.directory_provider", "local-heap");
|
||||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||||
return extraProperties;
|
return extraProperties;
|
||||||
|
|
|
@ -135,7 +135,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||||
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
extraProperties.put("hibernate.dialect", "ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect");
|
||||||
extraProperties.put("hibernate.search.model_mapping", ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory.class.getName());
|
extraProperties.put("hibernate.search.model_mapping", ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory.class.getName());
|
||||||
extraProperties.put("hibernate.search.default.directory_provider", "ram");
|
extraProperties.put("hibernate.search.default.directory_provider", "local-heap");
|
||||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
package ca.uhn.fhir.jpa.dao;
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
|
@ -12,6 +12,7 @@ import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
|
||||||
|
import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
|
||||||
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.util.LoggingRule;
|
import ca.uhn.fhir.jpa.util.LoggingRule;
|
||||||
|
@ -19,9 +20,7 @@ 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.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.BundleUtil;
|
import ca.uhn.fhir.util.BundleUtil;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
|
@ -63,7 +62,6 @@ import static ca.uhn.fhir.util.TestUtil.randomizeLocale;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
public abstract class BaseJpaTest {
|
public abstract class BaseJpaTest {
|
||||||
|
@ -85,12 +83,11 @@ public abstract class BaseJpaTest {
|
||||||
public LoggingRule myLoggingRule = new LoggingRule();
|
public LoggingRule myLoggingRule = new LoggingRule();
|
||||||
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
@Mock(answer = Answers.RETURNS_DEEP_STUBS)
|
||||||
protected ServletRequestDetails mySrd;
|
protected ServletRequestDetails mySrd;
|
||||||
protected ArrayList<IServerInterceptor> myServerInterceptorList;
|
protected InterceptorService myRequestOperationCallback;
|
||||||
protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class);
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected DatabaseBackedPagingProvider myDatabaseBackedPagingProvider;
|
protected DatabaseBackedPagingProvider myDatabaseBackedPagingProvider;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IInterceptorRegistry myInterceptorRegistry;
|
protected IInterceptorService myInterceptorRegistry;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected CircularQueueCaptureQueriesListener myCaptureQueriesListener;
|
protected CircularQueueCaptureQueriesListener myCaptureQueriesListener;
|
||||||
|
|
||||||
|
@ -131,11 +128,11 @@ public abstract class BaseJpaTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeInitMocks() {
|
public void beforeInitMocks() {
|
||||||
|
myRequestOperationCallback = new InterceptorService();
|
||||||
|
|
||||||
MockitoAnnotations.initMocks(this);
|
MockitoAnnotations.initMocks(this);
|
||||||
|
|
||||||
when(mySrd.getRequestOperationCallback()).thenReturn(myRequestOperationCallback);
|
when(mySrd.getInterceptorBroadcaster()).thenReturn(myRequestOperationCallback);
|
||||||
myServerInterceptorList = new ArrayList<>();
|
|
||||||
when(mySrd.getServer().getInterceptors()).thenReturn(myServerInterceptorList);
|
|
||||||
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
when(mySrd.getUserData()).thenReturn(new HashMap<>());
|
||||||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
|
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu2;
|
package ca.uhn.fhir.jpa.dao.dstu2;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import static org.mockito.Mockito.when;
|
import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import java.util.Enumeration;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import static org.mockito.Mockito.mock;
|
||||||
import org.junit.Before;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.rp.dstu2.PatientResourceProvider;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
|
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
|
|
||||||
public abstract class BaseJpaDstu2SystemTest extends BaseJpaDstu2Test {
|
public abstract class BaseJpaDstu2SystemTest extends BaseJpaDstu2Test {
|
||||||
private RestfulServer myServer;
|
private RestfulServer myServer;
|
||||||
|
@ -31,7 +29,7 @@ public abstract class BaseJpaDstu2SystemTest extends BaseJpaDstu2Test {
|
||||||
@Before
|
@Before
|
||||||
public void before() throws ServletException {
|
public void before() throws ServletException {
|
||||||
mySrd = mock(ServletRequestDetails.class);
|
mySrd = mock(ServletRequestDetails.class);
|
||||||
when(mySrd.getRequestOperationCallback()).thenReturn(mock(IRequestOperationCallback.class));
|
when(mySrd.getInterceptorBroadcaster()).thenReturn(mock(IInterceptorBroadcaster.class));
|
||||||
|
|
||||||
if (myServer == null) {
|
if (myServer == null) {
|
||||||
myServer = new RestfulServer(myFhirCtx);
|
myServer = new RestfulServer(myFhirCtx);
|
||||||
|
|
|
@ -18,18 +18,19 @@ import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
||||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.*;
|
import ca.uhn.fhir.model.dstu2.resource.*;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||||
import org.hibernate.search.jpa.Search;
|
import org.hibernate.search.jpa.Search;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
@ -39,6 +40,7 @@ import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
@ -47,7 +49,6 @@ import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(classes = {TestDstu2Config.class})
|
@ContextConfiguration(classes = {TestDstu2Config.class})
|
||||||
|
@ -104,7 +105,6 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myImmunizationDaoDstu2")
|
@Qualifier("myImmunizationDaoDstu2")
|
||||||
protected IFhirResourceDao<Immunization> myImmunizationDao;
|
protected IFhirResourceDao<Immunization> myImmunizationDao;
|
||||||
protected IServerInterceptor myInterceptor;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myLocationDaoDstu2")
|
@Qualifier("myLocationDaoDstu2")
|
||||||
protected IFhirResourceDao<Location> myLocationDao;
|
protected IFhirResourceDao<Location> myLocationDao;
|
||||||
|
@ -145,7 +145,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myResourceProvidersDstu2")
|
@Qualifier("myResourceProvidersDstu2")
|
||||||
protected Object myResourceProviders;
|
protected ResourceProviderFactory myResourceProviders;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
|
@ -183,12 +183,6 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
protected SubscriptionLoader mySubscriptionLoader;
|
protected SubscriptionLoader mySubscriptionLoader;
|
||||||
|
|
||||||
@Before
|
|
||||||
public void beforeCreateInterceptor() {
|
|
||||||
myInterceptor = mock(IServerInterceptor.class);
|
|
||||||
myDaoConfig.setInterceptors(myInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeFlushFT() {
|
public void beforeFlushFT() {
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
|
@ -204,7 +198,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@Transactional()
|
@Transactional()
|
||||||
public void beforePurgeDatabase() throws InterruptedException {
|
public void beforePurgeDatabase() {
|
||||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry);
|
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +210,11 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void afterResetInterceptors() {
|
||||||
|
myInterceptorRegistry.unregisterAllInterceptors();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected FhirContext getContext() {
|
protected FhirContext getContext() {
|
||||||
return myFhirCtx;
|
return myFhirCtx;
|
||||||
|
@ -239,7 +238,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
||||||
@Override
|
@Override
|
||||||
public TransactionTemplate newTxTemplate() {
|
public TransactionTemplate newTxTemplate() {
|
||||||
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
|
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
|
||||||
retVal.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
|
retVal.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||||
retVal.afterPropertiesSet();
|
retVal.afterPropertiesSet();
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,424 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu2;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.dao.DeleteMethodOutcome;
|
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
|
||||||
import org.mockito.stubbing.Answer;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
public class FhirResourceDaoDstu2InterceptorTest extends BaseJpaDstu2Test {
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu2InterceptorTest.class);
|
|
||||||
private IServerOperationInterceptor myJpaInterceptor;
|
|
||||||
private ServerOperationInterceptorAdapter myJpaInterceptorAdapter = new ServerOperationInterceptorAdapter();
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() {
|
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptorAdapter);
|
|
||||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
myJpaInterceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptorAdapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaCreate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Not do a conditional create
|
|
||||||
*/
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT1");
|
|
||||||
Long id2 = myPatientDao.create(p, "Patient?family=PATIENT", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
myPatientDao.delete(new IdDt("Patient", id), mySrd);
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* *****************************************************
|
|
||||||
* Note that non JPA specific operations get tested in individual
|
|
||||||
* operation test methods too
|
|
||||||
* *****************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdDt(id));
|
|
||||||
p.addName().addFamily("PATIENT1");
|
|
||||||
Long id2 = myPatientDao.update(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now do a conditional update
|
|
||||||
*/
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdDt(id));
|
|
||||||
p.addName().addFamily("PATIENT2");
|
|
||||||
id2 = myPatientDao.update(p, "Patient?family=PATIENT1", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertEquals(id, tableCapt.getAllValues().get(2).getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now do a conditional update where none will match (so this is actually a create)
|
|
||||||
*/
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT3");
|
|
||||||
id2 = myPatientDao.update(p, "Patient?family=ZZZ", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertNotEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertEquals(id2, tableCapt.getAllValues().get(3).getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationCreate() {
|
|
||||||
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
myServerInterceptorList.add(interceptor);
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
IIdType newId = myPatientDao.delete(new IdDt("Patient/" + id), mySrd).getId();
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationDeleteMulti() {
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?name=PATIENT", mySrd);
|
|
||||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
|
||||||
ourLog.info(oo);
|
|
||||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionCreate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleTypeEnum.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.setResource(p)
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient")
|
|
||||||
.setMethod(HTTPVerbEnum.POST);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdDt newId = new IdDt(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(1L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleTypeEnum.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient/" + id)
|
|
||||||
.setMethod(HTTPVerbEnum.DELETE);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdDt newId = new IdDt(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionDeleteMulti() {
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleTypeEnum.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient?name=PATIENT")
|
|
||||||
.setMethod(HTTPVerbEnum.DELETE);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
assertNotNull(resp);
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdDt("Patient/" + id));
|
|
||||||
p.addName().addFamily("PATIENT2");
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleTypeEnum.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.setResource(p)
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient/" + id)
|
|
||||||
.setMethod(HTTPVerbEnum.PUT);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdDt newId = new IdDt(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().addFamily("PATIENT");
|
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdDt("Patient/" + id));
|
|
||||||
p.addName().addFamily("PATIENT2");
|
|
||||||
IIdType newId = myPatientDao.update(p, mySrd).getId();
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -152,15 +152,12 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test {
|
||||||
public void testSearchAndReindex() {
|
public void testSearchAndReindex() {
|
||||||
SearchParameterMap map;
|
SearchParameterMap map;
|
||||||
|
|
||||||
final IIdType pId1= newTxTemplate().execute(new TransactionCallback<IIdType>() {
|
final IIdType pId1= newTxTemplate().execute(t -> {
|
||||||
@Override
|
// TODO Auto-generated method stub
|
||||||
public IIdType doInTransaction(TransactionStatus theStatus) {
|
Patient patient = new Patient();
|
||||||
// TODO Auto-generated method stub
|
patient.getText().setDiv("<div>DIVAAA</div>");
|
||||||
Patient patient = new Patient();
|
patient.addName().addGiven("NAMEAAA");
|
||||||
patient.getText().setDiv("<div>DIVAAA</div>");
|
return myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||||
patient.addName().addGiven("NAMEAAA");
|
|
||||||
return myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
map = new SearchParameterMap();
|
map = new SearchParameterMap();
|
||||||
|
@ -179,7 +176,7 @@ public class FhirResourceDaoDstu2SearchFtTest extends BaseJpaDstu2Test {
|
||||||
@Override
|
@Override
|
||||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.setId(pId1);
|
patient.setId(pId1.getValue());
|
||||||
patient.getText().setDiv("<div>DIVBBB</div>");
|
patient.getText().setDiv("<div>DIVBBB</div>");
|
||||||
patient.addName().addGiven("NAMEBBB");
|
patient.addName().addGiven("NAMEBBB");
|
||||||
myPatientDao.update(patient, mySrd);
|
myPatientDao.update(patient, mySrd);
|
||||||
|
|
|
@ -426,58 +426,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateWithIfNoneExistBasic() {
|
|
||||||
String methodName = "testCreateWithIfNoneExistBasic";
|
|
||||||
MethodOutcome results;
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
|
||||||
ourLog.info("Created patient, got it: {}", id);
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().addFamily("Hello");
|
|
||||||
results = myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
|
||||||
assertEquals(id.getIdPart(), results.getId().getIdPart());
|
|
||||||
assertFalse(results.getCreated().booleanValue());
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(myInterceptor);
|
|
||||||
|
|
||||||
// Now create a second one
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().addFamily("Hello");
|
|
||||||
results = myPatientDao.create(p, mySrd);
|
|
||||||
assertNotEquals(id.getIdPart(), results.getId().getIdPart());
|
|
||||||
assertTrue(results.getCreated().booleanValue());
|
|
||||||
|
|
||||||
// Now try to create one with the original match URL and it should fail
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().addFamily("Hello");
|
|
||||||
try {
|
|
||||||
myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
|
||||||
fail();
|
|
||||||
} catch (PreconditionFailedException e) {
|
|
||||||
assertThat(e.getMessage(), containsString("Failed to CREATE"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateWithIllegalReference() {
|
public void testCreateWithIllegalReference() {
|
||||||
Observation o1 = new Observation();
|
Observation o1 = new Observation();
|
||||||
|
@ -1830,44 +1778,6 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRead() {
|
|
||||||
Observation o1 = new Observation();
|
|
||||||
o1.getCode().addCoding().setSystem("foo").setCode("testRead");
|
|
||||||
IIdType id1 = myObservationDao.create(o1, mySrd).getId();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* READ
|
|
||||||
*/
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
Observation obs = myObservationDao.read(id1.toUnqualifiedVersionless(), mySrd);
|
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualifiedVersionless().getValue(), details.getId().toUnqualifiedVersionless().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* VREAD
|
|
||||||
*/
|
|
||||||
assertTrue(id1.hasVersionIdPart()); // just to make sure..
|
|
||||||
reset(myInterceptor);
|
|
||||||
obs = myObservationDao.read(id1, mySrd);
|
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualified().getValue(), details.getId().toUnqualified().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadForcedIdVersionHistory() throws InterruptedException {
|
public void testReadForcedIdVersionHistory() throws InterruptedException {
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
|
|
|
@ -38,77 +38,6 @@ public class FhirResourceDaoDstu2UpdateTest extends BaseJpaDstu2Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdateAndGetHistoryResource() throws InterruptedException {
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
|
||||||
patient.addName().addFamily("Tester").addGiven("Joe");
|
|
||||||
|
|
||||||
MethodOutcome outcome = myPatientDao.create(patient, mySrd);
|
|
||||||
assertNotNull(outcome.getId());
|
|
||||||
assertFalse(outcome.getId().isEmpty());
|
|
||||||
|
|
||||||
assertEquals("1", outcome.getId().getVersionIdPart());
|
|
||||||
|
|
||||||
Date now = new Date();
|
|
||||||
Patient retrieved = myPatientDao.read(outcome.getId(), mySrd);
|
|
||||||
InstantDt published = (InstantDt) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
|
|
||||||
InstantDt updated = (InstantDt) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
|
||||||
assertTrue(published.before(now));
|
|
||||||
assertTrue(updated.before(now));
|
|
||||||
|
|
||||||
Thread.sleep(1000);
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
retrieved.getIdentifierFirstRep().setValue("002");
|
|
||||||
MethodOutcome outcome2 = myPatientDao.update(retrieved, mySrd);
|
|
||||||
assertEquals(outcome.getId().getIdPart(), outcome2.getId().getIdPart());
|
|
||||||
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
|
|
||||||
assertEquals("2", outcome2.getId().getVersionIdPart());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.UPDATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNotNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
Date now2 = new Date();
|
|
||||||
|
|
||||||
Patient retrieved2 = myPatientDao.read(outcome.getId().toVersionless(), mySrd);
|
|
||||||
|
|
||||||
assertEquals("2", retrieved2.getId().getVersionIdPart());
|
|
||||||
assertEquals("002", retrieved2.getIdentifierFirstRep().getValue());
|
|
||||||
InstantDt published2 = (InstantDt) retrieved2.getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
|
|
||||||
InstantDt updated2 = (InstantDt) retrieved2.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
|
|
||||||
assertTrue(published2.before(now));
|
|
||||||
assertTrue(updated2.after(now));
|
|
||||||
assertTrue(updated2.before(now2));
|
|
||||||
|
|
||||||
Thread.sleep(2000);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get history
|
|
||||||
*/
|
|
||||||
|
|
||||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
|
|
||||||
|
|
||||||
assertEquals(2, historyBundle.size().intValue());
|
|
||||||
|
|
||||||
List<IBaseResource> history = historyBundle.getResources(0, 2);
|
|
||||||
assertEquals("1", history.get(1).getIdElement().getVersionIdPart());
|
|
||||||
assertEquals("2", history.get(0).getIdElement().getVersionIdPart());
|
|
||||||
assertEquals(published, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(1)));
|
|
||||||
assertEquals(published, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(1)));
|
|
||||||
assertEquals(updated, ResourceMetadataKeyEnum.UPDATED.get((IResource) history.get(1)));
|
|
||||||
assertEquals("001", ((Patient) history.get(1)).getIdentifierFirstRep().getValue());
|
|
||||||
assertEquals(published2, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(0)));
|
|
||||||
assertEquals(updated2, ResourceMetadataKeyEnum.UPDATED.get((IResource) history.get(0)));
|
|
||||||
assertEquals("002", ((Patient) history.get(0)).getIdentifierFirstRep().getValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateByUrl() {
|
public void testUpdateByUrl() {
|
||||||
String methodName = "testUpdateByUrl";
|
String methodName = "testUpdateByUrl";
|
||||||
|
@ -184,7 +113,7 @@ public class FhirResourceDaoDstu2UpdateTest extends BaseJpaDstu2Test {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
p1.setId(p1id);
|
p1.setId(p1id.getValue());
|
||||||
p1.addName().addFamily(methodName);
|
p1.addName().addFamily(methodName);
|
||||||
|
|
||||||
TagList tagList = new TagList();
|
TagList tagList = new TagList();
|
||||||
|
|
|
@ -401,42 +401,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
||||||
assertEquals(new IdDt(patientId).toUnqualifiedVersionless(), o.getSubject().getReference());
|
assertEquals(new IdDt(patientId).toUnqualifiedVersionless(), o.getSubject().getReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCreateNoMatchUrl() {
|
|
||||||
String methodName = "testTransactionCreateNoMatchUrl";
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerbEnum.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
|
|
||||||
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, resp.getEntry().size());
|
|
||||||
|
|
||||||
Entry respEntry = resp.getEntry().get(0);
|
|
||||||
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
|
|
||||||
String patientId = respEntry.getResponse().getLocation();
|
|
||||||
assertThat(patientId, not(containsString("test")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateWithDuplicateMatchUrl01() {
|
public void testTransactionCreateWithDuplicateMatchUrl01() {
|
||||||
String methodName = "testTransactionCreateWithDuplicateMatchUrl01";
|
String methodName = "testTransactionCreateWithDuplicateMatchUrl01";
|
||||||
|
@ -1182,76 +1146,6 @@ public class FhirSystemDaoDstu2Test extends BaseJpaDstu2SystemTest {
|
||||||
assertThat(respGetBundle.getLink("self").getUrl(), endsWith("/Patient?identifier=testTransactionOrdering"));
|
assertThat(respGetBundle.getLink("self").getUrl(), endsWith("/Patient?identifier=testTransactionOrdering"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionReadAndSearch() {
|
|
||||||
String methodName = "testTransactionReadAndSearch";
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
IIdType idv1 = myPatientDao.update(p, mySrd).getId();
|
|
||||||
ourLog.info("Created patient, got id: {}", idv1);
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().addFamily("Family Name");
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
IIdType idv2 = myPatientDao.update(p, mySrd).getId();
|
|
||||||
ourLog.info("Updated patient, got id: {}", idv2);
|
|
||||||
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualifiedVersionless().getValue());
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl(idv1.toUnqualified().getValue());
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerbEnum.GET).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
|
|
||||||
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
|
||||||
|
|
||||||
assertEquals(3, resp.getEntry().size());
|
|
||||||
|
|
||||||
Entry nextEntry;
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(0);
|
|
||||||
assertEquals(Patient.class, nextEntry.getResource().getClass());
|
|
||||||
assertEquals(idv2.toUnqualified(), nextEntry.getResource().getId().toUnqualified());
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(1);
|
|
||||||
assertEquals(Patient.class, nextEntry.getResource().getClass());
|
|
||||||
assertEquals(idv1.toUnqualified(), nextEntry.getResource().getId().toUnqualified());
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(2);
|
|
||||||
assertEquals(Bundle.class, nextEntry.getResource().getClass());
|
|
||||||
Bundle respBundle = (Bundle) nextEntry.getResource();
|
|
||||||
assertEquals(1, respBundle.getTotal().intValue());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualifiedVersionless(), details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualified(), details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.SEARCH_TYPE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionReadWithIfNoneMatch() {
|
public void testTransactionReadWithIfNoneMatch() {
|
||||||
String methodName = "testTransactionReadWithIfNoneMatch";
|
String methodName = "testTransactionReadWithIfNoneMatch";
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu3;
|
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import static org.mockito.Mockito.when;
|
import ca.uhn.fhir.jpa.rp.dstu3.PatientResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import java.util.Enumeration;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import static org.mockito.Mockito.mock;
|
||||||
import org.junit.Before;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.rp.dstu3.PatientResourceProvider;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
|
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
|
|
||||||
public abstract class BaseJpaDstu3SystemTest extends BaseJpaDstu3Test {
|
public abstract class BaseJpaDstu3SystemTest extends BaseJpaDstu3Test {
|
||||||
protected ServletRequestDetails mySrd;
|
protected ServletRequestDetails mySrd;
|
||||||
|
@ -32,7 +30,7 @@ public abstract class BaseJpaDstu3SystemTest extends BaseJpaDstu3Test {
|
||||||
@Before
|
@Before
|
||||||
public void before() throws ServletException {
|
public void before() throws ServletException {
|
||||||
mySrd = mock(ServletRequestDetails.class);
|
mySrd = mock(ServletRequestDetails.class);
|
||||||
when(mySrd.getRequestOperationCallback()).thenReturn(mock(IRequestOperationCallback.class));
|
when(mySrd.getInterceptorBroadcaster()).thenReturn(mock(IInterceptorBroadcaster.class));
|
||||||
|
|
||||||
if (myServer == null) {
|
if (myServer == null) {
|
||||||
myServer = new RestfulServer(myFhirCtx);
|
myServer = new RestfulServer(myFhirCtx);
|
||||||
|
|
|
@ -16,9 +16,11 @@ import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
|
@ -137,7 +139,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myImmunizationRecommendationDaoDstu3")
|
@Qualifier("myImmunizationRecommendationDaoDstu3")
|
||||||
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
||||||
protected IServerInterceptor myInterceptor;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myLocationDaoDstu3")
|
@Qualifier("myLocationDaoDstu3")
|
||||||
protected IFhirResourceDao<Location> myLocationDao;
|
protected IFhirResourceDao<Location> myLocationDao;
|
||||||
|
@ -196,7 +197,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||||
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myResourceProvidersDstu3")
|
@Qualifier("myResourceProvidersDstu3")
|
||||||
protected Object myResourceProviders;
|
protected ResourceProviderFactory myResourceProviders;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao;
|
protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -263,7 +264,11 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||||
myDaoConfig.setExpireSearchResultsAfterMillis(new DaoConfig().getExpireSearchResultsAfterMillis());
|
myDaoConfig.setExpireSearchResultsAfterMillis(new DaoConfig().getExpireSearchResultsAfterMillis());
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||||
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
||||||
myDaoConfig.getInterceptors().clear();
|
}
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void afterResetInterceptors() {
|
||||||
|
myInterceptorRegistry.unregisterAllInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -282,12 +287,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
||||||
ourJpaValidationSupportChainDstu3 = myJpaValidationSupportChainDstu3;
|
ourJpaValidationSupportChainDstu3 = myJpaValidationSupportChainDstu3;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
|
||||||
public void beforeCreateInterceptor() {
|
|
||||||
myInterceptor = mock(IServerInterceptor.class);
|
|
||||||
myDaoConfig.getInterceptors().add(myInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeFlushFT() {
|
public void beforeFlushFT() {
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
|
|
|
@ -1,488 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu3;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.dao.DeleteMethodOutcome;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.mockito.Mockito;
|
|
||||||
import org.mockito.invocation.InvocationOnMock;
|
|
||||||
import org.mockito.stubbing.Answer;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
public class FhirResourceDaoDstu3InterceptorTest extends BaseJpaDstu3Test {
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3InterceptorTest.class);
|
|
||||||
private IServerOperationInterceptor myJpaInterceptor;
|
|
||||||
private ServerOperationInterceptorAdapter myJpaInterceptorAdapter = new ServerOperationInterceptorAdapter();
|
|
||||||
private IServerOperationInterceptor myServerOperationInterceptor;
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() {
|
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptorAdapter);
|
|
||||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void before() {
|
|
||||||
myJpaInterceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
|
|
||||||
myServerOperationInterceptor = mock(IServerOperationInterceptor.class, new Answer<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
if (theInvocation.getMethod().getReturnType().equals(boolean.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptorAdapter);
|
|
||||||
myDaoConfig.getInterceptors().add(myServerOperationInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaCreate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Not do a conditional create
|
|
||||||
*/
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT1");
|
|
||||||
Long id2 = myPatientDao.create(p, "Patient?family=PATIENT", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* *****************************************************
|
|
||||||
* Note that non JPA specific operations get tested in individual
|
|
||||||
* operation test methods too
|
|
||||||
* *****************************************************
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
myPatientDao.delete(new IdType("Patient", id), mySrd);
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testJpaUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdType(id));
|
|
||||||
p.addName().setFamily("PATIENT1");
|
|
||||||
Long id2 = myPatientDao.update(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> detailsCapt;
|
|
||||||
ArgumentCaptor<IBaseResource> tableCapt;
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now do a conditional update
|
|
||||||
*/
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdType(id));
|
|
||||||
p.addName().setFamily("PATIENT2");
|
|
||||||
id2 = myPatientDao.update(p, "Patient?family=PATIENT1", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertEquals(id, tableCapt.getAllValues().get(2).getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Now do a conditional update where none will match (so this is actually a create)
|
|
||||||
*/
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT3");
|
|
||||||
id2 = myPatientDao.update(p, "Patient?family=ZZZ", mySrd).getId().getIdPartAsLong();
|
|
||||||
assertNotEquals(id, id2);
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
verify(myJpaInterceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
|
||||||
assertEquals(id2, tableCapt.getAllValues().get(3).getIdElement().getIdPartAsLong());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationCreate() {
|
|
||||||
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
myServerInterceptorList.add(interceptor);
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testServerOperationCreate() {
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
@Test
|
|
||||||
public void testServerOperationUpdate() {
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
p.addName().setFamily("2");
|
|
||||||
myPatientDao.update(p);
|
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testServerOperationDelete() {
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
IIdType id = myPatientDao.create(p, (RequestDetails)null).getId();
|
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
p.addName().setFamily("2");
|
|
||||||
myPatientDao.delete(p.getIdElement().toUnqualifiedVersionless());
|
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
IIdType newId = myPatientDao.delete(new IdType("Patient/" + id), mySrd).getId();
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationDeleteMulti() {
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?name=PATIENT", mySrd);
|
|
||||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
|
||||||
ourLog.info(oo);
|
|
||||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionCreate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.setResource(p)
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient")
|
|
||||||
.setMethod(HTTPVerb.POST);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(1L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionDelete() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient/" + id)
|
|
||||||
.setMethod(HTTPVerb.DELETE);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionDeleteMulti() {
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
Long id2 = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient?name=PATIENT")
|
|
||||||
.setMethod(HTTPVerb.DELETE);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp);
|
|
||||||
ourLog.info(oo);
|
|
||||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationTransactionUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdType("Patient/" + id));
|
|
||||||
p.addName().setFamily("PATIENT2");
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
|
||||||
xactBundle
|
|
||||||
.addEntry()
|
|
||||||
.setResource(p)
|
|
||||||
.getRequest()
|
|
||||||
.setUrl("Patient/" + id)
|
|
||||||
.setMethod(HTTPVerb.PUT);
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, xactBundle);
|
|
||||||
|
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRequestOperationUpdate() {
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addName().setFamily("PATIENT");
|
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
|
||||||
@Override
|
|
||||||
public Void answer(InvocationOnMock theInvocation) throws Throwable {
|
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
|
||||||
res = (IBaseResource) theInvocation.getArguments()[1];
|
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
|
||||||
return null;
|
|
||||||
}}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.setId(new IdType("Patient/" + id));
|
|
||||||
p.addName().setFamily("PATIENT2");
|
|
||||||
IIdType newId = myPatientDao.update(p, mySrd).getId();
|
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -264,7 +264,7 @@ public class FhirResourceDaoDstu3SearchFtTest extends BaseJpaDstu3Test {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
patient = new Patient();
|
patient = new Patient();
|
||||||
patient.setId(pId1);
|
patient.setId(pId1.getValue());
|
||||||
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
||||||
patient.addName().addGiven("NAMEBBB");
|
patient.addName().addGiven("NAMEBBB");
|
||||||
myPatientDao.update(patient, mockSrd());
|
myPatientDao.update(patient, mockSrd());
|
||||||
|
|
|
@ -675,58 +675,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
||||||
assertNotEquals("ABC", id);
|
assertNotEquals("ABC", id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateWithIfNoneExistBasic() {
|
|
||||||
String methodName = "testCreateWithIfNoneExistBasic";
|
|
||||||
MethodOutcome results;
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
|
||||||
ourLog.info("Created patient, got it: {}", id);
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().setFamily("Hello");
|
|
||||||
results = myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
|
||||||
assertEquals(id.getIdPart(), results.getId().getIdPart());
|
|
||||||
assertFalse(results.getCreated().booleanValue());
|
|
||||||
|
|
||||||
verifyNoMoreInteractions(myInterceptor);
|
|
||||||
|
|
||||||
// Now create a second one
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().setFamily("Hello");
|
|
||||||
results = myPatientDao.create(p, mySrd);
|
|
||||||
assertNotEquals(id.getIdPart(), results.getId().getIdPart());
|
|
||||||
assertTrue(results.getCreated().booleanValue());
|
|
||||||
|
|
||||||
// Now try to create one with the original match URL and it should fail
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().setFamily("Hello");
|
|
||||||
try {
|
|
||||||
myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
|
||||||
fail();
|
|
||||||
} catch (PreconditionFailedException e) {
|
|
||||||
assertThat(e.getMessage(), containsString("Failed to CREATE"));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateWithIfNoneExistId() {
|
public void testCreateWithIfNoneExistId() {
|
||||||
String methodName = "testCreateWithIfNoneExistId";
|
String methodName = "testCreateWithIfNoneExistId";
|
||||||
|
@ -2278,43 +2226,6 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testRead() {
|
|
||||||
Observation o1 = new Observation();
|
|
||||||
o1.getCode().addCoding().setSystem("foo").setCode("testRead");
|
|
||||||
IIdType id1 = myObservationDao.create(o1, mySrd).getId();
|
|
||||||
|
|
||||||
/*
|
|
||||||
* READ
|
|
||||||
*/
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
Observation obs = myObservationDao.read(id1.toUnqualifiedVersionless(), mySrd);
|
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualifiedVersionless().getValue(), details.getId().toUnqualifiedVersionless().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* VREAD
|
|
||||||
*/
|
|
||||||
assertTrue(id1.hasVersionIdPart()); // just to make sure..
|
|
||||||
reset(myInterceptor);
|
|
||||||
obs = myObservationDao.read(id1, mySrd);
|
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualified().getValue(), details.getId().toUnqualified().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadForcedIdVersionHistory() {
|
public void testReadForcedIdVersionHistory() {
|
||||||
|
|
|
@ -202,7 +202,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
{
|
{
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.setId(id);
|
patient.setId(id.getValue());
|
||||||
patient.setActive(true);
|
patient.setActive(true);
|
||||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
||||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
||||||
|
@ -294,76 +294,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testUpdateAndGetHistoryResource() throws InterruptedException {
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
|
||||||
|
|
||||||
MethodOutcome outcome = myPatientDao.create(patient, mySrd);
|
|
||||||
assertNotNull(outcome.getId());
|
|
||||||
assertFalse(outcome.getId().isEmpty());
|
|
||||||
|
|
||||||
assertEquals("1", outcome.getId().getVersionIdPart());
|
|
||||||
|
|
||||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
|
||||||
Date now = new Date();
|
|
||||||
Patient retrieved = myPatientDao.read(outcome.getId(), mySrd);
|
|
||||||
InstantType updated = retrieved.getMeta().getLastUpdatedElement().copy();
|
|
||||||
assertTrue(updated.before(now));
|
|
||||||
|
|
||||||
Thread.sleep(1000);
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
retrieved.getIdentifier().get(0).setValue("002");
|
|
||||||
MethodOutcome outcome2 = myPatientDao.update(retrieved, mySrd);
|
|
||||||
assertEquals(outcome.getId().getIdPart(), outcome2.getId().getIdPart());
|
|
||||||
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
|
|
||||||
assertEquals("2", outcome2.getId().getVersionIdPart());
|
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.UPDATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNotNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
Date now2 = new Date();
|
|
||||||
|
|
||||||
Patient retrieved2 = myPatientDao.read(outcome.getId().toVersionless(), mySrd);
|
|
||||||
|
|
||||||
assertEquals("2", retrieved2.getIdElement().getVersionIdPart());
|
|
||||||
assertEquals("002", retrieved2.getIdentifier().get(0).getValue());
|
|
||||||
InstantType updated2 = retrieved2.getMeta().getLastUpdatedElement();
|
|
||||||
assertTrue(updated2.after(now));
|
|
||||||
assertTrue(updated2.before(now2));
|
|
||||||
|
|
||||||
Thread.sleep(2000);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Get history
|
|
||||||
*/
|
|
||||||
|
|
||||||
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null, null, mySrd);
|
|
||||||
|
|
||||||
assertEquals(2, historyBundle.size().intValue());
|
|
||||||
|
|
||||||
List<IBaseResource> history = historyBundle.getResources(0, 2);
|
|
||||||
|
|
||||||
ourLog.info("updated : {}", updated.getValueAsString());
|
|
||||||
ourLog.info(" * Exp : {}", ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
|
|
||||||
ourLog.info("updated2: {}", updated2.getValueAsString());
|
|
||||||
ourLog.info(" * Exp : {}", ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString());
|
|
||||||
|
|
||||||
assertEquals("1", history.get(1).getIdElement().getVersionIdPart());
|
|
||||||
assertEquals("2", history.get(0).getIdElement().getVersionIdPart());
|
|
||||||
assertEquals(updated.getValueAsString(), ((Resource) history.get(1)).getMeta().getLastUpdatedElement().getValueAsString());
|
|
||||||
assertEquals("001", ((Patient) history.get(1)).getIdentifier().get(0).getValue());
|
|
||||||
assertEquals(updated2.getValueAsString(), ((Resource) history.get(0)).getMeta().getLastUpdatedElement().getValueAsString());
|
|
||||||
assertEquals("002", ((Patient) history.get(0)).getIdentifier().get(0).getValue());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateByUrl() {
|
public void testUpdateByUrl() {
|
||||||
|
@ -563,7 +494,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
p1.setId(p1id);
|
p1.setId(p1id.getValue());
|
||||||
p1.addName().setFamily(methodName);
|
p1.addName().setFamily(methodName);
|
||||||
|
|
||||||
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
|
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
|
||||||
|
@ -581,7 +512,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
||||||
}
|
}
|
||||||
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
|
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
|
||||||
List<Coding> secList = p1.getMeta().getSecurity();
|
List<Coding> secList = p1.getMeta().getSecurity();
|
||||||
secListValues = new HashSet<String>();
|
secListValues = new HashSet<>();
|
||||||
for (Coding next : secList) {
|
for (Coding next : secList) {
|
||||||
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -878,41 +878,6 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||||
assertEquals(new IdType(patientId).toUnqualifiedVersionless().getValue(), o.getSubject().getReference());
|
assertEquals(new IdType(patientId).toUnqualifiedVersionless().getValue(), o.getSubject().getReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionCreateNoMatchUrl() {
|
|
||||||
String methodName = "testTransactionCreateNoMatchUrl";
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setIfNoneExist("Patient?identifier=urn%3Asystem%7C" + methodName);
|
|
||||||
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
|
||||||
assertEquals(1, resp.getEntry().size());
|
|
||||||
|
|
||||||
BundleEntryComponent respEntry = resp.getEntry().get(0);
|
|
||||||
assertEquals(Constants.STATUS_HTTP_201_CREATED + " Created", respEntry.getResponse().getStatus());
|
|
||||||
String patientId = respEntry.getResponse().getLocation();
|
|
||||||
assertThat(patientId, not(containsString("test")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateWithBadRead() {
|
public void testTransactionCreateWithBadRead() {
|
||||||
|
@ -1920,75 +1885,7 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||||
assertEquals(1, allPatients.size().intValue());
|
assertEquals(1, allPatients.size().intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionReadAndSearch() {
|
|
||||||
String methodName = "testTransactionReadAndSearch";
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
IIdType idv1 = myPatientDao.update(p, mySrd).getId();
|
|
||||||
ourLog.info("Created patient, got id: {}", idv1);
|
|
||||||
|
|
||||||
p = new Patient();
|
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
|
||||||
p.addName().setFamily("Family Name");
|
|
||||||
p.setId("Patient/" + methodName);
|
|
||||||
IIdType idv2 = myPatientDao.update(p, mySrd).getId();
|
|
||||||
ourLog.info("Updated patient, got id: {}", idv2);
|
|
||||||
|
|
||||||
Bundle request = new Bundle();
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl(idv1.toUnqualifiedVersionless().getValue());
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl(idv1.toUnqualified().getValue());
|
|
||||||
request.addEntry().getRequest().setMethod(HTTPVerb.GET).setUrl("Patient?identifier=urn%3Asystem%7C" + methodName);
|
|
||||||
|
|
||||||
Bundle resp = mySystemDao.transaction(mySrd, request);
|
|
||||||
|
|
||||||
assertEquals(3, resp.getEntry().size());
|
|
||||||
|
|
||||||
BundleEntryComponent nextEntry;
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(0);
|
|
||||||
assertEquals(Patient.class, nextEntry.getResource().getClass());
|
|
||||||
assertEquals(idv2.toUnqualified(), nextEntry.getResource().getIdElement().toUnqualified());
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(1);
|
|
||||||
assertEquals(Patient.class, nextEntry.getResource().getClass());
|
|
||||||
assertEquals(idv1.toUnqualified(), nextEntry.getResource().getIdElement().toUnqualified());
|
|
||||||
|
|
||||||
nextEntry = resp.getEntry().get(2);
|
|
||||||
assertEquals(Bundle.class, nextEntry.getResource().getClass());
|
|
||||||
Bundle respBundle = (Bundle) nextEntry.getResource();
|
|
||||||
assertEquals(1, respBundle.getTotal());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualifiedVersionless().getValue(), details.getId().getValue());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualified().getValue(), details.getId().getValue());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.SEARCH_TYPE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionReadWithIfNoneMatch() {
|
public void testTransactionReadWithIfNoneMatch() {
|
||||||
|
|
|
@ -1,22 +1,20 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import static org.mockito.Mockito.mock;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import static org.mockito.Mockito.when;
|
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||||
import java.util.Enumeration;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
|
||||||
import javax.servlet.ServletConfig;
|
import javax.servlet.ServletConfig;
|
||||||
import javax.servlet.ServletException;
|
import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import org.junit.AfterClass;
|
import static org.mockito.Mockito.mock;
|
||||||
import org.junit.Before;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
|
|
||||||
import ca.uhn.fhir.rest.api.server.IRequestOperationCallback;
|
|
||||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
|
|
||||||
public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
|
public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
|
||||||
protected ServletRequestDetails mySrd;
|
protected ServletRequestDetails mySrd;
|
||||||
|
@ -32,7 +30,7 @@ public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
|
||||||
@Before
|
@Before
|
||||||
public void before() throws ServletException {
|
public void before() throws ServletException {
|
||||||
mySrd = mock(ServletRequestDetails.class);
|
mySrd = mock(ServletRequestDetails.class);
|
||||||
when(mySrd.getRequestOperationCallback()).thenReturn(mock(IRequestOperationCallback.class));
|
when(mySrd.getInterceptorBroadcaster()).thenReturn(mock(IInterceptorBroadcaster.class));
|
||||||
|
|
||||||
if (myServer == null) {
|
if (myServer == null) {
|
||||||
myServer = new RestfulServer(myFhirCtx);
|
myServer = new RestfulServer(myFhirCtx);
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
|
@ -17,15 +17,18 @@ import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.BaseSearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.BaseSearchParamRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
|
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.server.BasePagingProvider;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
|
@ -55,6 +58,7 @@ import org.springframework.transaction.annotation.Transactional;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
|
@ -155,7 +159,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
||||||
protected IServerInterceptor myInterceptor;
|
protected IServerInterceptor myInterceptor;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IInterceptorRegistry myInterceptorRegistry;
|
protected IInterceptorService myInterceptorRegistry;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myLocationDaoR4")
|
@Qualifier("myLocationDaoR4")
|
||||||
protected IFhirResourceDao<Location> myLocationDao;
|
protected IFhirResourceDao<Location> myLocationDao;
|
||||||
|
@ -220,7 +224,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myResourceProvidersR4")
|
@Qualifier("myResourceProvidersR4")
|
||||||
protected Object myResourceProviders;
|
protected ResourceProviderFactory myResourceProviders;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IResourceTagDao myResourceTagDao;
|
protected IResourceTagDao myResourceTagDao;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -291,6 +295,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
protected SubscriptionRegistry mySubscriptionRegistry;
|
protected SubscriptionRegistry mySubscriptionRegistry;
|
||||||
|
|
||||||
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
|
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
|
||||||
|
private List<Object> mySystemInterceptors;
|
||||||
|
|
||||||
@After()
|
@After()
|
||||||
public void afterCleanupDao() {
|
public void afterCleanupDao() {
|
||||||
|
@ -301,9 +306,13 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
||||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||||
|
|
||||||
myInterceptorRegistry.clearAnonymousHookForUnitTest();
|
myPagingProvider.setDefaultPageSize(BasePagingProvider.DEFAULT_DEFAULT_PAGE_SIZE);
|
||||||
|
myPagingProvider.setMaximumPageSize(BasePagingProvider.DEFAULT_MAX_PAGE_SIZE);
|
||||||
|
}
|
||||||
|
|
||||||
myInterceptorRegistry.unregisterInterceptor(myPerformanceTracingLoggingInterceptor);
|
@After
|
||||||
|
public void afterResetInterceptors() {
|
||||||
|
myInterceptorRegistry.unregisterAllInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
|
@ -324,8 +333,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeCreateInterceptor() {
|
public void beforeCreateInterceptor() {
|
||||||
|
mySystemInterceptors = myInterceptorRegistry.getAllRegisteredInterceptors();
|
||||||
|
|
||||||
myInterceptor = mock(IServerInterceptor.class);
|
myInterceptor = mock(IServerInterceptor.class);
|
||||||
myDaoConfig.setInterceptors(myInterceptor);
|
|
||||||
|
|
||||||
myPerformanceTracingLoggingInterceptor = new PerformanceTracingLoggingInterceptor();
|
myPerformanceTracingLoggingInterceptor = new PerformanceTracingLoggingInterceptor();
|
||||||
myInterceptorRegistry.registerInterceptor(myPerformanceTracingLoggingInterceptor);
|
myInterceptorRegistry.registerInterceptor(myPerformanceTracingLoggingInterceptor);
|
||||||
|
|
|
@ -2,7 +2,9 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
import ca.uhn.fhir.rest.param.ReferenceParam;
|
import ca.uhn.fhir.rest.param.ReferenceParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
@ -152,6 +154,12 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myPatientDao.read(new IdType("Patient/999999999999999"));
|
myPatientDao.read(new IdType("Patient/999999999999999"));
|
||||||
|
|
||||||
|
SearchParameterMap map = new SearchParameterMap();
|
||||||
|
map.setLoadSynchronous(true);
|
||||||
|
map.add("_id", new TokenParam("999999999999999"));
|
||||||
|
IBundleProvider outcome = myPatientDao.search(map);
|
||||||
|
assertEquals(1, outcome.size().intValue());
|
||||||
|
assertEquals("Patient/999999999999999", outcome.getResources(0,1).get(0).getIdElement().toUnqualifiedVersionless().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.DeleteMethodOutcome;
|
import ca.uhn.fhir.jpa.dao.DeleteMethodOutcome;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -28,46 +31,29 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.in;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Mockito.*;
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4InterceptorTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4InterceptorTest.class);
|
||||||
private IServerOperationInterceptor myJpaInterceptor;
|
|
||||||
private ServerOperationInterceptorAdapter myJpaInterceptorAdapter = new ServerOperationInterceptorAdapter();
|
|
||||||
private IServerOperationInterceptor myServerOperationInterceptor;
|
|
||||||
private List<IIdType> myIds = new ArrayList<>();
|
private List<IIdType> myIds = new ArrayList<>();
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().remove(myJpaInterceptorAdapter);
|
|
||||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
myJpaInterceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
myIds.clear();
|
|
||||||
|
|
||||||
myServerOperationInterceptor = mock(IServerOperationInterceptor.class, new Answer<Object>() {
|
|
||||||
@Override
|
|
||||||
public Object answer(InvocationOnMock theInvocation) {
|
|
||||||
if (theInvocation.getMethod().getReturnType().equals(boolean.class)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptor);
|
|
||||||
myDaoConfig.getInterceptors().add(myJpaInterceptorAdapter);
|
|
||||||
myDaoConfig.getInterceptors().add(myServerOperationInterceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJpaCreate() {
|
public void testJpaCreate() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -77,13 +63,13 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Not do a conditional create
|
* Not do a conditional create
|
||||||
|
@ -95,8 +81,8 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||||
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,6 +95,9 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJpaDelete() {
|
public void testJpaDelete() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -120,7 +109,7 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
||||||
|
|
||||||
|
@ -128,6 +117,9 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testJpaUpdate() {
|
public void testJpaUpdate() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -143,7 +135,7 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||||
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
assertNotNull(tableCapt.getValue().getIdElement().getIdPart());
|
||||||
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
assertEquals(id, tableCapt.getValue().getIdElement().getIdPartAsLong());
|
||||||
|
|
||||||
|
@ -159,8 +151,8 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||||
assertEquals(id, tableCapt.getAllValues().get(2).getIdElement().getIdPartAsLong());
|
assertEquals(id, tableCapt.getAllValues().get(2).getIdElement().getIdPartAsLong());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -174,8 +166,8 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
detailsCapt = ArgumentCaptor.forClass(RequestDetails.class);
|
||||||
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
tableCapt = ArgumentCaptor.forClass(IBaseResource.class);
|
||||||
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
|
||||||
verify(myJpaInterceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
verify(interceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
|
||||||
assertEquals(id2, tableCapt.getAllValues().get(3).getIdElement().getIdPartAsLong());
|
assertEquals(id2, tableCapt.getAllValues().get(3).getIdElement().getIdPartAsLong());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -183,56 +175,55 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationCreate() {
|
public void testRequestOperationCreate() {
|
||||||
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
myServerInterceptorList.add(interceptor);
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(t -> {
|
||||||
@Override
|
IBaseResource res = (IBaseResource) t.getArguments()[1];
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
Long id = res.getIdElement().getIdPartAsLong();
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
return null;
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
}).when(interceptor).resourceCreated(any(), any());
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationDelete() {
|
public void testRequestOperationDelete() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(t -> {
|
||||||
@Override
|
IBaseResource res = (IBaseResource) t.getArguments()[1];
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
Long id1 = res.getIdElement().getIdPartAsLong();
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
assertEquals("Patient/" + id1 + "/_history/2", res.getIdElement().getValue());
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
return null;
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
}).when(interceptor).resourceDeleted(any(), any());
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
|
||||||
|
|
||||||
IIdType newId = myPatientDao.delete(new IdType("Patient/" + id), mySrd).getId();
|
IIdType newId = myPatientDao.delete(new IdType("Patient/" + id), mySrd).getId();
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreDelete(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceDeleted(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
verifyNoMoreInteractions(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationDeleteMulti() {
|
public void testRequestOperationDeleteMulti() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
myDaoConfig.setAllowMultipleDelete(true);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
@ -246,39 +237,42 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
Long id = res.getIdElement().getIdPartAsLong();
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
}).when(interceptor).resourceDeleted(any(), any());
|
||||||
|
|
||||||
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?name=PATIENT", mySrd);
|
DeleteMethodOutcome outcome = myPatientDao.deleteByUrl("Patient?name=PATIENT", mySrd);
|
||||||
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
String oo = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
|
||||||
ourLog.info(oo);
|
ourLog.info(oo);
|
||||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
assertThat(oo, containsString("deleted 2 resource(s)"));
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourceDeleted(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourceCreated(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourcePreDelete(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourcePreCreate(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
verifyNoMoreInteractions(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationTransactionCreate() {
|
public void testRequestOperationTransactionCreate() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
|
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
Long id = res.getIdElement().getIdPartAsLong();
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceCreated(any(IBaseResource.class));
|
}).when(interceptor).resourceCreated(any(), any());
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
Bundle xactBundle = new Bundle();
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
xactBundle.setType(BundleType.TRANSACTION);
|
||||||
|
@ -293,13 +287,16 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||||
assertEquals(1L, newId.getVersionIdPartAsLong().longValue());
|
assertEquals(1L, newId.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
verifyNoMoreInteractions(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationTransactionDelete() {
|
public void testRequestOperationTransactionDelete() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -307,12 +304,12 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
Long id = res.getIdElement().getIdPartAsLong();
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
}).when(interceptor).resourceDeleted(any(), any());
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
Bundle xactBundle = new Bundle();
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
xactBundle.setType(BundleType.TRANSACTION);
|
||||||
|
@ -326,15 +323,18 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreDelete(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreDelete(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceDeleted(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceDeleted(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
verifyNoMoreInteractions(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationTransactionDeleteMulti() {
|
public void testRequestOperationTransactionDeleteMulti() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
myDaoConfig.setAllowMultipleDelete(true);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
@ -348,12 +348,12 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
Long id = res.getIdElement().getIdPartAsLong();
|
Long id = res.getIdElement().getIdPartAsLong();
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceDeleted(any(IBaseResource.class));
|
}).when(interceptor).resourceDeleted(any(), any());
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
Bundle xactBundle = new Bundle();
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
xactBundle.setType(BundleType.TRANSACTION);
|
||||||
|
@ -368,15 +368,18 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
ourLog.info(oo);
|
ourLog.info(oo);
|
||||||
assertThat(oo, containsString("deleted 2 resource(s)"));
|
assertThat(oo, containsString("deleted 2 resource(s)"));
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(2)).resourceDeleted(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourceDeleted(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourceCreated(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreDelete(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourcePreDelete(any(), any());
|
||||||
verify(myRequestOperationCallback, times(2)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(2)).resourcePreCreate(any(), any());
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
verifyNoMoreInteractions(interceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationTransactionUpdate() {
|
public void testRequestOperationTransactionUpdate() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -388,11 +391,17 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
|
// Old contents
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
|
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||||
|
|
||||||
|
// New contents
|
||||||
|
res = (IBaseResource) theInvocation.getArguments()[2];
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
}).when(interceptor).resourceUpdated(any(), any(), any());
|
||||||
|
|
||||||
Bundle xactBundle = new Bundle();
|
Bundle xactBundle = new Bundle();
|
||||||
xactBundle.setType(BundleType.TRANSACTION);
|
xactBundle.setType(BundleType.TRANSACTION);
|
||||||
|
@ -407,16 +416,17 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
IdType newId = new IdType(resp.getEntry().get(0).getResponse().getLocation());
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceUpdated(any(), any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreUpdate(any(), any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRequestOperationUpdate() {
|
public void testRequestOperationUpdate() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
final Long id = myPatientDao.create(p, mySrd).getId().getIdPartAsLong();
|
||||||
|
@ -424,13 +434,13 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
doAnswer(new Answer<Void>() {
|
doAnswer(new Answer<Void>() {
|
||||||
@Override
|
@Override
|
||||||
public Void answer(InvocationOnMock theInvocation) {
|
public Void answer(InvocationOnMock theInvocation) {
|
||||||
IBaseResource res = (IBaseResource) theInvocation.getArguments()[0];
|
IBaseResource res = (IBaseResource) theInvocation.getArguments()[1];
|
||||||
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/1", res.getIdElement().getValue());
|
||||||
res = (IBaseResource) theInvocation.getArguments()[1];
|
res = (IBaseResource) theInvocation.getArguments()[2];
|
||||||
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
assertEquals("Patient/" + id + "/_history/2", res.getIdElement().getValue());
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}).when(myRequestOperationCallback).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
}).when(interceptor).resourceUpdated(any(), any(), any());
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.setId(new IdType("Patient/" + id));
|
p.setId(new IdType("Patient/" + id));
|
||||||
|
@ -438,30 +448,34 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
IIdType newId = myPatientDao.update(p, mySrd).getId();
|
IIdType newId = myPatientDao.update(p, mySrd).getId();
|
||||||
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
assertEquals(2L, newId.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceUpdated(any(), any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreCreate(any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
verify(interceptor, times(1)).resourcePreUpdate(any(), any(), any());
|
||||||
verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
verifyNoMoreInteractions(myRequestOperationCallback);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationCreate() {
|
public void testServerOperationCreate() {
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
verify(interceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
IIdType id = myPatientDao.create(p, (RequestDetails) null).getId();
|
IIdType id = myPatientDao.create(p, (RequestDetails) null).getId();
|
||||||
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
assertEquals(1L, id.getVersionIdPartAsLong().longValue());
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationDelete() {
|
public void testServerOperationDelete() {
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
verify(interceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
|
verify(interceptor, times(0)).resourceDeleted(Mockito.isNull(RequestDetails.class), any());
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
|
@ -471,67 +485,73 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
p.addName().setFamily("2");
|
p.addName().setFamily("2");
|
||||||
myPatientDao.delete(p.getIdElement().toUnqualifiedVersionless());
|
myPatientDao.delete(p.getIdElement().toUnqualifiedVersionless());
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceDeleted(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceDeleted(Mockito.isNull(RequestDetails.class), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Make sure that both JPA interceptors and RestfulServer interceptors can
|
||||||
|
* get called
|
||||||
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationInterceptorCanModifyOnCreate() {
|
public void testServerOperationInterceptorCanModifyOnCreateForJpaInterceptor() {
|
||||||
|
|
||||||
ServerOperationInterceptorAdapter interceptor = new ServerOperationInterceptorAdapter() {
|
Object interceptor = new Object() {
|
||||||
@Override
|
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
||||||
public void resourcePreCreate(RequestDetails theRequest, IBaseResource theResource) {
|
public void resourcePreCreate(IBaseResource theResource) {
|
||||||
((Patient) theResource).setActive(true);
|
((Patient) theResource).setActive(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
myDaoConfig.getInterceptors().add(interceptor);
|
myRequestOperationCallback.registerInterceptor(interceptor);
|
||||||
try {
|
|
||||||
|
|
||||||
doAnswer(new MyOneResourceAnswer()).when(myJpaInterceptor).resourcePreCreate(any(RequestDetails.class), any(IBaseResource.class));
|
Patient p = new Patient();
|
||||||
doAnswer(new MyOneResourceAnswer()).when(myJpaInterceptor).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
p.setActive(false);
|
||||||
|
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
Patient p = new Patient();
|
p = myPatientDao.read(id);
|
||||||
p.setActive(false);
|
assertEquals(true, p.getActive());
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
InOrder inorder = inOrder(myJpaInterceptor, myRequestOperationCallback);
|
}
|
||||||
inorder.verify(myRequestOperationCallback, times(1)).resourcePreCreate(any(IBaseResource.class));
|
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourcePreCreate(any(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
inorder.verify(myRequestOperationCallback, times(1)).resourceCreated(any(IBaseResource.class));
|
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
assertNull(myIds.get(0).getIdPart());
|
/**
|
||||||
assertNull(myIds.get(0).getVersionIdPart());
|
* Make sure that both JPA interceptors and RestfulServer interceptors can
|
||||||
assertNotNull(myIds.get(1).getIdPart());
|
* get called
|
||||||
assertEquals("1", myIds.get(1).getVersionIdPart());
|
*/
|
||||||
|
@Test
|
||||||
|
public void testServerOperationInterceptorCanModifyOnCreateForServerInterceptor() {
|
||||||
|
|
||||||
p = myPatientDao.read(id);
|
Object interceptor = new Object() {
|
||||||
assertEquals(true, p.getActive());
|
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
||||||
|
public void resourcePreCreate(IBaseResource theResource) {
|
||||||
|
((Patient) theResource).setActive(true);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(false);
|
||||||
|
IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
p = myPatientDao.read(id);
|
||||||
|
assertEquals(true, p.getActive());
|
||||||
|
|
||||||
} finally {
|
|
||||||
myDaoConfig.getInterceptors().remove(interceptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationInterceptorCanModifyOnUpdate() {
|
public void testServerOperationInterceptorCanModifyOnUpdate() {
|
||||||
|
|
||||||
ServerOperationInterceptorAdapter interceptor = new ServerOperationInterceptorAdapter() {
|
Object interceptor = new Object() {
|
||||||
@Override
|
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
|
||||||
public void resourcePreUpdate(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourcePreUpdate(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
((Patient) theNewResource).setActive(true);
|
((Patient) theNewResource).setActive(true);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
myDaoConfig.getInterceptors().add(interceptor);
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
try {
|
|
||||||
|
|
||||||
doAnswer(new MyTwoResourceAnswer()).when(myJpaInterceptor).resourcePreUpdate(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
doAnswer(new MyTwoResourceAnswer()).when(myJpaInterceptor).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setActive(false);
|
p.setActive(false);
|
||||||
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();
|
||||||
String idPart = id.getIdPart();
|
|
||||||
|
|
||||||
p = myPatientDao.read(id);
|
p = myPatientDao.read(id);
|
||||||
assertEquals(false, p.getActive());
|
assertEquals(false, p.getActive());
|
||||||
|
@ -540,36 +560,18 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
p.addAddress().setCity("CITY");
|
p.addAddress().setCity("CITY");
|
||||||
myPatientDao.update(p, mySrd);
|
myPatientDao.update(p, mySrd);
|
||||||
|
|
||||||
InOrder inorder = inOrder(myJpaInterceptor, myRequestOperationCallback);
|
|
||||||
inorder.verify(myRequestOperationCallback, times(1)).resourcePreUpdate(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourcePreUpdate(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
inorder.verify(myRequestOperationCallback, times(1)).resourceUpdated(any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
|
||||||
// resourcePreUpdate
|
|
||||||
assertEquals(idPart, myIds.get(0).getIdPart());
|
|
||||||
assertEquals("1", myIds.get(0).getVersionIdPart());
|
|
||||||
assertEquals(idPart, myIds.get(1).getIdPart());
|
|
||||||
assertEquals(null, myIds.get(1).getVersionIdPart());
|
|
||||||
// resourceUpdated
|
|
||||||
assertEquals(idPart, myIds.get(2).getIdPart());
|
|
||||||
assertEquals("1", myIds.get(2).getVersionIdPart());
|
|
||||||
assertEquals(idPart, myIds.get(3).getIdPart());
|
|
||||||
assertEquals("2", myIds.get(3).getVersionIdPart());
|
|
||||||
|
|
||||||
p = myPatientDao.read(id);
|
p = myPatientDao.read(id);
|
||||||
assertEquals(true, p.getActive());
|
assertEquals(true, p.getActive());
|
||||||
|
|
||||||
} finally {
|
|
||||||
myDaoConfig.getInterceptors().remove(interceptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationPreDelete() {
|
public void testServerOperationPreDelete() {
|
||||||
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
|
|
||||||
doAnswer(new MyOneResourceAnswer()).when(myJpaInterceptor).resourcePreDelete(nullable(ServletRequestDetails.class), any(Patient.class));
|
doAnswer(new MyOneResourceAnswer()).when(interceptor).resourcePreDelete(nullable(ServletRequestDetails.class), any(Patient.class));
|
||||||
doAnswer(new MyOneResourceAnswer()).when(myJpaInterceptor).resourceDeleted(nullable(ServletRequestDetails.class), any(Patient.class));
|
doAnswer(new MyOneResourceAnswer()).when(interceptor).resourceDeleted(nullable(ServletRequestDetails.class), any(Patient.class));
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setActive(false);
|
p.setActive(false);
|
||||||
|
@ -578,9 +580,9 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
myPatientDao.delete(id);
|
myPatientDao.delete(id);
|
||||||
|
|
||||||
InOrder inorder = inOrder(myJpaInterceptor);
|
InOrder inorder = inOrder(interceptor);
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourcePreDelete(nullable(ServletRequestDetails.class), any(Patient.class));
|
inorder.verify(interceptor, times(1)).resourcePreDelete(nullable(ServletRequestDetails.class), any(Patient.class));
|
||||||
inorder.verify(myJpaInterceptor, times(1)).resourceDeleted(nullable(ServletRequestDetails.class), any(Patient.class));
|
inorder.verify(interceptor, times(1)).resourceDeleted(nullable(ServletRequestDetails.class), any(Patient.class));
|
||||||
// resourcePreDelete
|
// resourcePreDelete
|
||||||
assertEquals(idPart, myIds.get(0).getIdPart());
|
assertEquals(idPart, myIds.get(0).getIdPart());
|
||||||
assertEquals("1", myIds.get(0).getVersionIdPart());
|
assertEquals("1", myIds.get(0).getVersionIdPart());
|
||||||
|
@ -593,9 +595,12 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
@Test
|
@Test
|
||||||
public void testServerOperationUpdate() {
|
public void testServerOperationUpdate() {
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
IServerOperationInterceptor interceptor = mock(IServerOperationInterceptor.class);
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
verify(myServerOperationInterceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
|
||||||
|
verify(interceptor, times(0)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
|
verify(interceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any());
|
||||||
|
verify(interceptor, times(0)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(), any());
|
||||||
|
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("PATIENT");
|
p.addName().setFamily("PATIENT");
|
||||||
|
@ -605,14 +610,9 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
p.addName().setFamily("2");
|
p.addName().setFamily("2");
|
||||||
myPatientDao.update(p);
|
myPatientDao.update(p);
|
||||||
|
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceCreated(Mockito.isNull(RequestDetails.class), any());
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any());
|
||||||
verify(myServerOperationInterceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
verify(interceptor, times(1)).resourceUpdated(Mockito.isNull(RequestDetails.class), any(), any());
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyOneResourceAnswer implements Answer {
|
private class MyOneResourceAnswer implements Answer {
|
||||||
|
@ -634,4 +634,9 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -277,7 +277,7 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
*/
|
*/
|
||||||
|
|
||||||
patient = new Patient();
|
patient = new Patient();
|
||||||
patient.setId(pId1);
|
patient.setId(pId1.getValue());
|
||||||
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
patient.getText().setDivAsString("<div>DIVBBB</div>");
|
||||||
patient.addName().addGiven("NAMEBBB");
|
patient.addName().addGiven("NAMEBBB");
|
||||||
myPatientDao.update(patient, mockSrd());
|
myPatientDao.update(patient, mockSrd());
|
||||||
|
|
|
@ -21,41 +21,37 @@ public class FhirResourceDaoR4SelectiveUpdateTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testInterceptorPreservesAttribute() throws Exception {
|
public void testInterceptorPreservesAttribute() throws Exception {
|
||||||
CentralAttributesPreservationInterceptor interceptor = new CentralAttributesPreservationInterceptor();
|
CentralAttributesPreservationInterceptor interceptor = new CentralAttributesPreservationInterceptor();
|
||||||
myDaoConfig.getInterceptors().add(interceptor);
|
myInterceptorRegistry.registerInterceptor(interceptor);
|
||||||
try {
|
|
||||||
|
|
||||||
// Create the patient with no additional identifier
|
// Create the patient with no additional identifier
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
p.addIdentifier().setSystem("http://foo").setValue("bar");
|
p.addIdentifier().setSystem("http://foo").setValue("bar");
|
||||||
IIdType id = myPatientDao.create(p).getId().toUnqualified();
|
IIdType id = myPatientDao.create(p).getId().toUnqualified();
|
||||||
assertEquals("1", id.getVersionIdPart());
|
assertEquals("1", id.getVersionIdPart());
|
||||||
|
|
||||||
// Update to add a preserved identifier
|
// Update to add a preserved identifier
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.setId(id.toVersionless());
|
p.setId(id.toVersionless());
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
p.addIdentifier(new Identifier().setSystem("http://foo").setValue("bar"));
|
p.addIdentifier(new Identifier().setSystem("http://foo").setValue("bar"));
|
||||||
p.addIdentifier(new Identifier().setSystem(EUID_SYSTEM).setValue("123"));
|
p.addIdentifier(new Identifier().setSystem(EUID_SYSTEM).setValue("123"));
|
||||||
id = myPatientDao.update(p).getId().toUnqualified();
|
id = myPatientDao.update(p).getId().toUnqualified();
|
||||||
assertEquals("2", id.getVersionIdPart());
|
assertEquals("2", id.getVersionIdPart());
|
||||||
|
|
||||||
// Update to change something but include the preserved attribute
|
// Update to change something but include the preserved attribute
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.setId(id.toVersionless());
|
p.setId(id.toVersionless());
|
||||||
p.setActive(false);
|
p.setActive(false);
|
||||||
p.addIdentifier(new Identifier().setSystem("http://foo").setValue("bar"));
|
p.addIdentifier(new Identifier().setSystem("http://foo").setValue("bar"));
|
||||||
id = myPatientDao.update(p).getId().toUnqualified();
|
id = myPatientDao.update(p).getId().toUnqualified();
|
||||||
assertEquals("3", id.getVersionIdPart());
|
assertEquals("3", id.getVersionIdPart());
|
||||||
|
|
||||||
// Read it back
|
// Read it back
|
||||||
p = myPatientDao.read(id);
|
p = myPatientDao.read(id);
|
||||||
assertEquals(false, p.getActive());
|
assertEquals(false, p.getActive());
|
||||||
assertEquals(2, p.getIdentifier().size());
|
assertEquals(2, p.getIdentifier().size());
|
||||||
|
|
||||||
} finally {
|
|
||||||
myDaoConfig.getInterceptors().remove(interceptor);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CentralAttributesPreservationInterceptor extends ServerOperationInterceptorAdapter {
|
public class CentralAttributesPreservationInterceptor extends ServerOperationInterceptorAdapter {
|
||||||
|
|
|
@ -76,6 +76,12 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());
|
myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertGone(IIdType theId) {
|
private void assertGone(IIdType theId) {
|
||||||
try {
|
try {
|
||||||
assertNotGone(theId);
|
assertNotGone(theId);
|
||||||
|
@ -835,24 +841,12 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
IIdType id = myPatientDao.create(p, mySrd).getId();
|
IIdType id = myPatientDao.create(p, mySrd).getId();
|
||||||
ourLog.info("Created patient, got it: {}", id);
|
ourLog.info("Created patient, got it: {}", id);
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
p.addIdentifier().setSystem("urn:system").setValue(methodName);
|
||||||
p.addName().setFamily("Hello");
|
p.addName().setFamily("Hello");
|
||||||
results = myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
results = myPatientDao.create(p, "Patient?identifier=urn%3Asystem%7C" + methodName, mySrd);
|
||||||
assertEquals(id.getIdPart(), results.getId().getIdPart());
|
assertEquals(id.getIdPart(), results.getId().getIdPart());
|
||||||
assertFalse(results.getCreated().booleanValue());
|
assertFalse(results.getCreated());
|
||||||
|
|
||||||
verifyNoMoreInteractions(myInterceptor);
|
|
||||||
|
|
||||||
// Now create a second one
|
// Now create a second one
|
||||||
|
|
||||||
|
@ -1691,7 +1685,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
middleDate = new Date();
|
middleDate = new Date();
|
||||||
Thread.sleep(fullSize);
|
Thread.sleep(fullSize);
|
||||||
}
|
}
|
||||||
patient.setId(id);
|
patient.setId(id.getValue());
|
||||||
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
||||||
myPatientDao.update(patient, mySrd);
|
myPatientDao.update(patient, mySrd);
|
||||||
}
|
}
|
||||||
|
@ -1921,7 +1915,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
preDates.add(new Date());
|
preDates.add(new Date());
|
||||||
Thread.sleep(100);
|
Thread.sleep(100);
|
||||||
patient.setId(id);
|
patient.setId(id.getValue());
|
||||||
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
||||||
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());
|
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());
|
||||||
}
|
}
|
||||||
|
@ -2509,17 +2503,9 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
* READ
|
* READ
|
||||||
*/
|
*/
|
||||||
|
|
||||||
reset(myInterceptor);
|
|
||||||
Observation obs = myObservationDao.read(id1.toUnqualifiedVersionless(), mySrd);
|
Observation obs = myObservationDao.read(id1.toUnqualifiedVersionless(), mySrd);
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualifiedVersionless().getValue(), details.getId().toUnqualifiedVersionless().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* VREAD
|
* VREAD
|
||||||
*/
|
*/
|
||||||
|
@ -2528,13 +2514,6 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
obs = myObservationDao.read(id1, mySrd);
|
obs = myObservationDao.read(id1, mySrd);
|
||||||
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
assertEquals(o1.getCode().getCoding().get(0).getCode(), obs.getCode().getCoding().get(0).getCode());
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(id1.toUnqualified().getValue(), details.getId().toUnqualified().getValue());
|
|
||||||
assertEquals("Observation", details.getResourceType());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -2611,7 +2590,7 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
assertGone(id);
|
assertGone(id);
|
||||||
|
|
||||||
patient.setId(id);
|
patient.setId(id.getValue());
|
||||||
patient.addAddress().addLine("AAA");
|
patient.addAddress().addLine("AAA");
|
||||||
myPatientDao.update(patient, mySrd);
|
myPatientDao.update(patient, mySrd);
|
||||||
|
|
||||||
|
|
|
@ -662,8 +662,9 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
||||||
assertEquals(3, uniqueSearchParams.get(0).getComponents().size());
|
assertEquals(3, uniqueSearchParams.get(0).getComponents().size());
|
||||||
|
|
||||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||||
myResourceReindexingSvc.forceReindexingPass();
|
assertEquals(6, myResourceReindexingSvc.forceReindexingPass());
|
||||||
myResourceReindexingSvc.forceReindexingPass();
|
assertEquals(1, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
assertEquals(0, myResourceReindexingSvc.forceReindexingPass());
|
||||||
|
|
||||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||||
assertEquals(uniques.toString(), 1, uniques.size());
|
assertEquals(uniques.toString(), 1, uniques.size());
|
||||||
|
|
|
@ -18,10 +18,7 @@ import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetai
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.junit.After;
|
import org.junit.*;
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
import org.mockito.ArgumentCaptor;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
import org.springframework.test.context.TestPropertySource;
|
||||||
|
|
||||||
|
@ -45,6 +42,11 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void before() {
|
||||||
|
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateAndUpdateWithoutRequest() {
|
public void testCreateAndUpdateWithoutRequest() {
|
||||||
String methodName = "testUpdateByUrl";
|
String methodName = "testUpdateByUrl";
|
||||||
|
@ -96,7 +98,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
return myPatientDao.create(p).getId().toUnqualified();
|
return myPatientDao.create(p).getId().toUnqualified();
|
||||||
});
|
});
|
||||||
|
|
||||||
String createTime = runInTransaction(()->{
|
String createTime = runInTransaction(() -> {
|
||||||
List<ResourceTable> allResources = myResourceTableDao.findAll();
|
List<ResourceTable> allResources = myResourceTableDao.findAll();
|
||||||
assertEquals(1, allResources.size());
|
assertEquals(1, allResources.size());
|
||||||
ResourceTable resourceTable = allResources.get(0);
|
ResourceTable resourceTable = allResources.get(0);
|
||||||
|
@ -110,7 +112,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
});
|
});
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.setId(id.getIdPart());
|
p.setId(id.getIdPart());
|
||||||
p.addIdentifier().setSystem("urn:system").setValue("2");
|
p.addIdentifier().setSystem("urn:system").setValue("2");
|
||||||
|
@ -124,7 +126,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
assertThat(myCaptureQueriesListener.getInsertQueriesForCurrentThread(), empty());
|
assertThat(myCaptureQueriesListener.getInsertQueriesForCurrentThread(), empty());
|
||||||
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
|
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
|
||||||
|
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
List<ResourceTable> allResources = myResourceTableDao.findAll();
|
List<ResourceTable> allResources = myResourceTableDao.findAll();
|
||||||
assertEquals(1, allResources.size());
|
assertEquals(1, allResources.size());
|
||||||
ResourceTable resourceTable = allResources.get(0);
|
ResourceTable resourceTable = allResources.get(0);
|
||||||
|
@ -203,7 +205,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
{
|
{
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.setId(id);
|
patient.setId(id.getValue());
|
||||||
patient.setActive(true);
|
patient.setActive(true);
|
||||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val1");
|
||||||
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
patient.getMeta().addTag().setSystem("http://foo").setCode("bar").setDisplay("Val2");
|
||||||
|
@ -384,14 +386,6 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
|
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
|
||||||
assertEquals("2", outcome2.getId().getVersionIdPart());
|
assertEquals("2", outcome2.getId().getVersionIdPart());
|
||||||
|
|
||||||
// Verify interceptor
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.UPDATE), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertNotNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
TestUtil.sleepOneClick();
|
TestUtil.sleepOneClick();
|
||||||
Date now2 = new Date();
|
Date now2 = new Date();
|
||||||
|
|
||||||
|
@ -627,7 +621,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
Patient p1 = new Patient();
|
Patient p1 = new Patient();
|
||||||
p1.setId(p1id);
|
p1.setId(p1id.getValue());
|
||||||
p1.addName().setFamily(methodName);
|
p1.addName().setFamily(methodName);
|
||||||
|
|
||||||
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
|
p1.getMeta().addTag("tag_scheme2", "tag_term2", null);
|
||||||
|
@ -645,7 +639,7 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
||||||
}
|
}
|
||||||
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
|
assertThat(secListValues, containsInAnyOrder("tag_scheme1|tag_term1", "tag_scheme2|tag_term2"));
|
||||||
List<Coding> secList = p1.getMeta().getSecurity();
|
List<Coding> secList = p1.getMeta().getSecurity();
|
||||||
secListValues = new HashSet<String>();
|
secListValues = new HashSet<>();
|
||||||
for (Coding next : secList) {
|
for (Coding next : secList) {
|
||||||
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,6 +58,7 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void beforeDisableResultReuse() {
|
public void beforeDisableResultReuse() {
|
||||||
|
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -590,13 +591,13 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
final IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
final IIdType id = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.setId(id);
|
p.setId(id.getValue());
|
||||||
p.addName().setFamily("family1");
|
p.addName().setFamily("family1");
|
||||||
p.addName().setFamily("family2");
|
p.addName().setFamily("family2");
|
||||||
myPatientDao.update(p);
|
myPatientDao.update(p);
|
||||||
|
|
||||||
p = new Patient();
|
p = new Patient();
|
||||||
p.setId(id);
|
p.setId(id.getValue());
|
||||||
p.addName().setFamily("family1");
|
p.addName().setFamily("family1");
|
||||||
p.addName().setFamily("family2");
|
p.addName().setFamily("family2");
|
||||||
p.addName().setFamily("family3");
|
p.addName().setFamily("family3");
|
||||||
|
@ -1308,22 +1309,6 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
String patientId = respEntry.getResponse().getLocation();
|
String patientId = respEntry.getResponse().getLocation();
|
||||||
assertThat(patientId, not(containsString("test")));
|
assertThat(patientId, not(containsString("test")));
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.CREATE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertNull(details.getId());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
assertEquals(Patient.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -2374,33 +2359,6 @@ public class FhirSystemDaoR4Test extends BaseJpaR4SystemTest {
|
||||||
Bundle respBundle = (Bundle) nextEntry.getResource();
|
Bundle respBundle = (Bundle) nextEntry.getResource();
|
||||||
assertEquals(1, respBundle.getTotal());
|
assertEquals(1, respBundle.getTotal());
|
||||||
|
|
||||||
/*
|
|
||||||
* Interceptor should have been called once for the transaction, and once for the embedded operation
|
|
||||||
*/
|
|
||||||
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.TRANSACTION), detailsCapt.capture());
|
|
||||||
ActionRequestDetails details = detailsCapt.getValue();
|
|
||||||
assertEquals("Bundle", details.getResourceType());
|
|
||||||
assertEquals(Bundle.class, details.getResource().getClass());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.READ), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualifiedVersionless().getValue(), details.getId().getValue());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.VREAD), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals(idv1.toUnqualified().getValue(), details.getId().getValue());
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
verify(myInterceptor, times(1)).incomingRequestPreHandled(eq(RestOperationTypeEnum.SEARCH_TYPE), detailsCapt.capture());
|
|
||||||
details = detailsCapt.getValue();
|
|
||||||
assertEquals("Patient", details.getResourceType());
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -72,7 +72,7 @@ public abstract class BaseResourceProviderDstu2Test extends BaseJpaDstu2Test {
|
||||||
|
|
||||||
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
||||||
|
|
||||||
ourRestServer.setResourceProviders((List)myResourceProviders);
|
ourRestServer.registerProviders(myResourceProviders.createProviders());
|
||||||
|
|
||||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||||
|
|
||||||
|
|
|
@ -1,192 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.provider;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.provider.r4.ResourceProviderInterceptorR4Test;
|
|
||||||
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;
|
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
|
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.api.server.ResponseDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.entity.ContentType;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public class ResourceProviderInterceptorDstu2Test extends BaseResourceProviderDstu2Test {
|
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderInterceptorDstu2Test.class);
|
|
||||||
private IServerInterceptor myDaoInterceptor;
|
|
||||||
|
|
||||||
private IServerInterceptor myServerInterceptor;
|
|
||||||
private IServerOperationInterceptor myJpaServerInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@After
|
|
||||||
public void after() throws Exception {
|
|
||||||
super.after();
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().remove(myDaoInterceptor);
|
|
||||||
ourRestServer.unregisterInterceptor(myServerInterceptor);
|
|
||||||
ourRestServer.unregisterInterceptor(myJpaServerInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void before() throws Exception {
|
|
||||||
super.before();
|
|
||||||
|
|
||||||
myServerInterceptor = mock(IServerInterceptor.class);
|
|
||||||
myDaoInterceptor = mock(IServerInterceptor.class);
|
|
||||||
myJpaServerInterceptor = mock(IServerOperationInterceptor.class);
|
|
||||||
|
|
||||||
when(myServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
|
|
||||||
when(myJpaServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myJpaServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myJpaServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myJpaServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
|
||||||
when(myJpaServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myJpaServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().add(myDaoInterceptor);
|
|
||||||
ourRestServer.registerInterceptor(myServerInterceptor);
|
|
||||||
ourRestServer.registerInterceptor(myJpaServerInterceptor);
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new InterceptorAdapter() {
|
|
||||||
@Override
|
|
||||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
|
|
||||||
super.incomingRequestPreHandled(theOperation, theProcessedRequest);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateResource() throws IOException {
|
|
||||||
String methodName = "testCreateResource";
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().addFamily(methodName);
|
|
||||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
|
|
||||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info("Response was: {}", resp);
|
|
||||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
|
||||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
|
||||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
|
||||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getValue().getResource());
|
|
||||||
|
|
||||||
ResourceProviderInterceptorR4Test.verifyDaoInterceptor(myDaoInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateResourceInTransaction() throws IOException {
|
|
||||||
String methodName = "testCreateResourceInTransaction";
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().addFamily(methodName);
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.setType(BundleTypeEnum.TRANSACTION);
|
|
||||||
Entry entry = bundle.addEntry();
|
|
||||||
entry.setFullUrl("Patient");
|
|
||||||
entry.setResource(pt);
|
|
||||||
entry.getRequest().setMethod(HTTPVerbEnum.POST);
|
|
||||||
entry.getRequest().setUrl("Patient");
|
|
||||||
|
|
||||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(bundle);
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
try (CloseableHttpResponse response = ourHttpClient.execute(post)) {
|
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Server Interceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myServerInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals("Had types: " + opTypeCaptor.getAllValues() + " and requests: " + ardCaptor.getAllValues(), RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
assertNull(ardCaptor.getAllValues().get(0).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
|
||||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
ArgumentCaptor<HttpServletRequest> srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
|
||||||
ArgumentCaptor<HttpServletResponse> sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
|
||||||
|
|
||||||
verify(myJpaServerInterceptor, times(1)).resourceCreated(ArgumentCaptor.forClass(RequestDetails.class).capture(), ArgumentCaptor.forClass(IBaseResource.class).capture());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DAO Interceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, atLeast(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals("Had types: " + opTypeCaptor.getAllValues() + " and requests: " + ardCaptor.getAllValues(), RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
assertEquals("Bundle", ardCaptor.getAllValues().get(0).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
|
||||||
assertEquals("Had types: " + opTypeCaptor.getAllValues() + " and requests: " + ardCaptor.getAllValues(), RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
|
||||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
|
||||||
|
|
||||||
rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
|
||||||
sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -13,6 +13,7 @@ import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
|
||||||
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
import org.eclipse.jetty.websocket.api.annotations.WebSocket;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -21,19 +22,24 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.in;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
|
public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionsDstu2Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionsDstu2Test.class);
|
||||||
|
private SubscriptionsRequireManualActivationInterceptorDstu2 myInterceptor;
|
||||||
|
|
||||||
@Override
|
@Before
|
||||||
public void beforeCreateInterceptor() {
|
public void beforeCreateInterceptor() {
|
||||||
super.beforeCreateInterceptor();
|
myInterceptor = new SubscriptionsRequireManualActivationInterceptorDstu2();
|
||||||
|
myInterceptor.setDao(mySubscriptionDao);
|
||||||
|
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
SubscriptionsRequireManualActivationInterceptorDstu2 interceptor = new SubscriptionsRequireManualActivationInterceptorDstu2();
|
@After
|
||||||
interceptor.setDao(mySubscriptionDao);
|
public void afterDestroyInterceptor() {
|
||||||
myDaoConfig.getInterceptors().add(interceptor);
|
myInterceptorRegistry.unregisterInterceptor(myInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
|
|
@ -1,367 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.provider.dstu3;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.entity.ContentType;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Observation;
|
|
||||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
|
||||||
import org.hl7.fhir.dstu3.model.Practitioner;
|
|
||||||
import org.hl7.fhir.dstu3.model.Reference;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
public class AuthorizationInterceptorResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void before() throws Exception {
|
|
||||||
super.before();
|
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
|
||||||
unregisterInterceptors();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #778
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testReadingObservationAccessRight() {
|
|
||||||
Practitioner practitioner1 = new Practitioner();
|
|
||||||
final IIdType practitionerId1 = ourClient.create().resource(practitioner1).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Practitioner practitioner2 = new Practitioner();
|
|
||||||
final IIdType practitionerId2 = ourClient.create().resource(practitioner2).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.setActive(true);
|
|
||||||
final IIdType patientId = ourClient.create().resource(patient).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
// allow write all Observation resource
|
|
||||||
// allow read only Observation resource in which it has a practitioner1 or practitioner2 compartment
|
|
||||||
return new RuleBuilder().allow()
|
|
||||||
.write()
|
|
||||||
.resourcesOfType(Observation.class)
|
|
||||||
.withAnyId()
|
|
||||||
.andThen()
|
|
||||||
.allow()
|
|
||||||
.read()
|
|
||||||
.resourcesOfType(Observation.class)
|
|
||||||
.inCompartment("Practitioner", Arrays.asList(practitionerId1, practitionerId2))
|
|
||||||
.andThen()
|
|
||||||
.denyAll()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Observation obs1 = new Observation();
|
|
||||||
obs1.setStatus(ObservationStatus.FINAL);
|
|
||||||
obs1.setPerformer(
|
|
||||||
Arrays.asList(new Reference(practitionerId1), new Reference(practitionerId2)));
|
|
||||||
IIdType oid1 = ourClient.create().resource(obs1).execute().getId().toUnqualified();
|
|
||||||
|
|
||||||
// Observation with practitioner1 and practitioner1 as the Performer -> should have the read access
|
|
||||||
ourClient.read().resource(Observation.class).withId(oid1).execute();
|
|
||||||
|
|
||||||
Observation obs2 = new Observation();
|
|
||||||
obs2.setStatus(ObservationStatus.FINAL);
|
|
||||||
obs2.setSubject(new Reference(patientId));
|
|
||||||
IIdType oid2 = ourClient.create().resource(obs2).execute().getId().toUnqualified();
|
|
||||||
|
|
||||||
// Observation with patient as the subject -> read access should be blocked
|
|
||||||
try {
|
|
||||||
ourClient.read().resource(Observation.class).withId(oid2).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
// good
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #667
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testBlockUpdatingPatientUserDoesnNotHaveAccessTo() {
|
|
||||||
Patient pt1 = new Patient();
|
|
||||||
pt1.setActive(true);
|
|
||||||
final IIdType pid1 = ourClient.create().resource(pt1).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Patient pt2 = new Patient();
|
|
||||||
pt2.setActive(false);
|
|
||||||
final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow().write().allResources().inCompartment("Patient", pid1).andThen()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Observation obs = new Observation();
|
|
||||||
obs.setStatus(ObservationStatus.FINAL);
|
|
||||||
obs.setSubject(new Reference(pid1));
|
|
||||||
IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
|
|
||||||
|
|
||||||
|
|
||||||
unregisterInterceptors();
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow().write().allResources().inCompartment("Patient", pid2).andThen()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to update to a new patient. The user has access to write to things in
|
|
||||||
* pid2's compartment, so this would normally be ok, but in this case they are overwriting
|
|
||||||
* a resource that is already in pid1's compartment, which shouldn't be allowed.
|
|
||||||
*/
|
|
||||||
obs = new Observation();
|
|
||||||
obs.setId(oid);
|
|
||||||
obs.setStatus(ObservationStatus.FINAL);
|
|
||||||
obs.setSubject(new Reference(pid2));
|
|
||||||
|
|
||||||
try {
|
|
||||||
ourClient.update().resource(obs).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
// good
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateConditional() {
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
final MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
|
|
||||||
.allow().updateConditional().allResources()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
patient = new Patient();
|
|
||||||
patient.setId(output1.getId().toUnqualifiedVersionless());
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
MethodOutcome output2 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
|
||||||
|
|
||||||
assertEquals(output1.getId().getIdPart(), output2.getId().getIdPart());
|
|
||||||
|
|
||||||
patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
try {
|
|
||||||
ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|101").execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
patient = new Patient();
|
|
||||||
patient.setId("999");
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
try {
|
|
||||||
ourClient.update().resource(patient).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #503 #751
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteIsAllowedForCompartment() {
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
final IIdType id = ourClient.create().resource(patient).execute().getId();
|
|
||||||
|
|
||||||
Observation obsInCompartment = new Observation();
|
|
||||||
obsInCompartment.setStatus(ObservationStatus.FINAL);
|
|
||||||
obsInCompartment.getSubject().setReferenceElement(id.toUnqualifiedVersionless());
|
|
||||||
IIdType obsInCompartmentId = ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
// create a 2nd observation to be deleted by url Observation?patient=id
|
|
||||||
ourClient.create().resource(obsInCompartment).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
Observation obsNotInCompartment = new Observation();
|
|
||||||
obsNotInCompartment.setStatus(ObservationStatus.FINAL);
|
|
||||||
IIdType obsNotInCompartmentId = ourClient.create().resource(obsNotInCompartment).execute().getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow().delete().resourcesOfType(Observation.class).inCompartment("Patient", id).andThen()
|
|
||||||
.deny().delete().allResources().withAnyId().andThen()
|
|
||||||
.allowAll()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
ourClient.delete().resourceById(obsInCompartmentId.toUnqualifiedVersionless()).execute();
|
|
||||||
ourClient.delete().resourceConditionalByUrl("Observation?patient=" + id.toUnqualifiedVersionless()).execute();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ourClient.delete().resourceById(obsNotInCompartmentId.toUnqualifiedVersionless()).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
// good
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #503
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testDeleteIsBlocked() {
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
return new RuleBuilder()
|
|
||||||
.deny().delete().allResources().withAnyId().andThen()
|
|
||||||
.allowAll()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
|
||||||
IIdType id = ourClient.create().resource(patient).execute().getId();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ourClient.delete().resourceById(id.toUnqualifiedVersionless()).execute();
|
|
||||||
fail();
|
|
||||||
} catch (ForbiddenOperationException e) {
|
|
||||||
// good
|
|
||||||
}
|
|
||||||
|
|
||||||
patient = ourClient.read().resource(Patient.class).withId(id.toUnqualifiedVersionless()).execute();
|
|
||||||
assertEquals(id.getValue(), patient.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testDeleteResourceConditional() throws IOException {
|
|
||||||
String methodName = "testDeleteResourceConditional";
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().setFamily(methodName);
|
|
||||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
|
||||||
final IdType id;
|
|
||||||
try {
|
|
||||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
|
||||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
|
||||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
|
||||||
id = new IdType(newIdString);
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
pt = new Patient();
|
|
||||||
pt.addName().setFamily("FOOFOOFOO");
|
|
||||||
resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
|
||||||
|
|
||||||
post = new HttpPost(ourServerBase + "/Patient");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
response = ourHttpClient.execute(post);
|
|
||||||
final IdType id2;
|
|
||||||
try {
|
|
||||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
|
||||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
|
||||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
|
||||||
id2 = new IdType(newIdString);
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
|
||||||
//@formatter:off
|
|
||||||
return new RuleBuilder()
|
|
||||||
.allow("Rule 2").delete().allResources().inCompartment("Patient", new IdDt("Patient/" + id.getIdPart())).andThen()
|
|
||||||
.build();
|
|
||||||
//@formatter:on
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
HttpDelete delete = new HttpDelete(ourServerBase + "/Patient?name=" + methodName);
|
|
||||||
response = ourHttpClient.execute(delete);
|
|
||||||
try {
|
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
delete = new HttpDelete(ourServerBase + "/Patient?name=FOOFOOFOO");
|
|
||||||
response = ourHttpClient.execute(delete);
|
|
||||||
try {
|
|
||||||
assertEquals(403, response.getStatusLine().getStatusCode());
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void unregisterInterceptors() {
|
|
||||||
for (IServerInterceptor next : new ArrayList<IServerInterceptor>(ourRestServer.getInterceptors())) {
|
|
||||||
if (next instanceof AuthorizationInterceptor) {
|
|
||||||
ourRestServer.unregisterInterceptor(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -71,8 +71,8 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
||||||
@After
|
@After
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||||
myDaoConfig.getInterceptors().clear();
|
|
||||||
myResourceCountsCache.clear();
|
myResourceCountsCache.clear();
|
||||||
|
ourRestServer.getInterceptorService().unregisterAllInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
|
@ -90,7 +90,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
||||||
|
|
||||||
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
||||||
|
|
||||||
ourRestServer.setResourceProviders((List) myResourceProviders);
|
ourRestServer.registerProviders(myResourceProviders.createProviders());
|
||||||
|
|
||||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||||
|
|
||||||
|
|
|
@ -1,258 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.provider.dstu3;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.provider.r4.ResourceProviderInterceptorR4Test;
|
|
||||||
import ca.uhn.fhir.parser.IParser;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.api.server.ResponseDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
|
||||||
import org.apache.http.client.methods.HttpPost;
|
|
||||||
import org.apache.http.entity.ContentType;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleType;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.dstu3.model.Organization;
|
|
||||||
import org.hl7.fhir.dstu3.model.Patient;
|
|
||||||
import org.hl7.fhir.dstu3.model.Reference;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.mockito.ArgumentCaptor;
|
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
|
|
||||||
import javax.servlet.ServletException;
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.*;
|
|
||||||
|
|
||||||
@TestPropertySource(properties = {
|
|
||||||
"scheduling_disabled=true"
|
|
||||||
})
|
|
||||||
public class ResourceProviderInterceptorDstu3Test extends BaseResourceProviderDstu3Test {
|
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderInterceptorDstu3Test.class);
|
|
||||||
|
|
||||||
private IServerInterceptor myDaoInterceptor;
|
|
||||||
private IServerInterceptor myServerInterceptor;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@After
|
|
||||||
public void after() throws Exception {
|
|
||||||
super.after();
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().remove(myDaoInterceptor);
|
|
||||||
ourRestServer.unregisterInterceptor(myServerInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void before() throws Exception {
|
|
||||||
super.before();
|
|
||||||
|
|
||||||
myServerInterceptor = mock(IServerInterceptor.class, withSettings().verboseLogging());
|
|
||||||
myDaoInterceptor = mock(IServerInterceptor.class, withSettings().verboseLogging());
|
|
||||||
|
|
||||||
resetServerInterceptor();
|
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().add(myDaoInterceptor);
|
|
||||||
ourRestServer.registerInterceptor(myServerInterceptor);
|
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new InterceptorAdapter() {
|
|
||||||
@Override
|
|
||||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
|
|
||||||
super.incomingRequestPreHandled(theOperation, theProcessedRequest);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private void resetServerInterceptor() throws ServletException, IOException {
|
|
||||||
reset(myServerInterceptor);
|
|
||||||
reset(myDaoInterceptor);
|
|
||||||
when(myServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateResource() throws IOException, ServletException {
|
|
||||||
String methodName = "testCreateResource";
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().setFamily(methodName);
|
|
||||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(pt);
|
|
||||||
|
|
||||||
resetServerInterceptor();
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
|
||||||
try {
|
|
||||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info("Response was: {}", resp);
|
|
||||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
|
||||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
|
||||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
|
||||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getValue().getResource());
|
|
||||||
|
|
||||||
ResourceProviderInterceptorR4Test.verifyDaoInterceptor(myDaoInterceptor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateResourceInTransaction() throws IOException, ServletException {
|
|
||||||
String methodName = "testCreateResourceInTransaction";
|
|
||||||
|
|
||||||
ourLog.info("** Starting {}", methodName);
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().setFamily(methodName);
|
|
||||||
|
|
||||||
Bundle bundle = new Bundle();
|
|
||||||
bundle.setType(BundleType.TRANSACTION);
|
|
||||||
BundleEntryComponent entry = bundle.addEntry();
|
|
||||||
entry.setFullUrl("Patient");
|
|
||||||
entry.setResource(pt);
|
|
||||||
entry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
entry.getRequest().setUrl("Patient");
|
|
||||||
|
|
||||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(bundle);
|
|
||||||
|
|
||||||
resetServerInterceptor();
|
|
||||||
|
|
||||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
verify(myServerInterceptor, times(0)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
|
||||||
try {
|
|
||||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Server Interceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myServerInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
assertEquals(null, ardCaptor.getAllValues().get(0).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
|
||||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
|
||||||
|
|
||||||
ArgumentCaptor<RequestDetails> rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
ArgumentCaptor<HttpServletRequest> srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
|
||||||
ArgumentCaptor<HttpServletResponse> sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
|
||||||
|
|
||||||
/*
|
|
||||||
* DAO Interceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
assertEquals("Bundle", ardCaptor.getAllValues().get(0).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(0).getResource());
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getAllValues().get(1));
|
|
||||||
assertEquals("Patient", ardCaptor.getAllValues().get(1).getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getAllValues().get(1).getResource());
|
|
||||||
|
|
||||||
rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
|
||||||
sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testCreateResourceWithVersionedReference() throws IOException, ServletException {
|
|
||||||
String methodName = "testCreateResourceWithVersionedReference";
|
|
||||||
|
|
||||||
Organization org = new Organization();
|
|
||||||
org.setName("orgName");
|
|
||||||
IIdType orgId = ourClient.create().resource(org).execute().getId().toUnqualified();
|
|
||||||
assertNotNull(orgId.getVersionIdPartAsLong());
|
|
||||||
|
|
||||||
resetServerInterceptor();
|
|
||||||
|
|
||||||
Patient pt = new Patient();
|
|
||||||
pt.addName().setFamily(methodName);
|
|
||||||
pt.setManagingOrganization(new Reference(orgId));
|
|
||||||
|
|
||||||
IParser parser = myFhirCtx.newXmlParser();
|
|
||||||
parser.setDontStripVersionsFromReferencesAtPaths("Patient.managingOrganization");
|
|
||||||
parser.setPrettyPrint(true);
|
|
||||||
String resource = parser.encodeResourceToString(pt);
|
|
||||||
|
|
||||||
ourLog.info(resource);
|
|
||||||
|
|
||||||
HttpPost post = new HttpPost(ourServerBase + "/Patient");
|
|
||||||
post.setEntity(new StringEntity(resource, ContentType.create(Constants.CT_FHIR_XML, "UTF-8")));
|
|
||||||
CloseableHttpResponse response = ourHttpClient.execute(post);
|
|
||||||
try {
|
|
||||||
String resp = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
|
||||||
ourLog.info("Response was: {}", resp);
|
|
||||||
assertEquals(201, response.getStatusLine().getStatusCode());
|
|
||||||
String newIdString = response.getFirstHeader(Constants.HEADER_LOCATION_LC).getValue();
|
|
||||||
assertThat(newIdString, startsWith(ourServerBase + "/Patient/"));
|
|
||||||
} finally {
|
|
||||||
response.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
ArgumentCaptor<ActionRequestDetails> ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
ArgumentCaptor<RestOperationTypeEnum> opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
|
|
||||||
assertEquals(RestOperationTypeEnum.CREATE, opTypeCaptor.getValue());
|
|
||||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
|
||||||
assertNotNull(ardCaptor.getValue().getResource());
|
|
||||||
|
|
||||||
Patient patient;
|
|
||||||
patient = (Patient) ardCaptor.getAllValues().get(0).getResource();
|
|
||||||
assertEquals(orgId.getValue(), patient.getManagingOrganization().getReference());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -49,9 +49,9 @@ public class ResourceProviderQuestionnaireResponseDstu3Test extends BaseResource
|
||||||
for (IValidatorModule next : validators) {
|
for (IValidatorModule next : validators) {
|
||||||
ourValidatingInterceptor.addValidatorModule(next);
|
ourValidatingInterceptor.addValidatorModule(next);
|
||||||
}
|
}
|
||||||
ourRestServer.registerInterceptor(ourValidatingInterceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourRestServer.registerInterceptor(ourValidatingInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -26,14 +27,18 @@ import static org.junit.Assert.*;
|
||||||
public class SubscriptionsDstu3Test extends BaseResourceProviderDstu3Test {
|
public class SubscriptionsDstu3Test extends BaseResourceProviderDstu3Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionsDstu3Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SubscriptionsDstu3Test.class);
|
||||||
|
private SubscriptionsRequireManualActivationInterceptorDstu3 myInterceptor;
|
||||||
|
|
||||||
@Override
|
@Before
|
||||||
public void beforeCreateInterceptor() {
|
public void beforeCreateInterceptor() {
|
||||||
super.beforeCreateInterceptor();
|
myInterceptor = new SubscriptionsRequireManualActivationInterceptorDstu3();
|
||||||
|
myInterceptor.setDao(mySubscriptionDao);
|
||||||
|
myInterceptorRegistry.registerInterceptor(myInterceptor);
|
||||||
|
}
|
||||||
|
|
||||||
SubscriptionsRequireManualActivationInterceptorDstu3 interceptor = new SubscriptionsRequireManualActivationInterceptorDstu3();
|
@After
|
||||||
interceptor.setDao(mySubscriptionDao);
|
public void afterDestroyInterceptor() {
|
||||||
myDaoConfig.getInterceptors().add(interceptor);
|
myInterceptorRegistry.unregisterInterceptor(myInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
|
|
|
@ -8,7 +8,6 @@ import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
||||||
|
@ -26,11 +25,9 @@ import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.in;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
@ -40,7 +37,6 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
super.before();
|
super.before();
|
||||||
myDaoConfig.setAllowMultipleDelete(true);
|
myDaoConfig.setAllowMultipleDelete(true);
|
||||||
unregisterInterceptors();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -56,23 +52,23 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
pt2.setActive(false);
|
pt2.setActive(false);
|
||||||
final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
|
final IIdType pid2 = ourClient.create().resource(pt2).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
AuthorizationInterceptor authInterceptor = new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow().write().allResources().inCompartment("Patient", pid1).andThen()
|
.allow().write().allResources().inCompartment("Patient", pid1).andThen()
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
});
|
};
|
||||||
|
ourRestServer.getInterceptorService().registerInterceptor(authInterceptor);
|
||||||
|
|
||||||
Observation obs = new Observation();
|
Observation obs = new Observation();
|
||||||
obs.setStatus(ObservationStatus.FINAL);
|
obs.setStatus(ObservationStatus.FINAL);
|
||||||
obs.setSubject(new Reference(pid1));
|
obs.setSubject(new Reference(pid1));
|
||||||
IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
|
IIdType oid = ourClient.create().resource(obs).execute().getId().toUnqualified();
|
||||||
|
|
||||||
|
ourRestServer.getInterceptorService().unregisterInterceptor(authInterceptor);
|
||||||
unregisterInterceptors();
|
ourRestServer.getInterceptorService().registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
|
@ -108,15 +104,13 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||||
final MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
final MethodOutcome output1 = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute();
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
ourRestServer.getInterceptorService().registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
@Override
|
@Override
|
||||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
//@formatter:off
|
|
||||||
return new RuleBuilder()
|
return new RuleBuilder()
|
||||||
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdDt("Patient/" + output1.getId().getIdPart())).andThen()
|
.allow("Rule 2").write().allResources().inCompartment("Patient", new IdType("Patient/" + output1.getId().getIdPart())).andThen()
|
||||||
.allow().updateConditional().allResources()
|
.allow().updateConditional().allResources()
|
||||||
.build();
|
.build();
|
||||||
//@formatter:on
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -673,14 +667,6 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void unregisterInterceptors() {
|
|
||||||
for (IServerInterceptor next : new ArrayList<>(ourRestServer.getInterceptors())) {
|
|
||||||
if (next instanceof AuthorizationInterceptor) {
|
|
||||||
ourRestServer.unregisterInterceptor(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
public static void afterClassClearContext() {
|
public static void afterClassClearContext() {
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
|
|
@ -81,6 +81,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||||
@After
|
@After
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||||
|
ourRestServer.getInterceptorService().unregisterAllInterceptors();
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||||
|
@ -97,7 +98,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
||||||
|
|
||||||
ourRestServer.setResourceProviders((List) myResourceProviders);
|
ourRestServer.registerProviders(myResourceProviders.createProviders());
|
||||||
|
|
||||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IAnonymousInterceptor;
|
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
@ -58,7 +58,6 @@ public class CompositionDocumentR4Test extends BaseResourceProviderR4Test {
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
super.after();
|
super.after();
|
||||||
|
|
||||||
myInterceptorRegistry.clearAnonymousHookForUnitTest();
|
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,12 +138,12 @@ public class CompositionDocumentR4Test extends BaseResourceProviderR4Test {
|
||||||
public void testInterceptorHookIsCalledForAllContents_RESOURCE_MAY_BE_RETURNED() throws IOException {
|
public void testInterceptorHookIsCalledForAllContents_RESOURCE_MAY_BE_RETURNED() throws IOException {
|
||||||
|
|
||||||
IAnonymousInterceptor pointcut = mock(IAnonymousInterceptor.class);
|
IAnonymousInterceptor pointcut = mock(IAnonymousInterceptor.class);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.RESOURCE_MAY_BE_RETURNED, pointcut);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCE, pointcut);
|
||||||
|
|
||||||
String theUrl = ourServerBase + "/" + compId + "/$document?_format=json";
|
String theUrl = ourServerBase + "/" + compId + "/$document?_format=json";
|
||||||
fetchBundle(theUrl, EncodingEnum.JSON);
|
fetchBundle(theUrl, EncodingEnum.JSON);
|
||||||
|
|
||||||
Mockito.verify(pointcut, times(10)).invoke(eq(Pointcut.RESOURCE_MAY_BE_RETURNED), myHookParamsCaptor.capture());
|
Mockito.verify(pointcut, times(10)).invoke(eq(Pointcut.STORAGE_PREACCESS_RESOURCE), myHookParamsCaptor.capture());
|
||||||
|
|
||||||
List<String> returnedClasses = myHookParamsCaptor
|
List<String> returnedClasses = myHookParamsCaptor
|
||||||
.getAllValues()
|
.getAllValues()
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
@ -15,9 +16,17 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HookInterceptorR4Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HookInterceptorR4Test.class);
|
||||||
|
|
||||||
|
// @Override
|
||||||
|
// @After
|
||||||
|
// public void after( ) throws Exception {
|
||||||
|
// super.after();
|
||||||
|
//
|
||||||
|
// myInterceptorRegistry.unregisterAllInterceptors();
|
||||||
|
// }
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOP_PRESTORAGE_RESOURCE_CREATED_ModifyResource() {
|
public void testOP_PRESTORAGE_RESOURCE_CREATED_ModifyResource() {
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED, (thePointcut, t)->{
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, (thePointcut, t)->{
|
||||||
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
||||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||||
});
|
});
|
||||||
|
@ -36,7 +45,7 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testOP_PRECOMMIT_RESOURCE_CREATED_ModifyResource() {
|
public void testOP_PRECOMMIT_RESOURCE_CREATED_ModifyResource() {
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, (thePointcut, t)->{
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, (thePointcut, t)->{
|
||||||
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
||||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||||
});
|
});
|
||||||
|
@ -59,7 +68,7 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
IIdType id = ourClient.create().resource(p).execute().getId();
|
IIdType id = ourClient.create().resource(p).execute().getId();
|
||||||
|
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED, (thePointcut, t)->{
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, (thePointcut, t)->{
|
||||||
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
||||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||||
});
|
});
|
||||||
|
@ -83,7 +92,7 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||||
p.setActive(true);
|
p.setActive(true);
|
||||||
IIdType id = ourClient.create().resource(p).execute().getId();
|
IIdType id = ourClient.create().resource(p).execute().getId();
|
||||||
|
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, (thePointcut, t)->{
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, (thePointcut, t)->{
|
||||||
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
||||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.IAnonymousInterceptor;
|
|
||||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
@ -25,7 +26,6 @@ import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
@ -46,9 +46,7 @@ import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.in;
|
|
||||||
import static org.hamcrest.Matchers.startsWith;
|
import static org.hamcrest.Matchers.startsWith;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
@ -61,13 +59,16 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
|
|
||||||
private IServerOperationInterceptor myServerInterceptor;
|
private IServerOperationInterceptor myServerInterceptor;
|
||||||
private List<Object> myInterceptors = new ArrayList<>();
|
private List<Object> myInterceptors = new ArrayList<>();
|
||||||
|
@Mock
|
||||||
|
private IAnonymousInterceptor myHook;
|
||||||
|
@Captor
|
||||||
|
private ArgumentCaptor<HookParams> myParamsCaptor;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@After
|
@After
|
||||||
public void after() throws Exception {
|
public void after() throws Exception {
|
||||||
super.after();
|
super.after();
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().remove(myDaoInterceptor);
|
|
||||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||||
ourRestServer.unregisterInterceptor(myServerInterceptor);
|
ourRestServer.unregisterInterceptor(myServerInterceptor);
|
||||||
|
|
||||||
|
@ -84,7 +85,6 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
|
|
||||||
resetServerInterceptor();
|
resetServerInterceptor();
|
||||||
|
|
||||||
myDaoConfig.getInterceptors().add(myDaoInterceptor);
|
|
||||||
ourRestServer.registerInterceptor(myServerInterceptor);
|
ourRestServer.registerInterceptor(myServerInterceptor);
|
||||||
|
|
||||||
ourRestServer.registerInterceptor(new InterceptorAdapter() {
|
ourRestServer.registerInterceptor(new InterceptorAdapter() {
|
||||||
|
@ -102,43 +102,42 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
when(myServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
when(myServerInterceptor.handleException(any(RequestDetails.class), any(BaseServerResponseException.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
when(myServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
when(myServerInterceptor.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
when(myServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
when(myServerInterceptor.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
|
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class))).thenReturn(true);
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class))).thenReturn(true);
|
||||||
|
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(IBaseResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
when(myServerInterceptor.outgoingResponse(any(RequestDetails.class), any(ResponseDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mock
|
|
||||||
private IAnonymousInterceptor myHook;
|
|
||||||
|
|
||||||
@Captor
|
|
||||||
private ArgumentCaptor<HookParams> myParamsCaptor;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testPerfInterceptors() {
|
public void testPerfInterceptors() throws InterruptedException {
|
||||||
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(15, 100));
|
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(15, 100));
|
||||||
for (int i = 0; i < 30; i++) {
|
for (int i = 0; i < 30; i++) {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
p.addName().setFamily("FAM"+i);
|
p.addName().setFamily("FAM" + i);
|
||||||
ourLog.info("About to create patient");
|
ourLog.info("About to create patient");
|
||||||
myPatientDao.create(p);
|
myPatientDao.create(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
|
IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.PERFTRACE_SEARCH_FIRST_RESULT_LOADED, interceptor);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED, interceptor);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.PERFTRACE_SEARCH_COMPLETE, interceptor);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE, interceptor);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.PERFTRACE_SEARCH_FAILED, interceptor);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.JPA_PERFTRACE_SEARCH_FAILED, interceptor);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.PERFTRACE_SEARCH_PASS_COMPLETE, interceptor);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE, interceptor);
|
||||||
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.PERFTRACE_SEARCH_SELECT_COMPLETE, interceptor);
|
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE, interceptor);
|
||||||
myInterceptors.add(interceptor);
|
myInterceptors.add(interceptor);
|
||||||
|
|
||||||
|
myInterceptors.add(new PerformanceTracingLoggingInterceptor());
|
||||||
|
|
||||||
ourLog.info("About to perform search...");
|
ourLog.info("About to perform search...");
|
||||||
|
|
||||||
Bundle results = ourClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute();
|
Bundle results = ourClient.search().forResource(Patient.class).returnBundle(Bundle.class).execute();
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_FIRST_RESULT_LOADED), myParamsCaptor.capture());
|
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_SELECT_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(0)).invoke(eq(Pointcut.PERFTRACE_SEARCH_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_PASS_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(0)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(0)).invoke(eq(Pointcut.PERFTRACE_SEARCH_FAILED), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE), myParamsCaptor.capture());
|
||||||
|
verify(interceptor, times(0)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_FAILED), myParamsCaptor.capture());
|
||||||
|
|
||||||
SearchRuntimeDetails details = myParamsCaptor.getAllValues().get(0).get(SearchRuntimeDetails.class);
|
SearchRuntimeDetails details = myParamsCaptor.getAllValues().get(0).get(SearchRuntimeDetails.class);
|
||||||
assertEquals(SearchStatusEnum.PASSCMPLET, details.getSearchStatus());
|
assertEquals(SearchStatusEnum.PASSCMPLET, details.getSearchStatus());
|
||||||
|
@ -146,11 +145,11 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
// Load the next (and final) page
|
// Load the next (and final) page
|
||||||
reset(interceptor);
|
reset(interceptor);
|
||||||
results = ourClient.loadPage().next(results).execute();
|
results = ourClient.loadPage().next(results).execute();
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_FIRST_RESULT_LOADED), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_SELECT_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(1)).invoke(eq(Pointcut.PERFTRACE_SEARCH_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(1)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(0)).invoke(eq(Pointcut.PERFTRACE_SEARCH_PASS_COMPLETE), myParamsCaptor.capture());
|
verify(interceptor, times(0)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE), myParamsCaptor.capture());
|
||||||
verify(interceptor, times(0)).invoke(eq(Pointcut.PERFTRACE_SEARCH_FAILED), myParamsCaptor.capture());
|
verify(interceptor, times(0)).invoke(eq(Pointcut.JPA_PERFTRACE_SEARCH_FAILED), myParamsCaptor.capture());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,11 +194,6 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
* DAO Interceptor
|
* DAO Interceptor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, times(1)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||||
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||||
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||||
|
@ -234,7 +228,6 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
assertEquals("Patient", ardCaptor.getValue().getResourceType());
|
||||||
assertNotNull(ardCaptor.getValue().getResource());
|
assertNotNull(ardCaptor.getValue().getResource());
|
||||||
|
|
||||||
ResourceProviderInterceptorR4Test.verifyDaoInterceptor(myDaoInterceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -273,27 +266,6 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
ArgumentCaptor<HttpServletResponse> sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
ArgumentCaptor<HttpServletResponse> sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
||||||
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
verify(myServerInterceptor, times(1)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
||||||
|
|
||||||
/*
|
|
||||||
* DAO Interceptor
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Sometimes we get more than 2 hits of the incomingRequestPreHandled
|
|
||||||
* method. My working theory is that it's a scheduled background job,
|
|
||||||
* such as the subscription interceptor or the search parameter cache
|
|
||||||
* updating.
|
|
||||||
*/
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, atLeast(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertThat(ardCaptor.getAllValues().stream().map(ActionRequestDetails::getResourceType).collect(Collectors.toList()), Matchers.contains("Bundle", "Patient"));
|
|
||||||
assertThat(opTypeCaptor.getAllValues(), Matchers.contains(RestOperationTypeEnum.TRANSACTION, RestOperationTypeEnum.CREATE));
|
|
||||||
|
|
||||||
rdCaptor = ArgumentCaptor.forClass(RequestDetails.class);
|
|
||||||
srCaptor = ArgumentCaptor.forClass(HttpServletRequest.class);
|
|
||||||
sRespCaptor = ArgumentCaptor.forClass(HttpServletResponse.class);
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(rdCaptor.capture(), srCaptor.capture(), sRespCaptor.capture());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -413,12 +385,6 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
||||||
* DAO Interceptor
|
* DAO Interceptor
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ardCaptor = ArgumentCaptor.forClass(ActionRequestDetails.class);
|
|
||||||
opTypeCaptor = ArgumentCaptor.forClass(RestOperationTypeEnum.class);
|
|
||||||
verify(myDaoInterceptor, times(2)).incomingRequestPreHandled(opTypeCaptor.capture(), ardCaptor.capture());
|
|
||||||
assertEquals(RestOperationTypeEnum.TRANSACTION, opTypeCaptor.getAllValues().get(0));
|
|
||||||
assertEquals(RestOperationTypeEnum.UPDATE, opTypeCaptor.getAllValues().get(1));
|
|
||||||
|
|
||||||
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
verify(myDaoInterceptor, times(0)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||||
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
verify(myDaoInterceptor, times(0)).resourceCreated(any(RequestDetails.class), any(IBaseResource.class));
|
||||||
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
verify(myDaoInterceptor, times(0)).resourceUpdated(any(RequestDetails.class), any(IBaseResource.class), any(IBaseResource.class));
|
||||||
|
|
|
@ -1,85 +1,22 @@
|
||||||
package ca.uhn.fhir.jpa.provider.r4;
|
package ca.uhn.fhir.jpa.provider.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable;
|
|
||||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
|
||||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
|
||||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
|
||||||
import ca.uhn.fhir.parser.IParser;
|
|
||||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
|
||||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
|
||||||
import ca.uhn.fhir.rest.api.SummaryEnum;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
|
||||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
|
||||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
|
||||||
import ca.uhn.fhir.rest.param.*;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import org.hl7.fhir.r4.model.Practitioner;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
import org.junit.AfterClass;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import org.junit.Test;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
|
||||||
import com.google.common.base.Charsets;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.apache.http.NameValuePair;
|
|
||||||
import org.apache.http.client.entity.UrlEncodedFormEntity;
|
|
||||||
import org.apache.http.client.methods.*;
|
|
||||||
import org.apache.http.entity.ByteArrayEntity;
|
|
||||||
import org.apache.http.entity.ContentType;
|
|
||||||
import org.apache.http.entity.StringEntity;
|
|
||||||
import org.apache.http.message.BasicNameValuePair;
|
|
||||||
import org.hamcrest.Matchers;
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
|
||||||
import org.hl7.fhir.r4.model.*;
|
|
||||||
import org.hl7.fhir.r4.model.Bundle.*;
|
|
||||||
import org.hl7.fhir.r4.model.Encounter.EncounterLocationComponent;
|
|
||||||
import org.hl7.fhir.r4.model.Encounter.EncounterStatus;
|
|
||||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
|
||||||
import org.hl7.fhir.r4.model.Narrative.NarrativeStatus;
|
|
||||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
|
||||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemType;
|
|
||||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
|
||||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
|
||||||
import org.junit.*;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.util.AopTestUtils;
|
|
||||||
import org.springframework.transaction.TransactionStatus;
|
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.net.InetSocketAddress;
|
|
||||||
import java.net.Socket;
|
|
||||||
import java.net.SocketTimeoutException;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.*;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
@ContextConfiguration(classes = {ResourceProviderOnlySomeResourcesProvidedR4Test.OnlySomeResourcesProvidedCtxConfig.class})
|
@ContextConfiguration(classes = {ResourceProviderOnlySomeResourcesProvidedR4Test.OnlySomeResourcesProvidedCtxConfig.class})
|
||||||
|
@ -95,8 +32,8 @@ public class ResourceProviderOnlySomeResourcesProvidedR4Test extends BaseResourc
|
||||||
pract.setActive(true);
|
pract.setActive(true);
|
||||||
try {
|
try {
|
||||||
ourClient.create().resource(pract).execute();
|
ourClient.create().resource(pract).execute();
|
||||||
} catch (InvalidRequestException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
assertEquals("", e.getMessage());
|
assertThat(e.getMessage(), containsString("Unknown resource type 'Practitioner' - Server knows how to handle:"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,9 +49,9 @@ public class ResourceProviderQuestionnaireResponseR4Test extends BaseResourcePro
|
||||||
for (IValidatorModule next : validators) {
|
for (IValidatorModule next : validators) {
|
||||||
ourValidatingInterceptor.addValidatorModule(next);
|
ourValidatingInterceptor.addValidatorModule(next);
|
||||||
}
|
}
|
||||||
ourRestServer.registerInterceptor(ourValidatingInterceptor);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ourRestServer.getInterceptorService().registerInterceptor(ourValidatingInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue