theResultList) {
@@ -142,26 +140,33 @@ public class DeleteConflictService {
}
public static void validateDeleteConflictsEmptyOrThrowException(FhirContext theFhirContext, DeleteConflictList theDeleteConflicts) {
- if (theDeleteConflicts.isEmpty()) {
- return;
- }
-
- IBaseOperationOutcome oo = OperationOutcomeUtil.newInstance(theFhirContext);
+ IBaseOperationOutcome oo = null;
String firstMsg = null;
for (DeleteConflict next : theDeleteConflicts) {
+
+ if (theDeleteConflicts.isResourceIdToIgnoreConflict(next.getTargetId())) {
+ continue;
+ }
+
String msg = "Unable to delete " +
next.getTargetId().toUnqualifiedVersionless().getValue() +
" because at least one resource has a reference to this resource. First reference found was resource " +
next.getSourceId().toUnqualifiedVersionless().getValue() +
" in path " +
next.getSourcePath();
+
if (firstMsg == null) {
firstMsg = msg;
+ oo = OperationOutcomeUtil.newInstance(theFhirContext);
}
OperationOutcomeUtil.addIssue(theFhirContext, oo, BaseHapiFhirDao.OO_SEVERITY_ERROR, msg, null, "processing");
}
+ if (firstMsg == null) {
+ return;
+ }
+
throw new ResourceVersionConflictException(firstMsg, oo);
}
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptor.java
index fc8aa12388c..a2875454e06 100644
--- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptor.java
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptor.java
@@ -71,6 +71,13 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
@Interceptor
public class CascadingDeleteInterceptor {
+ /*
+ * We keep the orders for the various handlers of {@link Pointcut#STORAGE_PRESTORAGE_DELETE_CONFLICTS} in one place
+ * so it's easy to compare them
+ */
+ public static final int OVERRIDE_PATH_BASED_REF_INTEGRITY_INTERCEPTOR_ORDER = 0;
+ public static final int CASCADING_DELETE_INTERCEPTOR_ORDER = 1;
+
private static final Logger ourLog = LoggerFactory.getLogger(CascadingDeleteInterceptor.class);
private static final String CASCADED_DELETES_KEY = CascadingDeleteInterceptor.class.getName() + "_CASCADED_DELETES_KEY";
private static final String CASCADED_DELETES_FAILED_KEY = CascadingDeleteInterceptor.class.getName() + "_CASCADED_DELETES_FAILED_KEY";
@@ -94,7 +101,7 @@ public class CascadingDeleteInterceptor {
myFhirContext = theFhirContext;
}
- @Hook(Pointcut.STORAGE_PRESTORAGE_DELETE_CONFLICTS)
+ @Hook(value = Pointcut.STORAGE_PRESTORAGE_DELETE_CONFLICTS, order = CASCADING_DELETE_INTERCEPTOR_ORDER)
public DeleteConflictOutcome handleDeleteConflicts(DeleteConflictList theConflictList, RequestDetails theRequest, TransactionDetails theTransactionDetails) {
ourLog.debug("Have delete conflicts: {}", theConflictList);
diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptor.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptor.java
new file mode 100644
index 00000000000..e3e778cbb72
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptor.java
@@ -0,0 +1,127 @@
+package ca.uhn.fhir.jpa.interceptor;
+
+/*-
+ * #%L
+ * HAPI FHIR JPA Server
+ * %%
+ * 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.context.FhirContext;
+import ca.uhn.fhir.fhirpath.IFhirPath;
+import ca.uhn.fhir.interceptor.api.Hook;
+import ca.uhn.fhir.interceptor.api.Interceptor;
+import ca.uhn.fhir.interceptor.api.Pointcut;
+import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
+import ca.uhn.fhir.jpa.api.model.DeleteConflict;
+import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
+import ca.uhn.fhir.model.primitive.IdDt;
+import org.hl7.fhir.instance.model.api.IBaseReference;
+import org.hl7.fhir.instance.model.api.IBaseResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * This JPA interceptor can be configured with a collection of FHIRPath expressions, and will disable
+ * referential integrity for target resources at those paths.
+ *
+ * For example, suppose this interceptor is configured with a path of AuditEvent.entity.what
,
+ * and an AuditEvent resource exists in the repository that has a reference in that path to resource
+ * Patient/123
. Normally this reference would prevent the Patient resource from being deleted unless
+ * the AuditEvent was first deleted as well (or a cascading delete was used).
+ * With this interceptor in place, the Patient resource could be deleted, and the AuditEvent would remain intact.
+ *
+ */
+@Interceptor
+public class OverridePathBasedReferentialIntegrityForDeletesInterceptor {
+
+ private static final Logger ourLog = LoggerFactory.getLogger(OverridePathBasedReferentialIntegrityForDeletesInterceptor.class);
+ private final Set myPaths = new HashSet<>();
+
+ @Autowired
+ private FhirContext myFhirContext;
+ @Autowired
+ private DaoRegistry myDaoRegistry;
+
+ /**
+ * Constructor
+ */
+ public OverridePathBasedReferentialIntegrityForDeletesInterceptor() {
+ super();
+ }
+
+ /**
+ * Adds a FHIRPath expression indicating a resource path that should be ignored when considering referential
+ * integrity for deletes.
+ *
+ * @param thePath The FHIRPath expression, e.g. AuditEvent.agent.who
+ */
+ public void addPath(String thePath) {
+ getPaths().add(thePath);
+ }
+
+ /**
+ * Remove all paths registered to this interceptor
+ */
+ public void clearPaths() {
+ getPaths().clear();
+ }
+
+ /**
+ * Returns the paths that will be considered by this interceptor
+ *
+ * @see #addPath(String)
+ */
+ public Set getPaths() {
+ return myPaths;
+ }
+
+ /**
+ * Interceptor hook method. Do not invoke directly.
+ */
+ @Hook(value = Pointcut.STORAGE_PRESTORAGE_DELETE_CONFLICTS, order = CascadingDeleteInterceptor.OVERRIDE_PATH_BASED_REF_INTEGRITY_INTERCEPTOR_ORDER)
+ public void handleDeleteConflicts(DeleteConflictList theDeleteConflictList) {
+ for (DeleteConflict nextConflict : theDeleteConflictList) {
+ ourLog.info("Ignoring referential integrity deleting {} - Referred to from {} at path {}", nextConflict.getTargetId(), nextConflict.getSourceId(), nextConflict.getSourcePath());
+
+ IdDt sourceId = nextConflict.getSourceId();
+ IdDt targetId = nextConflict.getTargetId();
+ String targetIdValue = targetId.toVersionless().getValue();
+
+ IBaseResource sourceResource = myDaoRegistry.getResourceDao(sourceId.getResourceType()).read(sourceId);
+
+ IFhirPath fhirPath = myFhirContext.newFhirPath();
+ for (String nextPath : myPaths) {
+ List selections = fhirPath.evaluate(sourceResource, nextPath, IBaseReference.class);
+ for (IBaseReference nextSelection : selections) {
+ String selectionTargetValue = nextSelection.getReferenceElement().toVersionless().getValue();
+ if (Objects.equals(targetIdValue, selectionTargetValue)) {
+ theDeleteConflictList.setResourceIdToIgnoreConflict(nextConflict.getTargetId());
+ break;
+ }
+ }
+
+ }
+
+ }
+ }
+}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java
index bdeb2e803ca..8687c414f01 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao.dstu2;
+import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
@@ -28,6 +29,8 @@ import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
@@ -232,6 +235,47 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
}
+ /**
+ * See #2023
+ */
+ @Test
+ public void testNumberSearchParam() {
+ SearchParameter numberParameter = new ca.uhn.fhir.model.dstu2.resource.SearchParameter();
+ numberParameter.setId("future-appointment-count");
+ numberParameter.setName("Future Appointment Count");
+ numberParameter.setCode("future-appointment-count");
+ numberParameter.setDescription("Count of future appointments for the patient");
+ numberParameter.setUrl("http://integer");
+ numberParameter.setStatus(ca.uhn.fhir.model.dstu2.valueset.ConformanceResourceStatusEnum.ACTIVE);
+ numberParameter.setBase(ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum.PATIENT);
+ numberParameter.setType(ca.uhn.fhir.model.dstu2.valueset.SearchParamTypeEnum.NUMBER);
+ numberParameter.setXpathUsage(XPathUsageTypeEnum.NORMAL);
+ numberParameter.setXpath("Patient.extension('http://integer')");
+ mySearchParameterDao.update(numberParameter);
+
+ // This fires every 10 seconds
+ mySearchParamRegistry.refreshCacheIfNecessary();
+
+ Patient patient = new Patient();
+ patient.setId("future-appointment-count-pt");
+ patient.setActive(true);
+ patient.addUndeclaredExtension(false, "http://integer", new IntegerDt(1));
+ myPatientDao.update(patient);
+
+ IBundleProvider search;
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam(1)));
+ assertEquals(1, search.size());
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam("gt0")));
+ assertEquals(1, search.size());
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam("lt0")));
+ assertEquals(0, search.size());
+
+ }
+
+
@Test
public void testIncludeExtensionReferenceAsRecurse() {
SearchParameter attendingSp = new SearchParameter();
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ValidateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ValidateTest.java
index 620be635195..53da7983125 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ValidateTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2ValidateTest.java
@@ -144,7 +144,7 @@ public class FhirResourceDaoDstu2ValidateTest extends BaseJpaDstu2Test {
} catch (PreconditionFailedException e) {
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome());
ourLog.info(ooString);
- assertThat(ooString, containsString("Profile reference \\\"http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid\\\" could not be resolved, so has not been checked"));
+ assertThat(ooString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java
index 3745e2f2b53..350bf1aa0ab 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3ValidateTest.java
@@ -340,7 +340,7 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
ourLog.info(outputString);
- assertThat(outputString, containsString("Profile reference \\\"http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid\\\" could not be resolved, so has not been checked"));
+ assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
}
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4DeleteTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4DeleteTest.java
index 97cc8d26b42..1cac6951212 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4DeleteTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4DeleteTest.java
@@ -99,7 +99,7 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
@Test
- public void testDeleteCircularReferenceInTransaction() throws IOException {
+ public void testDeleteCircularReferenceInTransaction() {
// Create two resources with a circular reference
Organization org1 = new Organization();
@@ -221,4 +221,12 @@ public class FhirResourceDaoR4DeleteTest extends BaseJpaR4Test {
}
+ @Test
+ public void testDeleteIgnoreReferentialIntegrityForPaths() {
+
+
+
+ }
+
+
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
index 7b935e91508..398f6aae40f 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
@@ -1,5 +1,6 @@
package ca.uhn.fhir.jpa.dao.r4;
+import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.interceptor.api.HookParams;
import ca.uhn.fhir.interceptor.api.IAnonymousInterceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
@@ -9,7 +10,11 @@ import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.model.api.Include;
+import ca.uhn.fhir.model.dstu2.valueset.XPathUsageTypeEnum;
+import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.client.api.IGenericClient;
+import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.NumberParam;
import ca.uhn.fhir.rest.param.ReferenceOrListParam;
@@ -112,6 +117,46 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
mySearchParamRegistry.forceRefresh();
}
+ /**
+ * See #2023
+ */
+ @Test
+ public void testNumberSearchParam() {
+ SearchParameter numberParameter = new SearchParameter();
+ numberParameter.setId("future-appointment-count");
+ numberParameter.setName("Future Appointment Count");
+ numberParameter.setCode("future-appointment-count");
+ numberParameter.setDescription("Count of future appointments for the patient");
+ numberParameter.setUrl("http://integer");
+ numberParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
+ numberParameter.addBase("Patient");
+ numberParameter.setType(Enumerations.SearchParamType.NUMBER);
+ numberParameter.setExpression("Patient.extension('http://integer')");
+ mySearchParameterDao.update(numberParameter);
+
+ // This fires every 10 seconds
+ mySearchParamRegistry.refreshCacheIfNecessary();
+
+ Patient patient = new Patient();
+ patient.setId("future-appointment-count-pt");
+ patient.setActive(true);
+ patient.addExtension( "http://integer", new IntegerType(1));
+ myPatientDao.update(patient);
+
+ IBundleProvider search;
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam(1)));
+ assertEquals(1, search.size());
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam("gt0")));
+ assertEquals(1, search.size());
+
+ search = myPatientDao.search(SearchParameterMap.newSynchronous("future-appointment-count", new NumberParam("lt0")));
+ assertEquals(0, search.size());
+
+ }
+
+
/**
* Draft search parameters should be ok even if they aren't completely valid
*/
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java
index 732b0e451ae..9a6804f4020 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4ValidateTest.java
@@ -314,7 +314,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
outcome = (OperationOutcome) e.getOperationOutcome();
String outcomeStr = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
ourLog.info("Validation outcome: {}", outcomeStr);
- assertThat(outcomeStr, containsString("The Profile \\\"https://bb/StructureDefinition/BBDemographicAge\\\" definition allows for the type Quantity but found type string"));
+ assertThat(outcomeStr, containsString("The Profile 'https://bb/StructureDefinition/BBDemographicAge' definition allows for the type Quantity but found type string"));
}
}
@@ -466,7 +466,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.setSubject(new Reference("Group/123"));
OperationOutcome oo = validateAndReturnOutcome(obs);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
- assertEquals("Unable to resolve resource \"Group/123\"", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
+ assertEquals("Unable to resolve resource 'Group/123'", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
// Target of wrong type
obs.setSubject(new Reference("Group/ABC"));
@@ -530,7 +530,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.setSubject(new Reference("Group/123"));
OperationOutcome oo = validateAndReturnOutcome(obs);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
- assertEquals("Unable to resolve resource \"Group/123\"", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
+ assertEquals("Unable to resolve resource 'Group/123'", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
// Target of wrong type
obs.setSubject(new Reference("Group/ABC"));
@@ -595,7 +595,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
obs.setSubject(new Reference("Group/123"));
OperationOutcome oo = validateAndReturnOutcome(obs);
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo));
- assertEquals("Unable to resolve resource \"Group/123\"", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
+ assertEquals("Unable to resolve resource 'Group/123'", oo.getIssueFirstRep().getDiagnostics(), encode(oo));
// Target of wrong type
obs.setSubject(new Reference("Group/ABC"));
@@ -625,7 +625,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
" },\n" +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
- " \"div\": \"\"\n" +
+ " \"div\": \"HELLO
\"\n" +
" },\n" +
" \"url\": \"https://foo/bb\",\n" +
" \"name\": \"BBBehaviourType\",\n" +
@@ -1134,7 +1134,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
org.hl7.fhir.r4.model.OperationOutcome oo = (org.hl7.fhir.r4.model.OperationOutcome) e.getOperationOutcome();
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
ourLog.info(outputString);
- assertThat(outputString, containsString("Profile reference \\\"http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid\\\" could not be resolved, so has not been checked"));
+ assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
}
}
@@ -1170,7 +1170,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
org.hl7.fhir.r4.model.OperationOutcome oo = (org.hl7.fhir.r4.model.OperationOutcome) e.getOperationOutcome();
String outputString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(oo);
ourLog.info(outputString);
- assertThat(outputString, containsString("Profile reference \\\"http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid\\\" could not be resolved, so has not been checked"));
+ assertThat(outputString, containsString("Profile reference 'http://example.com/StructureDefinition/testValidateResourceContainingProfileDeclarationInvalid' could not be resolved, so has not been checked"));
}
}
@@ -1453,7 +1453,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
fail("Didn't fail- response was " + encode);
} catch (PreconditionFailedException e) {
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
- assertEquals("No response answer found for required item \"link0\"", oo.getIssueFirstRep().getDiagnostics());
+ assertEquals("No response answer found for required item 'link0'", oo.getIssueFirstRep().getDiagnostics());
}
}
@@ -1482,7 +1482,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
fail("Didn't fail- response was " + encode);
} catch (PreconditionFailedException e) {
OperationOutcome oo = (OperationOutcome) e.getOperationOutcome();
- assertEquals("No response answer found for required item \"link0\"", oo.getIssueFirstRep().getDiagnostics());
+ assertEquals("No response answer found for required item 'link0'", oo.getIssueFirstRep().getDiagnostics());
}
}
@@ -1506,7 +1506,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
try {
MethodOutcome validationOutcome = myQuestionnaireResponseDao.validate(qa, null, null, null, null, null, null);
OperationOutcome oo = (OperationOutcome) validationOutcome.getOperationOutcome();
- assertEquals("The questionnaire \"http://foo/Questionnaire/DOES_NOT_EXIST\" could not be resolved, so no validation can be performed against the base questionnaire", oo.getIssueFirstRep().getDiagnostics());
+ assertEquals("The questionnaire 'http://foo/Questionnaire/DOES_NOT_EXIST' could not be resolved, so no validation can be performed against the base questionnaire", oo.getIssueFirstRep().getDiagnostics());
} catch (PreconditionFailedException e) {
fail(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome()));
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/CascadingDeleteInterceptorR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptorTest.java
similarity index 82%
rename from hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/CascadingDeleteInterceptorR4Test.java
rename to hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptorTest.java
index 231d1ebc2de..afa85cc0522 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/CascadingDeleteInterceptorR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/CascadingDeleteInterceptorTest.java
@@ -1,8 +1,8 @@
-package ca.uhn.fhir.jpa.provider.r4;
+package ca.uhn.fhir.jpa.interceptor;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
-import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
+import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
@@ -20,7 +20,6 @@ import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.junit.jupiter.api.AfterEach;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@@ -31,9 +30,9 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
-public class CascadingDeleteInterceptorR4Test extends BaseResourceProviderR4Test {
+public class CascadingDeleteInterceptorTest extends BaseResourceProviderR4Test {
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CascadingDeleteInterceptorR4Test.class);
+ private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CascadingDeleteInterceptorTest.class);
private IIdType myDiagnosticReportId;
@Autowired
@@ -42,18 +41,13 @@ public class CascadingDeleteInterceptorR4Test extends BaseResourceProviderR4Test
private IInterceptorBroadcaster myInterceptorBroadcaster;
private IIdType myPatientId;
+ @Autowired
private CascadingDeleteInterceptor myDeleteInterceptor;
private IIdType myObservationId;
private IIdType myConditionId;
private IIdType myEncounterId;
-
- @Override
- @BeforeEach
- public void before() throws Exception {
- super.before();
-
- myDeleteInterceptor = new CascadingDeleteInterceptor(myFhirCtx, myDaoRegistry, myInterceptorBroadcaster);
- }
+ @Autowired
+ private OverridePathBasedReferentialIntegrityForDeletesInterceptor myOverridePathBasedReferentialIntegrityForDeletesInterceptor;
@Override
@AfterEach
@@ -161,6 +155,37 @@ public class CascadingDeleteInterceptorR4Test extends BaseResourceProviderR4Test
}
}
+ @Test
+ public void testDeleteCascadingWithOverridePathBasedReferentialIntegrityForDeletesInterceptorAlsoRegistered() throws IOException {
+ ourRestServer.getInterceptorService().registerInterceptor(myOverridePathBasedReferentialIntegrityForDeletesInterceptor);
+ try {
+
+ createResources();
+
+ ourRestServer.getInterceptorService().registerInterceptor(myDeleteInterceptor);
+
+ HttpDelete delete = new HttpDelete(ourServerBase + "/" + myPatientId.getValue() + "?" + Constants.PARAMETER_CASCADE_DELETE + "=" + Constants.CASCADE_DELETE + "&_pretty=true");
+ delete.addHeader(Constants.HEADER_ACCEPT, Constants.CT_FHIR_JSON_NEW);
+ try (CloseableHttpResponse response = ourHttpClient.execute(delete)) {
+ assertEquals(200, response.getStatusLine().getStatusCode());
+ String deleteResponse = IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8);
+ ourLog.info("Response: {}", deleteResponse);
+ assertThat(deleteResponse, containsString("Cascaded delete to "));
+ }
+
+ try {
+ ourLog.info("Reading {}", myPatientId);
+ myClient.read().resource(Patient.class).withId(myPatientId).execute();
+ fail();
+ } catch (ResourceGoneException e) {
+ // good
+ }
+
+ } finally {
+ ourRestServer.getInterceptorService().unregisterInterceptor(myOverridePathBasedReferentialIntegrityForDeletesInterceptor);
+ }
+ }
+
@Test
public void testDeleteCascadingWithCircularReference() throws IOException {
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptorTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptorTest.java
new file mode 100644
index 00000000000..14363d30a1a
--- /dev/null
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/interceptor/OverridePathBasedReferentialIntegrityForDeletesInterceptorTest.java
@@ -0,0 +1,141 @@
+package ca.uhn.fhir.jpa.interceptor;
+
+import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.param.ReferenceParam;
+import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
+import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
+import org.hl7.fhir.r4.model.AuditEvent;
+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.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class OverridePathBasedReferentialIntegrityForDeletesInterceptorTest extends BaseJpaR4Test {
+
+ @Autowired
+ private OverridePathBasedReferentialIntegrityForDeletesInterceptor mySvc;
+
+ @Autowired
+ private CascadingDeleteInterceptor myCascadingDeleteInterceptor;
+
+ @AfterEach
+ public void after() {
+ myInterceptorRegistry.unregisterInterceptor(mySvc);
+ mySvc.clearPaths();
+ }
+
+ @Test
+ public void testDeleteBlockedIfNoInterceptorInPlace() {
+ Patient patient = new Patient();
+ patient.setId("P");
+ patient.setActive(true);
+ myPatientDao.update(patient);
+
+ AuditEvent audit = new AuditEvent();
+ audit.setId("A");
+ audit.addAgent().getWho().setReference("Patient/P");
+ myAuditEventDao.update(audit);
+
+ try {
+ myPatientDao.delete(new IdType("Patient/P"));
+ fail();
+ } catch (ResourceVersionConflictException e) {
+ // good
+ }
+ }
+
+
+ @Test
+ public void testAllowDelete() {
+ mySvc.addPath("AuditEvent.agent.who");
+ myInterceptorRegistry.registerInterceptor(mySvc);
+
+ Patient patient = new Patient();
+ patient.setId("P");
+ patient.setActive(true);
+ myPatientDao.update(patient);
+
+ AuditEvent audit = new AuditEvent();
+ audit.setId("A");
+ audit.addAgent().getWho().setReference("Patient/P");
+ myAuditEventDao.update(audit);
+
+ // Delete should proceed
+ myPatientDao.delete(new IdType("Patient/P"));
+
+ // Make sure we're deleted
+ try {
+ myPatientDao.read(new IdType("Patient/P"));
+ fail();
+ } catch (ResourceGoneException e) {
+ // good
+ }
+
+ // Search should still work
+ IBundleProvider searchOutcome = myAuditEventDao.search(SearchParameterMap.newSynchronous(AuditEvent.SP_AGENT, new ReferenceParam("Patient/P")));
+ assertEquals(1, searchOutcome.size());
+
+
+ }
+
+ @Test
+ public void testWrongPath() {
+ mySvc.addPath("AuditEvent.identifier");
+ mySvc.addPath("Patient.agent.who");
+ myInterceptorRegistry.registerInterceptor(mySvc);
+
+ Patient patient = new Patient();
+ patient.setId("P");
+ patient.setActive(true);
+ myPatientDao.update(patient);
+
+ AuditEvent audit = new AuditEvent();
+ audit.setId("A");
+ audit.addAgent().getWho().setReference("Patient/P");
+ myAuditEventDao.update(audit);
+
+ // Delete should proceed
+ try {
+ myPatientDao.delete(new IdType("Patient/P"));
+ fail();
+ } catch (ResourceVersionConflictException e) {
+ // good
+ }
+
+
+ }
+
+ @Test
+ public void testCombineWithCascadeDeleteInterceptor() {
+ try {
+ myInterceptorRegistry.registerInterceptor(myCascadingDeleteInterceptor);
+
+ mySvc.addPath("AuditEvent.agent.who");
+ myInterceptorRegistry.registerInterceptor(mySvc);
+
+ Patient patient = new Patient();
+ patient.setId("P");
+ patient.setActive(true);
+ myPatientDao.update(patient);
+
+ AuditEvent audit = new AuditEvent();
+ audit.setId("A");
+ audit.addAgent().getWho().setReference("Patient/P");
+ myAuditEventDao.update(audit);
+
+ // Delete should proceed
+ myPatientDao.delete(new IdType("Patient/P"));
+
+ } finally {
+ myInterceptorRegistry.unregisterInterceptor(myCascadingDeleteInterceptor);
+ }
+
+ }
+
+}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
index 77c3c89e41d..76c30864d4a 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/ResourceProviderDstu2Test.java
@@ -35,6 +35,12 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
+import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
+import ca.uhn.fhir.model.dstu2.valueset.XPathUsageTypeEnum;
+import ca.uhn.fhir.model.primitive.IntegerDt;
+import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.gclient.NumberClientParam;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.client.methods.CloseableHttpResponse;
@@ -168,6 +174,52 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
}
}
+ /**
+ * See #2023
+ */
+ @Test
+ public void testCustomNumberSearchParam() {
+ SearchParameter numberParameter = new SearchParameter();
+ numberParameter.setId("future-appointment-count");
+ numberParameter.setName("Future Appointment Count");
+ numberParameter.setCode("future-appointment-count");
+ numberParameter.setDescription("Count of future appointments for the patient");
+ numberParameter.setUrl("http://integer");
+ numberParameter.setStatus(ca.uhn.fhir.model.dstu2.valueset.ConformanceResourceStatusEnum.ACTIVE);
+ numberParameter.setBase(ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum.PATIENT);
+ numberParameter.setType(ca.uhn.fhir.model.dstu2.valueset.SearchParamTypeEnum.NUMBER);
+ numberParameter.setXpathUsage(XPathUsageTypeEnum.NORMAL);
+ numberParameter.setXpath("Patient.extension('http://integer')");
+ ourClient.update().resource(numberParameter).execute();
+
+ // This fires every 10 seconds
+ mySearchParamRegistry.refreshCacheIfNecessary();
+
+ Patient patient = new Patient();
+ patient.setId("future-appointment-count-pt");
+ patient.setActive(true);
+ patient.addUndeclaredExtension(false, "http://integer", new IntegerDt(2));
+ ourClient.update().resource(patient).execute();
+
+ Bundle futureAppointmentCountBundle2 = ourClient
+ .search()
+ .forResource(Patient.class)
+ .where(new NumberClientParam("future-appointment-count").greaterThan().number(1))
+ .returnBundle(Bundle.class)
+ .execute();
+ assertEquals(futureAppointmentCountBundle2.getTotal().intValue(), 1);
+
+ Bundle futureAppointmentCountBundle3 = ourClient
+ .search()
+ .forResource(Patient.class)
+ .where(new NumberClientParam("future-appointment-count").exactly().number(2))
+ .returnBundle(Bundle.class)
+ .execute();
+ assertEquals(futureAppointmentCountBundle3.getTotal().intValue(), 1);
+
+ }
+
+
/**
* See #484
*/
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BinaryAccessProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BinaryAccessProviderR4Test.java
index f815d4cad34..a3832ebdb74 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BinaryAccessProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/BinaryAccessProviderR4Test.java
@@ -413,6 +413,8 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
}
+
+
/**
* Stores a binary large enough that it should live in binary storage
*/
@@ -469,6 +471,77 @@ public class BinaryAccessProviderR4Test extends BaseResourceProviderR4Test {
}
+
+ @Test
+ public void testWriteLargeBinaryToDocumentReference() throws IOException {
+ byte[] bytes = new byte[134696];
+ for (int i = 0; i < bytes.length; i++) {
+ bytes[i] = (byte) (((float)Byte.MAX_VALUE) * Math.random());
+ }
+
+ DocumentReference dr = new DocumentReference();
+ dr.addContent().getAttachment()
+ .setContentType("application/pdf")
+ .setSize(12345)
+ .setTitle("hello")
+ .setCreationElement(new DateTimeType("2002"));
+ IIdType id = myClient.create().resource(dr).execute().getId().toUnqualifiedVersionless();
+
+ IAnonymousInterceptor interceptor = mock(IAnonymousInterceptor.class);
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESHOW_RESOURCES, interceptor);
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, interceptor);
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, interceptor);
+
+ // Write using the operation
+
+ String path = ourServerBase +
+ "/DocumentReference/" + id.getIdPart() + "/" +
+ JpaConstants.OPERATION_BINARY_ACCESS_WRITE +
+ "?path=DocumentReference.content.attachment";
+ HttpPost post = new HttpPost(path);
+ post.setEntity(new ByteArrayEntity(bytes, ContentType.IMAGE_JPEG));
+ post.addHeader("Accept", "application/fhir+json; _pretty=true");
+ String attachmentId;
+ try (CloseableHttpResponse resp = ourHttpClient.execute(post)) {
+ assertEquals(200, resp.getStatusLine().getStatusCode());
+ assertThat(resp.getEntity().getContentType().getValue(), containsString("application/fhir+json"));
+
+ String response = IOUtils.toString(resp.getEntity().getContent(), Constants.CHARSET_UTF8);
+ ourLog.info("Response: {}", response);
+
+ DocumentReference target = myFhirCtx.newJsonParser().parseResource(DocumentReference.class, response);
+
+ assertEquals(null, target.getContentFirstRep().getAttachment().getData());
+ assertEquals("2", target.getMeta().getVersionId());
+ attachmentId = target.getContentFirstRep().getAttachment().getDataElement().getExtensionString(HapiExtensions.EXT_EXTERNALIZED_BINARY_ID);
+ assertThat(attachmentId, matchesPattern("[a-zA-Z0-9]{100}"));
+
+ }
+
+ verify(interceptor, timeout(5000).times(1)).invoke(eq(Pointcut.STORAGE_PRESHOW_RESOURCES), any());
+ verify(interceptor, timeout(5000).times(1)).invoke(eq(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED), any());
+ verifyNoMoreInteractions(interceptor);
+
+ // Read it back using the operation
+
+ path = ourServerBase +
+ "/DocumentReference/" + id.getIdPart() + "/" +
+ JpaConstants.OPERATION_BINARY_ACCESS_READ +
+ "?path=DocumentReference.content.attachment";
+ HttpGet get = new HttpGet(path);
+ try (CloseableHttpResponse resp = ourHttpClient.execute(get)) {
+
+ assertEquals(200, resp.getStatusLine().getStatusCode());
+ assertEquals("image/jpeg", resp.getEntity().getContentType().getValue());
+ assertEquals(bytes.length, resp.getEntity().getContentLength());
+
+ byte[] actualBytes = IOUtils.toByteArray(resp.getEntity().getContent());
+ assertArrayEquals(bytes, actualBytes);
+ }
+
+ }
+
+
private IIdType createDocumentReference(boolean theSetData) {
DocumentReference documentReference = new DocumentReference();
Attachment attachment = documentReference
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java
index ababc396273..2df8b6570a3 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ExpungeR4Test.java
@@ -8,11 +8,12 @@ import ca.uhn.fhir.jpa.dao.data.ISearchResultDao;
import ca.uhn.fhir.jpa.search.PersistedJpaSearchFirstPageBundleProvider;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
+import ca.uhn.fhir.rest.param.ReferenceParam;
+import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.HapiExtensions;
-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.BooleanType;
@@ -23,7 +24,6 @@ import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.SearchParameter;
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.slf4j.Logger;
@@ -36,7 +36,9 @@ import static org.awaitility.Awaitility.await;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
-import static org.junit.jupiter.api.Assertions.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
public class ExpungeR4Test extends BaseResourceProviderR4Test {
@@ -410,16 +412,16 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
public void testExpungeEverythingWhereResourceInSearchResults() {
createStandardPatients();
- await().until(()-> runInTransaction(() -> mySearchEntityDao.count() == 0));
- await().until(()-> runInTransaction(() -> mySearchResultDao.count() == 0));
+ await().until(() -> runInTransaction(() -> mySearchEntityDao.count() == 0));
+ await().until(() -> runInTransaction(() -> mySearchResultDao.count() == 0));
PersistedJpaSearchFirstPageBundleProvider search = (PersistedJpaSearchFirstPageBundleProvider) myPatientDao.search(new SearchParameterMap());
assertEquals(PersistedJpaSearchFirstPageBundleProvider.class, search.getClass());
assertEquals(2, search.size().intValue());
assertEquals(2, search.getResources(0, 2).size());
- await().until(()-> runInTransaction(() -> mySearchEntityDao.count() == 1));
- await().until(()-> runInTransaction(() -> mySearchResultDao.count() == 2));
+ await().until(() -> runInTransaction(() -> mySearchEntityDao.count() == 1));
+ await().until(() -> runInTransaction(() -> mySearchResultDao.count() == 2));
mySystemDao.expunge(new ExpungeOptions()
.setExpungeEverything(true), null);
@@ -465,4 +467,87 @@ public class ExpungeR4Test extends BaseResourceProviderR4Test {
}
+ @Test
+ public void testExpungeForcedIdAndThenReuseIt() {
+ // Create with forced ID, and an Observation that links to it
+ Patient p = new Patient();
+ p.setId("TEST");
+ p.setActive(true);
+ p.addName().setFamily("FOO");
+ myPatientDao.update(p);
+
+ Observation obs = new Observation();
+ obs.setId("OBS");
+ obs.getSubject().setReference("Patient/TEST");
+ myObservationDao.update(obs);
+
+ // Make sure read works
+ p = myPatientDao.read(new IdType("Patient/TEST"));
+ assertTrue(p.getActive());
+
+ // Make sure search by ID works
+ IBundleProvider outcome = myPatientDao.search(SearchParameterMap.newSynchronous("_id", new TokenParam("Patient/TEST")));
+ p = (Patient) outcome.getResources(0, 1).get(0);
+ assertTrue(p.getActive());
+
+ // Make sure search by Reference works
+ outcome = myObservationDao.search(SearchParameterMap.newSynchronous(Observation.SP_SUBJECT, new ReferenceParam("Patient/TEST")));
+ obs = (Observation) outcome.getResources(0, 1).get(0);
+ assertEquals("OBS", obs.getIdElement().getIdPart());
+
+ // Delete and expunge
+ myObservationDao.delete(new IdType("Observation/OBS"));
+ myPatientDao.delete(new IdType("Patient/TEST"));
+ myPatientDao.expunge(new ExpungeOptions()
+ .setExpungeDeletedResources(true)
+ .setExpungeOldVersions(true), null);
+ myObservationDao.expunge(new ExpungeOptions()
+ .setExpungeDeletedResources(true)
+ .setExpungeOldVersions(true), null);
+ runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
+ runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
+ runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
+
+ // Create again with the same forced ID
+ p = new Patient();
+ p.setId("TEST");
+ p.setActive(true);
+ p.addName().setFamily("FOO");
+ myPatientDao.update(p);
+
+ obs = new Observation();
+ obs.setId("OBS");
+ obs.getSubject().setReference("Patient/TEST");
+ myObservationDao.update(obs);
+
+ // Make sure read works
+ p = myPatientDao.read(new IdType("Patient/TEST"));
+ assertTrue(p.getActive());
+
+ // Make sure search works
+ outcome = myPatientDao.search(SearchParameterMap.newSynchronous("_id", new TokenParam("Patient/TEST")));
+ p = (Patient) outcome.getResources(0, 1).get(0);
+ assertTrue(p.getActive());
+
+ // Make sure search by Reference works
+ outcome = myObservationDao.search(SearchParameterMap.newSynchronous(Observation.SP_SUBJECT, new ReferenceParam("Patient/TEST")));
+ obs = (Observation) outcome.getResources(0, 1).get(0);
+ assertEquals("OBS", obs.getIdElement().getIdPart());
+
+ // Delete and expunge
+ myObservationDao.delete(new IdType("Observation/OBS"));
+ myPatientDao.delete(new IdType("Patient/TEST"));
+ myPatientDao.expunge(new ExpungeOptions()
+ .setExpungeDeletedResources(true)
+ .setExpungeOldVersions(true), null);
+ myObservationDao.expunge(new ExpungeOptions()
+ .setExpungeDeletedResources(true)
+ .setExpungeOldVersions(true), null);
+ runInTransaction(() -> assertThat(myResourceTableDao.findAll(), empty()));
+ runInTransaction(() -> assertThat(myResourceHistoryTableDao.findAll(), empty()));
+ runInTransaction(() -> assertThat(myForcedIdDao.findAll(), empty()));
+
+ }
+
+
}
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/HookInterceptorR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/HookInterceptorR4Test.java
index 040655c5158..80857380f8d 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/HookInterceptorR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/HookInterceptorR4Test.java
@@ -1,13 +1,25 @@
package ca.uhn.fhir.jpa.provider.r4;
import ca.uhn.fhir.interceptor.api.Pointcut;
+import ca.uhn.fhir.jpa.api.config.DaoConfig;
+import ca.uhn.fhir.jpa.api.dao.IDao;
+import ca.uhn.fhir.jpa.dao.index.IdHelperService;
+import ca.uhn.fhir.jpa.model.util.JpaConstants;
import ca.uhn.fhir.rest.api.MethodOutcome;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
+import org.hl7.fhir.r4.model.BooleanType;
+import org.hl7.fhir.r4.model.Parameters;
import org.hl7.fhir.r4.model.Patient;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import java.util.Collections;
import java.util.concurrent.atomic.AtomicLong;
import static org.junit.jupiter.api.Assertions.assertEquals;
@@ -15,16 +27,24 @@ import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
+ private static final Logger ourLog = LoggerFactory.getLogger(HookInterceptorR4Test.class);
- private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HookInterceptorR4Test.class);
+ @Autowired
+ IdHelperService myIdHelperService;
-// @Override
-// @AfterEach
-// public void after( ) throws Exception {
-// super.after();
-//
-// myInterceptorRegistry.unregisterAllInterceptors();
-// }
+ @BeforeEach
+ public void before() throws Exception {
+ super.before();
+
+ myDaoConfig.setExpungeEnabled(true);
+ }
+
+ @AfterEach
+ public void after() throws Exception {
+ myDaoConfig.setExpungeEnabled(new DaoConfig().isExpungeEnabled());
+
+ super.after();
+ }
@Test
public void testOP_PRESTORAGE_RESOURCE_CREATED_ModifyResource() {
@@ -69,7 +89,7 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
AtomicLong pid = new AtomicLong();
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, (thePointcut, t) -> {
IAnyResource resource = (IAnyResource) t.get(IBaseResource.class, 0);
- Long resourcePid = (Long) resource.getUserData("RESOURCE_PID");
+ Long resourcePid = (Long) resource.getUserData(IDao.RESOURCE_PID_KEY);
assertNotNull(resourcePid, "Expecting RESOURCE_PID to be set on resource user data.");
pid.set(resourcePid);
});
@@ -77,6 +97,72 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
assertTrue(pid.get() > 0);
}
+
+ @Test
+ public void testSTORAGE_PRECOMMIT_RESOURCE_CREATED_hasCorrectPid() {
+ AtomicLong pid = new AtomicLong();
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED, (thePointcut, t) -> {
+ IAnyResource resource = (IAnyResource) t.get(IBaseResource.class, 0);
+ Long resourcePid = (Long) resource.getUserData(IDao.RESOURCE_PID_KEY);
+ assertNotNull(resourcePid, "Expecting RESOURCE_PID to be set on resource user data.");
+ pid.set(resourcePid);
+ });
+ IIdType savedPatientId = myClient.create().resource(new Patient()).execute().getId();
+ Long savedPatientPid = myIdHelperService.resolveResourcePersistentIdsWithCache(null, Collections.singletonList(savedPatientId)).get(0).getIdAsLong();
+ assertEquals(savedPatientPid.longValue(), pid.get());
+ }
+
+ @Test
+ public void testSTORAGE_PRESTORAGE_EXPUNGE_RESOURCE_hasCorrectPid() {
+ AtomicLong pid = new AtomicLong();
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRESTORAGE_EXPUNGE_RESOURCE, (thePointcut, t) -> {
+ IAnyResource resource = (IAnyResource) t.get(IBaseResource.class, 0);
+ Long resourcePid = (Long) resource.getUserData(IDao.RESOURCE_PID_KEY);
+ assertNotNull(resourcePid, "Expecting RESOURCE_PID to be set on resource user data.");
+ pid.set(resourcePid);
+ });
+ IIdType savedPatientId = myClient.create().resource(new Patient()).execute().getId();
+ Long savedPatientPid = myIdHelperService.resolveResourcePersistentIdsWithCache(null, Collections.singletonList(savedPatientId)).get(0).getIdAsLong();
+
+ myClient.delete().resourceById(savedPatientId).execute();
+ Parameters parameters = new Parameters();
+
+ parameters.addParameter().setName(JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES).setValue(new BooleanType(true));
+ myClient
+ .operation()
+ .onInstance(savedPatientId)
+ .named(JpaConstants.OPERATION_EXPUNGE)
+ .withParameters(parameters)
+ .execute();
+
+ assertEquals(savedPatientPid.longValue(), pid.get());
+ }
+
+
+ @Test
+ public void testSTORAGE_PRECOMMIT_RESOURCE_UPDATED_hasCorrectPid() {
+ AtomicLong pidOld = new AtomicLong();
+ AtomicLong pidNew = new AtomicLong();
+ Patient patient = new Patient();
+ IIdType savedPatientId = myClient.create().resource(patient).execute().getId();
+ patient.setId(savedPatientId);
+ myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, (thePointcut, t) -> {
+ IAnyResource resourceOld = (IAnyResource) t.get(IBaseResource.class, 0);
+ IAnyResource resourceNew = (IAnyResource) t.get(IBaseResource.class, 1);
+ Long resourceOldPid = (Long) resourceOld.getUserData(IDao.RESOURCE_PID_KEY);
+ Long resourceNewPid = (Long) resourceNew.getUserData(IDao.RESOURCE_PID_KEY);
+ assertNotNull(resourceOldPid, "Expecting RESOURCE_PID to be set on resource user data.");
+ assertNotNull(resourceNewPid, "Expecting RESOURCE_PID to be set on resource user data.");
+ pidOld.set(resourceOldPid);
+ pidNew.set(resourceNewPid);
+ });
+ patient.setActive(true);
+ myClient.update().resource(patient).execute();
+ Long savedPatientPid = myIdHelperService.resolveResourcePersistentIdsWithCache(null, Collections.singletonList(savedPatientId)).get(0).getIdAsLong();
+ assertEquals(savedPatientPid.longValue(), pidOld.get());
+ assertEquals(savedPatientPid.longValue(), pidNew.get());
+ }
+
@Test
public void testSTORAGE_PRECOMMIT_RESOURCE_UPDATED_hasPid() {
AtomicLong oldPid = new AtomicLong();
@@ -84,12 +170,12 @@ public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
myInterceptorRegistry.registerAnonymousInterceptor(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED, (thePointcut, t) -> {
IAnyResource oldResource = (IAnyResource) t.get(IBaseResource.class, 0);
- Long oldResourcePid = (Long) oldResource.getUserData("RESOURCE_PID");
+ Long oldResourcePid = (Long) oldResource.getUserData(IDao.RESOURCE_PID_KEY);
assertNotNull(oldResourcePid, "Expecting RESOURCE_PID to be set on resource user data.");
oldPid.set(oldResourcePid);
IAnyResource newResource = (IAnyResource) t.get(IBaseResource.class, 1);
- Long newResourcePid = (Long) newResource.getUserData("RESOURCE_PID");
+ Long newResourcePid = (Long) newResource.getUserData(IDao.RESOURCE_PID_KEY);
assertNotNull(newResourcePid, "Expecting RESOURCE_PID to be set on resource user data.");
newPid.set(newResourcePid);
});
diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
index 5e9159f4c8f..5298e159403 100644
--- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
+++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java
@@ -2359,7 +2359,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
String respString = IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8);
ourLog.info(respString);
assertEquals(412, resp.getStatusLine().getStatusCode());
- assertThat(respString, containsString("Profile reference \\\"http://foo/structuredefinition/myprofile\\\" could not be resolved, so has not been checked"));
+ assertThat(respString, containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
}
}
diff --git a/hapi-fhir-jpaserver-batch/pom.xml b/hapi-fhir-jpaserver-batch/pom.xml
index 17d3851f73d..bc7b9f593d2 100644
--- a/hapi-fhir-jpaserver-batch/pom.xml
+++ b/hapi-fhir-jpaserver-batch/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-empi/pom.xml b/hapi-fhir-jpaserver-empi/pom.xml
index 7fcd22c274e..f657cd065d9 100644
--- a/hapi-fhir-jpaserver-empi/pom.xml
+++ b/hapi-fhir-jpaserver-empi/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
@@ -55,13 +55,13 @@
ca.uhn.hapi.fhir
hapi-fhir-test-utilities
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
test
ca.uhn.hapi.fhir
hapi-fhir-jpaserver-test-utilities
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
test
diff --git a/hapi-fhir-jpaserver-empi/src/main/java/ca/uhn/fhir/jpa/empi/svc/EmpiResourceFilteringSvc.java b/hapi-fhir-jpaserver-empi/src/main/java/ca/uhn/fhir/jpa/empi/svc/EmpiResourceFilteringSvc.java
index f1b425ebc03..eddf6d8e439 100644
--- a/hapi-fhir-jpaserver-empi/src/main/java/ca/uhn/fhir/jpa/empi/svc/EmpiResourceFilteringSvc.java
+++ b/hapi-fhir-jpaserver-empi/src/main/java/ca/uhn/fhir/jpa/empi/svc/EmpiResourceFilteringSvc.java
@@ -1,5 +1,25 @@
package ca.uhn.fhir.jpa.empi.svc;
+/*-
+ * #%L
+ * HAPI FHIR JPA Server - 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.context.FhirContext;
import ca.uhn.fhir.empi.api.IEmpiSettings;
import ca.uhn.fhir.empi.log.Logs;
diff --git a/hapi-fhir-jpaserver-migrate/pom.xml b/hapi-fhir-jpaserver-migrate/pom.xml
index b01c017ec53..ffc9eabb3a6 100644
--- a/hapi-fhir-jpaserver-migrate/pom.xml
+++ b/hapi-fhir-jpaserver-migrate/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml
index 0d091ad7b4d..c31d6607a05 100644
--- a/hapi-fhir-jpaserver-model/pom.xml
+++ b/hapi-fhir-jpaserver-model/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml
index aca48a8eda0..7891d8247d5 100755
--- a/hapi-fhir-jpaserver-searchparam/pom.xml
+++ b/hapi-fhir-jpaserver-searchparam/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImpl.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImpl.java
index 46b41128f83..54844451975 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImpl.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImpl.java
@@ -24,8 +24,10 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.context.phonetic.IPhoneticEncoder;
+import ca.uhn.fhir.interceptor.api.Hook;
import ca.uhn.fhir.interceptor.api.HookParams;
-import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
+import ca.uhn.fhir.interceptor.api.IInterceptorService;
+import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.interceptor.api.Pointcut;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.sched.HapiJob;
@@ -38,8 +40,6 @@ import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
-import ca.uhn.fhir.util.DatatypeUtil;
-import ca.uhn.fhir.util.HapiExtensions;
import ca.uhn.fhir.util.SearchParameterUtil;
import ca.uhn.fhir.util.StopWatch;
import org.apache.commons.lang3.StringUtils;
@@ -51,6 +51,7 @@ import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -89,7 +90,8 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
private volatile long myLastRefresh;
@Autowired
- private IInterceptorBroadcaster myInterceptorBroadcaster;
+ private IInterceptorService myInterceptorBroadcaster;
+ private RefreshSearchParameterCacheOnUpdate myInterceptor;
@Override
public RuntimeSearchParam getActiveSearchParam(String theResourceName, String theParamName) {
@@ -236,8 +238,16 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
}
@PostConstruct
- public void postConstruct() {
+ public void start() {
myBuiltInSearchParams = createBuiltInSearchParamMap(myFhirContext);
+
+ myInterceptor = new RefreshSearchParameterCacheOnUpdate();
+ myInterceptorBroadcaster.registerInterceptor(myInterceptor);
+ }
+
+ @PreDestroy
+ public void stop() {
+ myInterceptorBroadcaster.unregisterInterceptor(myInterceptor);
}
public int doRefresh(long theRefreshInterval) {
@@ -376,16 +386,6 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
mySchedulerService.scheduleLocalJob(10 * DateUtils.MILLIS_PER_SECOND, jobDetail);
}
- public static class Job implements HapiJob {
- @Autowired
- private ISearchParamRegistry myTarget;
-
- @Override
- public void execute(JobExecutionContext theContext) {
- myTarget.refreshCacheIfNecessary();
- }
- }
-
@Override
public boolean refreshCacheIfNecessary() {
if (myActiveSearchParams == null || System.currentTimeMillis() - REFRESH_INTERVAL > myLastRefresh) {
@@ -402,30 +402,12 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
return Collections.unmodifiableMap(myActiveSearchParams);
}
- public static Map> createBuiltInSearchParamMap(FhirContext theFhirContext) {
- Map> resourceNameToSearchParams = new HashMap<>();
-
- Set resourceNames = theFhirContext.getResourceTypes();
-
- for (String resourceName : resourceNames) {
- RuntimeResourceDefinition nextResDef = theFhirContext.getResourceDefinition(resourceName);
- String nextResourceName = nextResDef.getName();
- HashMap nameToParam = new HashMap<>();
- resourceNameToSearchParams.put(nextResourceName, nameToParam);
-
- for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
- nameToParam.put(nextSp.getName(), nextSp);
- }
- }
- return Collections.unmodifiableMap(resourceNameToSearchParams);
- }
-
/**
* All SearchParameters with the name "phonetic" encode the normalized index value using this phonetic encoder.
*
* @since 5.1.0
*/
-
+ @Override
public void setPhoneticEncoder(IPhoneticEncoder thePhoneticEncoder) {
myPhoneticEncoder = thePhoneticEncoder;
@@ -446,4 +428,58 @@ public class SearchParamRegistryImpl implements ISearchParamRegistry {
searchParam.setPhoneticEncoder(myPhoneticEncoder);
}
}
+
+ @Interceptor
+ public class RefreshSearchParameterCacheOnUpdate {
+
+ @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_CREATED)
+ public void created(IBaseResource theResource) {
+ handle(theResource);
+ }
+
+ @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_DELETED)
+ public void deleted(IBaseResource theResource) {
+ handle(theResource);
+ }
+
+ @Hook(Pointcut.STORAGE_PRECOMMIT_RESOURCE_UPDATED)
+ public void updated(IBaseResource theResource) {
+ handle(theResource);
+ }
+
+ private void handle(IBaseResource theResource) {
+ if (theResource != null && myFhirContext.getResourceType(theResource).equals("SearchParameter")) {
+ requestRefresh();
+ }
+ }
+
+ }
+
+ public static class Job implements HapiJob {
+ @Autowired
+ private ISearchParamRegistry myTarget;
+
+ @Override
+ public void execute(JobExecutionContext theContext) {
+ myTarget.refreshCacheIfNecessary();
+ }
+ }
+
+ public static Map> createBuiltInSearchParamMap(FhirContext theFhirContext) {
+ Map> resourceNameToSearchParams = new HashMap<>();
+
+ Set resourceNames = theFhirContext.getResourceTypes();
+
+ for (String resourceName : resourceNames) {
+ RuntimeResourceDefinition nextResDef = theFhirContext.getResourceDefinition(resourceName);
+ String nextResourceName = nextResDef.getName();
+ HashMap nameToParam = new HashMap<>();
+ resourceNameToSearchParams.put(nextResourceName, nameToParam);
+
+ for (RuntimeSearchParam nextSp : nextResDef.getSearchParams()) {
+ nameToParam.put(nextSp.getName(), nextSp);
+ }
+ }
+ return Collections.unmodifiableMap(resourceNameToSearchParams);
+ }
}
diff --git a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
index 0ce4a925e79..87f8ec0bc7d 100644
--- a/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
+++ b/hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParameterCanonicalizer.java
@@ -96,31 +96,33 @@ public class SearchParameterCanonicalizer {
String path = theNextSp.getXpath();
RestSearchParameterTypeEnum paramType = null;
RuntimeSearchParam.RuntimeSearchParamStatusEnum status = null;
- switch (theNextSp.getTypeElement().getValueAsEnum()) {
- case COMPOSITE:
- paramType = RestSearchParameterTypeEnum.COMPOSITE;
- break;
- case DATE_DATETIME:
- paramType = RestSearchParameterTypeEnum.DATE;
- break;
- case NUMBER:
- paramType = RestSearchParameterTypeEnum.NUMBER;
- break;
- case QUANTITY:
- paramType = RestSearchParameterTypeEnum.QUANTITY;
- break;
- case REFERENCE:
- paramType = RestSearchParameterTypeEnum.REFERENCE;
- break;
- case STRING:
- paramType = RestSearchParameterTypeEnum.STRING;
- break;
- case TOKEN:
- paramType = RestSearchParameterTypeEnum.TOKEN;
- break;
- case URI:
- paramType = RestSearchParameterTypeEnum.URI;
- break;
+ if (theNextSp.getTypeElement().getValueAsEnum() != null) {
+ switch (theNextSp.getTypeElement().getValueAsEnum()) {
+ case COMPOSITE:
+ paramType = RestSearchParameterTypeEnum.COMPOSITE;
+ break;
+ case DATE_DATETIME:
+ paramType = RestSearchParameterTypeEnum.DATE;
+ break;
+ case NUMBER:
+ paramType = RestSearchParameterTypeEnum.NUMBER;
+ break;
+ case QUANTITY:
+ paramType = RestSearchParameterTypeEnum.QUANTITY;
+ break;
+ case REFERENCE:
+ paramType = RestSearchParameterTypeEnum.REFERENCE;
+ break;
+ case STRING:
+ paramType = RestSearchParameterTypeEnum.STRING;
+ break;
+ case TOKEN:
+ paramType = RestSearchParameterTypeEnum.TOKEN;
+ break;
+ case URI:
+ paramType = RestSearchParameterTypeEnum.URI;
+ break;
+ }
}
if (theNextSp.getStatus() != null) {
switch (theNextSp.getStatusElement().getValueAsEnum()) {
diff --git a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImplTest.java b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImplTest.java
index 43eab94aa59..789c6716570 100644
--- a/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImplTest.java
+++ b/hapi-fhir-jpaserver-searchparam/src/test/java/ca/uhn/fhir/jpa/searchparam/registry/SearchParamRegistryImplTest.java
@@ -3,6 +3,7 @@ package ca.uhn.fhir.jpa.searchparam.registry;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
+import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
import ca.uhn.fhir.rest.server.SimpleBundleProvider;
@@ -46,7 +47,7 @@ public class SearchParamRegistryImplTest {
@MockBean
private ModelConfig myModelConfig;
@MockBean
- private IInterceptorBroadcaster myInterceptorBroadcaster;
+ private IInterceptorService myInterceptorBroadcaster;
@Configuration
static class SpringConfig {
diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml
index 49cdbd5a904..8958aa6ad1d 100644
--- a/hapi-fhir-jpaserver-subscription/pom.xml
+++ b/hapi-fhir-jpaserver-subscription/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml
index 22d8cf83731..aa04dd0888f 100644
--- a/hapi-fhir-jpaserver-test-utilities/pom.xml
+++ b/hapi-fhir-jpaserver-test-utilities/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
index 6da16e6154b..2f3c11b3f7c 100644
--- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
+++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
@@ -157,7 +157,7 @@
ca.uhn.hapi.fhir
hapi-fhir-converter
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
diff --git a/hapi-fhir-server-empi/pom.xml b/hapi-fhir-server-empi/pom.xml
index 3a00cbe9979..b9759c1dda8 100644
--- a/hapi-fhir-server-empi/pom.xml
+++ b/hapi-fhir-server-empi/pom.xml
@@ -7,7 +7,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml
index 2fb5c5bfc41..e57afa70464 100644
--- a/hapi-fhir-server/pom.xml
+++ b/hapi-fhir-server/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
index 20b28d9f538..7afdd3f9976 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
index 2aa29a39cf4..be4e5406fc7 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
hapi-fhir-spring-boot-sample-client-apache
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
index 172179d3278..d29270ada82 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
hapi-fhir-spring-boot-sample-client-okhttp
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
index f82983eca27..d450f6b60b5 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
hapi-fhir-spring-boot-sample-server-jersey
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jpa/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jpa/pom.xml
index 1e775b24432..896111a3e97 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jpa/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jpa/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot-samples
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
hapi-fhir-spring-boot-sample-server-jpa
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
index 313bbc066b5..143a8cc98b0 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir-spring-boot
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
hapi-fhir-spring-boot-samples
diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
index 52916fdbdec..f773d09efd8 100644
--- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
+++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml
index 31be0e2d12f..5231c4407b3 100644
--- a/hapi-fhir-spring-boot/pom.xml
+++ b/hapi-fhir-spring-boot/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml
index 50855a66acf..f79133f2e72 100644
--- a/hapi-fhir-structures-dstu2.1/pom.xml
+++ b/hapi-fhir-structures-dstu2.1/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml
index 6b7d221dcf4..0b2352a3ffa 100644
--- a/hapi-fhir-structures-dstu2/pom.xml
+++ b/hapi-fhir-structures-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml
index 48a45e42d2a..7e6a2c78f03 100644
--- a/hapi-fhir-structures-dstu3/pom.xml
+++ b/hapi-fhir-structures-dstu3/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/ServerExceptionDstu3Test.java b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/ServerExceptionDstu3Test.java
index 0d9eb02415c..86163674490 100644
--- a/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/ServerExceptionDstu3Test.java
+++ b/hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/rest/server/ServerExceptionDstu3Test.java
@@ -1,12 +1,14 @@
package ca.uhn.fhir.rest.server;
import ca.uhn.fhir.context.FhirContext;
+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.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
-import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.test.utilities.JettyUtil;
@@ -29,11 +31,13 @@ import org.hl7.fhir.dstu3.model.OperationOutcome.IssueType;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -44,11 +48,17 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
public class ServerExceptionDstu3Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerExceptionDstu3Test.class);
- public static BaseServerResponseException ourException;
+ public static Exception ourException;
private static CloseableHttpClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
private static int ourPort;
private static Server ourServer;
+ private static RestfulServer ourServlet;
+
+ @AfterEach
+ public void after() {
+ ourException = null;
+ }
@Test
public void testAddHeadersNotFound() throws Exception {
@@ -56,8 +66,8 @@ public class ServerExceptionDstu3Test {
OperationOutcome operationOutcome = new OperationOutcome();
operationOutcome.addIssue().setCode(IssueType.BUSINESSRULE);
- ourException = new ResourceNotFoundException("SOME MESSAGE");
- ourException.addResponseHeader("X-Foo", "BAR BAR");
+ ourException = new ResourceNotFoundException("SOME MESSAGE")
+ .addResponseHeader("X-Foo", "BAR BAR");
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient");
@@ -99,6 +109,65 @@ public class ServerExceptionDstu3Test {
}
+ @Test
+ public void testMethodThrowsNonHapiUncheckedExceptionHandledCleanly() throws Exception {
+
+ ourException = new NullPointerException("Hello");
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ assertEquals(500, status.getStatusLine().getStatusCode());
+ byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
+ String responseContent = new String(responseContentBytes, Charsets.UTF_8);
+ ourLog.info(status.getStatusLine().toString());
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"diagnostics\":\"Failed to call access method: java.lang.NullPointerException: Hello\""));
+ }
+
+ }
+
+ @Test
+ public void testMethodThrowsNonHapiCheckedExceptionHandledCleanly() throws Exception {
+
+ ourException = new IOException("Hello");
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ assertEquals(500, status.getStatusLine().getStatusCode());
+ byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
+ String responseContent = new String(responseContentBytes, Charsets.UTF_8);
+ ourLog.info(status.getStatusLine().toString());
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"diagnostics\":\"Failed to call access method: java.io.IOException: Hello\""));
+ }
+
+ }
+
+ @Test
+ public void testInterceptorThrowsNonHapiUncheckedExceptionHandledCleanly() throws Exception {
+
+ ourServlet.getInterceptorService().registerAnonymousInterceptor(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED, new IAnonymousInterceptor() {
+ @Override
+ public void invoke(Pointcut thePointcut, HookParams theArgs) {
+ throw new NullPointerException("Hello");
+ }
+ });
+
+ HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_format=json");
+ try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
+ assertEquals(500, status.getStatusLine().getStatusCode());
+ byte[] responseContentBytes = IOUtils.toByteArray(status.getEntity().getContent());
+ String responseContent = new String(responseContentBytes, Charsets.UTF_8);
+ ourLog.info(status.getStatusLine().toString());
+ ourLog.info(responseContent);
+ assertThat(responseContent, containsString("\"diagnostics\":\"Hello\""));
+ }
+
+ ourServlet.getInterceptorService().unregisterAllInterceptors();
+
+ }
+
+
@Test
public void testPostWithNoBody() throws IOException {
@@ -143,7 +212,10 @@ public class ServerExceptionDstu3Test {
}
@Search()
- public List search() {
+ public List search() throws Exception {
+ if (ourException == null) {
+ return Collections.emptyList();
+ }
throw ourException;
}
@@ -168,15 +240,15 @@ public class ServerExceptionDstu3Test {
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
ServletHandler proxyHandler = new ServletHandler();
- RestfulServer servlet = new RestfulServer(ourCtx);
- servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
+ ourServlet = new RestfulServer(ourCtx);
+ ourServlet.setPagingProvider(new FifoMemoryPagingProvider(10));
- servlet.setResourceProviders(patientProvider);
- ServletHolder servletHolder = new ServletHolder(servlet);
+ ourServlet.setResourceProviders(patientProvider);
+ ServletHolder servletHolder = new ServletHolder(ourServlet);
proxyHandler.addServletWithMapping(servletHolder, "/*");
ourServer.setHandler(proxyHandler);
JettyUtil.startServer(ourServer);
- ourPort = JettyUtil.getPortForStartedServer(ourServer);
+ ourPort = JettyUtil.getPortForStartedServer(ourServer);
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
HttpClientBuilder builder = HttpClientBuilder.create();
diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml
index 715cb77cfbf..d12aa7952d5 100644
--- a/hapi-fhir-structures-hl7org-dstu2/pom.xml
+++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml
index f20bd38071d..37bbf0c32d1 100644
--- a/hapi-fhir-structures-r4/pom.xml
+++ b/hapi-fhir-structures-r4/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml
index 974483c63aa..7f631e12f32 100644
--- a/hapi-fhir-structures-r5/pom.xml
+++ b/hapi-fhir-structures-r5/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java
index 897de87cd86..3bbc52fb524 100644
--- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java
+++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/ctx/HapiWorkerContext.java
@@ -33,6 +33,7 @@ import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.utilities.TranslationServices;
+import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.i18n.I18nBase;
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
@@ -171,6 +172,11 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
return validateCode(theOptions, system, code, display, theVs);
}
+ @Override
+ public void validateCodeBatch(ValidationOptions options, List extends CodingValidationRequest> codes, ValueSet vs) {
+ throw new UnsupportedOperationException();
+ }
+
@Override
public ValidationResult validateCode(ValidationOptions theOptions, String theSystem, String theCode, String theDisplay) {
IValidationSupport.CodeValidationResult result = myValidationSupport.validateCode(new ValidationSupportContext(myValidationSupport), convertConceptValidationOptions(theOptions), theSystem, theCode, theDisplay, null);
@@ -406,7 +412,17 @@ public final class HapiWorkerContext extends I18nBase implements IWorkerContext
}
@Override
- public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FHIRException {
+ public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FHIRException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FHIRException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FHIRException {
throw new UnsupportedOperationException();
}
diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml
index 974b9e9257c..0838d2e7d1a 100644
--- a/hapi-fhir-test-utilities/pom.xml
+++ b/hapi-fhir-test-utilities/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml
index 28ef8c7af91..59023100bcb 100644
--- a/hapi-fhir-testpage-overlay/pom.xml
+++ b/hapi-fhir-testpage-overlay/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
index 3d855284db4..39647b449c8 100644
--- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
+++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/BaseController.java
@@ -41,6 +41,7 @@ import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.*;
+import static ca.uhn.fhir.util.UrlUtil.sanitizeUrlPart;
import static org.apache.commons.lang3.StringUtils.defaultString;
public class BaseController {
@@ -49,7 +50,7 @@ public class BaseController {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseController.class);
@Autowired
protected TesterConfig myConfig;
- private Map myContexts = new HashMap();
+ private final Map myContexts = new HashMap();
private List myFilterHeaders;
@Autowired
private ITemplateEngine myTemplateEngine;
@@ -78,19 +79,6 @@ public class BaseController {
return loadAndAddConf(theServletRequest, theRequest, theModel);
}
- private Header[] applyHeaderFilters(Header[] theAllHeaders) {
- if (myFilterHeaders == null || myFilterHeaders.isEmpty()) {
- return theAllHeaders;
- }
- ArrayList retVal = new ArrayList();
- for (Header next : theAllHeaders) {
- if (!myFilterHeaders.contains(next.getName().toLowerCase())) {
- retVal.add(next);
- }
- }
- return retVal.toArray(new Header[retVal.size()]);
- }
-
private Header[] applyHeaderFilters(Map> theAllHeaders) {
ArrayList retVal = new ArrayList();
for (String nextKey : theAllHeaders.keySet()) {
@@ -274,7 +262,7 @@ public class BaseController {
}
protected RuntimeResourceDefinition getResourceType(HomeRequest theRequest, HttpServletRequest theReq) throws ServletException {
- String resourceName = StringUtils.defaultString(theReq.getParameter(PARAM_RESOURCE));
+ String resourceName = sanitizeUrlPart(defaultString(theReq.getParameter(PARAM_RESOURCE)));
RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(resourceName);
if (def == null) {
throw new ServletException("Invalid resourceName: " + resourceName);
@@ -317,7 +305,7 @@ public class BaseController {
ca.uhn.fhir.model.dstu2.resource.Conformance conformance;
try {
- conformance = (ca.uhn.fhir.model.dstu2.resource.Conformance) client.fetchConformance().ofType(Conformance.class).execute();
+ conformance = client.fetchConformance().ofType(Conformance.class).execute();
} catch (Exception e) {
ourLog.warn("Failed to load conformance statement, error was: {}", e.toString());
theModel.put("errorMsg", toDisplayError("Failed to load conformance statement, error was: " + e.toString(), e));
@@ -326,7 +314,7 @@ public class BaseController {
theModel.put("jsonEncodedConf", getContext(theRequest).newJsonParser().encodeResourceToString(conformance));
- Map resourceCounts = new HashMap();
+ Map resourceCounts = new HashMap<>();
long total = 0;
for (ca.uhn.fhir.model.dstu2.resource.Conformance.Rest nextRest : conformance.getRest()) {
for (ca.uhn.fhir.model.dstu2.resource.Conformance.RestResource nextResource : nextRest.getResource()) {
@@ -385,7 +373,7 @@ public class BaseController {
theModel.put("jsonEncodedConf", getContext(theRequest).newJsonParser().encodeResourceToString(capabilityStatement));
- Map resourceCounts = new HashMap();
+ Map resourceCounts = new HashMap<>();
long total = 0;
for (CapabilityStatementRestComponent nextRest : capabilityStatement.getRest()) {
@@ -446,7 +434,7 @@ public class BaseController {
theModel.put("jsonEncodedConf", getContext(theRequest).newJsonParser().encodeResourceToString(capabilityStatement));
- Map resourceCounts = new HashMap();
+ Map resourceCounts = new HashMap<>();
long total = 0;
for (org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent nextRest : capabilityStatement.getRest()) {
@@ -507,7 +495,7 @@ public class BaseController {
theModel.put("jsonEncodedConf", getContext(theRequest).newJsonParser().encodeResourceToString(capabilityStatement));
- Map resourceCounts = new HashMap();
+ Map resourceCounts = new HashMap<>();
long total = 0;
for (org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestComponent nextRest : capabilityStatement.getRest()) {
@@ -614,25 +602,6 @@ public class BaseController {
protected void processAndAddLastClientInvocation(GenericClient theClient, ResultType theResultType, ModelMap theModelMap, long theLatency, String outcomeDescription,
CaptureInterceptor theInterceptor, HomeRequest theRequest) {
try {
-// ApacheHttpRequest lastRequest = theInterceptor.getLastRequest();
-// HttpResponse lastResponse = theInterceptor.getLastResponse();
-// String requestBody = null;
-// String requestUrl = lastRequest != null ? lastRequest.getApacheRequest().getURI().toASCIIString() : null;
-// String action = lastRequest != null ? lastRequest.getApacheRequest().getMethod() : null;
-// String resultStatus = lastResponse != null ? lastResponse.getStatusLine().toString() : null;
-// String resultBody = StringUtils.defaultString(theInterceptor.getLastResponseBody());
-//
-// if (lastRequest instanceof HttpEntityEnclosingRequest) {
-// HttpEntity entity = ((HttpEntityEnclosingRequest) lastRequest).getEntity();
-// if (entity.isRepeatable()) {
-// requestBody = IOUtils.toString(entity.getContent());
-// }
-// }
-//
-// ContentType ct = lastResponse != null ? ContentType.get(lastResponse.getEntity()) : null;
-// String mimeType = ct != null ? ct.getMimeType() : null;
-
-
IHttpRequest lastRequest = theInterceptor.getLastRequest();
IHttpResponse lastResponse = theInterceptor.getLastResponse();
String requestBody = null;
diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java
index c0af8e3ea98..3a8031f07ca 100644
--- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java
+++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java
@@ -26,6 +26,7 @@ import ca.uhn.fhir.rest.gclient.TokenClientParam;
import ca.uhn.fhir.to.model.HomeRequest;
import ca.uhn.fhir.to.model.ResourceRequest;
import ca.uhn.fhir.to.model.TransactionRequest;
+import ca.uhn.fhir.util.UrlUtil;
import com.google.gson.stream.JsonWriter;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.dstu3.model.CapabilityStatement;
@@ -49,6 +50,7 @@ import java.util.Collections;
import java.util.List;
import java.util.TreeSet;
+import static ca.uhn.fhir.util.UrlUtil.sanitizeUrlPart;
import static org.apache.commons.lang3.StringUtils.defaultIfEmpty;
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
@@ -128,7 +130,7 @@ public class Controller extends BaseController {
return "resource";
}
- String id = StringUtils.defaultString(theServletRequest.getParameter("resource-delete-id"));
+ String id = sanitizeUrlPart(defaultString(theServletRequest.getParameter("resource-delete-id")));
if (StringUtils.isBlank(id)) {
populateModelForResource(theServletRequest, theRequest, theModel);
theModel.put("errorMsg", toDisplayError("No ID specified", null));
@@ -184,7 +186,7 @@ public class Controller extends BaseController {
FhirContext context = getContext(theRequest);
GenericClient client = theRequest.newClient(theReq, context, myConfig, interceptor);
- String url = defaultString(theReq.getParameter("page-url"));
+ String url = sanitizeUrlPart(defaultString(theReq.getParameter("page-url")));
if (myConfig.isRefuseToFetchThirdPartyUrls()) {
if (!url.startsWith(theModel.get("base").toString())) {
ourLog.warn(logPrefix(theModel) + "Refusing to load page URL: {}", url);
@@ -230,7 +232,7 @@ public class Controller extends BaseController {
theModel.put("errorMsg", toDisplayError(e.toString(), e));
return "resource";
}
- String id = StringUtils.defaultString(theServletRequest.getParameter("id"));
+ String id = sanitizeUrlPart(defaultString(theServletRequest.getParameter("id")));
if (StringUtils.isBlank(id)) {
populateModelForResource(theServletRequest, theRequest, theModel);
theModel.put("errorMsg", toDisplayError("No ID specified", null));
@@ -238,7 +240,7 @@ public class Controller extends BaseController {
}
ResultType returnsResource = ResultType.RESOURCE;
- String versionId = StringUtils.defaultString(theServletRequest.getParameter("vid"));
+ String versionId = sanitizeUrlPart(defaultString(theServletRequest.getParameter("vid")));
String outcomeDescription;
if (StringUtils.isBlank(versionId)) {
versionId = null;
@@ -353,7 +355,7 @@ public class Controller extends BaseController {
return "resource";
}
clientCodeJsonWriter.name("resource");
- clientCodeJsonWriter.value(theServletRequest.getParameter("resource"));
+ clientCodeJsonWriter.value(sanitizeUrlPart(theServletRequest.getParameter("resource")));
} else {
query = search.forAllResources();
clientCodeJsonWriter.name("resource");
@@ -394,7 +396,7 @@ public class Controller extends BaseController {
clientCodeJsonWriter.name("includes");
clientCodeJsonWriter.beginArray();
- String[] incValues = theServletRequest.getParameterValues(Constants.PARAM_INCLUDE);
+ String[] incValues = sanitizeUrlPart(theServletRequest.getParameterValues(Constants.PARAM_INCLUDE));
if (incValues != null) {
for (String next : incValues) {
if (isNotBlank(next)) {
@@ -407,7 +409,7 @@ public class Controller extends BaseController {
clientCodeJsonWriter.name("revincludes");
clientCodeJsonWriter.beginArray();
- String[] revIncValues = theServletRequest.getParameterValues(Constants.PARAM_REVINCLUDE);
+ String[] revIncValues = sanitizeUrlPart(theServletRequest.getParameterValues(Constants.PARAM_REVINCLUDE));
if (revIncValues != null) {
for (String next : revIncValues) {
if (isNotBlank(next)) {
@@ -418,7 +420,7 @@ public class Controller extends BaseController {
}
clientCodeJsonWriter.endArray();
- String limit = theServletRequest.getParameter("resource-search-limit");
+ String limit = sanitizeUrlPart(theServletRequest.getParameter("resource-search-limit"));
if (isNotBlank(limit)) {
if (!limit.matches("[0-9]+")) {
populateModelForResource(theServletRequest, theRequest, theModel);
@@ -434,13 +436,13 @@ public class Controller extends BaseController {
clientCodeJsonWriter.nullValue();
}
- String[] sort = theServletRequest.getParameterValues("sort_by");
+ String[] sort = sanitizeUrlPart(theServletRequest.getParameterValues("sort_by"));
if (sort != null) {
for (String next : sort) {
if (isBlank(next)) {
continue;
}
- String direction = theServletRequest.getParameter("sort_direction");
+ String direction = sanitizeUrlPart(theServletRequest.getParameter("sort_direction"));
if ("asc".equals(direction)) {
query.sort().ascending(new StringClientParam(next));
} else if ("desc".equals(direction)) {
@@ -545,6 +547,7 @@ public class Controller extends BaseController {
type = def.getImplementingClass();
}
+ // Don't sanitize this param, it's a raw resource body and may well be XML
String body = validate ? theReq.getParameter("resource-validate-body") : theReq.getParameter("resource-create-body");
if (isBlank(body)) {
theModel.put("errorMsg", toDisplayError("No message body specified", null));
@@ -583,7 +586,7 @@ public class Controller extends BaseController {
outcomeDescription = "Validate Resource";
client.validate().resource(resource).prettyPrint().execute();
} else {
- String id = theReq.getParameter("resource-create-id");
+ String id = sanitizeUrlPart(theReq.getParameter("resource-create-id"));
if ("update".equals(theMethod)) {
outcomeDescription = "Update Resource";
client.update(id, resource);
@@ -626,17 +629,17 @@ public class Controller extends BaseController {
if ("history-type".equals(theMethod)) {
RuntimeResourceDefinition def = getContext(theRequest).getResourceDefinition(theRequest.getResource());
type = def.getImplementingClass();
- id = StringUtils.defaultString(theReq.getParameter("resource-history-id"));
+ id = sanitizeUrlPart(defaultString(theReq.getParameter("resource-history-id")));
}
DateTimeDt since = null;
- String sinceStr = theReq.getParameter("since");
+ String sinceStr = sanitizeUrlPart(theReq.getParameter("since"));
if (isNotBlank(sinceStr)) {
since = new DateTimeDt(sinceStr);
}
Integer limit = null;
- String limitStr = theReq.getParameter("limit");
+ String limitStr = sanitizeUrlPart(theReq.getParameter("limit"));
if (isNotBlank(limitStr)) {
limit = Integer.parseInt(limitStr);
}
@@ -811,17 +814,17 @@ public class Controller extends BaseController {
}
private boolean handleSearchParam(String paramIdxString, HttpServletRequest theReq, IQuery theQuery, JsonWriter theClientCodeJsonWriter) throws IOException {
- String nextName = theReq.getParameter("param." + paramIdxString + ".name");
+ String nextName = sanitizeUrlPart(theReq.getParameter("param." + paramIdxString + ".name"));
if (isBlank(nextName)) {
return false;
}
- String nextQualifier = StringUtils.defaultString(theReq.getParameter("param." + paramIdxString + ".qualifier"));
- String nextType = theReq.getParameter("param." + paramIdxString + ".type");
+ String nextQualifier = sanitizeUrlPart(defaultString(theReq.getParameter("param." + paramIdxString + ".qualifier")));
+ String nextType = sanitizeUrlPart(theReq.getParameter("param." + paramIdxString + ".type"));
List parts = new ArrayList();
for (int i = 0; i < 5; i++) {
- parts.add(defaultString(theReq.getParameter("param." + paramIdxString + "." + i)));
+ parts.add(sanitizeUrlPart(defaultString(theReq.getParameter("param." + paramIdxString + "." + i))));
}
List values;
diff --git a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/FhirTesterConfig.java b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/FhirTesterConfig.java
index 035ff2caa16..8df0cd3f1f1 100644
--- a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/FhirTesterConfig.java
+++ b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/FhirTesterConfig.java
@@ -48,13 +48,13 @@ public class FhirTesterConfig {
.addServer()
.withId("hapi")
.withFhirVersion(FhirVersionEnum.DSTU2)
- .withBaseUrl("http://fhirtest.uhn.ca/baseDstu2")
+ .withBaseUrl("http://hapi.fhir.org/baseDstu2")
.withName("Public HAPI Test Server")
.allowsApiKey()
.addServer()
.withId("home3")
.withFhirVersion(FhirVersionEnum.DSTU3)
- .withBaseUrl("http://fhirtest.uhn.ca/baseDstu3")
+ .withBaseUrl("http://hapi.fhir.org/baseDstu3")
.withName("Public HAPI Test Server (STU3)")
.addServer()
.withId("home")
diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml
index dd5f6eea395..ac6d12d1177 100644
--- a/hapi-fhir-validation-resources-dstu2.1/pom.xml
+++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml
index 2970965dec0..36edd948d51 100644
--- a/hapi-fhir-validation-resources-dstu2/pom.xml
+++ b/hapi-fhir-validation-resources-dstu2/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml
index c269362f608..15b320aded4 100644
--- a/hapi-fhir-validation-resources-dstu3/pom.xml
+++ b/hapi-fhir-validation-resources-dstu3/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml
index 4c821400648..2a60ccd16c3 100644
--- a/hapi-fhir-validation-resources-r4/pom.xml
+++ b/hapi-fhir-validation-resources-r4/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml
index 344f6ba2ca4..72a869a7a59 100644
--- a/hapi-fhir-validation-resources-r5/pom.xml
+++ b/hapi-fhir-validation-resources-r5/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml
index 44818476928..8f4c0c9cf63 100644
--- a/hapi-fhir-validation/pom.xml
+++ b/hapi-fhir-validation/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-deployable-pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../hapi-deployable-pom/pom.xml
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/ValidatorWrapper.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/ValidatorWrapper.java
index 243fb93814e..9452feb433a 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/ValidatorWrapper.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/ValidatorWrapper.java
@@ -179,7 +179,7 @@ class ValidatorWrapper {
i--;
}
- if (message.endsWith("\" could not be resolved, so has not been checked") && next.getLevel() == ValidationMessage.IssueSeverity.WARNING) {
+ if (message.endsWith("' could not be resolved, so has not been checked") && next.getLevel() == ValidationMessage.IssueSeverity.WARNING) {
next.setLevel(ValidationMessage.IssueSeverity.ERROR);
}
diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
index 848ab9e1d5c..0d4ea9f735c 100644
--- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
+++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/validator/VersionSpecificWorkerContextWrapper.java
@@ -29,6 +29,7 @@ import org.hl7.fhir.r5.model.ValueSet;
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
import org.hl7.fhir.r5.utils.IResourceValidator;
import org.hl7.fhir.utilities.TranslationServices;
+import org.hl7.fhir.utilities.cache.BasePackageCacheManager;
import org.hl7.fhir.utilities.cache.NpmPackage;
import org.hl7.fhir.utilities.i18n.I18nBase;
import org.hl7.fhir.utilities.validation.ValidationMessage;
@@ -56,8 +57,8 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
private static final FhirContext ourR5Context = FhirContext.forR5();
private final ValidationSupportContext myValidationSupportContext;
private final IVersionTypeConverter myModelConverter;
- private volatile List myAllStructures;
private final LoadingCache myFetchResourceCache;
+ private volatile List myAllStructures;
private org.hl7.fhir.r5.model.Parameters myExpansionProfile;
public VersionSpecificWorkerContextWrapper(ValidationSupportContext theValidationSupportContext, IVersionTypeConverter theModelConverter) {
@@ -122,8 +123,18 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
}
@Override
- public void loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FHIRException {
+ public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
+ throw new UnsupportedOperationException();
+ }
+ @Override
+ public int loadFromPackage(NpmPackage pi, IContextResourceLoader loader, String[] types) throws FHIRException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int loadFromPackageAndDependencies(NpmPackage pi, IContextResourceLoader loader, BasePackageCacheManager pcm) throws FileNotFoundException, IOException, FHIRException {
+ throw new UnsupportedOperationException();
}
@Override
@@ -529,6 +540,14 @@ public class VersionSpecificWorkerContextWrapper extends I18nBase implements IWo
return doValidation(convertedVs, validationOptions, system, code, display);
}
+ @Override
+ public void validateCodeBatch(ValidationOptions options, List extends CodingValidationRequest> codes, ValueSet vs) {
+ for (CodingValidationRequest next : codes) {
+ ValidationResult outcome = validateCode(options, next.getCoding(), vs);
+ next.setResult(outcome);
+ }
+ }
+
@Nonnull
private ValidationResult doValidation(IBaseResource theValueSet, ConceptValidationOptions theValidationOptions, String theSystem, String theCode, String theDisplay) {
IValidationSupport.CodeValidationResult result;
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
index 26524f3f3dd..35265595c7c 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/FhirInstanceValidatorDstu3Test.java
@@ -352,7 +352,7 @@ public class FhirInstanceValidatorDstu3Test {
List all = logResultsAndReturnAll(result);
assertEquals(1, all.size());
assertEquals(ResultSeverityEnum.ERROR, all.get(0).getSeverity());
- assertEquals("Unknown code 'urn:iso:std:iso:3166#QQ' for \"urn:iso:std:iso:3166#QQ\"", all.get(0).getMessage());
+ assertEquals("Unknown code 'urn:iso:std:iso:3166#QQ' for 'urn:iso:std:iso:3166#QQ'", all.get(0).getMessage());
}
}
@@ -477,7 +477,7 @@ public class FhirInstanceValidatorDstu3Test {
QuestionnaireResponse qr = loadResource("/dstu3/fmc02-questionnaireresponse-01.json", QuestionnaireResponse.class);
ValidationResult result = myVal.validateWithResult(qr);
List errors = logResultsAndReturnNonInformationalOnes(result);
- assertThat(errors.get(0).getMessage(), containsString("Item has answer, even though it is not enabled (item id = \"BO_ConsDrop\")"));
+ assertThat(errors.get(0).getMessage(), containsString("Item has answer, even though it is not enabled (item id = 'BO_ConsDrop')"));
assertEquals(1, errors.size());
}
@@ -643,6 +643,9 @@ public class FhirInstanceValidatorDstu3Test {
ourLog.info("Skipping logical type: {}", next.getId());
continue;
}
+ if (sd.getUrl().equals("http://hl7.org/fhir/StructureDefinition/Resource")) {
+ continue;
+ }
}
ourLog.info("Validating {}", next.getId());
@@ -725,7 +728,7 @@ public class FhirInstanceValidatorDstu3Test {
ValidationResult results = myVal.validateWithResult(is);
List outcome = logResultsAndReturnNonInformationalOnes(results);
assertEquals(1, outcome.size());
- assertEquals("Unknown code 'http://dicom.nema.org/resources/ontology/DCM#BAR' for \"http://dicom.nema.org/resources/ontology/DCM#BAR\"", outcome.get(0).getMessage());
+ assertEquals("Unknown code 'http://dicom.nema.org/resources/ontology/DCM#BAR' for 'http://dicom.nema.org/resources/ontology/DCM#BAR'", outcome.get(0).getMessage());
// assertEquals("The Coding provided is not in the value set http://hl7.org/fhir/ValueSet/dicom-cid29, and a code should come from this value set unless it has no suitable code. (error message = Unknown code[BAR] in system[http://dicom.nema.org/resources/ontology/DCM])", outcome.get(1).getMessage());
}
@@ -762,7 +765,7 @@ public class FhirInstanceValidatorDstu3Test {
Patient resource = loadResource("/dstu3/nl/nl-core-patient-01.json", Patient.class);
ValidationResult results = myVal.validateWithResult(resource);
List outcome = logResultsAndReturnNonInformationalOnes(results);
- assertThat(outcome.toString(), containsString("The Coding provided is not in the value set http://decor.nictiz.nl/fhir/ValueSet/2.16.840.1.113883.2.4.3.11.60.40.2.20.5.1--20171231000000"));
+ assertThat(outcome.toString(), containsString("The Coding provided (urn:oid:2.16.840.1.113883.2.4.4.16.34#6030) is not in the value set http://decor.nictiz.nl/fhir/ValueSet/2.16.840.1.113883.2.4.3.11.60.40.2.20.5.1--20171231000000"));
}
private void loadNL() throws IOException {
@@ -1084,7 +1087,7 @@ public class FhirInstanceValidatorDstu3Test {
List errors = logResultsAndReturnAll(output);
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
- assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#12345'", errors.get(0).getMessage());
}
@Test
@@ -1121,7 +1124,7 @@ public class FhirInstanceValidatorDstu3Test {
myInstanceVal.setValidationSupport(myValidationSupport);
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
- assertThat(errors.toString(), containsString("Profile reference \"http://foo/structuredefinition/myprofile\" could not be resolved, so has not been checked"));
+ assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
}
@Test
@@ -1165,7 +1168,7 @@ public class FhirInstanceValidatorDstu3Test {
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnAll(output);
assertEquals(
- "The value provided (\"notvalidcode\") is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
+ "The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
output.getMessages().get(0).getMessage());
}
@@ -1197,7 +1200,7 @@ public class FhirInstanceValidatorDstu3Test {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0));
- assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://acme.org#9988877'", errors.get(0).getMessage());
}
@@ -1233,7 +1236,7 @@ public class FhirInstanceValidatorDstu3Test {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#1234'", errors.get(0).getMessage());
}
@Test
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
index 89b7d2dd3eb..95aecce3537 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/QuestionnaireResponseValidatorDstu3Test.java
@@ -364,7 +364,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@Test
@@ -490,7 +490,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString(" No response answer found for required item \"link1\""));
+ assertThat(errors.toString(), containsString(" No response answer found for required item 'link1'"));
}
@Test
@@ -532,7 +532,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
qa.addItem().setLinkId("link1").addAnswer().setValue(new StringType("HELLO"));
errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Item has answer, even though it is not enabled (item id = \"link1\")"));
+ assertThat(errors.toString(), containsString("Item has answer, even though it is not enabled (item id = 'link1')"));
// link0 has an answer, and it's the right one
qa = new QuestionnaireResponse();
@@ -541,7 +541,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
qa.addItem().setLinkId("link0").addAnswer().setValue(new Coding("http://foo", "YES", null));
errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link1\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link1'"));
}
@Test
@@ -669,7 +669,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
// Without an answer
ValidationResult errors = myVal.validateWithResult(qr);
- assertThat(errors.toString(), containsString("No response answer found for required item \"link2\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link2'"));
// With an answer
qr.getItem().get(2).addAnswer().setValue(new StringType("AAA"));
@@ -1064,7 +1064,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
errors = myVal.validateWithResult(qa);
errors = stripBindingHasNoSourceMessage(errors);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Unknown code for \"http://codesystems.com/system#code1\""));
+ assertThat(errors.toString(), containsString("Unknown code for 'http://codesystems.com/system#code1'"));
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
// Partial code
@@ -1132,7 +1132,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
qa.addItem().setLinkId("link0").addAnswer().setValue(new Coding().setDisplay(""));
errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@Test
@@ -1150,7 +1150,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@Test
@@ -1168,7 +1168,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@BeforeAll
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
index 72c38ab01c7..48d5cb31eb7 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/FhirInstanceValidatorR4Test.java
@@ -320,7 +320,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult result = val.validateWithResult(p);
List all = logResultsAndReturnErrorOnes(result);
assertFalse(result.isSuccessful());
- assertEquals("The code \"AA \" is not valid (whitespace rules)", all.get(0).getMessage());
+ assertEquals("The code 'AA ' is not valid (whitespace rules)", all.get(0).getMessage());
}
@@ -524,7 +524,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(encoded);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("The value \"%%%2@()()\" is not a valid Base64 value", errors.get(0).getMessage());
+ assertEquals("The value '%%%2@()()' is not a valid Base64 value", errors.get(0).getMessage());
}
@@ -826,7 +826,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
" \"resourceType\":\"Patient\"," +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
- " \"div\": \"
\"\n" +
+ " \"div\": \"HELLO
\"\n" +
" },\n" +
" \"id\":\"123\"" +
"}";
@@ -842,7 +842,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
"\"resourceType\":\"Patient\"," +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
- " \"div\": \"
\"\n" +
+ " \"div\": \"HELLO
\"\n" +
" },\n" +
"\"id\":\"123\"," +
"\"foo\":\"123\"" +
@@ -1111,7 +1111,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
List errors = logResultsAndReturnAll(output);
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
- assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#12345'", errors.get(0).getMessage());
}
@Test
@@ -1153,7 +1153,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("Profile reference \"http://foo/structuredefinition/myprofile\" could not be resolved, so has not been checked", errors.get(0).getMessage());
+ assertEquals("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked", errors.get(0).getMessage());
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
}
@@ -1202,7 +1202,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnAll(output);
assertEquals(
- "The value provided (\"notvalidcode\") is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.0.1 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
+ "The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.0.1 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
output.getMessages().get(0).getMessage());
}
@@ -1266,7 +1266,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0));
- assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://acme.org#9988877'", errors.get(0).getMessage());
}
@@ -1304,7 +1304,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#1234'", errors.get(0).getMessage());
}
@Test
@@ -1354,8 +1354,8 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
output = myVal.validateWithResult(input);
all = logResultsAndReturnNonInformationalOnes(output);
assertEquals(2, all.size());
- assertThat(all.get(0).getMessage(), containsString("Validation failed for \"http://unitsofmeasure.org#Heck\""));
- assertThat(all.get(1).getMessage(), containsString("The value provided (\"Heck\") is not in the value set http://hl7.org/fhir/ValueSet/ucum-bodytemp"));
+ assertThat(all.get(0).getMessage(), containsString("Validation failed for 'http://unitsofmeasure.org#Heck'"));
+ assertThat(all.get(1).getMessage(), containsString("The value provided ('Heck') is not in the value set http://hl7.org/fhir/ValueSet/ucum-bodytemp"));
}
@@ -1453,7 +1453,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size(), errors.toString());
- assertThat(errors.get(0).getMessage(), containsString("The value provided (\"BLAH\") is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
+ assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
}
@@ -1492,7 +1492,7 @@ public class FhirInstanceValidatorR4Test extends BaseTest {
ValidationResult output = myVal.validateWithResult(allergy);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, errors.size(), errors.toString());
- assertThat(errors.get(0).getMessage(), containsString("The value provided (\"BLAH\") is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
+ assertThat(errors.get(0).getMessage(), containsString("The value provided ('BLAH') is not in the value set http://hl7.org/fhir/ValueSet/currencies"));
}
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java
index e126ce078a5..152e911da2a 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r4/validation/QuestionnaireResponseValidatorR4Test.java
@@ -246,7 +246,7 @@ public class QuestionnaireResponseValidatorR4Test {
errors = myVal.validateWithResult(qa);
errors = stripBindingHasNoSourceMessage(errors);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Unknown code for \"http://codesystems.com/system#code1\""));
+ assertThat(errors.toString(), containsString("Unknown code for 'http://codesystems.com/system#code1'"));
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
qa = new QuestionnaireResponse();
@@ -257,7 +257,7 @@ public class QuestionnaireResponseValidatorR4Test {
errors = myVal.validateWithResult(qa);
errors = stripBindingHasNoSourceMessage(errors);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Unknown code 'http://codesystems.com/system2#code3' for \"http://codesystems.com/system2#code3\""));
+ assertThat(errors.toString(), containsString("Unknown code 'http://codesystems.com/system2#code3' for 'http://codesystems.com/system2#code3'"));
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
}
@@ -319,7 +319,7 @@ public class QuestionnaireResponseValidatorR4Test {
ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@Test
@@ -641,7 +641,7 @@ public class QuestionnaireResponseValidatorR4Test {
qa.addItem().setLinkId("link0").addAnswer().setValue(new Coding().setDisplay(""));
errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@@ -711,7 +711,7 @@ public class QuestionnaireResponseValidatorR4Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@Test
@@ -729,7 +729,7 @@ public class QuestionnaireResponseValidatorR4Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@Test
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
index 23433a1018a..1ba19b530a8 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/FhirInstanceValidatorR5Test.java
@@ -232,7 +232,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult result = val.validateWithResult(p);
List all = logResultsAndReturnErrorOnes(result);
assertFalse(result.isSuccessful());
- assertEquals("The code \"AA \" is not valid (whitespace rules)", all.get(0).getMessage());
+ assertEquals("The code 'AA ' is not valid (whitespace rules)", all.get(0).getMessage());
}
@@ -345,7 +345,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult output = myVal.validateWithResult(encoded);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("The value \"%%%2@()()\" is not a valid Base64 value", errors.get(0).getMessage());
+ assertEquals("The value '%%%2@()()' is not a valid Base64 value", errors.get(0).getMessage());
}
@@ -451,7 +451,7 @@ public class FhirInstanceValidatorR5Test {
" \"resourceType\":\"Patient\"," +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
- " \"div\": \"
\"\n" +
+ " \"div\": \"HELLO
\"\n" +
" },\n" +
" \"id\":\"123\"" +
"}";
@@ -467,7 +467,7 @@ public class FhirInstanceValidatorR5Test {
"\"resourceType\":\"Patient\"," +
" \"text\": {\n" +
" \"status\": \"generated\",\n" +
- " \"div\": \"
\"\n" +
+ " \"div\": \"HELLO
\"\n" +
" },\n" +
"\"id\":\"123\"," +
"\"foo\":\"123\"" +
@@ -673,7 +673,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult output = myVal.validateWithResult(input);
assertEquals(1, output.getMessages().size(), output.toString());
- assertEquals("This \"Patient\" cannot be parsed as a FHIR object (no namespace)", output.getMessages().get(0).getMessage());
+ assertEquals("This 'Patient' cannot be parsed as a FHIR object (no namespace)", output.getMessages().get(0).getMessage());
ourLog.info(output.getMessages().get(0).getLocationString());
}
@@ -755,7 +755,7 @@ public class FhirInstanceValidatorR5Test {
List errors = logResultsAndReturnAll(output);
assertEquals(ResultSeverityEnum.ERROR, errors.get(0).getSeverity());
- assertEquals("Unknown code for \"http://loinc.org#12345\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#12345'", errors.get(0).getMessage());
}
@Test
@@ -795,7 +795,7 @@ public class FhirInstanceValidatorR5Test {
myInstanceVal.setValidationSupport(myValidationSupport);
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
- assertThat(errors.toString(), containsString("Profile reference \"http://foo/structuredefinition/myprofile\" could not be resolved, so has not been checked"));
+ assertThat(errors.toString(), containsString("Profile reference 'http://foo/structuredefinition/myprofile' could not be resolved, so has not been checked"));
}
@Test
@@ -843,7 +843,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult output = myVal.validateWithResult(input);
logResultsAndReturnAll(output);
assertEquals(
- "The value provided (\"notvalidcode\") is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.4.0 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
+ "The value provided ('notvalidcode') is not in the value set http://hl7.org/fhir/ValueSet/observation-status|4.4.0 (http://hl7.org/fhir/ValueSet/observation-status), and a code is required from this value set) (error message = Unknown code 'notvalidcode')",
output.getMessages().get(0).getMessage());
}
@@ -877,7 +877,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnAll(output);
assertThat(errors.toString(), errors.size(), greaterThan(0));
- assertEquals("Unknown code for \"http://acme.org#9988877\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://acme.org#9988877'", errors.get(0).getMessage());
}
@@ -915,7 +915,7 @@ public class FhirInstanceValidatorR5Test {
ValidationResult output = myVal.validateWithResult(input);
List errors = logResultsAndReturnNonInformationalOnes(output);
assertEquals(1, errors.size());
- assertEquals("Unknown code for \"http://loinc.org#1234\"", errors.get(0).getMessage());
+ assertEquals("Unknown code for 'http://loinc.org#1234'", errors.get(0).getMessage());
}
@Test
diff --git a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/QuestionnaireResponseValidatorR5Test.java b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/QuestionnaireResponseValidatorR5Test.java
index 86a33a1a248..11878ec05dd 100644
--- a/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/QuestionnaireResponseValidatorR5Test.java
+++ b/hapi-fhir-validation/src/test/java/org/hl7/fhir/r5/validation/QuestionnaireResponseValidatorR5Test.java
@@ -250,7 +250,7 @@ public class QuestionnaireResponseValidatorR5Test {
errors = myVal.validateWithResult(qa);
errors = stripBindingHasNoSourceMessage(errors);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Unknown code for \"http://codesystems.com/system#code1\""));
+ assertThat(errors.toString(), containsString("Unknown code for 'http://codesystems.com/system#code1'"));
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
qa = new QuestionnaireResponse();
@@ -261,7 +261,7 @@ public class QuestionnaireResponseValidatorR5Test {
errors = myVal.validateWithResult(qa);
errors = stripBindingHasNoSourceMessage(errors);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("Unknown code 'http://codesystems.com/system2#code3' for \"http://codesystems.com/system2#code3\""));
+ assertThat(errors.toString(), containsString("Unknown code 'http://codesystems.com/system2#code3' for 'http://codesystems.com/system2#code3'"));
assertThat(errors.toString(), containsString("QuestionnaireResponse.item[0].answer[0]"));
}
@@ -323,7 +323,7 @@ public class QuestionnaireResponseValidatorR5Test {
ValidationResult errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@Test
@@ -584,7 +584,7 @@ public class QuestionnaireResponseValidatorR5Test {
qa.addItem().setLinkId("link0").addAnswer().setValue(new Coding().setDisplay(""));
errors = myVal.validateWithResult(qa);
ourLog.info(errors.toString());
- assertThat(errors.toString(), containsString("No response answer found for required item \"link0\""));
+ assertThat(errors.toString(), containsString("No response answer found for required item 'link0'"));
}
@@ -603,7 +603,7 @@ public class QuestionnaireResponseValidatorR5Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@Test
@@ -621,7 +621,7 @@ public class QuestionnaireResponseValidatorR5Test {
ourLog.info(errors.toString());
assertThat(errors.toString(), containsString(" - QuestionnaireResponse"));
- assertThat(errors.toString(), containsString("LinkId \"link1\" not found in questionnaire"));
+ assertThat(errors.toString(), containsString("LinkId 'link1' not found in questionnaire"));
}
@Test
diff --git a/hapi-fhir-validation/src/test/resources/bug872-ext-with-hl7-url.json b/hapi-fhir-validation/src/test/resources/bug872-ext-with-hl7-url.json
index f05cd34e26d..0aa5d2e6ebf 100644
--- a/hapi-fhir-validation/src/test/resources/bug872-ext-with-hl7-url.json
+++ b/hapi-fhir-validation/src/test/resources/bug872-ext-with-hl7-url.json
@@ -2,7 +2,7 @@
"resourceType": "Patient",
"text": {
"status": "generated",
- "div": "
"
+ "div": "HELLO
"
},
"extension": [
{
diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml
index 555a59caa36..650f877c7df 100644
--- a/hapi-tinder-plugin/pom.xml
+++ b/hapi-tinder-plugin/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
@@ -58,37 +58,37 @@
ca.uhn.hapi.fhir
hapi-fhir-structures-dstu3
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-hl7org-dstu2
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r4
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-structures-r5
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu2
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-dstu3
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
ca.uhn.hapi.fhir
hapi-fhir-validation-resources-r4
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
org.apache.velocity
diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml
index 05f230210af..8c83b8dacbd 100644
--- a/hapi-tinder-test/pom.xml
+++ b/hapi-tinder-test/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
diff --git a/pom.xml b/pom.xml
index ddc34694707..502cc36b392 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
pom
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
HAPI-FHIR
An open-source implementation of the FHIR specification in Java.
https://hapifhir.io
@@ -678,7 +678,7 @@
- 5.0.9
+ 5.1.0
1.0.2
-Dfile.encoding=UTF-8 -Xmx2048m
@@ -717,7 +717,7 @@
9.4.30.v20200611
3.0.2
- 6.4.1
+ 6.5.4
5.4.14.Final
diff --git a/restful-server-example/pom.xml b/restful-server-example/pom.xml
index 57d87df0199..647c5676335 100644
--- a/restful-server-example/pom.xml
+++ b/restful-server-example/pom.xml
@@ -8,7 +8,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../pom.xml
diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
index a07fff46c3f..54aae250dc9 100644
--- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
+++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml
@@ -6,7 +6,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../../pom.xml
diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml
index 19d7b614cce..ccffbd5aa4e 100644
--- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml
+++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml
@@ -4,7 +4,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../../pom.xml
diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml
index 47360a5a445..a22c7e9f6fb 100644
--- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml
+++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml
@@ -5,7 +5,7 @@
ca.uhn.hapi.fhir
hapi-fhir
- 5.1.0-SNAPSHOT
+ 5.2.0-SNAPSHOT
../../pom.xml