Compare commits
9 Commits
cfdcac44c7
...
b223410940
Author | SHA1 | Date |
---|---|---|
Mangala Ekanayake | b223410940 | |
James Agnew | 061390d76b | |
Michael Buckley | 3b8569127e | |
mangala.ekanayake | a43d12e042 | |
mangala.ekanayake | 0c656f072a | |
mangala.ekanayake | 7d4a243c5e | |
mangala.ekanayake | 883281afee | |
Mangala Ekanayake | 1d0b18d989 | |
Mangala Ekanayake | 674f4637a9 |
|
@ -1293,7 +1293,15 @@ public class FhirContext {
|
|||
* @since 5.1.0
|
||||
*/
|
||||
public static FhirContext forCached(FhirVersionEnum theFhirVersionEnum) {
|
||||
return ourStaticContexts.computeIfAbsent(theFhirVersionEnum, v -> new FhirContext(v));
|
||||
return ourStaticContexts.computeIfAbsent(theFhirVersionEnum, FhirContext::forVersion);
|
||||
}
|
||||
|
||||
/**
|
||||
* An uncached version of forCached()
|
||||
* @return a new FhirContext for theFhirVersionEnum
|
||||
*/
|
||||
public static FhirContext forVersion(FhirVersionEnum theFhirVersionEnum) {
|
||||
return new FhirContext(theFhirVersionEnum);
|
||||
}
|
||||
|
||||
private static Collection<Class<? extends IBaseResource>> toCollection(
|
||||
|
|
|
@ -135,15 +135,19 @@ public enum FhirVersionEnum {
|
|||
|
||||
/**
|
||||
* Creates a new FhirContext for this FHIR version
|
||||
* @deprecated since 7.7. Use {@link FhirContext#forVersion(FhirVersionEnum)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.7")
|
||||
public FhirContext newContext() {
|
||||
return new FhirContext(this);
|
||||
return FhirContext.forVersion(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new FhirContext for this FHIR version, or returns a previously created one if one exists. This
|
||||
* method uses {@link FhirContext#forCached(FhirVersionEnum)} to return a cached instance.
|
||||
* @deprecated since 7.7. Use {@link FhirContext#forCached(FhirVersionEnum)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.7")
|
||||
public FhirContext newContextCached() {
|
||||
return FhirContext.forCached(this);
|
||||
}
|
||||
|
|
|
@ -46,7 +46,11 @@ public @interface Hook {
|
|||
* 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.
|
||||
* the order specified at the {@link Interceptor#order() interceptor type level} will be used.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that if two hook methods have the same order, then the order of execution is undefined. If
|
||||
* order is important, then an order must always be explicitly stated.
|
||||
* </p>
|
||||
*/
|
||||
int order() default Interceptor.DEFAULT_ORDER;
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
*/
|
||||
package ca.uhn.fhir.interceptor.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public interface IBaseInterceptorBroadcaster<POINTCUT extends IPointcut> {
|
||||
|
@ -73,4 +74,15 @@ public interface IBaseInterceptorBroadcaster<POINTCUT extends IPointcut> {
|
|||
* @since 4.0.0
|
||||
*/
|
||||
boolean hasHooks(POINTCUT thePointcut);
|
||||
|
||||
List<IInvoker> getInvokersForPointcut(POINTCUT thePointcut);
|
||||
|
||||
interface IInvoker extends Comparable<IInvoker> {
|
||||
|
||||
Object invoke(HookParams theParams);
|
||||
|
||||
int getOrder();
|
||||
|
||||
Object getInterceptor();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ public interface IPointcut {
|
|||
@Nonnull
|
||||
Class<?> getReturnType();
|
||||
|
||||
Class<?> getBooleanReturnTypeForEnum();
|
||||
|
||||
@Nonnull
|
||||
List<String> getParameterTypes();
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseConformance;
|
||||
|
||||
import java.io.Writer;
|
||||
|
@ -3107,6 +3108,10 @@ public enum Pointcut implements IPointcut {
|
|||
@Nonnull Class<?> theReturnType,
|
||||
@Nonnull ExceptionHandlingSpec theExceptionHandlingSpec,
|
||||
String... theParameterTypes) {
|
||||
|
||||
// This enum uses the lowercase-b boolean type to indicate boolean return pointcuts
|
||||
Validate.isTrue(!theReturnType.equals(Boolean.class), "Return type Boolean not allowed here, must be boolean");
|
||||
|
||||
myReturnType = theReturnType;
|
||||
myExceptionHandlingSpec = theExceptionHandlingSpec;
|
||||
myParameterTypes = Collections.unmodifiableList(Arrays.asList(theParameterTypes));
|
||||
|
@ -3132,6 +3137,11 @@ public enum Pointcut implements IPointcut {
|
|||
return myReturnType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getBooleanReturnTypeForEnum() {
|
||||
return boolean.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public List<String> getParameterTypes() {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package ca.uhn.fhir.interceptor.executor;
|
||||
|
||||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IBaseInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.IBaseInterceptorService;
|
||||
|
@ -57,12 +58,13 @@ import java.util.HashMap;
|
|||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & IPointcut>
|
||||
implements IBaseInterceptorService<POINTCUT>, IBaseInterceptorBroadcaster<POINTCUT> {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseInterceptorService.class);
|
||||
|
@ -74,12 +76,11 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
AttributeKey.stringKey("hapifhir.interceptor.method_name");
|
||||
|
||||
private final List<Object> myInterceptors = new ArrayList<>();
|
||||
private final ListMultimap<POINTCUT, BaseInvoker> myGlobalInvokers = ArrayListMultimap.create();
|
||||
private final ListMultimap<POINTCUT, BaseInvoker> myAnonymousInvokers = ArrayListMultimap.create();
|
||||
private final ListMultimap<POINTCUT, IInvoker> myGlobalInvokers = ArrayListMultimap.create();
|
||||
private final ListMultimap<POINTCUT, IInvoker> myAnonymousInvokers = ArrayListMultimap.create();
|
||||
private final Object myRegistryMutex = new Object();
|
||||
private final Class<POINTCUT> myPointcutType;
|
||||
private volatile EnumSet<POINTCUT> myRegisteredPointcuts;
|
||||
private String myName;
|
||||
private boolean myWarnOnInterceptorWithNoHooks = true;
|
||||
|
||||
/**
|
||||
|
@ -93,10 +94,11 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
* Constructor
|
||||
*
|
||||
* @param theName The name for this registry (useful for troubleshooting)
|
||||
* @deprecated The name parameter is not used for anything
|
||||
*/
|
||||
@Deprecated(since = "8.0.0", forRemoval = true)
|
||||
public BaseInterceptorService(Class<POINTCUT> thePointcutType, String theName) {
|
||||
super();
|
||||
myName = theName;
|
||||
myPointcutType = thePointcutType;
|
||||
rebuildRegisteredPointcutSet();
|
||||
}
|
||||
|
@ -113,13 +115,17 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
return myInterceptors;
|
||||
}
|
||||
|
||||
public void setName(String theName) {
|
||||
myName = theName;
|
||||
/**
|
||||
* @deprecated This value is not used anywhere
|
||||
*/
|
||||
@Deprecated(since = "8.0.0", forRemoval = true)
|
||||
public void setName(@SuppressWarnings("unused") String theName) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
protected void registerAnonymousInterceptor(POINTCUT thePointcut, Object theInterceptor, BaseInvoker theInvoker) {
|
||||
Validate.notNull(thePointcut);
|
||||
Validate.notNull(theInterceptor);
|
||||
Validate.notNull(thePointcut, "thePointcut must not be null");
|
||||
Validate.notNull(theInterceptor, "theInterceptor must not be null");
|
||||
synchronized (myRegistryMutex) {
|
||||
myAnonymousInvokers.put(thePointcut, theInvoker);
|
||||
if (!isInterceptorAlreadyRegistered(theInterceptor)) {
|
||||
|
@ -179,9 +185,9 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
}
|
||||
|
||||
private void unregisterInterceptorsIf(
|
||||
Predicate<Object> theShouldUnregisterFunction, ListMultimap<POINTCUT, BaseInvoker> theGlobalInvokers) {
|
||||
Predicate<Object> theShouldUnregisterFunction, ListMultimap<POINTCUT, IInvoker> theGlobalInvokers) {
|
||||
synchronized (myRegistryMutex) {
|
||||
for (Map.Entry<POINTCUT, BaseInvoker> nextInvoker : new ArrayList<>(theGlobalInvokers.entries())) {
|
||||
for (Map.Entry<POINTCUT, IInvoker> nextInvoker : new ArrayList<>(theGlobalInvokers.entries())) {
|
||||
if (theShouldUnregisterFunction.test(nextInvoker.getValue().getInterceptor())) {
|
||||
unregisterInterceptor(nextInvoker.getValue().getInterceptor());
|
||||
}
|
||||
|
@ -265,7 +271,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
assert haveAppropriateParams(thePointcut, theParams);
|
||||
assert thePointcut.getReturnType() != void.class;
|
||||
|
||||
return doCallHooks(thePointcut, theParams, null);
|
||||
return doCallHooks(thePointcut, theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -282,116 +288,47 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
assert haveAppropriateParams(thePointcut, theParams);
|
||||
assert thePointcut.getReturnType() == void.class || thePointcut.getReturnType() == getBooleanReturnType();
|
||||
|
||||
Object retValObj = doCallHooks(thePointcut, theParams, true);
|
||||
Object retValObj = doCallHooks(thePointcut, theParams);
|
||||
retValObj = defaultIfNull(retValObj, true);
|
||||
return (Boolean) retValObj;
|
||||
}
|
||||
|
||||
private Object doCallHooks(POINTCUT thePointcut, HookParams theParams, Object theRetVal) {
|
||||
// use new list for loop to avoid ConcurrentModificationException in case invoker gets added while looping
|
||||
List<BaseInvoker> invokers = new ArrayList<>(getInvokersForPointcut(thePointcut));
|
||||
|
||||
/*
|
||||
* Call each hook in order
|
||||
*/
|
||||
for (BaseInvoker nextInvoker : invokers) {
|
||||
Object nextOutcome = nextInvoker.invoke(theParams);
|
||||
Class<?> pointcutReturnType = thePointcut.getReturnType();
|
||||
if (pointcutReturnType.equals(getBooleanReturnType())) {
|
||||
Boolean nextOutcomeAsBoolean = (Boolean) nextOutcome;
|
||||
if (Boolean.FALSE.equals(nextOutcomeAsBoolean)) {
|
||||
ourLog.trace("callHooks({}) for invoker({}) returned false", thePointcut, nextInvoker);
|
||||
theRetVal = false;
|
||||
break;
|
||||
} else {
|
||||
theRetVal = true;
|
||||
}
|
||||
} else if (!pointcutReturnType.equals(void.class)) {
|
||||
if (nextOutcome != null) {
|
||||
theRetVal = nextOutcome;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return theRetVal;
|
||||
private Object doCallHooks(POINTCUT thePointcut, HookParams theParams) {
|
||||
List<IInvoker> invokers = getInvokersForPointcut(thePointcut);
|
||||
return callInvokers(thePointcut, theParams, invokers);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<Object> getInterceptorsWithInvokersForPointcut(POINTCUT thePointcut) {
|
||||
return getInvokersForPointcut(thePointcut).stream()
|
||||
.map(BaseInvoker::getInterceptor)
|
||||
.map(IInvoker::getInterceptor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered list of invokers for the given pointcut. Note that
|
||||
* a new and stable list is returned to.. do whatever you want with it.
|
||||
* Returns a list of all invokers registered for the given pointcut. The list
|
||||
* is ordered by the invoker order (specified on the {@link Interceptor#order()}
|
||||
* and {@link Hook#order()} values.
|
||||
*
|
||||
* @return The list returned by this method will always be a newly created list, so it will be stable and can be modified.
|
||||
*/
|
||||
private List<BaseInvoker> getInvokersForPointcut(POINTCUT thePointcut) {
|
||||
List<BaseInvoker> invokers;
|
||||
@Override
|
||||
public List<IInvoker> getInvokersForPointcut(POINTCUT thePointcut) {
|
||||
List<IInvoker> invokers;
|
||||
|
||||
synchronized (myRegistryMutex) {
|
||||
List<BaseInvoker> globalInvokers = myGlobalInvokers.get(thePointcut);
|
||||
List<BaseInvoker> anonymousInvokers = myAnonymousInvokers.get(thePointcut);
|
||||
List<BaseInvoker> threadLocalInvokers = null;
|
||||
invokers = union(globalInvokers, anonymousInvokers, threadLocalInvokers);
|
||||
List<IInvoker> globalInvokers = myGlobalInvokers.get(thePointcut);
|
||||
List<IInvoker> anonymousInvokers = myAnonymousInvokers.get(thePointcut);
|
||||
invokers = union(Arrays.asList(globalInvokers, anonymousInvokers));
|
||||
}
|
||||
|
||||
return invokers;
|
||||
}
|
||||
|
||||
/**
|
||||
* First argument must be the global invoker list!!
|
||||
*/
|
||||
@SafeVarargs
|
||||
private List<BaseInvoker> union(List<BaseInvoker>... theInvokersLists) {
|
||||
List<BaseInvoker> haveOne = null;
|
||||
boolean haveMultiple = false;
|
||||
for (List<BaseInvoker> nextInvokerList : theInvokersLists) {
|
||||
if (nextInvokerList == null || nextInvokerList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (haveOne == null) {
|
||||
haveOne = nextInvokerList;
|
||||
} else {
|
||||
haveMultiple = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (haveOne == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<BaseInvoker> retVal;
|
||||
|
||||
if (!haveMultiple) {
|
||||
|
||||
// The global list doesn't need to be sorted every time since it's sorted on
|
||||
// insertion each time. Doing so is a waste of cycles..
|
||||
if (haveOne == theInvokersLists[0]) {
|
||||
retVal = haveOne;
|
||||
} else {
|
||||
retVal = new ArrayList<>(haveOne);
|
||||
retVal.sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
retVal = Arrays.stream(theInvokersLists)
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.sorted()
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call this when assertions are enabled, it's expensive
|
||||
*/
|
||||
final boolean haveAppropriateParams(POINTCUT thePointcut, HookParams theParams) {
|
||||
public static boolean haveAppropriateParams(IPointcut thePointcut, HookParams theParams) {
|
||||
if (theParams.getParamsForType().values().size()
|
||||
!= thePointcut.getParameterTypes().size()) {
|
||||
throw new IllegalArgumentException(Msg.code(1909)
|
||||
|
@ -430,7 +367,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
}
|
||||
|
||||
private List<HookInvoker> scanInterceptorAndAddToInvokerMultimap(
|
||||
Object theInterceptor, ListMultimap<POINTCUT, BaseInvoker> theInvokers) {
|
||||
Object theInterceptor, ListMultimap<POINTCUT, IInvoker> theInvokers) {
|
||||
Class<?> interceptorClass = theInterceptor.getClass();
|
||||
int typeOrder = determineOrder(interceptorClass);
|
||||
|
||||
|
@ -452,7 +389,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
|
||||
// Make sure we're always sorted according to the order declared in @Order
|
||||
for (POINTCUT nextPointcut : theInvokers.keys()) {
|
||||
List<BaseInvoker> nextInvokerList = theInvokers.get(nextPointcut);
|
||||
List<IInvoker> nextInvokerList = theInvokers.get(nextPointcut);
|
||||
nextInvokerList.sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
|
@ -483,6 +420,108 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
|
||||
protected abstract Optional<HookDescriptor> scanForHook(Method nextMethod);
|
||||
|
||||
public static Object callInvokers(IPointcut thePointcut, HookParams theParams, List<IInvoker> invokers) {
|
||||
|
||||
Object retVal = null;
|
||||
|
||||
/*
|
||||
* Call each hook in order
|
||||
*/
|
||||
for (IInvoker nextInvoker : invokers) {
|
||||
Object nextOutcome = nextInvoker.invoke(theParams);
|
||||
Class<?> pointcutReturnType = thePointcut.getReturnType();
|
||||
if (pointcutReturnType.equals(thePointcut.getBooleanReturnTypeForEnum())) {
|
||||
Boolean nextOutcomeAsBoolean = (Boolean) nextOutcome;
|
||||
if (Boolean.FALSE.equals(nextOutcomeAsBoolean)) {
|
||||
ourLog.trace("callHooks({}) for invoker({}) returned false", thePointcut, nextInvoker);
|
||||
retVal = false;
|
||||
break;
|
||||
} else {
|
||||
retVal = true;
|
||||
}
|
||||
} else if (!pointcutReturnType.equals(void.class)) {
|
||||
if (nextOutcome != null) {
|
||||
retVal = nextOutcome;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* First argument must be the global invoker list!!
|
||||
*/
|
||||
public static List<IInvoker> union(List<List<IInvoker>> theInvokersLists) {
|
||||
List<IInvoker> haveOne = null;
|
||||
boolean haveMultiple = false;
|
||||
for (List<IInvoker> nextInvokerList : theInvokersLists) {
|
||||
if (nextInvokerList == null || nextInvokerList.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (haveOne == null) {
|
||||
haveOne = nextInvokerList;
|
||||
} else {
|
||||
haveMultiple = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (haveOne == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<IInvoker> retVal;
|
||||
|
||||
if (!haveMultiple) {
|
||||
|
||||
// The global list doesn't need to be sorted every time since it's sorted on
|
||||
// insertion each time. Doing so is a waste of cycles..
|
||||
if (haveOne == theInvokersLists.get(0)) {
|
||||
retVal = haveOne;
|
||||
} else {
|
||||
retVal = new ArrayList<>(haveOne);
|
||||
retVal.sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
int totalSize = 0;
|
||||
for (List<IInvoker> list : theInvokersLists) {
|
||||
totalSize += list.size();
|
||||
}
|
||||
retVal = new ArrayList<>(totalSize);
|
||||
for (List<IInvoker> list : theInvokersLists) {
|
||||
retVal.addAll(list);
|
||||
}
|
||||
retVal.sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected 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) {
|
||||
return findAnnotation(theInterceptorClass, Interceptor.class)
|
||||
.map(Interceptor::order)
|
||||
.orElse(Interceptor.DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
private static String toErrorString(List<String> theParameterTypes) {
|
||||
return theParameterTypes.stream().sorted().collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
private class HookInvoker extends BaseInvoker {
|
||||
|
||||
private final Method myMethod;
|
||||
|
@ -501,10 +540,11 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
myMethod = theHookMethod;
|
||||
|
||||
Class<?> returnType = theHookMethod.getReturnType();
|
||||
if (myPointcut.getReturnType().equals(getBooleanReturnType())) {
|
||||
if (myPointcut.getReturnType().equals(myPointcut.getBooleanReturnTypeForEnum())) {
|
||||
Validate.isTrue(
|
||||
getBooleanReturnType().equals(returnType) || void.class.equals(returnType),
|
||||
"Method does not return boolean or void: %s",
|
||||
myPointcut.getBooleanReturnTypeForEnum().equals(returnType) || void.class.equals(returnType),
|
||||
"Method does not return %s or void: %s",
|
||||
myPointcut.getBooleanReturnTypeForEnum().getSimpleName(),
|
||||
theHookMethod);
|
||||
} else if (myPointcut.getReturnType().equals(void.class)) {
|
||||
Validate.isTrue(void.class.equals(returnType), "Method does not return void: %s", theHookMethod);
|
||||
|
@ -541,7 +581,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
* @return Returns true/false if the hook method returns a boolean, returns true otherwise
|
||||
*/
|
||||
@Override
|
||||
Object invoke(HookParams theParams) {
|
||||
public Object invoke(HookParams theParams) {
|
||||
|
||||
Object[] args = new Object[myParameterTypes.length];
|
||||
for (int i = 0; i < myParameterTypes.length; i++) {
|
||||
|
@ -610,7 +650,7 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract static class BaseInvoker implements Comparable<BaseInvoker> {
|
||||
public abstract static class BaseInvoker implements IInvoker {
|
||||
|
||||
private final int myOrder;
|
||||
private final Object myInterceptor;
|
||||
|
@ -620,36 +660,19 @@ public abstract class BaseInterceptorService<POINTCUT extends Enum<POINTCUT> & I
|
|||
myOrder = theOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInterceptor() {
|
||||
return myInterceptor;
|
||||
}
|
||||
|
||||
abstract Object invoke(HookParams theParams);
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return myOrder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BaseInvoker theInvoker) {
|
||||
return myOrder - theInvoker.myOrder;
|
||||
public int compareTo(IInvoker theInvoker) {
|
||||
return myOrder - theInvoker.getOrder();
|
||||
}
|
||||
}
|
||||
|
||||
protected 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) {
|
||||
return findAnnotation(theInterceptorClass, Interceptor.class)
|
||||
.map(Interceptor::order)
|
||||
.orElse(Interceptor.DEFAULT_ORDER);
|
||||
}
|
||||
|
||||
private static String toErrorString(List<String> theParameterTypes) {
|
||||
return theParameterTypes.stream().sorted().collect(Collectors.joining(","));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,8 +64,8 @@ public class InterceptorService extends BaseInterceptorService<Pointcut>
|
|||
|
||||
@Override
|
||||
public void registerAnonymousInterceptor(Pointcut thePointcut, int theOrder, IAnonymousInterceptor theInterceptor) {
|
||||
Validate.notNull(thePointcut);
|
||||
Validate.notNull(theInterceptor);
|
||||
Validate.notNull(thePointcut, "thePointcut must not be null");
|
||||
Validate.notNull(theInterceptor, "theInterceptor must not be null");
|
||||
BaseInvoker invoker = new AnonymousLambdaInvoker(thePointcut, theInterceptor, theOrder);
|
||||
registerAnonymousInterceptor(thePointcut, theInterceptor, invoker);
|
||||
}
|
||||
|
@ -81,7 +81,7 @@ public class InterceptorService extends BaseInterceptorService<Pointcut>
|
|||
}
|
||||
|
||||
@Override
|
||||
Object invoke(HookParams theParams) {
|
||||
public Object invoke(HookParams theParams) {
|
||||
myHook.invoke(myPointcut, theParams);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
package ca.uhn.fhir.narrative2;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
|
@ -42,7 +43,8 @@ public class NarrativeGeneratorTemplateUtils {
|
|||
* Given a Bundle as input, are any entries present with a given resource type
|
||||
*/
|
||||
public boolean bundleHasEntriesWithResourceType(IBaseBundle theBaseBundle, String theResourceType) {
|
||||
FhirContext ctx = theBaseBundle.getStructureFhirVersionEnum().newContextCached();
|
||||
FhirVersionEnum fhirVersionEnum = theBaseBundle.getStructureFhirVersionEnum();
|
||||
FhirContext ctx = FhirContext.forCached(fhirVersionEnum);
|
||||
List<Pair<String, IBaseResource>> entryResources =
|
||||
BundleUtil.getBundleEntryUrlsAndResources(ctx, theBaseBundle);
|
||||
return entryResources.stream()
|
||||
|
|
|
@ -668,7 +668,7 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
|
||||
protected void parseFhirContext(CommandLine theCommandLine) throws ParseException {
|
||||
FhirVersionEnum versionEnum = parseFhirVersion(theCommandLine);
|
||||
myFhirCtx = versionEnum.newContext();
|
||||
myFhirCtx = FhirContext.forVersion(versionEnum);
|
||||
}
|
||||
|
||||
public abstract void run(CommandLine theCommandLine) throws ParseException, ExecutionException;
|
||||
|
|
|
@ -98,7 +98,7 @@ public class VersionCanonicalizer {
|
|||
private final FhirContext myContext;
|
||||
|
||||
public VersionCanonicalizer(FhirVersionEnum theTargetVersion) {
|
||||
this(theTargetVersion.newContextCached());
|
||||
this(FhirContext.forCached(theTargetVersion));
|
||||
}
|
||||
|
||||
public VersionCanonicalizer(FhirContext theTargetContext) {
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
type: add
|
||||
issue: 6511
|
||||
title: "Interceptors can be defined against the registry on the RestfulServer, or on
|
||||
the registry in the JPA repository. Because these are separate registries, the order()
|
||||
attribute on the Hook annotation isn't correctly processed today across the two
|
||||
registries. The CompositeInterceptorRegistry has been reworked so ordering will be
|
||||
respected across both registries."
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
type: remove
|
||||
issue: 6512
|
||||
title: "The methods on FhirVersionEnum which produces a FhirContext (newContext() ,and newContextCached()) have been deprecated, and will be removed."
|
|
@ -27,7 +27,6 @@ import ca.uhn.fhir.i18n.Msg;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.model.PersistentIdToForcedIdMap;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.bulk.export.api.IBulkExportProcessor;
|
||||
|
@ -349,10 +348,9 @@ public class JpaBulkExportProcessor implements IBulkExportProcessor<JpaPid> {
|
|||
* Get a ISearchBuilder for the given resource type.
|
||||
*/
|
||||
protected ISearchBuilder<JpaPid> getSearchBuilderForResourceType(String theResourceType) {
|
||||
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(theResourceType);
|
||||
RuntimeResourceDefinition def = myContext.getResourceDefinition(theResourceType);
|
||||
Class<? extends IBaseResource> typeClass = def.getImplementingClass();
|
||||
return mySearchBuilderFactory.newSearchBuilder(dao, theResourceType, typeClass);
|
||||
return mySearchBuilderFactory.newSearchBuilder(theResourceType, typeClass);
|
||||
}
|
||||
|
||||
protected RuntimeSearchParam getPatientSearchParamForCurrentResourceType(String theResourceType) {
|
||||
|
|
|
@ -25,7 +25,6 @@ import ca.uhn.fhir.i18n.Msg;
|
|||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||
|
@ -158,10 +157,8 @@ public class SearchConfig {
|
|||
|
||||
@Bean(name = ISearchBuilder.SEARCH_BUILDER_BEAN_NAME)
|
||||
@Scope("prototype")
|
||||
public ISearchBuilder newSearchBuilder(
|
||||
IDao theDao, String theResourceName, Class<? extends IBaseResource> theResourceType) {
|
||||
public ISearchBuilder newSearchBuilder(String theResourceName, Class<? extends IBaseResource> theResourceType) {
|
||||
return new SearchBuilder(
|
||||
theDao,
|
||||
theResourceName,
|
||||
myStorageSettings,
|
||||
myEntityManagerFactory,
|
||||
|
|
|
@ -1057,8 +1057,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (!presenceCount.isEmpty()) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
message.setMessage(
|
||||
"For " + entity.getIdDt().toUnqualifiedVersionless().getValue() + " added "
|
||||
|
@ -1068,8 +1069,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1092,8 +1092,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (!searchParamAddRemoveCount.isEmpty()) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
message.setMessage("For "
|
||||
+ entity.getIdDt().toUnqualifiedVersionless().getValue() + " added "
|
||||
|
@ -1104,8 +1106,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,15 +227,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
@Nullable
|
||||
public static <T extends IBaseResource> T invokeStoragePreShowResources(
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequest, T retVal) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PRESHOW_RESOURCES, theInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(theInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
SimplePreResourceShowDetails showDetails = new SimplePreResourceShowDetails(retVal);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceShowDetails.class, showDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
theInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
//noinspection unchecked
|
||||
retVal = (T) showDetails.getResource(
|
||||
0); // TODO GGG/JA : getting resource 0 is interesting. We apparently allow null values in the list.
|
||||
|
@ -251,15 +251,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
RequestDetails theRequest,
|
||||
IIdType theId,
|
||||
IBaseResource theResource) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PREACCESS_RESOURCES, theInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(theInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
SimplePreResourceAccessDetails accessDetails = new SimplePreResourceAccessDetails(theResource);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
theInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
if (accessDetails.isDontReturnResourceAtIndex(0)) {
|
||||
throw new ResourceNotFoundException(Msg.code(1995) + "Resource " + theId + " is not known");
|
||||
}
|
||||
|
@ -1585,15 +1585,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
private Optional<T> invokeStoragePreAccessResources(RequestDetails theRequest, T theResource) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PREACCESS_RESOURCES, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
SimplePreResourceAccessDetails accessDetails = new SimplePreResourceAccessDetails(theResource);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
if (accessDetails.isDontReturnResourceAtIndex(0)) {
|
||||
return Optional.empty();
|
||||
}
|
||||
|
@ -2103,7 +2103,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
ISearchBuilder<JpaPid> builder =
|
||||
mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
||||
mySearchBuilderFactory.newSearchBuilder(getResourceName(), getResourceType());
|
||||
|
||||
List<JpaPid> ids = new ArrayList<>();
|
||||
|
||||
|
@ -2136,8 +2136,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
myRequestPartitionHelperService.determineReadPartitionForRequestForSearchType(
|
||||
theRequest, myResourceName, theParams, theConditionalOperationTargetOrNull);
|
||||
|
||||
ISearchBuilder<JpaPid> builder =
|
||||
mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
||||
ISearchBuilder<JpaPid> builder = mySearchBuilderFactory.newSearchBuilder(getResourceName(), getResourceType());
|
||||
|
||||
String uuid = UUID.randomUUID().toString();
|
||||
|
||||
|
@ -2175,7 +2174,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
.withPropagation(Propagation.REQUIRED)
|
||||
.searchList(() -> {
|
||||
ISearchBuilder<JpaPid> builder =
|
||||
mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
||||
mySearchBuilderFactory.newSearchBuilder(getResourceName(), getResourceType());
|
||||
Stream<JpaPid> pidStream =
|
||||
builder.createQueryStream(theParams, searchRuntimeDetails, theRequest, requestPartitionId);
|
||||
|
||||
|
@ -2191,7 +2190,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
@Nonnull
|
||||
private Stream<T> pidsToResource(RequestDetails theRequest, Stream<JpaPid> pidStream) {
|
||||
ISearchBuilder<JpaPid> searchBuilder =
|
||||
mySearchBuilderFactory.newSearchBuilder(this, getResourceName(), getResourceType());
|
||||
mySearchBuilderFactory.newSearchBuilder(getResourceName(), getResourceType());
|
||||
@SuppressWarnings("unchecked")
|
||||
Stream<T> resourceStream = (Stream<T>) new QueryChunker<>()
|
||||
.chunk(pidStream, SearchBuilder.getMaximumPageSize())
|
||||
|
|
|
@ -516,8 +516,9 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
private void logQuery(SearchQueryOptionsStep theQuery, RequestDetails theRequestDetails) {
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
StorageProcessingMessage storageProcessingMessage = new StorageProcessingMessage();
|
||||
String queryString = theQuery.toQuery().queryString();
|
||||
storageProcessingMessage.setMessage(queryString);
|
||||
|
@ -525,8 +526,7 @@ public class FulltextSearchSvcImpl implements IFulltextSearchSvc {
|
|||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(StorageProcessingMessage.class, storageProcessingMessage);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -273,7 +273,13 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
|||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
int versionSeparator = theUri.lastIndexOf('|');
|
||||
if (versionSeparator != -1) {
|
||||
params.add(StructureDefinition.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
|
||||
} else {
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
}
|
||||
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -124,12 +124,15 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
|||
final AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
// Notify Interceptors about pre-action call
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING)) {
|
||||
HookParams hooks = new HookParams()
|
||||
.add(AtomicInteger.class, counter)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING, hooks);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING, hooks);
|
||||
}
|
||||
|
||||
ourLog.info("BEGINNING GLOBAL $expunge");
|
||||
Propagation propagation = Propagation.REQUIRES_NEW;
|
||||
|
|
|
@ -256,8 +256,9 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
|
|||
ResourceHistoryTable theVersion,
|
||||
IdDt theId) {
|
||||
final AtomicInteger counter = new AtomicInteger();
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE)) {
|
||||
IBaseResource resource = myJpaStorageResourceParser.toResource(theVersion, false);
|
||||
HookParams params = new HookParams()
|
||||
.add(AtomicInteger.class, counter)
|
||||
|
@ -265,8 +266,7 @@ public class JpaResourceExpungeService implements IResourceExpungeService<JpaPid
|
|||
.add(IBaseResource.class, resource)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, params);
|
||||
}
|
||||
theRemainingCount.addAndGet(-1 * counter.get());
|
||||
}
|
||||
|
|
|
@ -106,13 +106,15 @@ public class DeleteConflictService {
|
|||
}
|
||||
|
||||
// Notify Interceptors about pre-action call
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
HookParams hooks = new HookParams()
|
||||
.add(DeleteConflictList.class, theDeleteConflicts)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(TransactionDetails.class, theTransactionDetails);
|
||||
return (DeleteConflictOutcome) CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESTORAGE_DELETE_CONFLICTS, hooks);
|
||||
return (DeleteConflictOutcome)
|
||||
compositeBroadcaster.callHooksAndReturnObject(Pointcut.STORAGE_PRESTORAGE_DELETE_CONFLICTS, hooks);
|
||||
}
|
||||
|
||||
private void addConflictsToList(
|
||||
|
|
|
@ -155,17 +155,19 @@ public class ThreadSafeResourceDeleterSvc {
|
|||
TransactionDetails theTransactionDetails,
|
||||
IdDt nextSource,
|
||||
IFhirResourceDao<?> dao) {
|
||||
// Interceptor call: STORAGE_CASCADE_DELETE
|
||||
|
||||
// Remove the version so we grab the latest version to delete
|
||||
IBaseResource resource = dao.read(nextSource.toVersionless(), theRequest);
|
||||
|
||||
// Interceptor call: STORAGE_CASCADE_DELETE
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(DeleteConflictList.class, theConflictList)
|
||||
.add(IBaseResource.class, resource);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_CASCADE_DELETE, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_CASCADE_DELETE, params);
|
||||
|
||||
return dao.delete(resource.getIdElement(), theConflictList, theRequest, theTransactionDetails);
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.svc.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.dao.HistoryBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.HistoryBuilderFactory;
|
||||
|
@ -189,15 +188,17 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
retVal.add(myJpaStorageResourceParser.toResource(resource, true));
|
||||
}
|
||||
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, myRequest);
|
||||
|
||||
// Interceptor call: STORAGE_PREACCESS_RESOURCES
|
||||
{
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
SimplePreResourceAccessDetails accessDetails = new SimplePreResourceAccessDetails(retVal);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
|
||||
for (int i = retVal.size() - 1; i >= 0; i--) {
|
||||
if (accessDetails.isDontReturnResourceAtIndex(i)) {
|
||||
|
@ -207,14 +208,13 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
}
|
||||
|
||||
// Interceptor broadcast: STORAGE_PRESHOW_RESOURCES
|
||||
{
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
SimplePreResourceShowDetails showDetails = new SimplePreResourceShowDetails(retVal);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceShowDetails.class, showDetails)
|
||||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
retVal = showDetails.toList();
|
||||
}
|
||||
|
||||
|
@ -254,9 +254,8 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
String resourceName = mySearchEntity.getResourceType();
|
||||
Class<? extends IBaseResource> resourceType =
|
||||
myContext.getResourceDefinition(resourceName).getImplementingClass();
|
||||
IFhirResourceDao<?> dao = myDaoRegistry.getResourceDao(resourceName);
|
||||
|
||||
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(dao, resourceName, resourceType);
|
||||
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(resourceName, resourceType);
|
||||
|
||||
RequestPartitionId requestPartitionId = getRequestPartitionId();
|
||||
// we request 1 more resource than we need
|
||||
|
|
|
@ -374,8 +374,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
|
||||
Class<? extends IBaseResource> resourceTypeClass =
|
||||
myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||
final ISearchBuilder<JpaPid> sb =
|
||||
mySearchBuilderFactory.newSearchBuilder(theCallingDao, theResourceType, resourceTypeClass);
|
||||
final ISearchBuilder<JpaPid> sb = mySearchBuilderFactory.newSearchBuilder(theResourceType, resourceTypeClass);
|
||||
sb.setFetchSize(mySyncSize);
|
||||
|
||||
final Integer loadSynchronousUpTo = getLoadSynchronousUpToOrNull(theCacheControlDirective);
|
||||
|
@ -599,17 +598,18 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
.withRequest(theRequestDetails)
|
||||
.withRequestPartitionId(theRequestPartitionId)
|
||||
.execute(() -> {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
|
||||
// Interceptor call: STORAGE_PRECHECK_FOR_CACHED_SEARCH
|
||||
|
||||
HookParams params = new HookParams()
|
||||
.add(SearchParameterMap.class, theParams)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
boolean canUseCache = CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster,
|
||||
theRequestDetails,
|
||||
Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH,
|
||||
params);
|
||||
boolean canUseCache =
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH, params);
|
||||
if (!canUseCache) {
|
||||
return null;
|
||||
}
|
||||
|
@ -626,11 +626,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
.add(SearchParameterMap.class, theParams)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster,
|
||||
theRequestDetails,
|
||||
Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED,
|
||||
params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED, params);
|
||||
|
||||
return myPersistedJpaBundleProviderFactory.newInstance(theRequestDetails, searchToUse.getUuid());
|
||||
});
|
||||
|
|
|
@ -27,7 +27,6 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||
|
@ -181,12 +180,16 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
|||
}
|
||||
|
||||
JpaPreResourceAccessDetails accessDetails = new JpaPreResourceAccessDetails(pids, () -> theSb);
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
}
|
||||
|
||||
for (int i = pids.size() - 1; i >= 0; i--) {
|
||||
if (accessDetails.isDontReturnResourceAtIndex(i)) {
|
||||
|
@ -279,12 +282,9 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
|||
RequestPartitionId theRequestPartitionId) {
|
||||
final String searchUuid = UUID.randomUUID().toString();
|
||||
|
||||
IFhirResourceDao<?> callingDao = myDaoRegistry.getResourceDao(theResourceType);
|
||||
|
||||
Class<? extends IBaseResource> resourceTypeClass =
|
||||
myContext.getResourceDefinition(theResourceType).getImplementingClass();
|
||||
final ISearchBuilder sb =
|
||||
mySearchBuilderFactory.newSearchBuilder(callingDao, theResourceType, resourceTypeClass);
|
||||
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(theResourceType, resourceTypeClass);
|
||||
sb.setFetchSize(mySyncSize);
|
||||
return executeQuery(
|
||||
theSearchParameterMap,
|
||||
|
|
|
@ -33,7 +33,6 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||
import ca.uhn.fhir.jpa.api.svc.ResolveIdentityMode;
|
||||
|
@ -192,7 +191,6 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
private final FhirContext myContext;
|
||||
private final IIdHelperService<JpaPid> myIdHelperService;
|
||||
private final JpaStorageSettings myStorageSettings;
|
||||
private final IDao myCallingDao;
|
||||
|
||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
protected EntityManager myEntityManager;
|
||||
|
@ -220,7 +218,6 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public SearchBuilder(
|
||||
IDao theDao,
|
||||
String theResourceName,
|
||||
JpaStorageSettings theStorageSettings,
|
||||
HapiFhirLocalContainerEntityManagerFactoryBean theEntityManagerFactory,
|
||||
|
@ -235,7 +232,6 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
FhirContext theContext,
|
||||
IIdHelperService theIdHelperService,
|
||||
Class<? extends IBaseResource> theResourceType) {
|
||||
myCallingDao = theDao;
|
||||
myResourceName = theResourceName;
|
||||
myResourceType = theResourceType;
|
||||
myStorageSettings = theStorageSettings;
|
||||
|
@ -426,15 +422,15 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
|
||||
if (theSearchRuntimeDetails != null) {
|
||||
theSearchRuntimeDetails.setFoundIndexMatchesCount(resultCount);
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INDEXSEARCH_QUERY_COMPLETE)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(SearchRuntimeDetails.class, theSearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster,
|
||||
theRequest,
|
||||
Pointcut.JPA_PERFTRACE_INDEXSEARCH_QUERY_COMPLETE,
|
||||
params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INDEXSEARCH_QUERY_COMPLETE, params);
|
||||
}
|
||||
}
|
||||
|
||||
// can we skip the database entirely and return the pid list from here?
|
||||
|
@ -1393,8 +1389,10 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
String searchIdOrDescription = theParameters.getSearchIdOrDescription();
|
||||
List<String> desiredResourceTypes = theParameters.getDesiredResourceTypes();
|
||||
boolean hasDesiredResourceTypes = desiredResourceTypes != null && !desiredResourceTypes.isEmpty();
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_RAW_SQL, myInterceptorBroadcaster, theParameters.getRequestDetails())) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, request);
|
||||
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_RAW_SQL)) {
|
||||
CurrentThreadCaptureQueriesListener.startCapturing();
|
||||
}
|
||||
if (matches.isEmpty()) {
|
||||
|
@ -1498,17 +1496,16 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
w.getMillisAndRestart(),
|
||||
searchIdOrDescription);
|
||||
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_RAW_SQL, myInterceptorBroadcaster, request)) {
|
||||
callRawSqlHookWithCurrentThreadQueries(request);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_RAW_SQL)) {
|
||||
callRawSqlHookWithCurrentThreadQueries(request, compositeBroadcaster);
|
||||
}
|
||||
|
||||
// Interceptor call: STORAGE_PREACCESS_RESOURCES
|
||||
// This can be used to remove results from the search result details before
|
||||
// the user has a chance to know that they were in the results
|
||||
if (!allAdded.isEmpty()) {
|
||||
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PREACCESS_RESOURCES, myInterceptorBroadcaster, request)) {
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
List<JpaPid> includedPidList = new ArrayList<>(allAdded);
|
||||
JpaPreResourceAccessDetails accessDetails =
|
||||
new JpaPreResourceAccessDetails(includedPidList, () -> this);
|
||||
|
@ -1516,8 +1513,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, request)
|
||||
.addIfMatchesType(ServletRequestDetails.class, request);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, request, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
|
||||
for (int i = includedPidList.size() - 1; i >= 0; i--) {
|
||||
if (accessDetails.isDontReturnResourceAtIndex(i)) {
|
||||
|
@ -1813,17 +1809,18 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
|
||||
/**
|
||||
* Calls Performance Trace Hook
|
||||
*
|
||||
* @param request the request deatils
|
||||
* Sends a raw SQL query to the Pointcut for raw SQL queries.
|
||||
*/
|
||||
private void callRawSqlHookWithCurrentThreadQueries(RequestDetails request) {
|
||||
private void callRawSqlHookWithCurrentThreadQueries(
|
||||
RequestDetails request, IInterceptorBroadcaster theCompositeBroadcaster) {
|
||||
SqlQueryList capturedQueries = CurrentThreadCaptureQueriesListener.getCurrentQueueAndStopCapturing();
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, request)
|
||||
.addIfMatchesType(ServletRequestDetails.class, request)
|
||||
.add(SqlQueryList.class, capturedQueries);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, request, Pointcut.JPA_PERFTRACE_RAW_SQL, params);
|
||||
theCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_RAW_SQL, params);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
@ -2095,6 +2092,9 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
indexStrings.sort(Comparator.naturalOrder());
|
||||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
String indexStringForLog = indexStrings.size() > 1 ? indexStrings.toString() : indexStrings.get(0);
|
||||
StorageProcessingMessage msg = new StorageProcessingMessage()
|
||||
.setMessage("Using " + theComboParam.getComboSearchParamType() + " index(es) for query for search: "
|
||||
|
@ -2103,8 +2103,8 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, msg);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
|
||||
switch (requireNonNull(theComboParam.getComboSearchParamType())) {
|
||||
case UNIQUE:
|
||||
|
@ -2330,6 +2330,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
private final boolean myHavePerfTraceFoundIdHook;
|
||||
private final SortSpec mySort;
|
||||
private final Integer myOffset;
|
||||
private final IInterceptorBroadcaster myCompositeBroadcaster;
|
||||
private boolean myFirst = true;
|
||||
private IncludesIterator myIncludesIterator;
|
||||
/**
|
||||
|
@ -2368,16 +2369,16 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
mySort = myParams.getSort();
|
||||
myOffset = myParams.getOffset();
|
||||
myRequest = theRequest;
|
||||
myCompositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
|
||||
// everything requires fetching recursively all related resources
|
||||
if (myParams.getEverythingMode() != null) {
|
||||
myFetchIncludesForEverythingOperation = true;
|
||||
}
|
||||
|
||||
myHavePerfTraceFoundIdHook = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_SEARCH_FOUND_ID, myInterceptorBroadcaster, myRequest);
|
||||
myHaveRawSqlHooks = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_RAW_SQL, myInterceptorBroadcaster, myRequest);
|
||||
myHavePerfTraceFoundIdHook = myCompositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_SEARCH_FOUND_ID);
|
||||
myHaveRawSqlHooks = myCompositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_RAW_SQL);
|
||||
}
|
||||
|
||||
private void fetchNext() {
|
||||
|
@ -2479,7 +2480,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
} finally {
|
||||
// search finished - fire hooks
|
||||
if (myHaveRawSqlHooks) {
|
||||
callRawSqlHookWithCurrentThreadQueries(myRequest);
|
||||
callRawSqlHookWithCurrentThreadQueries(myRequest, myCompositeBroadcaster);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2488,8 +2489,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest)
|
||||
.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_FIRST_RESULT_LOADED, params);
|
||||
myFirst = false;
|
||||
}
|
||||
|
||||
|
@ -2498,8 +2498,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest)
|
||||
.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_SELECT_COMPLETE, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2523,8 +2522,7 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
HookParams params = new HookParams()
|
||||
.add(Integer.class, System.identityHashCode(this))
|
||||
.add(Object.class, theNextLong);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_FOUND_ID, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_FOUND_ID, params);
|
||||
}
|
||||
|
||||
private void sendProcessingMsgAndFirePerformanceHook() {
|
||||
|
@ -2627,14 +2625,18 @@ public class SearchBuilder implements ISearchBuilder<JpaPid> {
|
|||
firePerformanceMessage(theRequest, theMessage, Pointcut.JPA_PERFTRACE_WARNING);
|
||||
}
|
||||
|
||||
private void firePerformanceMessage(RequestDetails theRequest, String theMessage, Pointcut pointcut) {
|
||||
private void firePerformanceMessage(RequestDetails theRequest, String theMessage, Pointcut thePointcut) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(thePointcut)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
message.setMessage(theMessage);
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, pointcut, params);
|
||||
compositeBroadcaster.callHooks(thePointcut, params);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getMaximumPageSize() {
|
||||
|
|
|
@ -53,14 +53,17 @@ public class StorageInterceptorHooksFacade {
|
|||
SearchParameterMap theParams,
|
||||
Search search,
|
||||
RequestPartitionId theRequestPartitionId) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESEARCH_REGISTERED)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(ICachedSearchDetails.class, search)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(SearchParameterMap.class, theParams)
|
||||
.add(RequestPartitionId.class, theRequestPartitionId);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRESEARCH_REGISTERED, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESEARCH_REGISTERED, params);
|
||||
}
|
||||
}
|
||||
// private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
}
|
||||
|
|
|
@ -407,12 +407,16 @@ public class ResourceLinkPredicateBuilder extends BaseJoiningPredicateBuilder im
|
|||
}
|
||||
String message = builder.toString();
|
||||
StorageProcessingMessage msg = new StorageProcessingMessage().setMessage(message);
|
||||
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_WARNING)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, msg);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -109,15 +109,18 @@ public class UriPredicateBuilder extends BaseSearchParamPredicateBuilder {
|
|||
+ "] param[" + theParamName + "]";
|
||||
ourLog.info(msg);
|
||||
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_WARNING)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
ourLog.warn(msg);
|
||||
message.setMessage(msg);
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
}
|
||||
|
||||
long hashIdentity = BaseResourceIndexedSearchParam.calculateHashIdentity(
|
||||
getPartitionSettings(), getRequestPartitionId(), getResourceType(), theParamName);
|
||||
|
|
|
@ -26,7 +26,6 @@ import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
|||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||
import ca.uhn.fhir.jpa.api.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||
|
@ -95,7 +94,6 @@ public class SearchTask implements Callable<Void> {
|
|||
protected final FhirContext myContext;
|
||||
protected final ISearchResultCacheSvc mySearchResultCacheSvc;
|
||||
private final SearchParameterMap myParams;
|
||||
private final IDao myCallingDao;
|
||||
private final String myResourceType;
|
||||
private final ArrayList<JpaPid> mySyncedPids = new ArrayList<>();
|
||||
private final CountDownLatch myInitialCollectionLatch = new CountDownLatch(1);
|
||||
|
@ -113,6 +111,7 @@ public class SearchTask implements Callable<Void> {
|
|||
private final JpaStorageSettings myStorageSettings;
|
||||
private final ISearchCacheSvc mySearchCacheSvc;
|
||||
private final IPagingProvider myPagingProvider;
|
||||
private final IInterceptorBroadcaster myCompositeBroadcaster;
|
||||
private Search mySearch;
|
||||
private boolean myAbortRequested;
|
||||
private int myCountSavedTotal = 0;
|
||||
|
@ -149,7 +148,6 @@ public class SearchTask implements Callable<Void> {
|
|||
// values
|
||||
myOnRemove = theCreationParams.OnRemove;
|
||||
mySearch = theCreationParams.Search;
|
||||
myCallingDao = theCreationParams.CallingDao;
|
||||
myParams = theCreationParams.Params;
|
||||
myResourceType = theCreationParams.ResourceType;
|
||||
myRequest = theCreationParams.Request;
|
||||
|
@ -158,9 +156,11 @@ public class SearchTask implements Callable<Void> {
|
|||
myLoadingThrottleForUnitTests = theCreationParams.getLoadingThrottleForUnitTests();
|
||||
|
||||
mySearchRuntimeDetails = new SearchRuntimeDetails(myRequest, mySearch.getUuid());
|
||||
mySearchRuntimeDetails.setQueryString(myParams.toNormalizedQueryString(myCallingDao.getContext()));
|
||||
mySearchRuntimeDetails.setQueryString(myParams.toNormalizedQueryString(myContext));
|
||||
myRequestPartitionId = theCreationParams.RequestPartitionId;
|
||||
myParentTransaction = ElasticApm.currentTransaction();
|
||||
myCompositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, myRequest);
|
||||
}
|
||||
|
||||
protected RequestPartitionId getRequestPartitionId() {
|
||||
|
@ -203,7 +203,7 @@ public class SearchTask implements Callable<Void> {
|
|||
private ISearchBuilder newSearchBuilder() {
|
||||
Class<? extends IBaseResource> resourceTypeClass =
|
||||
myContext.getResourceDefinition(myResourceType).getImplementingClass();
|
||||
return mySearchBuilderFactory.newSearchBuilder(myCallingDao, myResourceType, resourceTypeClass);
|
||||
return mySearchBuilderFactory.newSearchBuilder(myResourceType, resourceTypeClass);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
@ -280,7 +280,7 @@ public class SearchTask implements Callable<Void> {
|
|||
.withRequest(myRequest)
|
||||
.withRequestPartitionId(myRequestPartitionId)
|
||||
.withPropagation(Propagation.REQUIRES_NEW)
|
||||
.execute(() -> doSaveSearch());
|
||||
.execute(this::doSaveSearch);
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
|
@ -307,8 +307,7 @@ public class SearchTask implements Callable<Void> {
|
|||
.add(RequestDetails.class, mySearchRuntimeDetails.getRequestDetails())
|
||||
.addIfMatchesType(
|
||||
ServletRequestDetails.class, mySearchRuntimeDetails.getRequestDetails());
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
|
||||
for (int i = unsyncedPids.size() - 1; i >= 0; i--) {
|
||||
if (accessDetails.isDontReturnResourceAtIndex(i)) {
|
||||
|
@ -454,15 +453,13 @@ public class SearchTask implements Callable<Void> {
|
|||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest)
|
||||
.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_COMPLETE, params);
|
||||
} else {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest)
|
||||
.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_PASS_COMPLETE, params);
|
||||
}
|
||||
|
||||
ourLog.trace(
|
||||
|
@ -516,8 +513,7 @@ public class SearchTask implements Callable<Void> {
|
|||
.add(RequestDetails.class, myRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, myRequest)
|
||||
.add(SearchRuntimeDetails.class, mySearchRuntimeDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, myRequest, Pointcut.JPA_PERFTRACE_SEARCH_FAILED, params);
|
||||
myCompositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_SEARCH_FAILED, params);
|
||||
|
||||
saveSearch();
|
||||
span.captureException(t);
|
||||
|
|
|
@ -214,9 +214,7 @@ public class JpaBulkExportProcessorTest {
|
|||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters), any(boolean.class)))
|
||||
.thenReturn(maps);
|
||||
// from getSearchBuilderForLocalResourceType
|
||||
when(myDaoRegistry.getResourceDao(anyString()))
|
||||
.thenReturn(mockDao);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(mockDao), eq(parameters.getResourceType()), any()))
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(parameters.getResourceType()), any()))
|
||||
.thenReturn(searchBuilder);
|
||||
// ret
|
||||
when(searchBuilder.createQuery(
|
||||
|
@ -304,9 +302,7 @@ public class JpaBulkExportProcessorTest {
|
|||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(any(RuntimeResourceDefinition.class), eq(parameters), any(boolean.class)))
|
||||
.thenReturn(Collections.singletonList(new SearchParameterMap()));
|
||||
// from getSearchBuilderForLocalResourceType
|
||||
when(myDaoRegistry.getResourceDao(not(eq("Group"))))
|
||||
.thenReturn(mockDao);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(mockDao), eq(parameters.getResourceType()), any()))
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(parameters.getResourceType()), any()))
|
||||
.thenReturn(searchBuilder);
|
||||
// ret
|
||||
when(searchBuilder.createQuery(
|
||||
|
@ -432,9 +428,7 @@ public class JpaBulkExportProcessorTest {
|
|||
when(myIdHelperService.getPidOrNull(eq(getPartitionIdFromParams(thePartitioned)), eq(groupResource)))
|
||||
.thenReturn(groupId);
|
||||
// getMembersFromGroupWithFilter
|
||||
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
||||
.thenReturn(patientDao);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(patientDao), eq("Patient"), eq(Patient.class)))
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq("Patient"), eq(Patient.class)))
|
||||
.thenReturn(patientSearchBuilder);
|
||||
RuntimeResourceDefinition patientDef = myFhirContext.getResourceDefinition("Patient");
|
||||
SearchParameterMap patientSpMap = new SearchParameterMap();
|
||||
|
@ -447,9 +441,7 @@ public class JpaBulkExportProcessorTest {
|
|||
RuntimeResourceDefinition observationDef = myFhirContext.getResourceDefinition("Observation");
|
||||
when(myBulkExportHelperService.createSearchParameterMapsForResourceType(eq(observationDef), eq(parameters), any(boolean.class)))
|
||||
.thenReturn(Collections.singletonList(observationSpMap));
|
||||
when(myDaoRegistry.getResourceDao((eq("Observation"))))
|
||||
.thenReturn(observationDao);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq(observationDao), eq("Observation"), eq(Observation.class)))
|
||||
when(mySearchBuilderFactory.newSearchBuilder(eq("Observation"), eq(Observation.class)))
|
||||
.thenReturn(observationSearchBuilder);
|
||||
when(observationSearchBuilder.loadIncludes(
|
||||
any(SearchBuilderLoadIncludesParameters.class)
|
||||
|
@ -520,10 +512,7 @@ public class JpaBulkExportProcessorTest {
|
|||
any(ExportPIDIteratorParameters.class),
|
||||
any(boolean.class)
|
||||
)).thenReturn(Collections.singletonList(new SearchParameterMap()));
|
||||
when(myDaoRegistry.getResourceDao(eq("Patient")))
|
||||
.thenReturn(dao);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(
|
||||
any(IFhirResourceDao.class),
|
||||
anyString(),
|
||||
any()
|
||||
)).thenReturn(searchBuilder);
|
||||
|
|
|
@ -941,8 +941,9 @@ public class SearchParamExtractorService {
|
|||
if (myPartitionSettings.getAllowReferencesAcrossPartitions() == ALLOWED_UNQUALIFIED) {
|
||||
|
||||
// Interceptor: Pointcut.JPA_CROSS_PARTITION_REFERENCE_DETECTED
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_RESOLVE_CROSS_PARTITION_REFERENCE, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_RESOLVE_CROSS_PARTITION_REFERENCE)) {
|
||||
CrossPartitionReferenceDetails referenceDetails = new CrossPartitionReferenceDetails(
|
||||
theRequestPartitionId,
|
||||
theSourceResourceName,
|
||||
|
@ -950,12 +951,8 @@ public class SearchParamExtractorService {
|
|||
theRequest,
|
||||
theTransactionDetails);
|
||||
HookParams params = new HookParams(referenceDetails);
|
||||
targetResource =
|
||||
(IResourceLookup<JpaPid>) CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster,
|
||||
theRequest,
|
||||
Pointcut.JPA_RESOLVE_CROSS_PARTITION_REFERENCE,
|
||||
params);
|
||||
targetResource = (IResourceLookup<JpaPid>) compositeBroadcaster.callHooksAndReturnObject(
|
||||
Pointcut.JPA_RESOLVE_CROSS_PARTITION_REFERENCE, params);
|
||||
} else {
|
||||
targetResource = myResourceLinkResolver.findTargetResource(
|
||||
RequestPartitionId.allPartitions(),
|
||||
|
@ -1089,8 +1086,9 @@ public class SearchParamExtractorService {
|
|||
}
|
||||
|
||||
// If extraction generated any warnings, broadcast an error
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_WARNING, theInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(theInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_WARNING)) {
|
||||
for (String next : theSearchParamSet.getWarnings()) {
|
||||
StorageProcessingMessage messageHolder = new StorageProcessingMessage();
|
||||
messageHolder.setMessage(next);
|
||||
|
@ -1098,8 +1096,7 @@ public class SearchParamExtractorService {
|
|||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(StorageProcessingMessage.class, messageHolder);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
theInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_WARNING, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,20 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
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.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.test.utilities.MockInvoker;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.times;
|
||||
|
@ -36,14 +42,17 @@ public class SearchParamExtractorServiceTest {
|
|||
searchParamSet.addWarning("help i'm a bug");
|
||||
searchParamSet.addWarning("Spiff");
|
||||
|
||||
when(myJpaInterceptorBroadcaster.hasHooks(any())).thenReturn(true);
|
||||
when(myJpaInterceptorBroadcaster.callHooks(any(), any())).thenReturn(true);
|
||||
AtomicInteger counter = new AtomicInteger();
|
||||
|
||||
when(myJpaInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(true);
|
||||
when(myJpaInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(MockInvoker.list((Consumer<HookParams>) params->counter.incrementAndGet()));
|
||||
|
||||
ServletRequestDetails requestDetails = new ServletRequestDetails(myRequestInterceptorBroadcaster);
|
||||
SearchParamExtractorService.handleWarnings(requestDetails, myJpaInterceptorBroadcaster, searchParamSet);
|
||||
|
||||
verify(myJpaInterceptorBroadcaster, times(2)).callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), any());
|
||||
verify(myRequestInterceptorBroadcaster, times(2)).callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), any());
|
||||
verify(myJpaInterceptorBroadcaster, times(3)).hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING));
|
||||
verify(myRequestInterceptorBroadcaster, times(2)).hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING));
|
||||
assertEquals(2, counter.get());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -118,13 +118,16 @@ public class SubscriptionMatcherInterceptor {
|
|||
ResourceModifiedMessage msg = createResourceModifiedMessage(theNewResource, theOperationType, theRequest);
|
||||
|
||||
// Interceptor call: SUBSCRIPTION_RESOURCE_MODIFIED
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED)) {
|
||||
HookParams params = new HookParams().add(ResourceModifiedMessage.class, msg);
|
||||
boolean outcome = CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED, params);
|
||||
boolean outcome = compositeBroadcaster.callHooks(Pointcut.SUBSCRIPTION_RESOURCE_MODIFIED, params);
|
||||
|
||||
if (!outcome) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
processResourceModifiedMessage(msg);
|
||||
}
|
||||
|
|
|
@ -383,8 +383,8 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
String resourceType = myFhirContext.getResourceType(theJobDetails.getCurrentSearchResourceType());
|
||||
RuntimeResourceDefinition resourceDef =
|
||||
myFhirContext.getResourceDefinition(theJobDetails.getCurrentSearchResourceType());
|
||||
ISearchBuilder searchBuilder = mySearchBuilderFactory.newSearchBuilder(
|
||||
resourceDao, resourceType, resourceDef.getImplementingClass());
|
||||
ISearchBuilder searchBuilder =
|
||||
mySearchBuilderFactory.newSearchBuilder(resourceType, resourceDef.getImplementingClass());
|
||||
List<IBaseResource> listToPopulate = new ArrayList<>();
|
||||
|
||||
myTransactionService.withRequest(null).execute(() -> {
|
||||
|
|
|
@ -113,7 +113,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
myClient.create().resource(subs).execute();
|
||||
fail("");
|
||||
} catch (UnprocessableEntityException e) {
|
||||
assertThat(e.getMessage()).contains("Unknown SubscriptionStatus code 'aaaaa'");
|
||||
assertThat(e.getMessage()).containsAnyOf("invalid value aaaaa", "Unknown SubscriptionStatus code 'aaaaa'");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ public class BaseSearchSvc {
|
|||
protected static final FhirContext ourCtx = FhirContext.forDstu3Cached();
|
||||
|
||||
public void after() {
|
||||
verify(mySearchBuilderFactory, atMost(myExpectedNumberOfSearchBuildersCreated)).newSearchBuilder(any(), any(), any());
|
||||
verify(mySearchBuilderFactory, atMost(myExpectedNumberOfSearchBuildersCreated)).newSearchBuilder(any(), any());
|
||||
}
|
||||
|
||||
protected List<JpaPid> createPidSequence(int to) {
|
||||
|
|
|
@ -76,6 +76,7 @@ import static org.mockito.Mockito.doAnswer;
|
|||
import static org.mockito.Mockito.lenient;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoInteractions;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SuppressWarnings({"unchecked"})
|
||||
|
@ -91,7 +92,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
@Mock
|
||||
private ISearchResultCacheSvc mySearchResultCacheSvc;
|
||||
private Search myCurrentSearch;
|
||||
@Mock
|
||||
@Mock(strictness = Mock.Strictness.STRICT_STUBS)
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
@Mock
|
||||
private SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
||||
|
@ -289,7 +290,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
}
|
||||
|
||||
private void initSearches() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
}
|
||||
|
||||
private void initAsyncSearches() {
|
||||
|
@ -318,8 +319,8 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
SlowIterator iter = new SlowIterator(pids.iterator(), 500);
|
||||
when(mySearchBuilder.createQuery(same(params), any(), any(), nullable(RequestPartitionId.class))).thenReturn(iter);
|
||||
mockSearchTask();
|
||||
when(myInterceptorBroadcaster.callHooks(any(), any()))
|
||||
.thenReturn(true);
|
||||
when(myInterceptorBroadcaster.hasHooks(any())).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(any())).thenReturn(List.of());
|
||||
|
||||
ourLog.info("Registering the first search");
|
||||
new Thread(() -> mySvc.registerSearch(myCallingDao, params, "Patient", new CacheControlDirective(), null, RequestPartitionId.allPartitions())).start();
|
||||
|
@ -437,7 +438,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testLoadSearchResultsFromDifferentCoordinator() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
|
||||
|
@ -517,7 +518,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearch() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronous(true);
|
||||
|
@ -531,7 +532,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearchWithOffset() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setOffset(10);
|
||||
|
@ -544,7 +545,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearchUpTo() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
int loadUpto = 30;
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
@ -584,7 +585,6 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc {
|
|||
@Test
|
||||
public void testFetchAllResultsReturnsNull() {
|
||||
when(myDaoRegistry.getResourceDao(anyString())).thenReturn(myCallingDao);
|
||||
when(myCallingDao.getContext()).thenReturn(ourCtx);
|
||||
|
||||
Search search = new Search();
|
||||
search.setUuid("0000-1111");
|
||||
|
|
|
@ -41,7 +41,7 @@ public class SynchronousSearchSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearch() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any()))
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any()))
|
||||
.thenReturn(mySearchBuilder);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
@ -65,7 +65,7 @@ public class SynchronousSearchSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearchWithOffset() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setCount(10);
|
||||
|
@ -87,7 +87,7 @@ public class SynchronousSearchSvcImplTest extends BaseSearchSvc {
|
|||
|
||||
@Test
|
||||
public void testSynchronousSearchUpTo() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(mySearchBuilder);
|
||||
when(myStorageSettings.getDefaultTotalMode()).thenReturn(null);
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class TerminologySvcImplDstu2Test extends BaseJpaDstu2Test {
|
||||
|
||||
|
@ -29,6 +30,8 @@ public class TerminologySvcImplDstu2Test extends BaseJpaDstu2Test {
|
|||
List<FhirVersionIndependentConcept> concepts;
|
||||
Set<String> codes;
|
||||
|
||||
when(mySrd.getInterceptorBroadcaster()).thenReturn(null);
|
||||
|
||||
ValueSet upload = new ValueSet();
|
||||
upload.setId(new IdDt("testVs"));
|
||||
upload.setUrl("http://myVs");
|
||||
|
@ -61,6 +64,8 @@ public class TerminologySvcImplDstu2Test extends BaseJpaDstu2Test {
|
|||
List<FhirVersionIndependentConcept> concepts;
|
||||
Set<String> codes;
|
||||
|
||||
when(mySrd.getInterceptorBroadcaster()).thenReturn(null);
|
||||
|
||||
ValueSet upload = new ValueSet();
|
||||
upload.setId(new IdDt("testVs"));
|
||||
upload.setUrl("http://myVs");
|
||||
|
|
|
@ -33,6 +33,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
|
||||
import ca.uhn.fhir.test.utilities.HttpClientExtension;
|
||||
import ca.uhn.fhir.test.utilities.MockInvoker;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.util.JsonUtil;
|
||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||
|
@ -1054,18 +1055,18 @@ public class BulkDataExportProviderR4Test {
|
|||
AtomicBoolean initiateCalled = new AtomicBoolean(false);
|
||||
|
||||
// when
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT), any(HookParams.class)))
|
||||
.thenAnswer((args) -> {
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT))).thenReturn(MockInvoker.list(params->{
|
||||
assertFalse(initiateCalled.get());
|
||||
assertFalse(preInitiateCalled.getAndSet(true));
|
||||
return true;
|
||||
});
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT), any(HookParams.class)))
|
||||
.thenAnswer((args) -> {
|
||||
}));
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT))).thenReturn(MockInvoker.list(params->{
|
||||
assertTrue(preInitiateCalled.get());
|
||||
assertFalse(initiateCalled.getAndSet(true));
|
||||
return true;
|
||||
});
|
||||
}));
|
||||
when(myJobCoordinator.startInstance(isNotNull(), any()))
|
||||
.thenReturn(createJobStartResponse());
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
|||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
|
||||
import ca.uhn.fhir.test.utilities.HttpClientExtension;
|
||||
import ca.uhn.fhir.test.utilities.MockInvoker;
|
||||
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||
import ca.uhn.fhir.util.JsonUtil;
|
||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||
|
@ -1057,18 +1058,18 @@ public class BulkDataExportProviderR5Test {
|
|||
AtomicBoolean initiateCalled = new AtomicBoolean(false);
|
||||
|
||||
// when
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT), any(HookParams.class)))
|
||||
.thenAnswer((args) -> {
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT))).thenReturn(MockInvoker.list(params -> {
|
||||
assertFalse(initiateCalled.get());
|
||||
assertFalse(preInitiateCalled.getAndSet(true));
|
||||
return true;
|
||||
});
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT), any(HookParams.class)))
|
||||
.thenAnswer((args) -> {
|
||||
}));
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.STORAGE_INITIATE_BULK_EXPORT))).thenReturn(MockInvoker.list(params -> {
|
||||
assertTrue(preInitiateCalled.get());
|
||||
assertFalse(initiateCalled.getAndSet(true));
|
||||
return true;
|
||||
});
|
||||
}));
|
||||
when(myJobCoordinator.startInstance(isNotNull(), any()))
|
||||
.thenReturn(createJobStartResponse());
|
||||
|
||||
|
|
|
@ -320,7 +320,7 @@ class BaseHapiFhirResourceDaoTest {
|
|||
mySvc.setTransactionService(myTransactionService);
|
||||
|
||||
when(myRequestPartitionHelperSvc.determineReadPartitionForRequestForSearchType(any(), any(), any(), any())).thenReturn(mock(RequestPartitionId.class));
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(myISearchBuilder);
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any())).thenReturn(myISearchBuilder);
|
||||
when(myISearchBuilder.createQuery(any(), any(), any(), any())).thenReturn(mock(IResultIterator.class));
|
||||
|
||||
lenient().when(myStorageSettings.getInternalSynchronousSearchSize()).thenReturn(5000);
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
|
@ -25,15 +24,23 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.sl.cache.Cache;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.Captor;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
@ -41,13 +48,18 @@ import org.springframework.test.util.ReflectionTestUtils;
|
|||
|
||||
import java.util.function.Function;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||
import static org.hl7.fhir.common.hapi.validation.support.ValidationConstants.LOINC_LOW;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.ArgumentMatchers.isA;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class JpaPersistedResourceValidationSupportTest {
|
||||
|
@ -115,5 +127,68 @@ class JpaPersistedResourceValidationSupportTest {
|
|||
|
||||
}
|
||||
|
||||
@Nested
|
||||
class FetchStructureDefinitionTests {
|
||||
|
||||
@Mock
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
@InjectMocks
|
||||
private final JpaPersistedResourceValidationSupport testClass = new JpaPersistedResourceValidationSupport(theFhirContext);
|
||||
|
||||
@Captor
|
||||
ArgumentCaptor<SearchParameterMap> searchParameterMapCaptor;
|
||||
@Test
|
||||
@DisplayName("fetch StructureDefinition by version less url")
|
||||
void fetchStructureDefinitionForUrl() {
|
||||
final String profileUrl = "http://example.com/fhir/StructureDefinition/exampleProfile";
|
||||
IFhirResourceDao mockDao = mock(IFhirResourceDao.class);
|
||||
when(mockDao.search(any())).thenReturn(mock(IBundleProvider.class));
|
||||
when(myDaoRegistry.getResourceDao(anyString())).thenReturn(mockDao);
|
||||
|
||||
testClass.fetchResource(StructureDefinition.class, profileUrl);
|
||||
|
||||
verify(mockDao).search(searchParameterMapCaptor.capture());
|
||||
SearchParameterMap searchParams = searchParameterMapCaptor.getValue();
|
||||
String uriParam = searchParams.get(StructureDefinition.SP_URL)
|
||||
.get(0)
|
||||
.stream()
|
||||
.map(UriParam.class::cast)
|
||||
.map(UriParam::getValue)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(uriParam).isEqualTo(profileUrl);
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("fetch StructureDefinition by versioned url")
|
||||
void fetchStructureDefinitionForVersionedUrl() {
|
||||
final String profileUrl = "http://example.com/fhir/StructureDefinition/exampleProfile|1.1.0";
|
||||
IFhirResourceDao mockDao = mock(IFhirResourceDao.class);
|
||||
when(mockDao.search(any())).thenReturn(mock(IBundleProvider.class));
|
||||
when(myDaoRegistry.getResourceDao(anyString())).thenReturn(mockDao);
|
||||
|
||||
testClass.fetchResource(StructureDefinition.class, profileUrl);
|
||||
|
||||
verify(mockDao).search(searchParameterMapCaptor.capture());
|
||||
SearchParameterMap searchParams = searchParameterMapCaptor.getValue();
|
||||
String uriParam = searchParams.get(StructureDefinition.SP_URL)
|
||||
.get(0)
|
||||
.stream()
|
||||
.map(UriParam.class::cast)
|
||||
.map(UriParam::getValue)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(uriParam).isEqualTo("http://example.com/fhir/StructureDefinition/exampleProfile");
|
||||
|
||||
String versionParam = searchParams.get(StructureDefinition.SP_VERSION)
|
||||
.get(0)
|
||||
.stream()
|
||||
.map(TokenParam.class::cast)
|
||||
.map(TokenParam::getValue)
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
assertThat(versionParam).isEqualTo("1.1.0");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
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.api.config.JpaStorageSettings;
|
||||
|
@ -10,9 +9,9 @@ import ca.uhn.fhir.jpa.search.reindex.ResourceReindexingSvcImpl;
|
|||
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.util.SpringObjectCaster;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.test.utilities.MockInvoker;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.mockito.ArgumentMatchers;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -47,24 +46,22 @@ public abstract class BaseComboParamsR4Test extends BaseJpaR4Test {
|
|||
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_INFO))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_INFO), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||
HookParams params = t.getArgument(1, HookParams.class);
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.hasHooks(eq(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.JPA_PERFTRACE_INFO))).thenReturn(MockInvoker.list(params->{
|
||||
myMessages.add("INFO " + params.get(StorageProcessingMessage.class).getMessage());
|
||||
return null;
|
||||
});
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_WARNING), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||
HookParams params = t.getArgument(1, HookParams.class);
|
||||
}));
|
||||
|
||||
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.JPA_PERFTRACE_WARNING))).thenReturn(MockInvoker.list(params->{
|
||||
myMessages.add("WARN " + params.get(StorageProcessingMessage.class).getMessage());
|
||||
return null;
|
||||
});
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED), ArgumentMatchers.any(HookParams.class))).thenAnswer(t -> {
|
||||
HookParams params = t.getArgument(1, HookParams.class);
|
||||
}));
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.JPA_PERFTRACE_SEARCH_REUSING_CACHED))).thenReturn(MockInvoker.list(params->{
|
||||
myMessages.add("REUSING CACHED SEARCH");
|
||||
return null;
|
||||
});
|
||||
}));
|
||||
|
||||
// allow searches to use cached results
|
||||
when(myInterceptorBroadcaster.callHooks(eq(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH), ArgumentMatchers.any(HookParams.class))).thenReturn(true);
|
||||
when(myInterceptorBroadcaster.getInvokersForPointcut(eq(Pointcut.STORAGE_PRECHECK_FOR_CACHED_SEARCH))).thenReturn(MockInvoker.list(params->true));
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -83,4 +80,5 @@ public abstract class BaseComboParamsR4Test extends BaseJpaR4Test {
|
|||
ourLog.info("Messages:\n {}", String.join("\n ", myMessages));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Tes
|
|||
final String classSystem = "http://terminology.hl7.org/CodeSystem/v3-ActCode";
|
||||
final String identifierTypeSystem = "http://terminology.hl7.org/CodeSystem/v2-0203";
|
||||
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/encounter-status", "http://hl7.org/fhir/encounter-status", statusCode, "validation/encounter/validateCode-ValueSet-encounter-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/encounter-status", "4.0.1", "http://hl7.org/fhir/encounter-status", statusCode, "validation/encounter/validateCode-ValueSet-encounter-status.json");
|
||||
setupValueSetValidateCode("http://terminology.hl7.org/ValueSet/v3-ActEncounterCode", "http://terminology.hl7.org/CodeSystem/v3-ActCode", classCode, "validation/encounter/validateCode-ValueSet-v3-ActEncounterCode.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/identifier-type", "http://hl7.org/fhir/identifier-type", identifierTypeCode, "validation/encounter/validateCode-ValueSet-identifier-type.json");
|
||||
|
||||
|
@ -138,7 +138,7 @@ public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Tes
|
|||
final String loincSystem = "http://loinc.org";
|
||||
final String system = "http://fhir.infoway-inforoute.ca/io/psca/CodeSystem/ICD9CM";
|
||||
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/observation-status", statusSystem, statusCode, "validation/observation/validateCode-ValueSet-observation-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/observation-status", "4.0.1", statusSystem, statusCode, "validation/observation/validateCode-ValueSet-observation-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/observation-codes", loincSystem, statusCode, "validation/observation/validateCode-ValueSet-codes.json");
|
||||
|
||||
setupCodeSystemValidateCode(statusSystem, statusCode, "validation/observation/validateCode-CodeSystem-observation-status.json");
|
||||
|
@ -171,7 +171,7 @@ public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Tes
|
|||
final String statusSystem = "http://hl7.org/fhir/event-status";
|
||||
final String snomedSystem = "http://snomed.info/sct";
|
||||
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", "4.0.1", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode1, "validation/procedure/validateCode-ValueSet-procedure-code-valid.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode2, "validation/procedure/validateCode-ValueSet-procedure-code-invalid.json");
|
||||
|
||||
|
@ -213,7 +213,7 @@ public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Tes
|
|||
final String snomedSystem = "http://snomed.info/sct";
|
||||
final String absentUnknownSystem = "http://hl7.org/fhir/uv/ips/CodeSystem/absent-unknown-uv-ips";
|
||||
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/event-status", "4.0.1", statusSystem, statusCode, "validation/procedure/validateCode-ValueSet-event-status.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/ValueSet/procedure-code", snomedSystem, procedureCode, "validation/procedure/validateCode-ValueSet-procedure-code-invalid-slice.json");
|
||||
setupValueSetValidateCode("http://hl7.org/fhir/uv/ips/ValueSet/absent-or-unknown-procedures-uv-ips", absentUnknownSystem, procedureCode, "validation/procedure/validateCode-ValueSet-absent-or-unknown-procedure.json");
|
||||
|
||||
|
@ -245,6 +245,15 @@ public class ValidateWithRemoteTerminologyTest extends BaseResourceProviderR4Tes
|
|||
// which also attempts a validateCode against the CodeSystem after the validateCode against the ValueSet
|
||||
}
|
||||
|
||||
private void setupValueSetValidateCode(String theUrl, String theVersion, String theSystem, String theCode, String theTerminologyResponseFile) {
|
||||
ValueSet valueSet = myValueSetProvider.addTerminologyResource(theUrl, theVersion);
|
||||
myValueSetProvider.addTerminologyResource(theSystem, theVersion);
|
||||
myValueSetProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, valueSet.getUrl(), theCode, ourCtx, theTerminologyResponseFile);
|
||||
|
||||
valueSet.getCompose().addInclude().setSystem(theSystem);
|
||||
}
|
||||
|
||||
|
||||
private void setupCodeSystemValidateCode(String theUrl, String theCode, String theTerminologyResponseFile) {
|
||||
CodeSystem codeSystem = myCodeSystemProvider.addTerminologyResource(theUrl);
|
||||
myCodeSystemProvider.addTerminologyResponse(OPERATION_VALIDATE_CODE, codeSystem.getUrl(), theCode, ourCtx, theTerminologyResponseFile);
|
||||
|
|
|
@ -90,7 +90,7 @@ public class MdmReadVirtualizationInterceptor<P extends IResourcePersistentId<?>
|
|||
@Hook(
|
||||
value = Pointcut.STORAGE_PRESEARCH_REGISTERED,
|
||||
order = MdmConstants.ORDER_PRESEARCH_REGISTERED_MDM_READ_VIRTUALIZATION_INTERCEPTOR)
|
||||
public void hook(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap) {
|
||||
public void preSearchRegistered(RequestDetails theRequestDetails, SearchParameterMap theSearchParameterMap) {
|
||||
ourMdmTroubleshootingLog
|
||||
.atTrace()
|
||||
.setMessage("MDM virtualization original search: {}{}")
|
||||
|
|
|
@ -85,14 +85,15 @@ public class MdmSearchExpansionSvc {
|
|||
|
||||
// Try to detect if the RequestDetails is being reused across multiple different queries, which
|
||||
// can happen during CQL measure evaluation
|
||||
{
|
||||
String resourceName = theRequestDetails.getResourceName();
|
||||
String queryString = theSearchParameterMap.toNormalizedQueryString(myFhirContext);
|
||||
if (!Objects.equals(resourceName, theRequestDetails.getUserData().get(RESOURCE_NAME))
|
||||
|| !Objects.equals(queryString, theRequestDetails.getUserData().get(QUERY_STRING))) {
|
||||
|| !Objects.equals(
|
||||
queryString, theRequestDetails.getUserData().get(QUERY_STRING))) {
|
||||
theRequestDetails.getUserData().remove(EXPANSION_RESULTS);
|
||||
}
|
||||
theRequestDetails.getUserData().put(RESOURCE_NAME, resourceName);
|
||||
theRequestDetails.getUserData().put(QUERY_STRING, queryString);
|
||||
}
|
||||
|
||||
MdmSearchExpansionResults expansionResults = getCachedExpansionResults(theRequestDetails);
|
||||
if (expansionResults != null) {
|
||||
|
@ -123,6 +124,15 @@ public class MdmSearchExpansionSvc {
|
|||
|
||||
theRequestDetails.getUserData().put(EXPANSION_RESULTS, expansionResults);
|
||||
|
||||
/*
|
||||
* Note: Do this at the end so that the query string reflects the post-translated
|
||||
* query string
|
||||
*/
|
||||
String resourceName = theRequestDetails.getResourceName();
|
||||
String queryString = theSearchParameterMap.toNormalizedQueryString(myFhirContext);
|
||||
theRequestDetails.getUserData().put(RESOURCE_NAME, resourceName);
|
||||
theRequestDetails.getUserData().put(QUERY_STRING, queryString);
|
||||
|
||||
return expansionResults;
|
||||
}
|
||||
|
||||
|
|
|
@ -92,7 +92,7 @@ public class MdmSearchParamSvc {
|
|||
|
||||
public ISearchBuilder generateSearchBuilderForType(String theSourceType) {
|
||||
IFhirResourceDao resourceDao = myDaoRegistry.getResourceDao(theSourceType);
|
||||
return mySearchBuilderFactory.newSearchBuilder(resourceDao, theSourceType, resourceDao.getResourceType());
|
||||
return mySearchBuilderFactory.newSearchBuilder(theSourceType, resourceDao.getResourceType());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -41,6 +41,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import static java.util.Objects.nonNull;
|
||||
|
@ -241,6 +242,11 @@ public class SystemRequestDetails extends RequestDetails {
|
|||
public boolean hasHooks(Pointcut thePointcut) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IInvoker> getInvokersForPointcut(Pointcut thePointcut) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
}
|
||||
|
||||
public static SystemRequestDetails forAllPartitions() {
|
||||
|
|
|
@ -686,7 +686,7 @@ public class RestfulServerUtils {
|
|||
if (context.getVersion().getVersion() != theForVersion) {
|
||||
context = myFhirContextMap.get(theForVersion);
|
||||
if (context == null) {
|
||||
context = theForVersion.newContext();
|
||||
context = FhirContext.forVersion(theForVersion);
|
||||
myFhirContextMap.put(theForVersion, context);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -54,18 +54,21 @@ public class ServerInterceptorUtil {
|
|||
// Interceptor call: STORAGE_PRESHOW_RESOURCE
|
||||
// This can be used to remove results from the search result details before
|
||||
// the user has a chance to know that they were in the results
|
||||
if (retVal.size() > 0) {
|
||||
if (!retVal.isEmpty()) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(theInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
SimplePreResourceShowDetails accessDetails = new SimplePreResourceShowDetails(retVal);
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceShowDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
theInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
|
||||
retVal = accessDetails.toList();
|
||||
retVal.removeIf(Objects::isNull);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -19,97 +19,105 @@
|
|||
*/
|
||||
package ca.uhn.fhir.rest.server.util;
|
||||
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
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.interceptor.executor.BaseInterceptorService;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
|
||||
public class CompositeInterceptorBroadcaster {
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
|
||||
/**
|
||||
* This is an {@link IInterceptorBroadcaster} which combines multiple interceptor
|
||||
* broadcasters. Hook methods are called across all broadcasters, respecting
|
||||
* the {@link Hook#order()} across all broadcasters.
|
||||
*/
|
||||
public class CompositeInterceptorBroadcaster implements IInterceptorBroadcaster {
|
||||
|
||||
private final List<IInterceptorBroadcaster> myServices;
|
||||
|
||||
/**
|
||||
* Non instantiable
|
||||
* Constructor
|
||||
*/
|
||||
private CompositeInterceptorBroadcaster() {
|
||||
// nothing
|
||||
private CompositeInterceptorBroadcaster(Collection<IInterceptorBroadcaster> theServices) {
|
||||
myServices = theServices.stream().filter(t -> t != null).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
||||
assert BaseInterceptorService.haveAppropriateParams(thePointcut, theParams);
|
||||
assert thePointcut.getReturnType() == void.class
|
||||
|| thePointcut.getReturnType() == thePointcut.getBooleanReturnTypeForEnum();
|
||||
|
||||
List<IInvoker> invokers = getInvokersForPointcut(thePointcut);
|
||||
Object retVal = BaseInterceptorService.callInvokers(thePointcut, theParams, invokers);
|
||||
retVal = defaultIfNull(retVal, true);
|
||||
return (Boolean) retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams) {
|
||||
assert BaseInterceptorService.haveAppropriateParams(thePointcut, theParams);
|
||||
assert thePointcut.getReturnType() != void.class;
|
||||
|
||||
List<IInvoker> invokers = getInvokersForPointcut(thePointcut);
|
||||
return BaseInterceptorService.callInvokers(thePointcut, theParams, invokers);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nonnull
|
||||
public List<IInvoker> getInvokersForPointcut(Pointcut thePointcut) {
|
||||
List<IInvoker> invokers = new ArrayList<>();
|
||||
for (IInterceptorBroadcaster services : myServices) {
|
||||
if (services.hasHooks(thePointcut)) {
|
||||
List<IInvoker> serviceInvokers = services.getInvokersForPointcut(thePointcut);
|
||||
assert serviceInvokers != null;
|
||||
invokers.addAll(serviceInvokers);
|
||||
}
|
||||
}
|
||||
invokers.sort(Comparator.naturalOrder());
|
||||
return invokers;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHooks(Pointcut thePointcut) {
|
||||
for (IInterceptorBroadcaster service : myServices) {
|
||||
if (service.hasHooks(thePointcut)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast hooks to both the interceptor service associated with the request, as well
|
||||
* as the one associated with the JPA module.
|
||||
* @since 8.0.0
|
||||
*/
|
||||
public static boolean doCallHooks(
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||
@Nullable RequestDetails theRequestDetails,
|
||||
Pointcut thePointcut,
|
||||
HookParams theParams) {
|
||||
return newCompositeBroadcaster(theInterceptorBroadcaster, theRequestDetails)
|
||||
.callHooks(thePointcut, theParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Broadcast hooks to both the interceptor service associated with the request, as well
|
||||
* as the one associated with the JPA module.
|
||||
*/
|
||||
public static Object doCallHooksAndReturnObject(
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||
RequestDetails theRequestDetails,
|
||||
Pointcut thePointcut,
|
||||
HookParams theParams) {
|
||||
return newCompositeBroadcaster(theInterceptorBroadcaster, theRequestDetails)
|
||||
.callHooksAndReturnObject(thePointcut, theParams);
|
||||
}
|
||||
|
||||
// TODO: JA - Refactor to make thePointcut the last argument in order to be consistent with thr other methods here
|
||||
public static boolean hasHooks(
|
||||
Pointcut thePointcut, IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequestDetails) {
|
||||
return newCompositeBroadcaster(theInterceptorBroadcaster, theRequestDetails)
|
||||
.hasHooks(thePointcut);
|
||||
public static IInterceptorBroadcaster newCompositeBroadcaster(IInterceptorBroadcaster... theServices) {
|
||||
return new CompositeInterceptorBroadcaster(Arrays.asList(theServices));
|
||||
}
|
||||
|
||||
/**
|
||||
* @since 5.5.0
|
||||
*/
|
||||
public static IInterceptorBroadcaster newCompositeBroadcaster(
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster, RequestDetails theRequestDetails) {
|
||||
return new IInterceptorBroadcaster() {
|
||||
@Override
|
||||
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
||||
boolean retVal = true;
|
||||
if (theInterceptorBroadcaster != null) {
|
||||
retVal = theInterceptorBroadcaster.callHooks(thePointcut, theParams);
|
||||
@Nonnull IInterceptorBroadcaster theInterceptorBroadcaster, @Nullable RequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
IInterceptorBroadcaster requestBroadcaster = theRequestDetails.getInterceptorBroadcaster();
|
||||
if (requestBroadcaster != null) {
|
||||
return newCompositeBroadcaster(theInterceptorBroadcaster, requestBroadcaster);
|
||||
}
|
||||
if (theRequestDetails != null && theRequestDetails.getInterceptorBroadcaster() != null && retVal) {
|
||||
IInterceptorBroadcaster interceptorBroadcaster = theRequestDetails.getInterceptorBroadcaster();
|
||||
retVal = interceptorBroadcaster.callHooks(thePointcut, theParams);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object callHooksAndReturnObject(Pointcut thePointcut, HookParams theParams) {
|
||||
Object retVal = true;
|
||||
if (theInterceptorBroadcaster != null) {
|
||||
retVal = theInterceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams);
|
||||
}
|
||||
if (theRequestDetails != null
|
||||
&& theRequestDetails.getInterceptorBroadcaster() != null
|
||||
&& retVal == null) {
|
||||
IInterceptorBroadcaster interceptorBroadcaster = theRequestDetails.getInterceptorBroadcaster();
|
||||
retVal = interceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasHooks(Pointcut thePointcut) {
|
||||
if (theInterceptorBroadcaster != null && theInterceptorBroadcaster.hasHooks(thePointcut)) {
|
||||
return true;
|
||||
}
|
||||
return theRequestDetails != null
|
||||
&& theRequestDetails.getInterceptorBroadcaster() != null
|
||||
&& theRequestDetails.getInterceptorBroadcaster().hasHooks(thePointcut);
|
||||
}
|
||||
};
|
||||
return newCompositeBroadcaster(theInterceptorBroadcaster);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,161 +1,314 @@
|
|||
package ca.uhn.fhir.rest.server.util;
|
||||
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IBaseInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.interceptor.executor.InterceptorService;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import com.google.common.collect.MultimapBuilder;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.junit.jupiter.MockitoExtension;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@ExtendWith(MockitoExtension.class)
|
||||
class CompositeInterceptorBroadcasterTest {
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private static final Class BOOLEAN_CLASS = boolean.class;
|
||||
private final List<Integer> myOrders = new ArrayList<>();
|
||||
@Mock
|
||||
private IInterceptorBroadcaster myModuleBroadcasterMock;
|
||||
@Mock
|
||||
private IInterceptorBroadcaster myReqDetailsBroadcasterMock;
|
||||
@Mock
|
||||
private IBaseInterceptorBroadcaster.IInvoker myModuleBroadcasterInvokerMock;
|
||||
@Mock
|
||||
private IBaseInterceptorBroadcaster.IInvoker myReqDetailsInvokerMock;
|
||||
@Mock
|
||||
private Pointcut myPointcutMock;
|
||||
@Mock
|
||||
private HookParams myHookParamsMock;
|
||||
@Mock
|
||||
private RequestDetails myRequestDetailsMock;
|
||||
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_RequestDetailsBroadcasterReturnsTrue_ThenReturnsTrue() {
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myReqDetailsBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myReqDetailsBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myReqDetailsInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
when(myModuleBroadcasterInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(true);
|
||||
when(myReqDetailsInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(true);
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
|
||||
myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, myRequestDetailsMock);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isTrue();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
verify(myReqDetailsInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_RequestDetailsBroadcasterReturnsFalse_ThenReturnsFalse() {
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myReqDetailsBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myReqDetailsBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myReqDetailsInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
when(myModuleBroadcasterInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(true);
|
||||
when(myReqDetailsInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(false);
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
|
||||
myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, myRequestDetailsMock);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isFalse();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock).invoke(eq(myHookParamsMock));
|
||||
verify(myReqDetailsInvokerMock).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsFalse_ThenSkipsBroadcasterInRequestDetails_And_ReturnsFalse() {
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myReqDetailsBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myReqDetailsBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myReqDetailsInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
when(myModuleBroadcasterInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(false);
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock,
|
||||
myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, myRequestDetailsMock);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isFalse();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myReqDetailsBroadcasterMock, never()).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
verify(myReqDetailsInvokerMock, never()).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_NullRequestDetailsBroadcaster_ThenReturnsTrue() {
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(null);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock, myPointcutMock,
|
||||
myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, myRequestDetailsMock);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isTrue();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
verify(myReqDetailsInvokerMock, never()).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsFalse_And_NullRequestDetailsBroadcaster_ThenReturnsFalse() {
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(null);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
when(myModuleBroadcasterInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(false);
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, myRequestDetailsMock, myPointcutMock,
|
||||
myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, myRequestDetailsMock);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isFalse();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsTrue_And_NullRequestDetails_ThenReturnsTrue() {
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, null, myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, null);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isTrue();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock, times(1)).invoke(eq(myHookParamsMock));
|
||||
verify(myReqDetailsInvokerMock, never()).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
void doCallHooks_WhenModuleBroadcasterReturnsFalse_And_NullRequestDetails_ThenReturnsFalse() {
|
||||
|
||||
when(myModuleBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
|
||||
when(myPointcutMock.getReturnType()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getBooleanReturnTypeForEnum()).thenReturn(BOOLEAN_CLASS);
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
when(myModuleBroadcasterMock.hasHooks(eq(myPointcutMock))).thenReturn(true);
|
||||
when(myModuleBroadcasterMock.getInvokersForPointcut(eq(myPointcutMock))).thenReturn(List.of(myModuleBroadcasterInvokerMock));
|
||||
when(myModuleBroadcasterInvokerMock.invoke(eq(myHookParamsMock))).thenReturn(false);
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(myModuleBroadcasterMock, null, myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster(myModuleBroadcasterMock, null);
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isFalse();
|
||||
|
||||
verify(myModuleBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
verify(myModuleBroadcasterInvokerMock).invoke(eq(myHookParamsMock));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenNullModuleBroadcaster_And_NullRequestDetails_ThenReturnsTrue() {
|
||||
when(myPointcutMock.getParameterTypes()).thenReturn(List.of());
|
||||
when(myHookParamsMock.getParamsForType()).thenReturn(MultimapBuilder.hashKeys().arrayListValues().build());
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, null, myPointcutMock, myHookParamsMock);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = CompositeInterceptorBroadcaster
|
||||
.newCompositeBroadcaster();
|
||||
boolean retVal = interceptorBroadcaster.callHooks(myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenNullModuleBroadcaster_And_RequestDetailsBroadcasterReturnsTrue_ThenReturnsTrue() {
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
|
||||
when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(true);
|
||||
@ParameterizedTest
|
||||
@CsvSource({
|
||||
"0, 1, 2",
|
||||
"1, 0, 2",
|
||||
"2, 0, 1"
|
||||
})
|
||||
public void testCompositeBroadcasterBroadcastsInOrder(int theIndex0, int theIndex1, int theIndex2) {
|
||||
// Setup
|
||||
InterceptorService svc0 = new InterceptorService();
|
||||
svc0.registerInterceptor(new Interceptor0());
|
||||
InterceptorService svc1 = new InterceptorService();
|
||||
svc1.registerInterceptor(new Interceptor1());
|
||||
InterceptorService svc2 = new InterceptorService();
|
||||
svc2.registerInterceptor(new Interceptor2());
|
||||
InterceptorService[] services = new InterceptorService[]{svc0, svc1, svc2};
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, myRequestDetailsMock, myPointcutMock, myHookParamsMock);
|
||||
List<IInterceptorBroadcaster> serviceList = List.of(
|
||||
services[theIndex0], services[theIndex1], services[theIndex2]
|
||||
);
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(serviceList.toArray(new IInterceptorBroadcaster[0]));
|
||||
|
||||
assertThat(retVal).isTrue();
|
||||
verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
assertTrue(compositeBroadcaster.hasHooks(Pointcut.TEST_RO));
|
||||
assertFalse(compositeBroadcaster.hasHooks(Pointcut.TEST_RB));
|
||||
|
||||
// Test
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(String.class, "PARAM_A")
|
||||
.add(String.class, "PARAM_B");
|
||||
Object outcome = compositeBroadcaster.callHooksAndReturnObject(Pointcut.TEST_RO, hookParams);
|
||||
|
||||
// Verify
|
||||
assertNull(outcome);
|
||||
assertThat(myOrders).asList().containsExactly(
|
||||
-2, -1, 0, 1, 2, 3
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void doCallHooks_WhenNullModuleBroadcaster_And_RequestDetailsBroadcasterReturnsFalse_ThenReturnsFalse() {
|
||||
when(myRequestDetailsMock.getInterceptorBroadcaster()).thenReturn(myReqDetailsBroadcasterMock);
|
||||
when(myReqDetailsBroadcasterMock.callHooks(myPointcutMock, myHookParamsMock)).thenReturn(false);
|
||||
@Interceptor
|
||||
private class Interceptor0 {
|
||||
|
||||
boolean retVal = CompositeInterceptorBroadcaster.doCallHooks(null, myRequestDetailsMock, myPointcutMock, myHookParamsMock);
|
||||
|
||||
assertThat(retVal).isFalse();
|
||||
verify(myReqDetailsBroadcasterMock).callHooks(myPointcutMock, myHookParamsMock);
|
||||
@Hook(value = Pointcut.TEST_RO, order = 0)
|
||||
public BaseServerResponseException hook0() {
|
||||
myOrders.add(0);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Hook(value = Pointcut.TEST_RO, order = 2)
|
||||
public BaseServerResponseException hook2() {
|
||||
myOrders.add(2);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
private class Interceptor1 {
|
||||
|
||||
@Hook(value = Pointcut.TEST_RO, order = 1)
|
||||
public BaseServerResponseException hook1() {
|
||||
myOrders.add(1);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Hook(value = Pointcut.TEST_RO, order = 3)
|
||||
public BaseServerResponseException hook3() {
|
||||
myOrders.add(3);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
private class Interceptor2 {
|
||||
|
||||
@Hook(value = Pointcut.TEST_RO, order = -1)
|
||||
public BaseServerResponseException hookMinus1() {
|
||||
myOrders.add(-1);
|
||||
return null;
|
||||
}
|
||||
|
||||
@Hook(value = Pointcut.TEST_RO, order = -2)
|
||||
public BaseServerResponseException hookMinus2() {
|
||||
myOrders.add(-2);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -173,15 +173,15 @@ public class BulkDataExportProvider {
|
|||
expandParameters(theRequestDetails, theOptions);
|
||||
|
||||
// permission check
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_INITIATE_BULK_EXPORT)) {
|
||||
HookParams initiateBulkExportHookParams = (new HookParams())
|
||||
.add(BulkExportJobParameters.class, theOptions)
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
this.myInterceptorBroadcaster,
|
||||
theRequestDetails,
|
||||
Pointcut.STORAGE_INITIATE_BULK_EXPORT,
|
||||
initiateBulkExportHookParams);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_INITIATE_BULK_EXPORT, initiateBulkExportHookParams);
|
||||
}
|
||||
|
||||
// get cache boolean
|
||||
boolean useCache = shouldUseCache(theRequestDetails);
|
||||
|
@ -220,15 +220,15 @@ public class BulkDataExportProvider {
|
|||
theOptions.setPartitionId(partitionId);
|
||||
|
||||
// call hook so any other parameter manipulation can be done
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT)) {
|
||||
HookParams preInitiateBulkExportHookParams = new HookParams();
|
||||
preInitiateBulkExportHookParams.add(BulkExportJobParameters.class, theOptions);
|
||||
preInitiateBulkExportHookParams.add(RequestDetails.class, theRequestDetails);
|
||||
preInitiateBulkExportHookParams.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster,
|
||||
theRequestDetails,
|
||||
Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT,
|
||||
preInitiateBulkExportHookParams);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRE_INITIATE_BULK_EXPORT, preInitiateBulkExportHookParams);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean shouldUseCache(ServletRequestDetails theRequestDetails) {
|
||||
|
|
|
@ -78,13 +78,16 @@ public class DeleteExpungeJobSubmitterImpl implements IDeleteExpungeJobSubmitter
|
|||
Msg.code(820) + "Delete Expunge not allowed: " + myStorageSettings.cannotDeleteExpungeReason());
|
||||
}
|
||||
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRE_DELETE_EXPUNGE)) {
|
||||
for (String url : theUrlsToDeleteExpunge) {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(String.class, url);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PRE_DELETE_EXPUNGE, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRE_DELETE_EXPUNGE, params);
|
||||
}
|
||||
}
|
||||
|
||||
DeleteExpungeJobParameters deleteExpungeJobParameters = new DeleteExpungeJobParameters();
|
||||
|
|
|
@ -274,12 +274,15 @@ public class BinaryStorageInterceptor<T extends IPrimitiveType<byte[]>> {
|
|||
* @return A string, which will be used to prefix the blob ID. May be null.
|
||||
*/
|
||||
private String invokeAssignBinaryContentPrefix(RequestDetails theRequest, IBaseResource theResource) {
|
||||
// TODO: to be removed when pointcut STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX has exceeded the grace period
|
||||
boolean hasStorageBinaryAssignBlobIdPrefixHooks = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX, myInterceptorBroadcaster, theRequest);
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
|
||||
boolean hasStorageBinaryAssignBinaryContentIdPrefixHooks = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_BINARY_ASSIGN_BINARY_CONTENT_ID_PREFIX, myInterceptorBroadcaster, theRequest);
|
||||
// TODO: to be removed when pointcut STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX has exceeded the grace period
|
||||
boolean hasStorageBinaryAssignBlobIdPrefixHooks =
|
||||
compositeBroadcaster.hasHooks(Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX);
|
||||
|
||||
boolean hasStorageBinaryAssignBinaryContentIdPrefixHooks =
|
||||
compositeBroadcaster.hasHooks(Pointcut.STORAGE_BINARY_ASSIGN_BINARY_CONTENT_ID_PREFIX);
|
||||
|
||||
if (!(hasStorageBinaryAssignBlobIdPrefixHooks || hasStorageBinaryAssignBinaryContentIdPrefixHooks)) {
|
||||
return null;
|
||||
|
@ -297,8 +300,7 @@ public class BinaryStorageInterceptor<T extends IPrimitiveType<byte[]>> {
|
|||
pointcutToInvoke = Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX;
|
||||
}
|
||||
|
||||
return (String) CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, theRequest, pointcutToInvoke, params);
|
||||
return (String) compositeBroadcaster.callHooksAndReturnObject(pointcutToInvoke, params);
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
|
|
|
@ -174,13 +174,16 @@ public abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc {
|
|||
@Nullable
|
||||
private String callBinaryContentIdPointcut(
|
||||
byte[] theBytes, RequestDetails theRequestDetails, String theContentType) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
|
||||
// TODO: to be removed when pointcut STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX has exceeded the grace period.
|
||||
// Deprecated in 7.2.0.
|
||||
boolean hasStorageBinaryAssignBlobIdPrefixHooks = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX, myInterceptorBroadcaster, theRequestDetails);
|
||||
boolean hasStorageBinaryAssignBlobIdPrefixHooks =
|
||||
compositeBroadcaster.hasHooks(Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX);
|
||||
|
||||
boolean hasStorageBinaryAssignBinaryContentIdPrefixHooks = CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_BINARY_ASSIGN_BINARY_CONTENT_ID_PREFIX, myInterceptorBroadcaster, theRequestDetails);
|
||||
boolean hasStorageBinaryAssignBinaryContentIdPrefixHooks =
|
||||
compositeBroadcaster.hasHooks(Pointcut.STORAGE_BINARY_ASSIGN_BINARY_CONTENT_ID_PREFIX);
|
||||
|
||||
if (!(hasStorageBinaryAssignBlobIdPrefixHooks || hasStorageBinaryAssignBinaryContentIdPrefixHooks)) {
|
||||
return null;
|
||||
|
@ -201,8 +204,7 @@ public abstract class BaseBinaryStorageSvcImpl implements IBinaryStorageSvc {
|
|||
pointcutToInvoke = Pointcut.STORAGE_BINARY_ASSIGN_BLOB_ID_PREFIX;
|
||||
}
|
||||
|
||||
return (String) CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, theRequestDetails, pointcutToInvoke, hookParams);
|
||||
return (String) compositeBroadcaster.callHooksAndReturnObject(pointcutToInvoke, hookParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -335,16 +335,19 @@ public abstract class BaseStorageDao {
|
|||
// Interceptor broadcast: STORAGE_PREACCESS_RESOURCES
|
||||
if (outcome.getResource() != null) {
|
||||
SimplePreResourceAccessDetails accessDetails = new SimplePreResourceAccessDetails(outcome.getResource());
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(getInterceptorBroadcaster(), theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
getInterceptorBroadcaster(), theRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
if (accessDetails.isDontReturnResourceAtIndex(0)) {
|
||||
outcome.setResource(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interceptor broadcast: STORAGE_PRESHOW_RESOURCES
|
||||
// Note that this will only fire if someone actually goes to use the
|
||||
|
@ -352,15 +355,18 @@ public abstract class BaseStorageDao {
|
|||
// outcome.fireResourceViewCallback())
|
||||
outcome.registerResourceViewCallback(() -> {
|
||||
if (outcome.getResource() != null) {
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
getInterceptorBroadcaster(), theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
SimplePreResourceShowDetails showDetails = new SimplePreResourceShowDetails(outcome.getResource());
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceShowDetails.class, showDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
getInterceptorBroadcaster(), theRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
outcome.setResource(showDetails.getResource(0));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return outcome;
|
||||
|
@ -378,18 +384,21 @@ public abstract class BaseStorageDao {
|
|||
outcome.setEntitySupplierUseCallback(() -> {
|
||||
// Interceptor broadcast: STORAGE_PREACCESS_RESOURCES
|
||||
if (outcome.getResource() != null) {
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
getInterceptorBroadcaster(), theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PREACCESS_RESOURCES)) {
|
||||
SimplePreResourceAccessDetails accessDetails =
|
||||
new SimplePreResourceAccessDetails(outcome.getResource());
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceAccessDetails.class, accessDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
getInterceptorBroadcaster(), theRequest, Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PREACCESS_RESOURCES, params);
|
||||
if (accessDetails.isDontReturnResourceAtIndex(0)) {
|
||||
outcome.setResource(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Interceptor broadcast: STORAGE_PRESHOW_RESOURCES
|
||||
// Note that this will only fire if someone actually goes to use the
|
||||
|
@ -397,15 +406,20 @@ public abstract class BaseStorageDao {
|
|||
// outcome.fireResourceViewCallback())
|
||||
outcome.registerResourceViewCallback(() -> {
|
||||
if (outcome.getResource() != null) {
|
||||
SimplePreResourceShowDetails showDetails = new SimplePreResourceShowDetails(outcome.getResource());
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
getInterceptorBroadcaster(), theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
SimplePreResourceShowDetails showDetails =
|
||||
new SimplePreResourceShowDetails(outcome.getResource());
|
||||
HookParams params = new HookParams()
|
||||
.add(IPreResourceShowDetails.class, showDetails)
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
getInterceptorBroadcaster(), theRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
outcome.setResource(showDetails.getResource(0));
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -420,8 +434,9 @@ public abstract class BaseStorageDao {
|
|||
if (theTransactionDetails.isAcceptingDeferredInterceptorBroadcasts(thePointcut)) {
|
||||
theTransactionDetails.addDeferredInterceptorBroadcast(thePointcut, theParams);
|
||||
} else {
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
getInterceptorBroadcaster(), theRequestDetails, thePointcut, theParams);
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
getInterceptorBroadcaster(), theRequestDetails);
|
||||
compositeBroadcaster.callHooks(thePointcut, theParams);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -359,14 +359,14 @@ public abstract class BaseTransactionProcessor {
|
|||
try {
|
||||
|
||||
// Interceptor call: STORAGE_TRANSACTION_PROCESSING
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_TRANSACTION_PROCESSING, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_TRANSACTION_PROCESSING)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(IBaseBundle.class, theRequest);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_TRANSACTION_PROCESSING, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_TRANSACTION_PROCESSING, params);
|
||||
}
|
||||
|
||||
return processTransaction(theRequestDetails, theRequest, theActionName, theNestedMode);
|
||||
|
@ -561,8 +561,9 @@ public abstract class BaseTransactionProcessor {
|
|||
theRequestDetails, response, getEntries, originalRequestOrder, transactionStopWatch, theNestedMode);
|
||||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
String taskDurations = transactionStopWatch.formatTaskDurations();
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
message.setMessage("Transaction timing:\n" + taskDurations);
|
||||
|
@ -570,8 +571,7 @@ public abstract class BaseTransactionProcessor {
|
|||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
|
||||
return response;
|
||||
|
@ -821,12 +821,10 @@ public abstract class BaseTransactionProcessor {
|
|||
}
|
||||
|
||||
private boolean haveWriteOperationsHooks(RequestDetails theRequestDetails) {
|
||||
return CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_PRE, myInterceptorBroadcaster, theRequestDetails)
|
||||
|| CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_POST,
|
||||
myInterceptorBroadcaster,
|
||||
theRequestDetails);
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
return compositeBroadcaster.hasHooks(Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_PRE)
|
||||
|| compositeBroadcaster.hasHooks(Pointcut.STORAGE_TRANSACTION_WRITE_OPERATIONS_POST);
|
||||
}
|
||||
|
||||
private void callWriteOperationsHook(
|
||||
|
@ -834,10 +832,14 @@ public abstract class BaseTransactionProcessor {
|
|||
RequestDetails theRequestDetails,
|
||||
TransactionDetails theTransactionDetails,
|
||||
TransactionWriteOperationsDetails theWriteOperationsDetails) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(thePointcut)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(TransactionDetails.class, theTransactionDetails)
|
||||
.add(TransactionWriteOperationsDetails.class, theWriteOperationsDetails);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequestDetails, thePointcut, params);
|
||||
compositeBroadcaster.callHooks(thePointcut, params);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
|
@ -967,18 +969,16 @@ public abstract class BaseTransactionProcessor {
|
|||
+ " as it contained a duplicate conditional " + verb;
|
||||
ourLog.info(msg);
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_WARNING, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_WARNING)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage().setMessage(msg);
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster,
|
||||
theRequestDetails,
|
||||
Pointcut.JPA_PERFTRACE_INFO,
|
||||
params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
|
||||
theEntries.remove(index);
|
||||
|
@ -1475,13 +1475,14 @@ public abstract class BaseTransactionProcessor {
|
|||
}
|
||||
}
|
||||
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
ListMultimap<Pointcut, HookParams> deferredBroadcastEvents =
|
||||
theTransactionDetails.endAcceptingDeferredInterceptorBroadcasts();
|
||||
for (Map.Entry<Pointcut, HookParams> nextEntry : deferredBroadcastEvents.entries()) {
|
||||
Pointcut nextPointcut = nextEntry.getKey();
|
||||
HookParams nextParams = nextEntry.getValue();
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, nextPointcut, nextParams);
|
||||
compositeBroadcaster.callHooks(nextPointcut, nextParams);
|
||||
}
|
||||
|
||||
DeferredInterceptorBroadcasts deferredInterceptorBroadcasts =
|
||||
|
@ -1492,8 +1493,7 @@ public abstract class BaseTransactionProcessor {
|
|||
.add(DeferredInterceptorBroadcasts.class, deferredInterceptorBroadcasts)
|
||||
.add(TransactionDetails.class, theTransactionDetails)
|
||||
.add(IBaseBundle.class, theResponse);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_TRANSACTION_PROCESSED, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_TRANSACTION_PROCESSED, params);
|
||||
|
||||
theTransactionDetails.deferredBroadcastProcessingFinished();
|
||||
|
||||
|
|
|
@ -135,8 +135,9 @@ public class MatchResourceUrlService<T extends IResourcePersistentId> {
|
|||
}
|
||||
|
||||
// Interceptor broadcast: STORAGE_PRESHOW_RESOURCES
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.STORAGE_PRESHOW_RESOURCES, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PRESHOW_RESOURCES)) {
|
||||
Map<IBaseResource, T> resourceToPidMap = new HashMap<>();
|
||||
|
||||
IFhirResourceDao<R> dao = getResourceDao(theResourceType);
|
||||
|
@ -152,8 +153,7 @@ public class MatchResourceUrlService<T extends IResourcePersistentId> {
|
|||
.addIfMatchesType(ServletRequestDetails.class, theRequest);
|
||||
|
||||
try {
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PRESHOW_RESOURCES, params);
|
||||
|
||||
retVal = accessDetails.toList().stream()
|
||||
.map(resourceToPidMap::get)
|
||||
|
@ -222,16 +222,16 @@ public class MatchResourceUrlService<T extends IResourcePersistentId> {
|
|||
List<T> retVal = dao.searchForIds(theParamMap, theRequest, theConditionalOperationTargetOrNull);
|
||||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (CompositeInterceptorBroadcaster.hasHooks(
|
||||
Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO)) {
|
||||
StorageProcessingMessage message = new StorageProcessingMessage();
|
||||
message.setMessage("Processed conditional resource URL with " + retVal.size() + " result(s) in " + sw);
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(StorageProcessingMessage.class, message);
|
||||
CompositeInterceptorBroadcaster.doCallHooks(
|
||||
myInterceptorBroadcaster, theRequest, Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.JPA_PERFTRACE_INFO, params);
|
||||
}
|
||||
|
||||
return new HashSet<>(retVal);
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
*/
|
||||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.jpa.api.dao.IDao;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -32,9 +31,8 @@ public class SearchBuilderFactory<T extends IResourcePersistentId<?>> {
|
|||
|
||||
public SearchBuilderFactory() {}
|
||||
|
||||
public ISearchBuilder<T> newSearchBuilder(
|
||||
IDao theDao, String theResourceName, Class<? extends IBaseResource> theResourceType) {
|
||||
return (ISearchBuilder<T>) myApplicationContext.getBean(
|
||||
ISearchBuilder.SEARCH_BUILDER_BEAN_NAME, theDao, theResourceName, theResourceType);
|
||||
public ISearchBuilder<T> newSearchBuilder(String theResourceName, Class<? extends IBaseResource> theResourceType) {
|
||||
return (ISearchBuilder<T>)
|
||||
myApplicationContext.getBean(ISearchBuilder.SEARCH_BUILDER_BEAN_NAME, theResourceName, theResourceType);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -364,21 +364,23 @@ public class HapiTransactionService implements IHapiTransactionService {
|
|||
}
|
||||
|
||||
if (maxRetries == 0) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theExecutionBuilder.myRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_VERSION_CONFLICT)) {
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theExecutionBuilder.myRequestDetails)
|
||||
.addIfMatchesType(
|
||||
ServletRequestDetails.class, theExecutionBuilder.myRequestDetails);
|
||||
ResourceVersionConflictResolutionStrategy conflictResolutionStrategy =
|
||||
(ResourceVersionConflictResolutionStrategy)
|
||||
CompositeInterceptorBroadcaster.doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster,
|
||||
theExecutionBuilder.myRequestDetails,
|
||||
Pointcut.STORAGE_VERSION_CONFLICT,
|
||||
params);
|
||||
compositeBroadcaster.callHooksAndReturnObject(
|
||||
Pointcut.STORAGE_VERSION_CONFLICT, params);
|
||||
if (conflictResolutionStrategy != null && conflictResolutionStrategy.isRetry()) {
|
||||
maxRetries = conflictResolutionStrategy.getMaxRetries();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (i < maxRetries) {
|
||||
if (theExecutionBuilder.myTransactionDetails != null) {
|
||||
|
|
|
@ -34,12 +34,11 @@ import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
@ -48,12 +47,7 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster.doCallHooks;
|
||||
import static ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster.doCallHooksAndReturnObject;
|
||||
import static ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster.hasHooks;
|
||||
|
||||
public abstract class BaseRequestPartitionHelperSvc implements IRequestPartitionHelperSvc {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseRequestPartitionHelperSvc.class);
|
||||
|
||||
private final HashSet<Object> myNonPartitionableResourceNames;
|
||||
|
||||
|
@ -124,21 +118,25 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
|
|||
requestPartitionId = getSystemRequestPartitionId((SystemRequestDetails) requestDetails, false);
|
||||
} else if ((requestDetails instanceof SystemRequestDetails) && nonPartitionableResource) {
|
||||
requestPartitionId = RequestPartitionId.fromPartitionId(myPartitionSettings.getDefaultPartitionId());
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, myInterceptorBroadcaster, requestDetails)) {
|
||||
} else {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, requestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, requestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, requestDetails);
|
||||
requestPartitionId = (RequestPartitionId) doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, requestDetails, Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_READ, myInterceptorBroadcaster, requestDetails)) {
|
||||
requestPartitionId = (RequestPartitionId)
|
||||
compositeBroadcaster.callHooksAndReturnObject(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
} else if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_READ)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_READ
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, requestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, requestDetails)
|
||||
.add(ReadPartitionIdRequestDetails.class, theDetails);
|
||||
requestPartitionId = (RequestPartitionId) doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, requestDetails, Pointcut.STORAGE_PARTITION_IDENTIFY_READ, params);
|
||||
requestPartitionId = (RequestPartitionId)
|
||||
compositeBroadcaster.callHooksAndReturnObject(Pointcut.STORAGE_PARTITION_IDENTIFY_READ, params);
|
||||
}
|
||||
}
|
||||
|
||||
validateRequestPartitionNotNull(
|
||||
|
@ -158,13 +156,17 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
|
|||
if (theRequestDetails instanceof SystemRequestDetails
|
||||
&& systemRequestHasExplicitPartition((SystemRequestDetails) theRequestDetails)) {
|
||||
requestPartitionId = getSystemRequestPartitionId((SystemRequestDetails) theRequestDetails);
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, myInterceptorBroadcaster, theRequestDetails)) {
|
||||
} else {
|
||||
IInterceptorBroadcaster compositeBroadcaster = CompositeInterceptorBroadcaster.newCompositeBroadcaster(
|
||||
myInterceptorBroadcaster, theRequestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, theRequestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||
requestPartitionId = (RequestPartitionId) doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, theRequestDetails, Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
requestPartitionId = (RequestPartitionId)
|
||||
compositeBroadcaster.callHooksAndReturnObject(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO MM: at the moment it is ok for this method to return null
|
||||
|
@ -244,21 +246,25 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
|
|||
&& systemRequestHasExplicitPartition((SystemRequestDetails) theRequest)) {
|
||||
requestPartitionId =
|
||||
getSystemRequestPartitionId((SystemRequestDetails) theRequest, nonPartitionableResource);
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, myInterceptorBroadcaster, requestDetails)) {
|
||||
} else {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, requestDetails);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_ANY
|
||||
HookParams params = new HookParams()
|
||||
.add(RequestDetails.class, requestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, requestDetails);
|
||||
requestPartitionId = (RequestPartitionId) doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, requestDetails, Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
} else if (hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE, myInterceptorBroadcaster, requestDetails)) {
|
||||
requestPartitionId = (RequestPartitionId)
|
||||
compositeBroadcaster.callHooksAndReturnObject(Pointcut.STORAGE_PARTITION_IDENTIFY_ANY, params);
|
||||
} else if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE)) {
|
||||
// Interceptor call: STORAGE_PARTITION_IDENTIFY_CREATE
|
||||
HookParams params = new HookParams()
|
||||
.add(IBaseResource.class, theResource)
|
||||
.add(RequestDetails.class, requestDetails)
|
||||
.addIfMatchesType(ServletRequestDetails.class, requestDetails);
|
||||
requestPartitionId = (RequestPartitionId) doCallHooksAndReturnObject(
|
||||
myInterceptorBroadcaster, requestDetails, Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE, params);
|
||||
requestPartitionId = (RequestPartitionId) compositeBroadcaster.callHooksAndReturnObject(
|
||||
Pointcut.STORAGE_PARTITION_IDENTIFY_CREATE, params);
|
||||
}
|
||||
}
|
||||
|
||||
// If the interceptors haven't selected a partition, and its a non-partitionable resource anyhow, send
|
||||
|
@ -322,7 +328,9 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
|
|||
@Override
|
||||
public void validateHasPartitionPermissions(
|
||||
@Nonnull RequestDetails theRequest, String theResourceType, RequestPartitionId theRequestPartitionId) {
|
||||
if (myInterceptorBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_SELECTED)) {
|
||||
IInterceptorBroadcaster compositeBroadcaster =
|
||||
CompositeInterceptorBroadcaster.newCompositeBroadcaster(myInterceptorBroadcaster, theRequest);
|
||||
if (compositeBroadcaster.hasHooks(Pointcut.STORAGE_PARTITION_SELECTED)) {
|
||||
RuntimeResourceDefinition runtimeResourceDefinition = null;
|
||||
if (theResourceType != null) {
|
||||
runtimeResourceDefinition = myFhirContext.getResourceDefinition(theResourceType);
|
||||
|
@ -332,7 +340,7 @@ public abstract class BaseRequestPartitionHelperSvc implements IRequestPartition
|
|||
.add(RequestDetails.class, theRequest)
|
||||
.addIfMatchesType(ServletRequestDetails.class, theRequest)
|
||||
.add(RuntimeResourceDefinition.class, runtimeResourceDefinition);
|
||||
doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PARTITION_SELECTED, params);
|
||||
compositeBroadcaster.callHooks(Pointcut.STORAGE_PARTITION_SELECTED, params);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.api.server.RequestDetails;
|
|||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.test.utilities.MockInvoker;
|
||||
import ca.uhn.fhir.util.SleepUtil;
|
||||
import org.hibernate.exception.ConstraintViolationException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
|
@ -80,17 +81,15 @@ class HapiTransactionServiceTest {
|
|||
}
|
||||
|
||||
private void mockInterceptorBroadcaster() {
|
||||
lenient().when(myInterceptorBroadcasterMock.callHooksAndReturnObject(eq(Pointcut.STORAGE_VERSION_CONFLICT),
|
||||
isA(HookParams.class)))
|
||||
.thenAnswer(invocationOnMock -> {
|
||||
HookParams hookParams = (HookParams) invocationOnMock.getArguments()[1];
|
||||
lenient().when(myInterceptorBroadcasterMock.hasHooks(eq(Pointcut.STORAGE_VERSION_CONFLICT))).thenReturn(true);
|
||||
lenient().when(myInterceptorBroadcasterMock.getInvokersForPointcut(eq(Pointcut.STORAGE_VERSION_CONFLICT))).thenReturn(MockInvoker.list(hookParams->{
|
||||
//answer with whatever retry settings passed in as HookParam
|
||||
RequestDetails requestDetails = hookParams.get(RequestDetails.class);
|
||||
ResourceVersionConflictResolutionStrategy answer = new ResourceVersionConflictResolutionStrategy();
|
||||
answer.setRetry(requestDetails.isRetry());
|
||||
answer.setMaxRetries(requestDetails.getMaxRetries());
|
||||
return answer;
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
package ca.uhn.fhir.test.utilities;
|
||||
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.IBaseInterceptorBroadcaster;
|
||||
import jakarta.annotation.Nonnull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
|
||||
public class MockInvoker implements IBaseInterceptorBroadcaster.IInvoker {
|
||||
|
||||
private final Function<HookParams, Object> myFunction;
|
||||
|
||||
private MockInvoker(Consumer<HookParams> theRunnable) {
|
||||
this(param -> { theRunnable.accept(param); return null; });
|
||||
}
|
||||
|
||||
private MockInvoker(Function<HookParams, Object> theFunction) {
|
||||
myFunction = theFunction;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object invoke(HookParams theParams) {
|
||||
return myFunction.apply(theParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getInterceptor() {
|
||||
return new Object();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(@Nonnull IBaseInterceptorBroadcaster.IInvoker o) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static List<IBaseInterceptorBroadcaster.IInvoker> list(Consumer<HookParams> theRunnable) {
|
||||
return List.of(new MockInvoker(theRunnable));
|
||||
}
|
||||
|
||||
public static List<IBaseInterceptorBroadcaster.IInvoker> list(Function<HookParams, Object> theRunnable) {
|
||||
return List.of(new MockInvoker(theRunnable));
|
||||
}
|
||||
|
||||
}
|
|
@ -84,9 +84,14 @@ public interface IValidationProviders {
|
|||
protected void addTerminologyResource(String theUrl, T theResource) {
|
||||
myTerminologyResourceMap.put(theUrl, theResource);
|
||||
}
|
||||
protected void addVersionedTerminologyResource(String theUrl, String theVersion, T theResource) {
|
||||
myTerminologyResourceMap.put(theUrl + "|" + theVersion, theResource);
|
||||
}
|
||||
|
||||
public abstract T addTerminologyResource(String theUrl);
|
||||
|
||||
public abstract T addTerminologyResource(String theUrl, String theVersion);
|
||||
|
||||
protected IBaseParameters getTerminologyResponse(String theOperation, String theUrl, String theCode) throws Exception {
|
||||
String inputKey = getInputKey(theOperation, theUrl, theCode);
|
||||
if (myExceptionMap.containsKey(inputKey)) {
|
||||
|
|
|
@ -95,6 +95,11 @@ public interface IValidationProvidersDstu3 {
|
|||
addTerminologyResource(theUrl, codeSystem);
|
||||
return codeSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem addTerminologyResource(String theUrl, String theVersion) {
|
||||
return addTerminologyResource(theUrl);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -133,5 +138,10 @@ public interface IValidationProvidersDstu3 {
|
|||
addTerminologyResource(theUrl, valueSet);
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet addTerminologyResource(String theUrl, String theVersion) {
|
||||
return addTerminologyResource(theUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,14 @@ public interface IValidationProvidersR4 {
|
|||
addTerminologyResource(theUrl, codeSystem);
|
||||
return codeSystem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem addTerminologyResource(String theUrl, String theVersion) {
|
||||
CodeSystem codeSystem = addTerminologyResource(theUrl);
|
||||
codeSystem.setVersion(theVersion);
|
||||
addVersionedTerminologyResource(theUrl, theVersion, codeSystem);
|
||||
return codeSystem;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -130,6 +138,7 @@ public interface IValidationProvidersR4 {
|
|||
Class<Parameters> getParameterType() {
|
||||
return Parameters.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet addTerminologyResource(String theUrl) {
|
||||
ValueSet valueSet = new ValueSet();
|
||||
|
@ -138,5 +147,12 @@ public interface IValidationProvidersR4 {
|
|||
addTerminologyResource(theUrl, valueSet);
|
||||
return valueSet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet addTerminologyResource(String theUrl, String theVersion) {
|
||||
ValueSet valueSet = addTerminologyResource(theUrl);
|
||||
addVersionedTerminologyResource(theUrl, theVersion, valueSet);
|
||||
return valueSet;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -297,7 +297,7 @@ public class BaseController {
|
|||
FhirVersionEnum version = theRequest.getFhirVersion(myConfig);
|
||||
VersionCanonicalizer retVal = myCanonicalizers.get(version);
|
||||
if (retVal == null) {
|
||||
retVal = new VersionCanonicalizer(version.newContext());
|
||||
retVal = new VersionCanonicalizer(FhirContext.forVersion(version));
|
||||
myCanonicalizers.put(version, retVal);
|
||||
}
|
||||
return retVal;
|
||||
|
|
|
@ -12,6 +12,7 @@ import ca.uhn.fhir.system.HapiSystemProperties;
|
|||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||
import jakarta.annotation.Nonnull;
|
||||
import jakarta.annotation.Nullable;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.EqualsBuilder;
|
||||
import org.apache.commons.lang3.builder.HashCodeBuilder;
|
||||
|
@ -466,18 +467,11 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
|
|||
return null;
|
||||
}
|
||||
|
||||
String uri = theUri;
|
||||
// handle profile version, if present
|
||||
if (theUri.contains("|")) {
|
||||
String[] parts = theUri.split("\\|");
|
||||
if (parts.length == 2) {
|
||||
uri = parts[0];
|
||||
} else {
|
||||
if (StringUtils.countMatches(theUri, "|") > 1) {
|
||||
ourLog.warn("Unrecognized profile uri: {}", theUri);
|
||||
}
|
||||
}
|
||||
|
||||
ResourceKey key = new ResourceKey(class_.getSimpleName(), uri);
|
||||
ResourceKey key = new ResourceKey(class_.getSimpleName(), theUri);
|
||||
@SuppressWarnings("unchecked")
|
||||
T retVal = (T) myFetchResourceCache.get(key);
|
||||
|
||||
|
|
Loading…
Reference in New Issue