* ca.uhn.fhir.rest.api.RestOperationTypeEnum - The type of operation that the FHIR server has determined that the client is trying to invoke
*
- *
- * ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails - This parameter is provided for legacy reasons only and will be removed in the future. Do not use.
- *
*
*
*
@@ -360,8 +357,7 @@ public enum Pointcut implements IPointcut {
SERVER_INCOMING_REQUEST_PRE_HANDLED(void.class,
"ca.uhn.fhir.rest.api.server.RequestDetails",
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails",
- "ca.uhn.fhir.rest.api.RestOperationTypeEnum",
- "ca.uhn.fhir.rest.server.interceptor.IServerInterceptor$ActionRequestDetails"
+ "ca.uhn.fhir.rest.api.RestOperationTypeEnum"
),
diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
index c93dabab28f..47384a87f58 100644
--- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
+++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java
@@ -62,47 +62,25 @@ public class UrlUtil {
private static final String URL_FORM_PARAMETER_OTHER_SAFE_CHARS = "-_.*";
private static final Escaper PARAMETER_ESCAPER = new PercentEscaper(URL_FORM_PARAMETER_OTHER_SAFE_CHARS, false);
- public static String sanitizeBaseUrl(String theBaseUrl) {
- return theBaseUrl.replaceAll("[^a-zA-Z0-9:/._-]", "");
+ /**
+ * Non instantiable
+ */
+ private UrlUtil() {
}
- public static class UrlParts {
- private String myParams;
- private String myResourceId;
- private String myResourceType;
- private String myVersionId;
+ /**
+ * Cleans up a value that will be serialized as an HTTP header. This method:
+ *
+ * - Strips any newline (\r or \n) characters
+ *
+ * @since 6.2.0
+ */
+ public static String sanitizeHeaderValue(String theHeader) {
+ return theHeader.replace("\n", "").replace("\r", "");
+ }
- public String getParams() {
- return myParams;
- }
-
- public void setParams(String theParams) {
- myParams = theParams;
- }
-
- public String getResourceId() {
- return myResourceId;
- }
-
- public void setResourceId(String theResourceId) {
- myResourceId = theResourceId;
- }
-
- public String getResourceType() {
- return myResourceType;
- }
-
- public void setResourceType(String theResourceType) {
- myResourceType = theResourceType;
- }
-
- public String getVersionId() {
- return myVersionId;
- }
-
- public void setVersionId(String theVersionId) {
- myVersionId = theVersionId;
- }
+ public static String sanitizeBaseUrl(String theBaseUrl) {
+ return theBaseUrl.replaceAll("[^a-zA-Z0-9:/._-]", "");
}
/**
@@ -186,7 +164,6 @@ public class UrlUtil {
.collect(Collectors.toList());
}
-
public static boolean isAbsolute(String theValue) {
String value = theValue.toLowerCase();
return value.startsWith("http://") || value.startsWith("https://");
@@ -570,4 +547,43 @@ public class UrlUtil {
return parameters;
}
+
+ public static class UrlParts {
+ private String myParams;
+ private String myResourceId;
+ private String myResourceType;
+ private String myVersionId;
+
+ public String getParams() {
+ return myParams;
+ }
+
+ public void setParams(String theParams) {
+ myParams = theParams;
+ }
+
+ public String getResourceId() {
+ return myResourceId;
+ }
+
+ public void setResourceId(String theResourceId) {
+ myResourceId = theResourceId;
+ }
+
+ public String getResourceType() {
+ return myResourceType;
+ }
+
+ public void setResourceType(String theResourceType) {
+ myResourceType = theResourceType;
+ }
+
+ public String getVersionId() {
+ return myVersionId;
+ }
+
+ public void setVersionId(String theVersionId) {
+ myVersionId = theVersionId;
+ }
+ }
}
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-drop-actionrequestdetails.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-drop-actionrequestdetails.yaml
new file mode 100644
index 00000000000..e78fddcea17
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-drop-actionrequestdetails.yaml
@@ -0,0 +1,12 @@
+---
+type: remove
+issue: 3527
+title: "The `ActionRequestDetails` class has been dropped (it has been deprecated
+ since HAPI FHIR 4.0.0). This class was used as a parameter to the
+ `SERVER_INCOMING_REQUEST_PRE_HANDLED` interceptor pointcut, but can be
+ replaced in any existing client code with `RequestDetails`. This change
+ also removes an undocumented behaviour where the JPA server internally
+ invoked the `SERVER_INCOMING_REQUEST_PRE_HANDLED` a second time from
+ within various processing methods. This behaviour caused performance
+ problems for some interceptors (e.g. `SearchNarrowingInterceptor`) and
+ no longer offers any benefit so it is being removed."
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-searchnarrowinginterceptor-and-batch-perf-issue.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-searchnarrowinginterceptor-and-batch-perf-issue.yaml
new file mode 100644
index 00000000000..14aeeb9149d
--- /dev/null
+++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/3527-searchnarrowinginterceptor-and-batch-perf-issue.yaml
@@ -0,0 +1,6 @@
+---
+type: perf
+issue: 3527
+title: "When using SearchNarrowingInterceptor, FHIR batch operations with a large number
+ of conditional create/update entries exhibited very slow performance due to an
+ unnecessary nested loop. This has been corrected."
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
index 52565ce2cb3..ef1110fe13f 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
@@ -82,7 +82,6 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
import ca.uhn.fhir.rest.server.util.ResourceSearchParams;
@@ -224,28 +223,18 @@ public abstract class BaseHapiFhirDao extends BaseStora
@Autowired
ExpungeService myExpungeService;
@Autowired
- private HistoryBuilderFactory myHistoryBuilderFactory;
- @Autowired
private DaoConfig myConfig;
@Autowired
- private PlatformTransactionManager myPlatformTransactionManager;
- @Autowired
- private ISearchCacheSvc mySearchCacheSvc;
- @Autowired
private ISearchParamPresenceSvc mySearchParamPresenceSvc;
@Autowired
private SearchParamWithInlineReferencesExtractor mySearchParamWithInlineReferencesExtractor;
@Autowired
private DaoSearchParamSynchronizer myDaoSearchParamSynchronizer;
- @Autowired
- private SearchBuilderFactory mySearchBuilderFactory;
private FhirContext myContext;
private ApplicationContext myApplicationContext;
@Autowired
private PartitionSettings myPartitionSettings;
@Autowired
- private RequestPartitionHelperSvc myRequestPartitionHelperSvc;
- @Autowired
private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
@Autowired
private IPartitionLookupSvc myPartitionLookupSvc;
@@ -272,7 +261,7 @@ public abstract class BaseHapiFhirDao extends BaseStora
}
@Override
- public void setApplicationContext(ApplicationContext theApplicationContext) throws BeansException {
+ public void setApplicationContext(@Nonnull ApplicationContext theApplicationContext) throws BeansException {
/*
* We do a null check here because Smile's module system tries to
* initialize the application context twice if two modules depend on
@@ -363,9 +352,7 @@ public abstract class BaseHapiFhirDao extends BaseStora
private Set getAllTagDefinitions(ResourceTable theEntity) {
HashSet retVal = Sets.newHashSet();
if (theEntity.isHasTags()) {
- for (ResourceTag next : theEntity.getTags()) {
- retVal.add(next);
- }
+ retVal.addAll(theEntity.getTags());
}
return retVal;
}
@@ -1505,9 +1492,6 @@ public abstract class BaseHapiFhirDao extends BaseStora
oldResource = toResource(entity, false);
}
- if (theRequest.getServer() != null) {
- ActionRequestDetails actionRequestDetails = new ActionRequestDetails(theRequest, theResource, theResourceId.getResourceType(), theResourceId);
- }
notifyInterceptors(theRequest, theResource, oldResource, theTransactionDetails, true);
ResourceTable savedEntity = updateEntity(theRequest, theResource, entity, null, true, false, theTransactionDetails, false, false);
@@ -1684,13 +1668,6 @@ public abstract class BaseHapiFhirDao extends BaseStora
// now at least set it to something useful for the interceptors
theResource.setId(entity.getIdDt());
- // Notify interceptors
- ActionRequestDetails requestDetails;
- if (theRequestDetails != null && theRequestDetails.getServer() != null) {
- requestDetails = new ActionRequestDetails(theRequestDetails, theResource, theResourceId.getResourceType(), theResourceId);
- notifyInterceptors(RestOperationTypeEnum.UPDATE, requestDetails);
- }
-
// Notify IServerOperationInterceptors about pre-action call
notifyInterceptors(theRequestDetails, theResource, theOldResource, theTransactionDetails, true);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
index 683c18499ab..4701343427b 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java
@@ -99,7 +99,6 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
import ca.uhn.fhir.util.ObjectUtil;
@@ -126,7 +125,7 @@ import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
-import org.springframework.transaction.support.TransactionSynchronizationAdapter;
+import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.transaction.support.TransactionTemplate;
@@ -155,9 +154,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseHapiFhirResourceDao extends BaseHapiFhirDao implements IFhirResourceDao {
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
public static final String BASE_RESOURCE_NAME = "resource";
-
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class);
@Autowired
protected PlatformTransactionManager myPlatformTransactionManager;
@Autowired(required = false)
@@ -309,12 +307,6 @@ public abstract class BaseHapiFhirResourceDao extends B
}
}
- // Notify interceptors
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), theResource);
- notifyInterceptors(RestOperationTypeEnum.CREATE, requestDetails);
- }
-
String resourceIdBeforeStorage = theResource.getIdElement().getIdPart();
boolean resourceHadIdBeforeStorage = isNotBlank(resourceIdBeforeStorage);
boolean resourceIdWasServerAssigned = theResource.getUserData(JpaConstants.RESOURCE_ID_SERVER_ASSIGNED) == Boolean.TRUE;
@@ -584,12 +576,6 @@ public abstract class BaseHapiFhirResourceDao extends B
preDelete(resourceToDelete, entity, theRequestDetails);
- // Notify interceptors
- if (theRequestDetails != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getContext(), theId.getResourceType(), theId);
- notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
- }
-
ResourceTable savedEntity = updateEntityForDelete(theRequestDetails, theTransactionDetails, entity);
resourceToDelete.setId(entity.getIdDt());
@@ -704,20 +690,13 @@ public abstract class BaseHapiFhirResourceDao extends B
myDeleteConflictService.validateOkToDelete(theDeleteConflicts, entity, false, theRequest, transactionDetails);
- // Notify interceptors
- IdDt idToDelete = entity.getIdDt();
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, idToDelete.getResourceType(), idToDelete);
- notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
- }
-
// Perform delete
updateEntityForDelete(theRequest, transactionDetails, entity);
resourceToDelete.setId(entity.getIdDt());
// Notify JPA interceptors
- TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
+ TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
@Override
public void beforeCommit(boolean readOnly) {
HookParams hookParams = new HookParams()
@@ -937,10 +916,6 @@ public abstract class BaseHapiFhirResourceDao extends B
@Override
@Transactional
public IBundleProvider history(Date theSince, Date theUntil, Integer theOffset, RequestDetails theRequestDetails) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.HISTORY_TYPE, requestDetails);
-
StopWatch w = new StopWatch();
IBundleProvider retVal = super.history(theRequestDetails, myResourceName, null, theSince, theUntil, theOffset);
ourLog.debug("Processed history on {} in {}ms", myResourceName, w.getMillisAndRestart());
@@ -950,12 +925,6 @@ public abstract class BaseHapiFhirResourceDao extends B
@Override
@Transactional
public IBundleProvider history(final IIdType theId, final Date theSince, Date theUntil, Integer theOffset, RequestDetails theRequest) {
- if (theRequest != null) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theId);
- notifyInterceptors(RestOperationTypeEnum.HISTORY_INSTANCE, requestDetails);
- }
-
StopWatch w = new StopWatch();
IIdType id = theId.withResourceType(myResourceName).toUnqualifiedVersionless();
@@ -990,7 +959,7 @@ public abstract class BaseHapiFhirResourceDao extends B
addAllResourcesTypesToReindex(theBase, theRequestDetails, params);
}
- ReadPartitionIdRequestDetails details= new ReadPartitionIdRequestDetails(null, RestOperationTypeEnum.EXTENDED_OPERATION_SERVER, null, null, null);
+ ReadPartitionIdRequestDetails details = new ReadPartitionIdRequestDetails(null, RestOperationTypeEnum.EXTENDED_OPERATION_SERVER, null, null, null);
RequestPartitionId requestPartition = myRequestPartitionHelperService.determineReadPartitionForRequest(theRequestDetails, null, details);
params.setRequestPartitionId(requestPartition);
@@ -1034,12 +1003,6 @@ public abstract class BaseHapiFhirResourceDao extends B
public MT metaAddOperation(IIdType theResourceId, MT theMetaAdd, RequestDetails theRequest) {
TransactionDetails transactionDetails = new TransactionDetails();
- // Notify interceptors
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theResourceId);
- notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails);
- }
-
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theResourceId, theRequest);
if (entity == null) {
@@ -1069,12 +1032,6 @@ public abstract class BaseHapiFhirResourceDao extends B
public MT metaDeleteOperation(IIdType theResourceId, MT theMetaDel, RequestDetails theRequest) {
TransactionDetails transactionDetails = new TransactionDetails();
- // Notify interceptors
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theResourceId);
- notifyInterceptors(RestOperationTypeEnum.META_DELETE, requestDetails);
- }
-
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theResourceId, theRequest);
if (entity == null) {
@@ -1102,12 +1059,6 @@ public abstract class BaseHapiFhirResourceDao extends B
@Override
@Transactional
public MT metaGetOperation(Class theType, IIdType theId, RequestDetails theRequest) {
- // Notify interceptors
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theId);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
- }
-
Set tagDefs = new HashSet<>();
BaseHasResource entity = readEntity(theId, theRequest);
for (BaseTag next : entity.getTags()) {
@@ -1124,12 +1075,6 @@ public abstract class BaseHapiFhirResourceDao extends B
@Override
@Transactional
public MT metaGetOperation(Class theType, RequestDetails theRequestDetails) {
- // Notify interceptors
- if (theRequestDetails != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, getResourceName(), null);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
- }
-
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t WHERE t.myResourceType = :res_type)";
TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class);
q.setParameter("res_type", myResourceName);
@@ -1273,13 +1218,6 @@ public abstract class BaseHapiFhirResourceDao extends B
public T doRead(IIdType theId, RequestDetails theRequest, boolean theDeletedOk) {
assert TransactionSynchronizationManager.isActualTransactionActive();
- // Notify interceptors
- if (theRequest != null && theRequest.getServer() != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theId);
- RestOperationTypeEnum operationType = theId.hasVersionIdPart() ? RestOperationTypeEnum.VREAD : RestOperationTypeEnum.READ;
- notifyInterceptors(operationType, requestDetails);
- }
-
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId, theRequest);
validateResourceType(entity);
@@ -1485,12 +1423,6 @@ public abstract class BaseHapiFhirResourceDao extends B
@Transactional
@Override
public void removeTag(IIdType theId, TagTypeEnum theTagType, String theScheme, String theTerm, RequestDetails theRequest) {
- // Notify interceptors
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getResourceName(), theId);
- notifyInterceptors(RestOperationTypeEnum.DELETE_TAGS, requestDetails);
- }
-
StopWatch w = new StopWatch();
BaseHasResource entity = readEntity(theId, theRequest);
if (entity == null) {
@@ -1537,7 +1469,7 @@ public abstract class BaseHapiFhirResourceDao extends B
if (theParams.getSearchContainedMode() != SearchContainedModeEnum.FALSE && !myModelConfig.isIndexOnContainedResources()) {
throw new MethodNotAllowedException(Msg.code(984) + "Searching with _contained mode enabled is not enabled on this server");
}
-
+
translateListSearchParams(theParams);
notifySearchInterceptors(theParams, theRequest);
@@ -1587,8 +1519,6 @@ public abstract class BaseHapiFhirResourceDao extends B
private void notifySearchInterceptors(SearchParameterMap theParams, RequestDetails theRequest) {
if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), getResourceName(), null);
- notifyInterceptors(RestOperationTypeEnum.SEARCH_TYPE, requestDetails);
if (theRequest.isSubRequest()) {
Integer max = getConfig().getMaximumSearchResultCountInTransaction();
@@ -1928,11 +1858,6 @@ public abstract class BaseHapiFhirResourceDao extends B
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequest) {
TransactionDetails transactionDetails = new TransactionDetails();
- if (theRequest != null) {
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, theResource, null, theId);
- notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
- }
-
if (theMode == ValidationModeEnum.DELETE) {
if (theId == null || theId.hasIdPart() == false) {
throw new InvalidRequestException(Msg.code(991) + "No ID supplied. ID is required when validating with mode=DELETE");
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
index 29a22be18a9..78739652c06 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirSystemDao.java
@@ -10,12 +10,10 @@ import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
import ca.uhn.fhir.jpa.util.QueryChunker;
import ca.uhn.fhir.jpa.util.ResourceCountCache;
-import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.StopWatch;
import com.google.common.annotations.VisibleForTesting;
import org.hl7.fhir.instance.model.api.IBaseBundle;
@@ -62,8 +60,8 @@ import java.util.stream.Collectors;
public abstract class BaseHapiFhirSystemDao extends BaseHapiFhirDao implements IFhirSystemDao {
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirSystemDao.class);
public static final Predicate[] EMPTY_PREDICATE_ARRAY = new Predicate[0];
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirSystemDao.class);
public ResourceCountCache myResourceCountsCache;
@Autowired
private TransactionProcessor myTransactionProcessor;
@@ -125,12 +123,6 @@ public abstract class BaseHapiFhirSystemDao extends B
@Override
public IBundleProvider history(Date theSince, Date theUntil, Integer theOffset, RequestDetails theRequestDetails) {
- if (theRequestDetails != null) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.HISTORY_SYSTEM, requestDetails);
- }
-
StopWatch w = new StopWatch();
IBundleProvider retVal = super.history(theRequestDetails, null, null, theSince, theUntil, theOffset);
ourLog.info("Processed global history in {}ms", w.getMillisAndRestart());
@@ -242,8 +234,6 @@ public abstract class BaseHapiFhirSystemDao extends B
});
-
-
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java
index 2089189c0f5..09154a3d98a 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoPatientDstu2.java
@@ -31,12 +31,13 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.rest.api.CacheControlDirective;
import ca.uhn.fhir.rest.api.Constants;
-import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.param.*;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
+import ca.uhn.fhir.rest.param.DateRangeParam;
+import ca.uhn.fhir.rest.param.StringAndListParam;
+import ca.uhn.fhir.rest.param.TokenOrListParam;
+import ca.uhn.fhir.rest.param.TokenParam;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
@@ -91,9 +92,6 @@ public class FhirResourceDaoPatientDstu2 extends BaseHapiFhirResourceDao {
@Override
public MetaDt metaGetOperation(RequestDetails theRequestDetails) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
-
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class);
List tagDefinitions = q.getResultList();
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
index 5b744599551..a0c96b07e38 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/dstu3/FhirSystemDaoDstu3.java
@@ -25,7 +25,6 @@ import ca.uhn.fhir.jpa.dao.FhirResourceDaoMessageHeaderDstu2;
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.instance.model.api.IBaseBundle;
@@ -45,10 +44,6 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao {
@Override
public Meta metaGetOperation(RequestDetails theRequestDetails) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
-
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class);
List tagDefinitions = q.getResultList();
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
index 5c03e4cc620..d7f9596b02f 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r4/FhirSystemDaoR4.java
@@ -23,9 +23,7 @@ package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoMessageHeaderDstu2;
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
-import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Meta;
@@ -38,10 +36,6 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao {
@Override
public Meta metaGetOperation(RequestDetails theRequestDetails) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
-
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class);
List tagDefinitions = q.getResultList();
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirSystemDaoR5.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirSystemDaoR5.java
index 385533a81f7..eb7ffa901fe 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirSystemDaoR5.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/r5/FhirSystemDaoR5.java
@@ -23,9 +23,7 @@ package ca.uhn.fhir.jpa.dao.r5;
import ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoMessageHeaderDstu2;
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
-import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.server.RequestDetails;
-import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import org.hl7.fhir.instance.model.api.IBaseBundle;
import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r5.model.Meta;
@@ -40,10 +38,6 @@ public class FhirSystemDaoR5 extends BaseHapiFhirSystemDao {
@Override
public Meta metaGetOperation(RequestDetails theRequestDetails) {
- // Notify interceptors
- ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
- notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
-
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
TypedQuery q = myEntityManager.createQuery(sql, TagDefinition.class);
List tagDefinitions = q.getResultList();
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderInterceptorR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderInterceptorR4Test.java
index 6fcc54e3735..dc951b067f7 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderInterceptorR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderInterceptorR4Test.java
@@ -224,8 +224,8 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
transaction(bundle);
- verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(2)).invoke(eq(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED), myParamsCaptor.capture());
- assertEquals(RestOperationTypeEnum.CREATE, myParamsCaptor.getValue().get(RestOperationTypeEnum.class));
+ verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(1)).invoke(eq(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED), myParamsCaptor.capture());
+ assertEquals(RestOperationTypeEnum.TRANSACTION, myParamsCaptor.getValue().get(RestOperationTypeEnum.class));
verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(1)).invoke(eq(Pointcut.SERVER_INCOMING_REQUEST_POST_PROCESSED), myParamsCaptor.capture());
verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(1)).invoke(eq(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED), myParamsCaptor.capture());
@@ -326,9 +326,8 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
entry.getRequest().setIfNoneExist("Patient?name=" + methodName);
transaction(bundle);
- verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(2)).invoke(eq(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED), myParamsCaptor.capture());
+ verify(interceptor, timeout(10 * MILLIS_PER_SECOND).times(1)).invoke(eq(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED), myParamsCaptor.capture());
assertEquals(RestOperationTypeEnum.TRANSACTION, myParamsCaptor.getAllValues().get(0).get(RestOperationTypeEnum.class));
- assertEquals(RestOperationTypeEnum.UPDATE, myParamsCaptor.getAllValues().get(1).get(RestOperationTypeEnum.class));
verify(interceptor, times(0)).invoke(eq(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED), any());
verify(interceptor, times(0)).invoke(eq(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED), any());
diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/SystemProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/SystemProviderR4Test.java
index 43c3706f566..45c8f85de09 100644
--- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/SystemProviderR4Test.java
+++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/SystemProviderR4Test.java
@@ -4,6 +4,9 @@ import ca.uhn.fhir.batch2.jobs.expunge.DeleteExpungeProvider;
import ca.uhn.fhir.context.FhirContext;
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.IAnonymousInterceptor;
+import ca.uhn.fhir.interceptor.api.IPointcut;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.rp.r4.BinaryResourceProvider;
@@ -13,6 +16,7 @@ import ca.uhn.fhir.jpa.rp.r4.ObservationResourceProvider;
import ca.uhn.fhir.jpa.rp.r4.OrganizationResourceProvider;
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
import ca.uhn.fhir.jpa.rp.r4.PractitionerResourceProvider;
+import ca.uhn.fhir.jpa.rp.r4.PractitionerRoleResourceProvider;
import ca.uhn.fhir.jpa.rp.r4.ServiceRequestResourceProvider;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
@@ -21,6 +25,7 @@ import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
@@ -31,6 +36,8 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
+import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizedList;
+import ca.uhn.fhir.rest.server.interceptor.auth.SearchNarrowingInterceptor;
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
import ca.uhn.fhir.test.utilities.BatchJobHelper;
import ca.uhn.fhir.test.utilities.JettyUtil;
@@ -58,6 +65,7 @@ import org.hl7.fhir.r4.hapi.rest.server.helper.BatchHelperR4;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleType;
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
+import org.hl7.fhir.r4.model.CapabilityStatement;
import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.DecimalType;
import org.hl7.fhir.r4.model.DiagnosticReport;
@@ -69,12 +77,15 @@ import org.hl7.fhir.r4.model.OperationOutcome;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
+import org.hl7.fhir.r4.model.Practitioner;
import org.hl7.fhir.r4.model.Reference;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import java.io.IOException;
@@ -83,6 +94,7 @@ import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.containsString;
@@ -117,6 +129,8 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
myDaoConfig.setDeleteExpungeEnabled(new DaoConfig().isDeleteExpungeEnabled());
+ myDaoConfig.setAutoCreatePlaceholderReferenceTargets(new DaoConfig().isAutoCreatePlaceholderReferenceTargets());
+ myDaoConfig.setPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets(new DaoConfig().isPopulateIdentifierInAutoCreatedPlaceholderReferenceTargets());
}
@BeforeEach
@@ -144,11 +158,15 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
diagnosticReportRp.setDao(myDiagnosticReportDao);
ServiceRequestResourceProvider diagnosticOrderRp = new ServiceRequestResourceProvider();
diagnosticOrderRp.setDao(myServiceRequestDao);
+
PractitionerResourceProvider practitionerRp = new PractitionerResourceProvider();
practitionerRp.setDao(myPractitionerDao);
+ PractitionerRoleResourceProvider practitionerRoleRp = new PractitionerRoleResourceProvider();
+ practitionerRoleRp.setDao(myPractitionerRoleDao);
+
RestfulServer restServer = new RestfulServer(ourCtx);
- restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp, locationRp, binaryRp, diagnosticReportRp, diagnosticOrderRp, practitionerRp);
+ restServer.setResourceProviders(patientRp, questionnaireRp, observationRp, organizationRp, locationRp, binaryRp, diagnosticReportRp, diagnosticOrderRp, practitionerRp, practitionerRoleRp);
restServer.registerProviders(mySystemProvider, myDeleteExpungeProvider);
@@ -490,6 +508,78 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
}
+ /**
+ * Ensure that the interceptor is called an appropriate number of times
+ */
+ @Test
+ public void testBatchWithMultipleConditionalCreates() {
+
+ AtomicInteger counter0 = new AtomicInteger(0);
+ AtomicInteger counter1 = new AtomicInteger(0);
+ AtomicInteger counter2 = new AtomicInteger(0);
+
+ class MyAnonymousInterceptor0 implements IAnonymousInterceptor {
+
+ @Override
+ public void invoke(IPointcut thePointcut, HookParams theArgs) {
+ int count = counter0.incrementAndGet();
+ ourLog.info("counter0 have been called {} times", count);
+ }
+ }
+
+ class MyAnonymousInterceptor1 implements IAnonymousInterceptor {
+
+ @Override
+ public void invoke(IPointcut thePointcut, HookParams theArgs) {
+ int count = counter1.incrementAndGet();
+ ourLog.info("counter1 have been called {} times", count);
+ }
+ }
+
+ class MySearchNarrowingInterceptor extends SearchNarrowingInterceptor {
+ private static final Logger ourLog = LoggerFactory.getLogger(MySearchNarrowingInterceptor.class);
+
+
+ @Override
+ protected AuthorizedList buildAuthorizedList(RequestDetails theRequestDetails) {
+ int count = counter2.incrementAndGet();
+ ourLog.info("Have been called {} times", count);
+ return super.buildAuthorizedList(theRequestDetails);
+ }
+ }
+
+ BundleBuilder bb = new BundleBuilder(myFhirContext);
+ bb.setType("batch");
+
+ for (int i = 0; i < 5; i++) {
+ Practitioner p0 = new Practitioner();
+ p0.addIdentifier().setSystem("sys").setValue("p" + i);
+ bb.addTransactionCreateEntry(p0).conditional("Practitioner?identifier=sys|p" + i);
+ }
+
+ // Avoid the auto-CS fetching affecting counts
+ myClient.capabilities().ofType(CapabilityStatement.class).execute();
+
+ Bundle input = (Bundle) bb.getBundle();
+
+ MyAnonymousInterceptor0 interceptor0 = new MyAnonymousInterceptor0();
+ ourRestServer.getInterceptorService().registerAnonymousInterceptor(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED, interceptor0);
+ MyAnonymousInterceptor1 interceptor1 = new MyAnonymousInterceptor1();
+ ourRestServer.getInterceptorService().registerAnonymousInterceptor(Pointcut.SERVER_INCOMING_REQUEST_POST_PROCESSED, interceptor1);
+ MySearchNarrowingInterceptor interceptor2 = new MySearchNarrowingInterceptor();
+ ourRestServer.getInterceptorService().registerInterceptor(interceptor2);
+ try {
+ myClient.transaction().withBundle(input).execute();
+ assertEquals(1, counter0.get());
+ assertEquals(1, counter1.get());
+ assertEquals(5, counter2.get());
+
+ } finally {
+ ourRestServer.getInterceptorService().unregisterInterceptor(interceptor1);
+ }
+ }
+
+
@Test
public void testTransactionFromBundle() throws Exception {
InputStream bundleRes = SystemProviderR4Test.class.getResourceAsStream("/transaction_link_patient_eve.xml");
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
index ddc5687d799..cf438c864da 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
+++ b/hapi-fhir-jpaserver-uhnfhirtest/src/main/java/ca/uhn/fhirtest/interceptor/AnalyticsInterceptor.java
@@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.model.sched.HapiJob;
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
+import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.client.apache.ApacheRestfulClientFactory;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
@@ -32,10 +33,9 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
public class AnalyticsInterceptor extends InterceptorAdapter {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(AnalyticsInterceptor.class);
-
+ private final LinkedList myEventBuffer = new LinkedList<>();
private String myAnalyticsTid;
private int myCollectThreshold = 100000;
- private final LinkedList myEventBuffer = new LinkedList<>();
private String myHostname;
private HttpClient myHttpClient;
private long mySubmitPeriod = 60000;
@@ -63,16 +63,6 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
mySchedulerService.scheduleLocalJob(5000, jobDetail);
}
- public static class Job implements HapiJob {
- @Autowired
- private AnalyticsInterceptor myAnalyticsInterceptor;
-
- @Override
- public void execute(JobExecutionContext theContext) {
- myAnalyticsInterceptor.flush();
- }
- }
-
@PreDestroy
public void stop() throws IOException {
if (myHttpClient instanceof CloseableHttpClient) {
@@ -105,13 +95,13 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
b.append("&an=").append(UrlUtil.escapeUrlParam(myHostname)).append('+').append(UrlUtil.escapeUrlParam(next.getApplicationName()));
b.append("&ec=").append(next.getResourceName());
b.append("&ea=").append(next.getRestOperation());
-
+
b.append("&cid=").append(next.getClientId());
b.append("&uip=").append(UrlUtil.escapeUrlParam(next.getSourceIp()));
b.append("&ua=").append(UrlUtil.escapeUrlParam(next.getUserAgent()));
b.append("\n");
}
-
+
String contents = b.toString();
HttpPost post = new HttpPost("https://www.google-analytics.com/batch");
post.setEntity(new StringEntity(contents, ContentType.APPLICATION_FORM_URLENCODED));
@@ -121,7 +111,7 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
} catch (Exception e) {
ourLog.error("Failed to submit analytics:", e);
}
-
+
}
private synchronized void flush() {
@@ -145,15 +135,15 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
}
@Override
- public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theRequest) {
- ServletRequestDetails details = (ServletRequestDetails) theRequest.getRequestDetails();
-
+ public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, RequestDetails theRequest) {
+ ServletRequestDetails details = (ServletRequestDetails) theRequest;
+
// Make sure we only send one event per request
if (details.getUserData().containsKey(getClass().getName())) {
return;
}
details.getUserData().put(getClass().getName(), "");
-
+
String sourceIp = details.getHeader("x-forwarded-for");
if (isBlank(sourceIp)) {
sourceIp = details.getServletRequest().getRemoteAddr();
@@ -178,64 +168,74 @@ public class AnalyticsInterceptor extends InterceptorAdapter {
myEventBuffer.add(event);
}
}
-
+
public void setAnalyticsTid(String theAnalyticsTid) {
myAnalyticsTid = theAnalyticsTid;
}
-
+
+ public static class Job implements HapiJob {
+ @Autowired
+ private AnalyticsInterceptor myAnalyticsInterceptor;
+
+ @Override
+ public void execute(JobExecutionContext theContext) {
+ myAnalyticsInterceptor.flush();
+ }
+ }
+
public static class AnalyticsEvent {
private String myApplicationName;
private String myClientId;
private String myResourceName;
private RestOperationTypeEnum myRestOperation;
private String mySourceIp;
-
+
private String myUserAgent;
String getApplicationName() {
return myApplicationName;
}
- String getClientId() {
- return myClientId;
- }
-
- String getResourceName() {
- return myResourceName;
- }
-
- RestOperationTypeEnum getRestOperation() {
- return myRestOperation;
- }
-
- String getSourceIp() {
- return mySourceIp;
- }
-
- String getUserAgent() {
- return myUserAgent;
- }
-
void setApplicationName(String theApplicationName) {
myApplicationName = theApplicationName;
}
+ String getClientId() {
+ return myClientId;
+ }
+
void setClientId(String theClientId) {
myClientId = theClientId;
}
+ String getResourceName() {
+ return myResourceName;
+ }
+
void setResourceName(String theResourceName) {
myResourceName = theResourceName;
}
+ RestOperationTypeEnum getRestOperation() {
+ return myRestOperation;
+ }
+
void setRestOperation(RestOperationTypeEnum theRestOperation) {
myRestOperation = theRestOperation;
}
+ String getSourceIp() {
+ return mySourceIp;
+ }
+
void setSourceIp(String theSourceIp) {
mySourceIp = theSourceIp;
}
+ String getUserAgent() {
+ return myUserAgent;
+ }
+
void setUserAgent(String theUserAgent) {
myUserAgent = theUserAgent;
}
diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
index 7d941c0e886..69ed1b21be5 100644
--- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
+++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/IServerInterceptor.java
@@ -119,7 +119,6 @@ public interface IServerInterceptor {
* Invoked before an incoming request is processed. Note that this method is called
* after the server has begin preparing the response to the incoming client request.
* As such, it is not able to supply a response to the incoming request in the way that
- * {@link #incomingRequestPreHandled(RestOperationTypeEnum, ActionRequestDetails)} and
* {@link #incomingRequestPostProcessed(RequestDetails, HttpServletRequest, HttpServletResponse)}
* are.
*
@@ -132,7 +131,7 @@ public interface IServerInterceptor {
* server, e.g. the FHIR operation type and the parsed resource body (if any).
*/
@Hook(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED)
- void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest);
+ void incomingRequestPreHandled(RestOperationTypeEnum theOperation, RequestDetails theProcessedRequest);
/**
* This method is called before any other processing takes place for each incoming request. It may be used to provide
@@ -291,168 +290,4 @@ public interface IServerInterceptor {
@Hook(Pointcut.SERVER_PROCESSING_COMPLETED_NORMALLY)
void processingCompletedNormally(ServletRequestDetails theRequestDetails);
- /**
- * @deprecated This class doesn't bring anything that can't be done with {@link RequestDetails}. That
- * class should be used instead. Deprecated in 4.0.0
- */
- @Deprecated
- class ActionRequestDetails {
- private final FhirContext myContext;
- private final IIdType myId;
- private final String myResourceType;
- private RequestDetails myRequestDetails;
- private IBaseResource myResource;
-
- public ActionRequestDetails(RequestDetails theRequestDetails) {
- myId = theRequestDetails.getId();
- myResourceType = theRequestDetails.getResourceName();
- myContext = theRequestDetails.getServer().getFhirContext();
- myRequestDetails = theRequestDetails;
- }
-
- public ActionRequestDetails(RequestDetails theRequestDetails, FhirContext theContext, IBaseResource theResource) {
- this(theRequestDetails, theContext, theContext.getResourceType(theResource), theResource.getIdElement());
- myResource = theResource;
- }
-
- public ActionRequestDetails(RequestDetails theRequestDetails, FhirContext theContext, String theResourceType, IIdType theId) {
- if (theId != null && isBlank(theId.getValue())) {
- myId = null;
- } else {
- myId = theId;
- }
- myResourceType = theResourceType;
- myContext = theContext;
- myRequestDetails = theRequestDetails;
- }
-
- public ActionRequestDetails(RequestDetails theRequestDetails, IBaseResource theResource) {
- this(theRequestDetails, theRequestDetails.getServer().getFhirContext().getResourceType(theResource), theResource.getIdElement());
- myResource = theResource;
- }
-
- public ActionRequestDetails(RequestDetails theRequestDetails, IBaseResource theResource, String theResourceType, IIdType theId) {
- this(theRequestDetails, theResourceType, theId);
- myResource = theResource;
- }
-
- /**
- * Constructor
- *
- * @param theRequestDetails The request details to wrap
- * @param theId The ID of the resource being created (note that the ID should have the resource type populated)
- */
- public ActionRequestDetails(RequestDetails theRequestDetails, IIdType theId) {
- this(theRequestDetails, theId.getResourceType(), theId);
- }
-
- public ActionRequestDetails(RequestDetails theRequestDetails, String theResourceType, IIdType theId) {
- this(theRequestDetails, theRequestDetails.getServer().getFhirContext(), theResourceType, theId);
- }
-
- public FhirContext getContext() {
- return myContext;
- }
-
- /**
- * Returns the ID of the incoming request (typically this is from the request URL)
- */
- public IIdType getId() {
- return myId;
- }
-
- /**
- * Returns the request details associated with this request
- */
- public RequestDetails getRequestDetails() {
- return myRequestDetails;
- }
-
- /**
- * For requests where a resource is passed from the client to the server (e.g. create, update, etc.) this method
- * will return the resource which was provided by the client. Otherwise, this method will return null
- * .
- *
- * Note that this method is currently only populated if the handling method has a parameter annotated with the
- * {@link ResourceParam} annotation.
- *
- */
- public IBaseResource getResource() {
- return myResource;
- }
-
- /**
- * This method should not be called by client code
- */
- public void setResource(IBaseResource theObject) {
- myResource = theObject;
- }
-
- /**
- * Returns the resource type this request pertains to, or null if this request is not type specific
- * (e.g. server-history)
- */
- public String getResourceType() {
- return myResourceType;
- }
-
- @Override
- public String toString() {
- return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
- .append("id", myId)
- .append("resourceType", myResourceType)
- .append("resource", myResource)
- .toString();
- }
-
- /**
- * Returns the same map which was
- */
- public Map