Merge remote-tracking branch 'origin/master' into gg_20201105-remove-person-references

This commit is contained in:
Nick 2020-12-03 11:28:21 -05:00
commit 4352e0a61f
32 changed files with 596 additions and 272 deletions

View File

@ -1710,7 +1710,7 @@ public enum Pointcut {
* Hooks may accept the following parameters: * Hooks may accept the following parameters:
* <ul> * <ul>
* <li>ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage - This parameter should not be modified as processing is complete when this hook is invoked.</li> * <li>ca.uhn.fhir.rest.server.messaging.ResourceOperationMessage - This parameter should not be modified as processing is complete when this hook is invoked.</li>
* <li>ca.uhn.fhir.rest.server.TransactionLogMessages - This parameter is for informational messages provided by the MDM module during MDM procesing.</li> * <li>ca.uhn.fhir.rest.server.TransactionLogMessages - This parameter is for informational messages provided by the MDM module during MDM processing.</li>
* </ul> * </ul>
* </p> * </p>
* <p> * <p>

View File

@ -37,11 +37,16 @@ public class VersionUtil {
private static String ourVersion; private static String ourVersion;
private static String ourBuildNumber; private static String ourBuildNumber;
private static String ourBuildTime; private static String ourBuildTime;
private static boolean ourSnapshot;
static { static {
initialize(); initialize();
} }
public static boolean isSnapshot() {
return ourSnapshot;
}
public static String getBuildNumber() { public static String getBuildNumber() {
return ourBuildNumber; return ourBuildNumber;
} }
@ -65,11 +70,18 @@ public class VersionUtil {
ourVersion = p.getProperty("hapifhir.version"); ourVersion = p.getProperty("hapifhir.version");
ourVersion = defaultIfBlank(ourVersion, "(unknown)"); ourVersion = defaultIfBlank(ourVersion, "(unknown)");
ourBuildNumber = p.getProperty("hapifhir.buildnumber"); ourSnapshot = ourVersion.contains("SNAPSHOT");
ourBuildNumber = StringUtils.left(p.getProperty("hapifhir.buildnumber"), 10);
ourBuildTime = p.getProperty("hapifhir.timestamp"); ourBuildTime = p.getProperty("hapifhir.timestamp");
if (System.getProperty("suppress_hapi_fhir_version_log") == null) { if (System.getProperty("suppress_hapi_fhir_version_log") == null) {
ourLog.info("HAPI FHIR version {} - Rev {}", ourVersion, StringUtils.right(ourBuildNumber, 10)); String buildNumber = ourBuildNumber;
if (isSnapshot()) {
buildNumber = buildNumber + "/" + getBuildDate();
}
ourLog.info("HAPI FHIR version {} - Rev {}", ourVersion, buildNumber);
} }
} catch (Exception e) { } catch (Exception e) {
@ -77,4 +89,8 @@ public class VersionUtil {
} }
} }
public static String getBuildDate() {
return ourBuildTime.substring(0, 10);
}
} }

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 2208
title: "When performing a JPA server search on a partitioned server, searches with only the `_id` parameter and no other
parameters did not include the partition selector in the generated SQL, resulting in leakage across partitions. Thanks to
GitHub user @jtheory for reporting!"

View File

@ -0,0 +1,6 @@
---
type: add
issue: 2213
title: "Non release (i.e. SNAPSHOT) builds of HAPI FHIR will now include the Git revision hash as well as the build date in the
version string that is logged on initialization, and included in the default server X-Powered-By string. Release builds are
not affected by this change."

View File

@ -0,0 +1,5 @@
---
type: fix
issue: 2214
title: "When using the validator from within the JPA server, validating CapabilityStatement resources failed with
an error when trying to load linked SearchParameter resources. This has been corrected."

View File

@ -0,0 +1,6 @@
---
type: fix
issue: 2215
title: "When using a partitioned JPA server, auto-create placeholder targets did not work if the partition interceptor was
registered against the server (e.g. for a multitenancy configuration). This has been corrected. Thanks to Rob Whelan for
reporting!"

View File

@ -5,5 +5,5 @@
(dependent HAPI modules listed in brackets): (dependent HAPI modules listed in brackets):
<ul> <ul>
<li>Woodstox (XML FHIR Parser): 4.4.1 -&gt; 6.2.3 (Note that the Maven groupId has changed from <code>org.codehaus.woodstox</code> to <code>com.fasterxml.woodstox</code> and the Maven artifactId has changed from <code>woodstox-core-asl</code> to <code>woodstox-core</code> for this library)</li> <li>Woodstox (XML FHIR Parser): 4.4.1 -&gt; 6.2.3 (Note that the Maven groupId has changed from <code>org.codehaus.woodstox</code> to <code>com.fasterxml.woodstox</code> and the Maven artifactId has changed from <code>woodstox-core-asl</code> to <code>woodstox-core</code> for this library)</li>
<li>Jetty (JPA Starter): 9.4.30.v20200611 -&gt; 9.4.34.v20201102</li> <li>Jetty (JPA Starter): 9.4.30.v20200611 -&gt; 9.4.35.v20201120</li>
</ul>" </ul>"

View File

@ -609,7 +609,13 @@
<groupId>org.jetbrains</groupId> <groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId> <artifactId>annotations</artifactId>
</dependency> </dependency>
</dependencies> <dependency>
<groupId>org.mortbay.jetty</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5-20081211</version>
<scope>test</scope>
</dependency>
</dependencies>
<properties> <properties>

View File

@ -361,7 +361,7 @@ public abstract class BaseConfig {
@Bean @Bean
public IInterceptorService jpaInterceptorService() { public IInterceptorService jpaInterceptorService() {
return new InterceptorService(); return new InterceptorService("JPA");
} }
/** /**

View File

@ -119,71 +119,82 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
String resourceName = myFhirContext.getResourceType(theClass); String resourceName = myFhirContext.getResourceType(theClass);
IBundleProvider search; IBundleProvider search;
if ("ValueSet".equals(resourceName)) { switch (resourceName) {
if (localReference) { case "ValueSet":
SearchParameterMap params = new SearchParameterMap(); if (localReference) {
params.setLoadSynchronousUpTo(1); SearchParameterMap params = new SearchParameterMap();
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
if (search.size() == 0) {
params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
params.add(ValueSet.SP_URL, new UriParam(theUri)); params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
if (search.size() == 0) {
params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
params.add(ValueSet.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
}
} else {
int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
if (versionSeparator != -1) {
params.add(ValueSet.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
params.add(ValueSet.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
} else {
params.add(ValueSet.SP_URL, new UriParam(theUri));
}
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params); search = myDaoRegistry.getResourceDao(resourceName).search(params);
} }
} else { break;
case "StructureDefinition": {
// Don't allow the core FHIR definitions to be overwritten
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
if (myFhirContext.getElementDefinition(typeName) != null) {
return myNoMatch;
}
}
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
break;
}
case "Questionnaire": {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
} else {
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
}
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
break;
}
case "CodeSystem": {
int versionSeparator = theUri.lastIndexOf('|'); int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap(); SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1); params.setLoadSynchronousUpTo(1);
if (versionSeparator != -1) { if (versionSeparator != -1) {
params.add(ValueSet.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1))); params.add(CodeSystem.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
params.add(ValueSet.SP_URL, new UriParam(theUri.substring(0,versionSeparator))); params.add(CodeSystem.SP_URL, new UriParam(theUri.substring(0, versionSeparator)));
} else { } else {
params.add(ValueSet.SP_URL, new UriParam(theUri)); params.add(CodeSystem.SP_URL, new UriParam(theUri));
} }
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC)); params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params); search = myDaoRegistry.getResourceDao(resourceName).search(params);
break;
} }
} else if ("StructureDefinition".equals(resourceName)) { case "ImplementationGuide":
// Don't allow the core FHIR definitions to be overwritten case "SearchParameter": {
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) { SearchParameterMap params = new SearchParameterMap();
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length()); params.setLoadSynchronousUpTo(1);
if (myFhirContext.getElementDefinition(typeName) != null) { params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
return myNoMatch; search = myDaoRegistry.getResourceDao(resourceName).search(params);
} break;
} }
SearchParameterMap params = new SearchParameterMap(); default:
params.setLoadSynchronousUpTo(1); throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
} else if ("Questionnaire".equals(resourceName)) {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
} else {
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
}
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
} else if ("CodeSystem".equals(resourceName)) {
int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
if (versionSeparator != -1) {
params.add(CodeSystem.SP_VERSION, new TokenParam(theUri.substring(versionSeparator + 1)));
params.add(CodeSystem.SP_URL, new UriParam(theUri.substring(0,versionSeparator)));
} else {
params.add(CodeSystem.SP_URL, new UriParam(theUri));
}
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
} else if ("ImplementationGuide".equals(resourceName)) {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("ImplementationGuide").search(params);
} else {
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
} }
Integer size = search.size(); Integer size = search.size();

View File

@ -72,7 +72,7 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
ourLog.trace("Translated {}/{} to resource PID {}", theType, idPart, resolvedResource); ourLog.trace("Translated {}/{} to resource PID {}", theType, idPart, resolvedResource);
} catch (ResourceNotFoundException e) { } catch (ResourceNotFoundException e) {
Optional<ResourceTable> createdTableOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart); Optional<ResourceTable> createdTableOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart, theRequest);
if (!createdTableOpt.isPresent()) { if (!createdTableOpt.isPresent()) {
if (myDaoConfig.isEnforceReferentialIntegrityOnWrite() == false) { if (myDaoConfig.isEnforceReferentialIntegrityOnWrite() == false) {
@ -109,7 +109,7 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
/** /**
* @param theIdToAssignToPlaceholder If specified, the placeholder resource created will be given a specific ID * @param theIdToAssignToPlaceholder If specified, the placeholder resource created will be given a specific ID
*/ */
public <T extends IBaseResource> Optional<ResourceTable> createPlaceholderTargetIfConfiguredToDoSo(Class<T> theType, IBaseReference theReference, @Nullable String theIdToAssignToPlaceholder) { public <T extends IBaseResource> Optional<ResourceTable> createPlaceholderTargetIfConfiguredToDoSo(Class<T> theType, IBaseReference theReference, @Nullable String theIdToAssignToPlaceholder, RequestDetails theRequest) {
ResourceTable valueOf = null; ResourceTable valueOf = null;
if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) { if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {
@ -128,9 +128,9 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
if (theIdToAssignToPlaceholder != null) { if (theIdToAssignToPlaceholder != null) {
newResource.setId(resName + "/" + theIdToAssignToPlaceholder); newResource.setId(resName + "/" + theIdToAssignToPlaceholder);
valueOf = ((ResourceTable) placeholderResourceDao.update(newResource).getEntity()); valueOf = ((ResourceTable) placeholderResourceDao.update(newResource, theRequest).getEntity());
} else { } else {
valueOf = ((ResourceTable) placeholderResourceDao.create(newResource).getEntity()); valueOf = ((ResourceTable) placeholderResourceDao.create(newResource, theRequest).getEntity());
} }
} }

View File

@ -254,7 +254,7 @@ public class SearchParamWithInlineReferencesExtractor {
ResourcePersistentId match; ResourcePersistentId match;
if (matches.isEmpty()) { if (matches.isEmpty()) {
Optional<ResourceTable> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null); Optional<ResourceTable> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null, theRequest);
if (placeholderOpt.isPresent()) { if (placeholderOpt.isPresent()) {
match = new ResourcePersistentId(placeholderOpt.get().getResourceId()); match = new ResourcePersistentId(placeholderOpt.get().getResourceId());
} else { } else {

View File

@ -739,7 +739,7 @@ public class QueryStack {
codePredicates.add(singleCode); codePredicates.add(singleCode);
} }
return join.combineWithRequestPartitionIdPredicate(theRequestPartitionId, ComboCondition.or(codePredicates.toArray(new Condition[0]))); return join.combineWithRequestPartitionIdPredicate(theRequestPartitionId, toOrPredicate(codePredicates));
} }
public Condition createPredicateTag(@Nullable DbColumn theSourceJoinColumn, List<List<IQueryParameterType>> theList, String theParamName, RequestPartitionId theRequestPartitionId) { public Condition createPredicateTag(@Nullable DbColumn theSourceJoinColumn, List<List<IQueryParameterType>> theList, String theParamName, RequestPartitionId theRequestPartitionId) {

View File

@ -115,12 +115,15 @@ public class ResourceIdPredicateBuilder extends BasePredicateBuilder {
List<Long> resourceIds = ResourcePersistentId.toLongList(allOrPids); List<Long> resourceIds = ResourcePersistentId.toLongList(allOrPids);
if (theSourceJoinColumn == null) { if (theSourceJoinColumn == null) {
BaseJoiningPredicateBuilder queryRootTable = super.getOrCreateQueryRootTable(); BaseJoiningPredicateBuilder queryRootTable = super.getOrCreateQueryRootTable();
Condition predicate;
switch (operation) { switch (operation) {
default: default:
case eq: case eq:
return queryRootTable.createPredicateResourceIds(false, resourceIds); predicate = queryRootTable.createPredicateResourceIds(false, resourceIds);
return queryRootTable.combineWithRequestPartitionIdPredicate(theRequestPartitionId, predicate);
case ne: case ne:
return queryRootTable.createPredicateResourceIds(true, resourceIds); predicate = queryRootTable.createPredicateResourceIds(true, resourceIds);
return queryRootTable.combineWithRequestPartitionIdPredicate(theRequestPartitionId, predicate);
} }
} else { } else {
return QueryStack.toEqualToOrInPredicate(theSourceJoinColumn, generatePlaceholders(resourceIds), operation == SearchFilterParser.CompareOperation.ne); return QueryStack.toEqualToOrInPredicate(theSourceJoinColumn, generatePlaceholders(resourceIds), operation == SearchFilterParser.CompareOperation.ne);

View File

@ -38,14 +38,13 @@ import ca.uhn.fhir.test.utilities.LoggingExtension;
import ca.uhn.fhir.test.utilities.ProxyUtil; import ca.uhn.fhir.test.utilities.ProxyUtil;
import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor; import ca.uhn.fhir.test.utilities.UnregisterScheduledProcessor;
import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.BundleUtil;
import ca.uhn.fhir.util.FhirVersionIndependentConcept;
import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.TestUtil; import ca.uhn.fhir.util.TestUtil;
import ca.uhn.fhir.util.FhirVersionIndependentConcept;
import org.apache.commons.io.IOUtils; import org.apache.commons.io.IOUtils;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.Session; import org.hibernate.Session;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
import org.hibernate.jdbc.Work;
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent; import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.Resource;
@ -70,10 +69,9 @@ import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate; import org.springframework.transaction.support.TransactionTemplate;
import javax.annotation.Nonnull;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -85,6 +83,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import static ca.uhn.fhir.util.TestUtil.randomizeLocale; import static ca.uhn.fhir.util.TestUtil.randomizeLocale;
import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.eq;
@ -116,7 +115,7 @@ public abstract class BaseJpaTest extends BaseTest {
public LoggingExtension myLoggingExtension = new LoggingExtension(); public LoggingExtension myLoggingExtension = new LoggingExtension();
@Mock(answer = Answers.RETURNS_DEEP_STUBS) @Mock(answer = Answers.RETURNS_DEEP_STUBS)
protected ServletRequestDetails mySrd; protected ServletRequestDetails mySrd;
protected InterceptorService myRequestOperationCallback; protected InterceptorService mySrdInterceptorService;
@Autowired @Autowired
protected DatabaseBackedPagingProvider myDatabaseBackedPagingProvider; protected DatabaseBackedPagingProvider myDatabaseBackedPagingProvider;
@Autowired @Autowired
@ -173,18 +172,13 @@ public abstract class BaseJpaTest extends BaseTest {
AtomicBoolean isReadOnly = new AtomicBoolean(); AtomicBoolean isReadOnly = new AtomicBoolean();
Session currentSession; Session currentSession;
try { try {
assert sessionFactory != null;
currentSession = sessionFactory.getCurrentSession(); currentSession = sessionFactory.getCurrentSession();
} catch (HibernateException e) { } catch (HibernateException e) {
currentSession = null; currentSession = null;
} }
if (currentSession != null) { if (currentSession != null) {
currentSession.doWork(new Work() { currentSession.doWork(connection -> isReadOnly.set(connection.isReadOnly()));
@Override
public void execute(Connection connection) throws SQLException {
isReadOnly.set(connection.isReadOnly());
}
});
assertFalse(isReadOnly.get()); assertFalse(isReadOnly.get());
} }
@ -199,12 +193,12 @@ public abstract class BaseJpaTest extends BaseTest {
} }
@BeforeEach @BeforeEach
public void beforeInitMocks() { public void beforeInitMocks() throws Exception {
myRequestOperationCallback = new InterceptorService(); mySrdInterceptorService = new InterceptorService();
MockitoAnnotations.initMocks(this); MockitoAnnotations.initMocks(this);
when(mySrd.getInterceptorBroadcaster()).thenReturn(myRequestOperationCallback); when(mySrd.getInterceptorBroadcaster()).thenReturn(mySrdInterceptorService);
when(mySrd.getUserData()).thenReturn(new HashMap<>()); when(mySrd.getUserData()).thenReturn(new HashMap<>());
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>()); when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
when(mySrd.getServer().getDefaultPageSize()).thenReturn(null); when(mySrd.getServer().getDefaultPageSize()).thenReturn(null);
@ -231,7 +225,7 @@ public abstract class BaseJpaTest extends BaseTest {
public void runInTransaction(Runnable theRunnable) { public void runInTransaction(Runnable theRunnable) {
newTxTemplate().execute(new TransactionCallbackWithoutResult() { newTxTemplate().execute(new TransactionCallbackWithoutResult() {
@Override @Override
protected void doInTransactionWithoutResult(TransactionStatus theStatus) { protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) {
theRunnable.run(); theRunnable.run();
} }
}); });
@ -250,16 +244,14 @@ public abstract class BaseJpaTest extends BaseTest {
/** /**
* Sleep until at least 1 ms has elapsed * Sleep until at least 1 ms has elapsed
*/ */
public void sleepUntilTimeChanges() throws InterruptedException { public void sleepUntilTimeChanges() {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
while (sw.getMillis() == 0) { await().until(() -> sw.getMillis() > 0);
Thread.sleep(10);
}
} }
protected org.hl7.fhir.dstu3.model.Bundle toBundle(IBundleProvider theSearch) { protected org.hl7.fhir.dstu3.model.Bundle toBundle(IBundleProvider theSearch) {
org.hl7.fhir.dstu3.model.Bundle bundle = new org.hl7.fhir.dstu3.model.Bundle(); org.hl7.fhir.dstu3.model.Bundle bundle = new org.hl7.fhir.dstu3.model.Bundle();
for (IBaseResource next : theSearch.getResources(0, theSearch.size())) { for (IBaseResource next : theSearch.getResources(0, theSearch.sizeOrThrowNpe())) {
bundle.addEntry().setResource((Resource) next); bundle.addEntry().setResource((Resource) next);
} }
return bundle; return bundle;
@ -267,7 +259,7 @@ public abstract class BaseJpaTest extends BaseTest {
protected org.hl7.fhir.r4.model.Bundle toBundleR4(IBundleProvider theSearch) { protected org.hl7.fhir.r4.model.Bundle toBundleR4(IBundleProvider theSearch) {
org.hl7.fhir.r4.model.Bundle bundle = new org.hl7.fhir.r4.model.Bundle(); org.hl7.fhir.r4.model.Bundle bundle = new org.hl7.fhir.r4.model.Bundle();
for (IBaseResource next : theSearch.getResources(0, theSearch.size())) { for (IBaseResource next : theSearch.getResources(0, theSearch.sizeOrThrowNpe())) {
bundle.addEntry().setResource((org.hl7.fhir.r4.model.Resource) next); bundle.addEntry().setResource((org.hl7.fhir.r4.model.Resource) next);
} }
return bundle; return bundle;
@ -275,11 +267,11 @@ public abstract class BaseJpaTest extends BaseTest {
@SuppressWarnings({"rawtypes"}) @SuppressWarnings({"rawtypes"})
protected List toList(IBundleProvider theSearch) { protected List toList(IBundleProvider theSearch) {
return theSearch.getResources(0, theSearch.size()); return theSearch.getResources(0, theSearch.sizeOrThrowNpe());
} }
protected List<String> toUnqualifiedIdValues(IBaseBundle theFound) { protected List<String> toUnqualifiedIdValues(IBaseBundle theFound) {
List<String> retVal = new ArrayList<String>(); List<String> retVal = new ArrayList<>();
List<IBaseResource> res = BundleUtil.toListOfResources(getContext(), theFound); List<IBaseResource> res = BundleUtil.toListOfResources(getContext(), theFound);
int size = res.size(); int size = res.size();
@ -291,8 +283,8 @@ public abstract class BaseJpaTest extends BaseTest {
} }
protected List<String> toUnqualifiedIdValues(IBundleProvider theFound) { protected List<String> toUnqualifiedIdValues(IBundleProvider theFound) {
List<String> retVal = new ArrayList<String>(); List<String> retVal = new ArrayList<>();
int size = theFound.size(); int size = theFound.sizeOrThrowNpe();
ourLog.info("Found {} results", size); ourLog.info("Found {} results", size);
List<IBaseResource> resources = theFound.getResources(0, size); List<IBaseResource> resources = theFound.getResources(0, size);
for (IBaseResource next : resources) { for (IBaseResource next : resources) {
@ -302,7 +294,7 @@ public abstract class BaseJpaTest extends BaseTest {
} }
protected List<String> toUnqualifiedVersionlessIdValues(IBaseBundle theFound) { protected List<String> toUnqualifiedVersionlessIdValues(IBaseBundle theFound) {
List<String> retVal = new ArrayList<String>(); List<String> retVal = new ArrayList<>();
List<IBaseResource> res = BundleUtil.toListOfResources(getContext(), theFound); List<IBaseResource> res = BundleUtil.toListOfResources(getContext(), theFound);
int size = res.size(); int size = res.size();
@ -429,6 +421,7 @@ public abstract class BaseJpaTest extends BaseTest {
return retVal.toArray(new String[0]); return retVal.toArray(new String[0]);
} }
@SuppressWarnings("BusyWait")
protected void waitForActivatedSubscriptionCount(int theSize) throws Exception { protected void waitForActivatedSubscriptionCount(int theSize) throws Exception {
for (int i = 0; ; i++) { for (int i = 0; ; i++) {
if (i == 10) { if (i == 10) {
@ -473,6 +466,7 @@ public abstract class BaseJpaTest extends BaseTest {
return IOUtils.toByteArray(bundleRes); return IOUtils.toByteArray(bundleRes);
} }
@SuppressWarnings("BusyWait")
protected static void purgeDatabase(DaoConfig theDaoConfig, IFhirSystemDao<?, ?> theSystemDao, IResourceReindexingSvc theResourceReindexingSvc, ISearchCoordinatorSvc theSearchCoordinatorSvc, ISearchParamRegistry theSearchParamRegistry, IBulkDataExportSvc theBulkDataExportSvc) { protected static void purgeDatabase(DaoConfig theDaoConfig, IFhirSystemDao<?, ?> theSystemDao, IResourceReindexingSvc theResourceReindexingSvc, ISearchCoordinatorSvc theSearchCoordinatorSvc, ISearchParamRegistry theSearchParamRegistry, IBulkDataExportSvc theBulkDataExportSvc) {
theSearchCoordinatorSvc.cancelAllActiveSearches(); theSearchCoordinatorSvc.cancelAllActiveSearches();
theResourceReindexingSvc.cancelAndPurgeAllJobs(); theResourceReindexingSvc.cancelAndPurgeAllJobs();
@ -519,6 +513,7 @@ public abstract class BaseJpaTest extends BaseTest {
return retVal; return retVal;
} }
@SuppressWarnings("BusyWait")
public static void waitForSize(int theTarget, List<?> theList) { public static void waitForSize(int theTarget, List<?> theList) {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
while (theList.size() != theTarget && sw.getMillis() <= 16000) { while (theList.size() != theTarget && sw.getMillis() <= 16000) {
@ -549,6 +544,7 @@ public abstract class BaseJpaTest extends BaseTest {
waitForSize(theTarget, 10000, theCallable); waitForSize(theTarget, 10000, theCallable);
} }
@SuppressWarnings("BusyWait")
public static void waitForSize(int theTarget, int theTimeout, Callable<Number> theCallable) throws Exception { public static void waitForSize(int theTarget, int theTimeout, Callable<Number> theCallable) throws Exception {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
while (theCallable.call().intValue() != theTarget && sw.getMillis() < theTimeout) { while (theCallable.call().intValue() != theTarget && sw.getMillis() < theTimeout) {
@ -568,6 +564,7 @@ public abstract class BaseJpaTest extends BaseTest {
waitForSize(theTarget, 10000, theCallable, theFailureMessage); waitForSize(theTarget, 10000, theCallable, theFailureMessage);
} }
@SuppressWarnings("BusyWait")
public static void waitForSize(int theTarget, int theTimeout, Callable<Number> theCallable, Callable<String> theFailureMessage) throws Exception { public static void waitForSize(int theTarget, int theTimeout, Callable<Number> theCallable, Callable<String> theFailureMessage) throws Exception {
StopWatch sw = new StopWatch(); StopWatch sw = new StopWatch();
while (theCallable.call().intValue() != theTarget && sw.getMillis() < theTimeout) { while (theCallable.call().intValue() != theTarget && sw.getMillis() < theTimeout) {

View File

@ -1,15 +1,10 @@
package ca.uhn.fhir.jpa.dao.r4; package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider; import ca.uhn.fhir.jpa.rp.r4.PatientResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import javax.servlet.ServletConfig; import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration; import java.util.Enumeration;
@ -17,17 +12,16 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when; import static org.mockito.Mockito.when;
public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test { public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
protected ServletRequestDetails mySrd;
private RestfulServer myServer; private RestfulServer myServer;
@Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@BeforeEach @BeforeEach
public void before() throws ServletException { public void beforeInitMocks() throws Exception {
mySrd = mock(ServletRequestDetails.class); super.beforeInitMocks();
when(mySrd.getInterceptorBroadcaster()).thenReturn(mock(IInterceptorBroadcaster.class));
if (myServer == null) { if (myServer == null) {
myServer = new RestfulServer(myFhirCtx); myServer = new RestfulServer(myFhirCtx, mySrdInterceptorService);
PatientResourceProvider patientRp = new PatientResourceProvider(); PatientResourceProvider patientRp = new PatientResourceProvider();
patientRp.setDao(myPatientDao); patientRp.setDao(myPatientDao);

View File

@ -98,6 +98,7 @@ import org.hl7.fhir.r4.model.Appointment;
import org.hl7.fhir.r4.model.AuditEvent; import org.hl7.fhir.r4.model.AuditEvent;
import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Binary;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.CapabilityStatement;
import org.hl7.fhir.r4.model.CarePlan; import org.hl7.fhir.r4.model.CarePlan;
import org.hl7.fhir.r4.model.CareTeam; import org.hl7.fhir.r4.model.CareTeam;
import org.hl7.fhir.r4.model.ChargeItem; import org.hl7.fhir.r4.model.ChargeItem;
@ -356,6 +357,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@Qualifier("myDocumentReferenceDaoR4") @Qualifier("myDocumentReferenceDaoR4")
protected IFhirResourceDao<DocumentReference> myDocumentReferenceDao; protected IFhirResourceDao<DocumentReference> myDocumentReferenceDao;
@Autowired @Autowired
@Qualifier("myCapabilityStatementDaoR4")
protected IFhirResourceDao<CapabilityStatement> myCapabilityStatementDao;
@Autowired
@Qualifier("myPatientDaoR4") @Qualifier("myPatientDaoR4")
protected IFhirResourceDaoPatient<Patient> myPatientDao; protected IFhirResourceDaoPatient<Patient> myPatientDao;
@Autowired @Autowired

View File

@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.dao.r4;
import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor; import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.interceptor.executor.InterceptorService;
import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.config.TestR4Config; import ca.uhn.fhir.jpa.config.TestR4Config;
import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.entity.Search;
@ -52,7 +51,6 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
private static final Logger ourLog = LoggerFactory.getLogger(ConsentEventsDaoR4Test.class); private static final Logger ourLog = LoggerFactory.getLogger(ConsentEventsDaoR4Test.class);
private List<String> myObservationIds; private List<String> myObservationIds;
private List<String> myPatientIds; private List<String> myPatientIds;
private InterceptorService myInterceptorService;
private List<String> myObservationIdsOddOnly; private List<String> myObservationIdsOddOnly;
private List<String> myObservationIdsEvenOnly; private List<String> myObservationIdsEvenOnly;
private List<String> myObservationIdsWithVersions; private List<String> myObservationIdsWithVersions;
@ -64,16 +62,11 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields()); myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
} }
@Override
@BeforeEach @BeforeEach
public void before() throws ServletException { public void before() throws ServletException {
super.before();
RestfulServer restfulServer = new RestfulServer(); RestfulServer restfulServer = new RestfulServer();
restfulServer.setPagingProvider(myPagingProvider); restfulServer.setPagingProvider(myPagingProvider);
myInterceptorService = new InterceptorService();
when(mySrd.getInterceptorBroadcaster()).thenReturn(myInterceptorService);
when(mySrd.getServer()).thenReturn(restfulServer); when(mySrd.getServer()).thenReturn(restfulServer);
myDaoConfig.setSearchPreFetchThresholds(Arrays.asList(20, 50, 190)); myDaoConfig.setSearchPreFetchThresholds(Arrays.asList(20, 50, 190));
@ -86,7 +79,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -118,7 +111,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -158,7 +151,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -191,7 +184,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -216,7 +209,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -244,7 +237,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -269,7 +262,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -292,7 +285,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search // Perform a search
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -316,7 +309,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a history // Perform a history
SearchParameterMap map = new SearchParameterMap(); SearchParameterMap map = new SearchParameterMap();
@ -346,7 +339,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0); AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>(); List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds); IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor); mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
myObservationDao.read(new IdType(myObservationIdsEvenOnly.get(0)), mySrd); myObservationDao.read(new IdType(myObservationIdsEvenOnly.get(0)), mySrd);
myObservationDao.read(new IdType(myObservationIdsEvenOnly.get(1)), mySrd); myObservationDao.read(new IdType(myObservationIdsEvenOnly.get(1)), mySrd);

View File

@ -7,7 +7,6 @@ import ca.uhn.fhir.jpa.api.model.DeleteMethodOutcome;
import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerOperationInterceptor;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
@ -16,7 +15,6 @@ import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.IdType;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Patient;
import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor; import org.mockito.ArgumentCaptor;
@ -508,7 +506,7 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
((Patient) theResource).setActive(true); ((Patient) theResource).setActive(true);
} }
}; };
myRequestOperationCallback.registerInterceptor(interceptor); mySrdInterceptorService.registerInterceptor(interceptor);
Patient p = new Patient(); Patient p = new Patient();
p.setActive(false); p.setActive(false);

View File

@ -36,6 +36,7 @@ import org.hl7.fhir.r4.model.AllergyIntolerance;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.CanonicalType;
import org.hl7.fhir.r4.model.CapabilityStatement;
import org.hl7.fhir.r4.model.CodeSystem; import org.hl7.fhir.r4.model.CodeSystem;
import org.hl7.fhir.r4.model.CodeType; import org.hl7.fhir.r4.model.CodeType;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
@ -56,6 +57,7 @@ import org.hl7.fhir.r4.model.Quantity;
import org.hl7.fhir.r4.model.Questionnaire; import org.hl7.fhir.r4.model.Questionnaire;
import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.hl7.fhir.r4.model.QuestionnaireResponse;
import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.SearchParameter;
import org.hl7.fhir.r4.model.StringType; import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.UriType; import org.hl7.fhir.r4.model.UriType;
@ -1236,6 +1238,40 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
myFhirCtx.setParserErrorHandler(new StrictErrorHandler()); myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
} }
@Test
public void testValidateCapabilityStatement() {
SearchParameter sp = new SearchParameter();
sp.setUrl("http://example.com/name");
sp.setId("name");
sp.setCode("name");
sp.setType(Enumerations.SearchParamType.STRING);
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
sp.addBase("Patient");
sp.setExpression("Patient.name");
mySearchParameterDao.update(sp);
CapabilityStatement cs = new CapabilityStatement();
cs.getText().setStatus(Narrative.NarrativeStatus.GENERATED).getDiv().setValue("<div>aaaa</div>");
CapabilityStatement.CapabilityStatementRestComponent rest = cs.addRest();
CapabilityStatement.CapabilityStatementRestResourceComponent patient = rest.addResource();
patient .setType("Patient");
patient.addSearchParam().setName("foo").setType(Enumerations.SearchParamType.DATE).setDefinition("http://example.com/name");
try {
myCapabilityStatementDao.validate(cs, null, null, null, ValidationModeEnum.CREATE, null, mySrd);
fail();
} catch (PreconditionFailedException e) {
String oo = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome());
ourLog.info(oo);
assertThat(oo, oo, containsString("Type mismatch - SearchParameter 'http://example.com/name' type is string, but type here is date"));
}
}
@Test @Test
public void testValidateForCreate() { public void testValidateForCreate() {
String methodName = "testValidateForCreate"; String methodName = "testValidateForCreate";

View File

@ -67,11 +67,8 @@ public class PartitioningInterceptorR4Test extends BaseJpaR4SystemTest {
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields()); myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
} }
@Override
@BeforeEach @BeforeEach
public void before() throws ServletException { public void before() throws ServletException {
super.before();
myPartitionSettings.setPartitioningEnabled(true); myPartitionSettings.setPartitioningEnabled(true);
myPartitionInterceptor = new MyWriteInterceptor(); myPartitionInterceptor = new MyWriteInterceptor();

View File

@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.rest.server.TransactionLogMessages; import ca.uhn.fhir.rest.server.TransactionLogMessages;
import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;

View File

@ -39,7 +39,8 @@ public class JpaInterceptorBroadcaster {
retVal = theInterceptorBroadcaster.callHooks(thePointcut, theParams); retVal = theInterceptorBroadcaster.callHooks(thePointcut, theParams);
} }
if (theRequestDetails != null && retVal) { if (theRequestDetails != null && retVal) {
theRequestDetails.getInterceptorBroadcaster().callHooks(thePointcut, theParams); IInterceptorBroadcaster interceptorBroadcaster = theRequestDetails.getInterceptorBroadcaster();
interceptorBroadcaster.callHooks(thePointcut, theParams);
} }
return retVal; return retVal;
} }
@ -54,7 +55,8 @@ public class JpaInterceptorBroadcaster {
retVal = theInterceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams); retVal = theInterceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams);
} }
if (theRequestDetails != null && retVal == null) { if (theRequestDetails != null && retVal == null) {
retVal = theRequestDetails.getInterceptorBroadcaster().callHooksAndReturnObject(thePointcut, theParams); IInterceptorBroadcaster interceptorBroadcaster = theRequestDetails.getInterceptorBroadcaster();
retVal = interceptorBroadcaster.callHooksAndReturnObject(thePointcut, theParams);
} }
return retVal; return retVal;
} }

View File

@ -1,25 +1,5 @@
package ca.uhn.fhir.mdm.model; package ca.uhn.fhir.mdm.model;
/*-
* #%L
* HAPI FHIR - Enterprise Master Patient Index
* %%
* Copyright (C) 2014 - 2020 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.rest.server.TransactionLogMessages; import ca.uhn.fhir.rest.server.TransactionLogMessages;
public class MdmTransactionContext { public class MdmTransactionContext {

View File

@ -175,7 +175,7 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
* Constructor * Constructor
*/ */
public RestfulServer(FhirContext theCtx) { public RestfulServer(FhirContext theCtx) {
this(theCtx, new InterceptorService()); this(theCtx, new InterceptorService("RestfulServer"));
} }
public RestfulServer(FhirContext theCtx, IInterceptorService theInterceptorService) { public RestfulServer(FhirContext theCtx, IInterceptorService theInterceptorService) {
@ -299,7 +299,11 @@ public class RestfulServer extends HttpServlet implements IRestfulServer<Servlet
* @see #createPoweredByHeader() * @see #createPoweredByHeader()
*/ */
protected String createPoweredByHeaderProductVersion() { protected String createPoweredByHeaderProductVersion() {
return VersionUtil.getVersion(); String version = VersionUtil.getVersion();
if (VersionUtil.isSnapshot()) {
version = version + "/" + VersionUtil.getBuildNumber() + "/" + VersionUtil.getBuildDate();
}
return version;
} }
@Override @Override

View File

@ -110,7 +110,8 @@ public class MetadataConformanceDstu2_1Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(output, containsString("<Conformance")); assertThat(output, containsString("<Conformance"));
assertEquals("HAPI FHIR " + VersionUtil.getVersion() + " REST Server (FHIR Server; FHIR " + FhirVersionEnum.DSTU2_1.getFhirVersionString() + "/DSTU2_1)", status.getFirstHeader("X-Powered-By").getValue()); assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("HAPI FHIR " + VersionUtil.getVersion()));
assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("REST Server (FHIR Server; FHIR " + ourCtx.getVersion().getVersion().getFhirVersionString() + "/" + ourCtx.getVersion().getVersion().name() + ")"));
} finally { } finally {
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
} }
@ -120,7 +121,7 @@ public class MetadataConformanceDstu2_1Test {
status = ourClient.execute(httpPost); status = ourClient.execute(httpPost);
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(405, status.getStatusLine().getStatusCode()); assertEquals(405, status.getStatusLine().getStatusCode());
assertEquals("<OperationOutcome xmlns=\"http://hl7.org/fhir\"><issue><severity value=\"error\"/><code value=\"processing\"/><diagnostics value=\"/metadata request must use HTTP GET\"/></issue></OperationOutcome>", output); assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("REST Server (FHIR Server; FHIR " + ourCtx.getVersion().getVersion().getFhirVersionString() + "/" + ourCtx.getVersion().getVersion().name() + ")"));
} finally { } finally {
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
} }

View File

@ -86,8 +86,8 @@ public class MetadataCapabilityStatementDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(output, containsString("<CapabilityStatement")); assertThat(output, containsString("<CapabilityStatement"));
assertEquals("HAPI FHIR " + VersionUtil.getVersion() + " REST Server (FHIR Server; FHIR " + FhirVersionEnum.DSTU3.getFhirVersionString() + "/DSTU3)", assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("HAPI FHIR " + VersionUtil.getVersion()));
status.getFirstHeader("X-Powered-By").getValue()); assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("REST Server (FHIR Server; FHIR " + ourCtx.getVersion().getVersion().getFhirVersionString() + "/" + ourCtx.getVersion().getVersion().name() + ")"));
} finally { } finally {
IOUtils.closeQuietly(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent());
} }

View File

@ -108,7 +108,8 @@ public class MetadataConformanceDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(output, containsString("<CapabilityStatement")); assertThat(output, containsString("<CapabilityStatement"));
assertEquals("HAPI FHIR " + VersionUtil.getVersion() + " REST Server (FHIR Server; FHIR " + FhirVersionEnum.DSTU3.getFhirVersionString() + "/DSTU3)", status.getFirstHeader("X-Powered-By").getValue()); assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("HAPI FHIR " + VersionUtil.getVersion()));
assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("REST Server (FHIR Server; FHIR " + ourCtx.getVersion().getVersion().getFhirVersionString() + "/" + ourCtx.getVersion().getVersion().name() + ")"));
} }
httpOperation = new HttpOptions("http://localhost:" + ourPort); httpOperation = new HttpOptions("http://localhost:" + ourPort);
@ -116,7 +117,8 @@ public class MetadataConformanceDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode()); assertEquals(200, status.getStatusLine().getStatusCode());
assertThat(output, containsString("<CapabilityStatement")); assertThat(output, containsString("<CapabilityStatement"));
assertEquals("HAPI FHIR " + VersionUtil.getVersion() + " REST Server (FHIR Server; FHIR " + FhirVersionEnum.DSTU3.getFhirVersionString() + "/DSTU3)", status.getFirstHeader("X-Powered-By").getValue()); assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("HAPI FHIR " + VersionUtil.getVersion()));
assertThat(status.getFirstHeader("X-Powered-By").getValue(), containsString("REST Server (FHIR Server; FHIR " + ourCtx.getVersion().getVersion().getFhirVersionString() + "/" + ourCtx.getVersion().getVersion().name() + ")"));
} }
httpOperation = new HttpPost("http://localhost:" + ourPort + "/metadata"); httpOperation = new HttpPost("http://localhost:" + ourPort + "/metadata");

View File

@ -115,7 +115,7 @@ public interface ITestDataBuilder {
default Consumer<IBaseResource> withId(String theId) { default Consumer<IBaseResource> withId(String theId) {
return t -> { return t -> {
assertThat(theId, matchesPattern("[a-zA-Z0-9]+")); assertThat(theId, matchesPattern("[a-zA-Z0-9-]+"));
t.setId(theId); t.setId(theId);
}; };
} }

View File

@ -738,7 +738,7 @@
<jena_version>3.16.0</jena_version> <jena_version>3.16.0</jena_version>
<jersey_version>2.25.1</jersey_version> <jersey_version>2.25.1</jersey_version>
<!-- 9.4.17 seems to have issues --> <!-- 9.4.17 seems to have issues -->
<jetty_version>9.4.34.v20201102</jetty_version> <jetty_version>9.4.35.v20201120</jetty_version>
<jsr305_version>3.0.2</jsr305_version> <jsr305_version>3.0.2</jsr305_version>
<junit_version>5.6.2</junit_version> <junit_version>5.6.2</junit_version>
<flyway_version>6.5.4</flyway_version> <flyway_version>6.5.4</flyway_version>