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:
* <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.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>
* </p>
* <p>

View File

@ -37,11 +37,16 @@ public class VersionUtil {
private static String ourVersion;
private static String ourBuildNumber;
private static String ourBuildTime;
private static boolean ourSnapshot;
static {
initialize();
}
public static boolean isSnapshot() {
return ourSnapshot;
}
public static String getBuildNumber() {
return ourBuildNumber;
}
@ -65,11 +70,18 @@ public class VersionUtil {
ourVersion = p.getProperty("hapifhir.version");
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");
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) {
@ -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):
<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>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>"

View File

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

View File

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

View File

@ -119,7 +119,8 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
String resourceName = myFhirContext.getResourceType(theClass);
IBundleProvider search;
if ("ValueSet".equals(resourceName)) {
switch (resourceName) {
case "ValueSet":
if (localReference) {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
@ -144,7 +145,8 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
}
} else if ("StructureDefinition".equals(resourceName)) {
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());
@ -156,7 +158,9 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
params.setLoadSynchronousUpTo(1);
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("StructureDefinition").search(params);
} else if ("Questionnaire".equals(resourceName)) {
break;
}
case "Questionnaire": {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
if (localReference || myFhirContext.getVersion().getVersion().isEquivalentTo(FhirVersionEnum.DSTU2)) {
@ -165,7 +169,9 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
params.add(Questionnaire.SP_URL, new UriParam(id.getValue()));
}
search = myDaoRegistry.getResourceDao("Questionnaire").search(params);
} else if ("CodeSystem".equals(resourceName)) {
break;
}
case "CodeSystem": {
int versionSeparator = theUri.lastIndexOf('|');
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
@ -177,12 +183,17 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
}
params.setSort(new SortSpec("_lastUpdated").setOrder(SortOrderEnum.DESC));
search = myDaoRegistry.getResourceDao(resourceName).search(params);
} else if ("ImplementationGuide".equals(resourceName)) {
break;
}
case "ImplementationGuide":
case "SearchParameter": {
SearchParameterMap params = new SearchParameterMap();
params.setLoadSynchronousUpTo(1);
params.add(ImplementationGuide.SP_URL, new UriParam(theUri));
search = myDaoRegistry.getResourceDao("ImplementationGuide").search(params);
} else {
search = myDaoRegistry.getResourceDao(resourceName).search(params);
break;
}
default:
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
}

View File

@ -72,7 +72,7 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
ourLog.trace("Translated {}/{} to resource PID {}", theType, idPart, resolvedResource);
} catch (ResourceNotFoundException e) {
Optional<ResourceTable> createdTableOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart);
Optional<ResourceTable> createdTableOpt = createPlaceholderTargetIfConfiguredToDoSo(theType, theReference, idPart, theRequest);
if (!createdTableOpt.isPresent()) {
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
*/
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;
if (myDaoConfig.isAutoCreatePlaceholderReferenceTargets()) {
@ -128,9 +128,9 @@ public class DaoResourceLinkResolver implements IResourceLinkResolver {
if (theIdToAssignToPlaceholder != null) {
newResource.setId(resName + "/" + theIdToAssignToPlaceholder);
valueOf = ((ResourceTable) placeholderResourceDao.update(newResource).getEntity());
valueOf = ((ResourceTable) placeholderResourceDao.update(newResource, theRequest).getEntity());
} 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;
if (matches.isEmpty()) {
Optional<ResourceTable> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null);
Optional<ResourceTable> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null, theRequest);
if (placeholderOpt.isPresent()) {
match = new ResourcePersistentId(placeholderOpt.get().getResourceId());
} else {

View File

@ -739,7 +739,7 @@ public class QueryStack {
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) {

View File

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

View File

@ -1,15 +1,10 @@
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.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 javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.util.Enumeration;
@ -17,17 +12,16 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public abstract class BaseJpaR4SystemTest extends BaseJpaR4Test {
protected ServletRequestDetails mySrd;
private RestfulServer myServer;
@Override
@SuppressWarnings("unchecked")
@BeforeEach
public void before() throws ServletException {
mySrd = mock(ServletRequestDetails.class);
when(mySrd.getInterceptorBroadcaster()).thenReturn(mock(IInterceptorBroadcaster.class));
public void beforeInitMocks() throws Exception {
super.beforeInitMocks();
if (myServer == null) {
myServer = new RestfulServer(myFhirCtx);
myServer = new RestfulServer(myFhirCtx, mySrdInterceptorService);
PatientResourceProvider patientRp = new PatientResourceProvider();
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.Binary;
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.CareTeam;
import org.hl7.fhir.r4.model.ChargeItem;
@ -356,6 +357,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
@Qualifier("myDocumentReferenceDaoR4")
protected IFhirResourceDao<DocumentReference> myDocumentReferenceDao;
@Autowired
@Qualifier("myCapabilityStatementDaoR4")
protected IFhirResourceDao<CapabilityStatement> myCapabilityStatementDao;
@Autowired
@Qualifier("myPatientDaoR4")
protected IFhirResourceDaoPatient<Patient> myPatientDao;
@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.IAnonymousInterceptor;
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.config.TestR4Config;
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 List<String> myObservationIds;
private List<String> myPatientIds;
private InterceptorService myInterceptorService;
private List<String> myObservationIdsOddOnly;
private List<String> myObservationIdsEvenOnly;
private List<String> myObservationIdsWithVersions;
@ -64,16 +62,11 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
}
@Override
@BeforeEach
public void before() throws ServletException {
super.before();
RestfulServer restfulServer = new RestfulServer();
restfulServer.setPagingProvider(myPagingProvider);
myInterceptorService = new InterceptorService();
when(mySrd.getInterceptorBroadcaster()).thenReturn(myInterceptorService);
when(mySrd.getServer()).thenReturn(restfulServer);
myDaoConfig.setSearchPreFetchThresholds(Arrays.asList(20, 50, 190));
@ -86,7 +79,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -118,7 +111,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -158,7 +151,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -191,7 +184,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -216,7 +209,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -244,7 +237,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -269,7 +262,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCounting(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -292,7 +285,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a search
SearchParameterMap map = new SearchParameterMap();
@ -316,7 +309,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
IAnonymousInterceptor interceptor = new PreAccessInterceptorCountingAndBlockOdd(hitCount, interceptedResourceIds);
myInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
mySrdInterceptorService.registerAnonymousInterceptor(Pointcut.STORAGE_PREACCESS_RESOURCES, interceptor);
// Perform a history
SearchParameterMap map = new SearchParameterMap();
@ -346,7 +339,7 @@ public class ConsentEventsDaoR4Test extends BaseJpaR4SystemTest {
AtomicInteger hitCount = new AtomicInteger(0);
List<String> interceptedResourceIds = new ArrayList<>();
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(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.server.interceptor.IServerOperationInterceptor;
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.IIdType;
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.Patient;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
@ -508,7 +506,7 @@ public class FhirResourceDaoR4InterceptorTest extends BaseJpaR4Test {
((Patient) theResource).setActive(true);
}
};
myRequestOperationCallback.registerInterceptor(interceptor);
mySrdInterceptorService.registerInterceptor(interceptor);
Patient p = new Patient();
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.BundleEntryComponent;
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.CodeType;
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.QuestionnaireResponse;
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.StructureDefinition;
import org.hl7.fhir.r4.model.UriType;
@ -1236,6 +1238,40 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
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
public void testValidateForCreate() {
String methodName = "testValidateForCreate";

View File

@ -67,11 +67,8 @@ public class PartitioningInterceptorR4Test extends BaseJpaR4SystemTest {
myDaoConfig.setIndexMissingFields(new DaoConfig().getIndexMissingFields());
}
@Override
@BeforeEach
public void before() throws ServletException {
super.before();
myPartitionSettings.setPartitioningEnabled(true);
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.model.DaoMethodOutcome;
import ca.uhn.fhir.rest.server.TransactionLogMessages;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.springframework.beans.factory.annotation.Autowired;

View File

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

View File

@ -1,25 +1,5 @@
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;
public class MdmTransactionContext {

View File

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

View File

@ -110,7 +110,8 @@ public class MetadataConformanceDstu2_1Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode());
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 {
IOUtils.closeQuietly(status.getEntity().getContent());
}
@ -120,7 +121,7 @@ public class MetadataConformanceDstu2_1Test {
status = ourClient.execute(httpPost);
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
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 {
IOUtils.closeQuietly(status.getEntity().getContent());
}

View File

@ -86,8 +86,8 @@ public class MetadataCapabilityStatementDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode());
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() + ")"));
} finally {
IOUtils.closeQuietly(status.getEntity().getContent());
}

View File

@ -108,7 +108,8 @@ public class MetadataConformanceDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode());
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);
@ -116,7 +117,8 @@ public class MetadataConformanceDstu3Test {
output = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertEquals(200, status.getStatusLine().getStatusCode());
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");

View File

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

View File

@ -738,7 +738,7 @@
<jena_version>3.16.0</jena_version>
<jersey_version>2.25.1</jersey_version>
<!-- 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>
<junit_version>5.6.2</junit_version>
<flyway_version>6.5.4</flyway_version>