Merge branch 'master' into reuse-subscription-channels
This commit is contained in:
commit
b3e80f8da7
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
<artifactId>hapi-fhir-standalone-overlay-example</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -16,14 +16,14 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- Server -->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
@ -35,43 +35,43 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
|
|
|
@ -32,16 +32,9 @@ import org.hl7.fhir.dstu3.model.ExpansionProfile.SystemVersionProcessingMode;
|
|||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||
import org.hl7.fhir.r4.model.Enumeration;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Expression.ExpressionLanguage;
|
||||
import org.hl7.fhir.r4.model.HealthcareService.HealthcareServiceEligibilityComponent;
|
||||
import org.hl7.fhir.r4.model.Identifier;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.TerminologyCapabilities;
|
||||
import org.hl7.fhir.r4.model.Type;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.hl7.fhir.utilities.Utilities;
|
||||
|
||||
|
||||
|
@ -76,7 +69,7 @@ import org.hl7.fhir.utilities.Utilities;
|
|||
|
||||
|
||||
public class VersionConvertor_30_40 {
|
||||
private static List<String> CANONICAL_URLS = new ArrayList<String>();
|
||||
private static List<String> CANONICAL_URLS = new ArrayList<>();
|
||||
static {
|
||||
CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-conceptmap");
|
||||
CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-valueset");
|
||||
|
@ -16013,6 +16006,7 @@ public class VersionConvertor_30_40 {
|
|||
tgt.setType(convertQuestionnaireItemType(src.getType()));
|
||||
for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent t : src.getEnableWhen())
|
||||
tgt.addEnableWhen(convertQuestionnaireItemEnableWhenComponent(t));
|
||||
tgt.setEnableBehavior(Questionnaire.EnableWhenBehavior.ANY);
|
||||
if (src.hasRequired())
|
||||
tgt.setRequired(src.getRequired());
|
||||
if (src.hasRepeats())
|
||||
|
@ -16029,6 +16023,9 @@ public class VersionConvertor_30_40 {
|
|||
tgt.addInitial().setValue(convertType(src.getInitial()));
|
||||
for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
|
||||
tgt.addItem(convertQuestionnaireItemComponent(t));
|
||||
for (org.hl7.fhir.dstu3.model.Extension t : src.getModifierExtension()) {
|
||||
tgt.addModifierExtension(convertExtension(t));
|
||||
}
|
||||
return tgt;
|
||||
}
|
||||
|
||||
|
@ -16131,8 +16128,10 @@ public class VersionConvertor_30_40 {
|
|||
tgt.setOperator(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator.EXISTS);
|
||||
tgt.setAnswer(convertType(src.getHasAnswerElement()));
|
||||
}
|
||||
else if (src.hasAnswer())
|
||||
tgt.setAnswer(convertType(src.getAnswer()));
|
||||
else if (src.hasAnswer()) {
|
||||
tgt.setOperator(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator.EQUAL);
|
||||
tgt.setAnswer(convertType(src.getAnswer()));
|
||||
}
|
||||
return tgt;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -144,6 +144,9 @@ public class RestHookWithInterceptorR4Test extends BaseSubscriptionsR4Test {
|
|||
|
||||
interceptor.getFinishedLatch().await(10, TimeUnit.SECONDS);
|
||||
ResourceDeliveryMessage lastDelivery = interceptor.getLastDelivery();
|
||||
assertTrue(lastDelivery.getAttribute("ATTR1").isPresent());
|
||||
assertTrue(lastDelivery.getAttribute("ATTR2").isPresent());
|
||||
assertTrue(lastDelivery.getAttribute("ATTRBLANK").isPresent());
|
||||
assertEquals("Some value 1", lastDelivery.getAttribute("ATTR1").get());
|
||||
assertEquals("Some value 2", lastDelivery.getAttribute("ATTR2").get());
|
||||
assertEquals("", lastDelivery.getAttribute("ATTRBLANK").get());
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -158,7 +158,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-converter</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -87,18 +87,19 @@ public class ElementsParameter implements IParameter {
|
|||
if (theExclude) {
|
||||
paramName = Constants.PARAM_ELEMENTS + Constants.PARAM_ELEMENTS_EXCLUDE_MODIFIER;
|
||||
}
|
||||
String[] summary = theRequest.getParameters().get(paramName);
|
||||
String[] elementsValues = theRequest.getParameters().get(paramName);
|
||||
|
||||
if (summary != null && summary.length > 0) {
|
||||
Set<String> retVal = new HashSet<String>();
|
||||
for (String next : summary) {
|
||||
if (elementsValues != null && elementsValues.length > 0) {
|
||||
Set<String> retVal = new HashSet<>();
|
||||
for (String next : elementsValues) {
|
||||
StringTokenizer tok = new StringTokenizer(next, ",");
|
||||
while (tok.hasMoreTokens()) {
|
||||
String token = tok.nextToken();
|
||||
if (isNotBlank(token)) {
|
||||
if (token.contains(".") && standardMode) {
|
||||
continue;
|
||||
}
|
||||
if (token.contains("."))
|
||||
if (standardMode) {
|
||||
continue;
|
||||
}
|
||||
retVal.add(token);
|
||||
}
|
||||
}
|
||||
|
@ -107,11 +108,6 @@ public class ElementsParameter implements IParameter {
|
|||
return null;
|
||||
}
|
||||
|
||||
// Always include the meta element even for subsetted values
|
||||
if (!theExclude) {
|
||||
retVal.add("meta");
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-client-okhttp</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jersey</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-sample-server-jpa</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -62,7 +62,7 @@ public class ElementsParamR4Test {
|
|||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, (containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("name", "maritalStatus"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -77,7 +77,7 @@ public class ElementsParamR4Test {
|
|||
assertThat(responseContent, not(containsString("<div>THE DIV</div>")));
|
||||
assertThat(responseContent, (containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("name"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ public class ElementsParamR4Test {
|
|||
assertThat(responseContent, not(containsString("THE DIV")));
|
||||
assertThat(responseContent, containsString("family"));
|
||||
assertThat(responseContent, containsString("maritalStatus"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "name", "maritalStatus"));
|
||||
assertThat(ourLastElements, containsInAnyOrder("name", "maritalStatus"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -108,7 +108,7 @@ public class ElementsParamR4Test {
|
|||
assertThat(responseContent, containsString("THE DIV"));
|
||||
assertThat(responseContent, not(containsString("family")));
|
||||
assertThat(responseContent, not(containsString("maritalStatus")));
|
||||
assertThat(ourLastElements, containsInAnyOrder("meta", "text"));
|
||||
assertThat(ourLastElements, containsInAnyOrder( "text"));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -184,6 +184,34 @@ public class ElementsParamR4Test {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A search on procedure, with only resource specific elements filters that are specifically
|
||||
* on other resources but Procedure, should not affect the output of the procedure resource.
|
||||
*/
|
||||
@Test
|
||||
public void testMultiResourceElementsFilterDoesntAffectFocalResource() throws IOException {
|
||||
createProcedureWithLongChain();
|
||||
verifyXmlAndJson(
|
||||
"http://localhost:" + ourPort + "/Procedure?_include=*&_elements=Observation.subject",
|
||||
bundle -> {
|
||||
Procedure procedure = (Procedure) bundle.getEntry().get(0).getResource();
|
||||
assertEquals(true, procedure.getMeta().isEmpty());
|
||||
assertEquals("REASON_CODE", procedure.getReasonCode().get(0).getCoding().get(0).getCode());
|
||||
assertEquals("USED_CODE", procedure.getUsedCode().get(0).getCoding().get(0).getCode());
|
||||
|
||||
DiagnosticReport dr = (DiagnosticReport) bundle.getEntry().get(1).getResource();
|
||||
assertEquals(true, dr.getMeta().isEmpty());
|
||||
assertEquals(1, dr.getResult().size());
|
||||
|
||||
Observation obs = (Observation ) bundle.getEntry().get(2).getResource();
|
||||
assertEquals("SUBSETTED", obs.getMeta().getTag().get(0).getCode());
|
||||
assertEquals(null, obs.getStatus());
|
||||
assertEquals(0, obs.getCode().getCoding().size());
|
||||
assertEquals(false, obs.hasValue());
|
||||
assertEquals("Patient/123", obs.getSubject().getReference());
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultiResourceElementsFilterWithMetadataExcludedStandardMode() throws IOException {
|
||||
ourServlet.setElementsSupport(ElementsSupportEnum.STANDARD);
|
||||
|
|
|
@ -95,7 +95,7 @@ public class SearchR4Test {
|
|||
linkSelf = bundle.getLink(Constants.LINK_SELF).getUrl();
|
||||
assertThat(linkSelf, containsString("_elements=name"));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
|
||||
ourLog.info(toJson(bundle));
|
||||
|
||||
|
@ -104,7 +104,7 @@ public class SearchR4Test {
|
|||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
// Fetch the next page
|
||||
|
@ -112,7 +112,7 @@ public class SearchR4Test {
|
|||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
// Fetch the next page
|
||||
|
@ -120,7 +120,7 @@ public class SearchR4Test {
|
|||
bundle = executeAndReturnLinkNext(httpGet, EncodingEnum.JSON);
|
||||
assertThat(toJson(bundle), not(containsString("\"active\"")));
|
||||
linkNext = bundle.getLink(Constants.LINK_NEXT).getUrl();
|
||||
assertThat(linkNext, containsString("_elements=meta,name"));
|
||||
assertThat(linkNext, containsString("_elements=name"));
|
||||
assertThat(linkNext, containsString("_elements:exclude=active,birthDate"));
|
||||
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -31,6 +31,8 @@ import org.hl7.fhir.r4.utils.INarrativeGenerator;
|
|||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.IdStatus;
|
||||
import org.hl7.fhir.r4.validation.DefaultEnableWhenEvaluator;
|
||||
import org.hl7.fhir.r4.validation.IEnableWhenEvaluator;
|
||||
import org.hl7.fhir.r4.validation.InstanceValidator;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
|
@ -47,6 +49,7 @@ import java.net.MalformedURLException;
|
|||
import java.net.URL;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
|
||||
@SuppressWarnings({"PackageAccessibility", "Duplicates"})
|
||||
public class FhirInstanceValidator extends BaseValidatorBridge implements IValidatorModule {
|
||||
|
@ -60,6 +63,9 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
private IValidationSupport myValidationSupport;
|
||||
private boolean noTerminologyChecks = false;
|
||||
private volatile WorkerContextWrapper myWrappedWorkerContext;
|
||||
private Function<IWorkerContext, IEnableWhenEvaluator> enableWhenEvaluatorSupplier;
|
||||
|
||||
private boolean errorForUnknownProfiles;
|
||||
private List<String> extensionDomains = Collections.emptyList();
|
||||
|
||||
/**
|
||||
|
@ -80,6 +86,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
myDocBuilderFactory = DocumentBuilderFactory.newInstance();
|
||||
myDocBuilderFactory.setNamespaceAware(true);
|
||||
myValidationSupport = theValidationSupport;
|
||||
setEnableWhenEvaluatorSupplier(ctx -> new DefaultEnableWhenEvaluator());
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -222,6 +229,14 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
return myAnyExtensionsAllowed;
|
||||
}
|
||||
|
||||
public boolean isErrorForUnknownProfiles() {
|
||||
return errorForUnknownProfiles;
|
||||
}
|
||||
|
||||
public void setErrorForUnknownProfiles(boolean errorForUnknownProfiles) {
|
||||
this.errorForUnknownProfiles = errorForUnknownProfiles;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is true) extensions which are not known to the
|
||||
* validator (e.g. because they have not been explicitly declared in a profile) will
|
||||
|
@ -238,6 +253,14 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
return noTerminologyChecks;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a customized {@link IEnableWhenEvaluator} which is injected to created InstanceValidators
|
||||
*/
|
||||
public void setEnableWhenEvaluatorSupplier(
|
||||
Function<IWorkerContext, IEnableWhenEvaluator> enableWhenEvaluatorSupplier) {
|
||||
this.enableWhenEvaluatorSupplier = enableWhenEvaluatorSupplier;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to {@literal true} (default is false) the valueSet will not be validate
|
||||
*/
|
||||
|
@ -270,6 +293,8 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
|||
v.setAnyExtensionsAllowed(isAnyExtensionsAllowed());
|
||||
v.setResourceIdRule(IdStatus.OPTIONAL);
|
||||
v.setNoTerminologyChecks(isNoTerminologyChecks());
|
||||
v.setEnableWhenEvaluator(enableWhenEvaluatorSupplier.apply(wrappedWorkerContext));
|
||||
v.setErrorForUnknownProfiles(isErrorForUnknownProfiles());
|
||||
v.getExtensionDomains().addAll(extensionDomains);
|
||||
|
||||
List<ValidationMessage> messages = new ArrayList<>();
|
||||
|
|
|
@ -2539,6 +2539,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress);
|
||||
else
|
||||
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), !qItem.getRequired(), "No response found for required item "+qItem.getLinkId());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -390,3 +390,4 @@ public class QuestionnaireResponseValidator extends BaseValidator {
|
|||
return allowedAnswerTypes;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.hl7.fhir.instance.validation;
|
||||
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent;
|
||||
|
||||
public class EnableWhenResult {
|
||||
private final boolean enabled;
|
||||
private final QuestionnaireItemEnableWhenComponent enableWhenCondition;
|
||||
private final Element answerItem;
|
||||
private final String linkId;
|
||||
|
||||
/**
|
||||
* Evaluation result of enableWhen condition
|
||||
*
|
||||
* @param enabled
|
||||
* Evaluation result
|
||||
* @param linkId
|
||||
* LinkId of the questionnaire item
|
||||
* @param enableWhenCondition
|
||||
* Evaluated enableWhen condition
|
||||
* @param answerItem
|
||||
* item in QuestionnaireResponse
|
||||
*/
|
||||
public EnableWhenResult(boolean enabled, String linkId, QuestionnaireItemEnableWhenComponent enableWhenCondition,
|
||||
Element answerItem) {
|
||||
this.enabled = enabled;
|
||||
this.linkId = linkId;
|
||||
this.answerItem = answerItem;
|
||||
this.enableWhenCondition = enableWhenCondition;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getLinkId() {
|
||||
return linkId;
|
||||
}
|
||||
|
||||
public Element getAnswerItem() {
|
||||
return answerItem;
|
||||
}
|
||||
|
||||
public QuestionnaireItemEnableWhenComponent getEnableWhenCondition() {
|
||||
return enableWhenCondition;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,216 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.*;
|
||||
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.*;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
/**
|
||||
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
||||
* Ignores possible modifierExtensions and extensions.
|
||||
*
|
||||
*/
|
||||
public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||
public static final String LINKID_ELEMENT = "linkId";
|
||||
public static final String ITEM_ELEMENT = "item";
|
||||
public static final String ANSWER_ELEMENT = "answer";
|
||||
|
||||
@Override
|
||||
public boolean isQuestionEnabled(QuestionnaireItemComponent questionnaireItem, Element questionnaireResponse) {
|
||||
if (!questionnaireItem.hasEnableWhen()) {
|
||||
return true;
|
||||
}
|
||||
List<EnableWhenResult> evaluationResults = questionnaireItem.getEnableWhen()
|
||||
.stream()
|
||||
.map(enableCondition -> evaluateCondition(enableCondition, questionnaireResponse,
|
||||
questionnaireItem.getLinkId()))
|
||||
.collect(Collectors.toList());
|
||||
return checkConditionResults(evaluationResults, questionnaireItem);
|
||||
}
|
||||
|
||||
|
||||
public boolean checkConditionResults(List<EnableWhenResult> evaluationResults,
|
||||
QuestionnaireItemComponent questionnaireItem) {
|
||||
if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY){
|
||||
return evaluationResults.stream().anyMatch(EnableWhenResult::isEnabled);
|
||||
} if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ALL){
|
||||
return evaluationResults.stream().allMatch(EnableWhenResult::isEnabled);
|
||||
}
|
||||
//TODO: Throw exception? enableBehavior is mandatory when there are multiple conditions
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
protected EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition,
|
||||
Element questionnaireResponse, String linkId) {
|
||||
//TODO: Fix EnableWhenResult stuff
|
||||
List<Element> answerItems = findQuestionAnswers(questionnaireResponse,
|
||||
enableCondition.getQuestion());
|
||||
QuestionnaireItemOperator operator = enableCondition.getOperator();
|
||||
if (operator == QuestionnaireItemOperator.EXISTS){
|
||||
Type answer = enableCondition.getAnswer();
|
||||
if (!(answer instanceof BooleanType)){
|
||||
throw new UnprocessableEntityException("Exists-operator requires answerBoolean");
|
||||
}
|
||||
return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(),
|
||||
linkId, enableCondition, questionnaireResponse);
|
||||
}
|
||||
boolean result = answerItems
|
||||
.stream()
|
||||
.anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator()));
|
||||
return new EnableWhenResult(result, linkId, enableCondition, questionnaireResponse);
|
||||
}
|
||||
|
||||
public Type convertToType(Element element) {
|
||||
Type b = new Factory().create(element.fhirType());
|
||||
if (b instanceof PrimitiveType) {
|
||||
((PrimitiveType<?>) b).setValueAsString(element.primitiveValue());
|
||||
} else {
|
||||
for (Element child : element.getChildren()) {
|
||||
if (!isExtension(child)) {
|
||||
b.setProperty(child.getName(), convertToType(child));
|
||||
}
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
private boolean isExtension(Element element) {
|
||||
return "Extension".equals(element.fhirType());
|
||||
}
|
||||
|
||||
protected boolean evaluateAnswer(Element answer, Type expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
Type actualAnswer;
|
||||
if (isExtension(answer)) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
actualAnswer = convertToType(answer);
|
||||
} catch (FHIRException e) {
|
||||
throw new UnprocessableEntityException("Unexpected answer type", e);
|
||||
}
|
||||
if (!actualAnswer.getClass().equals(expectedAnswer.getClass())) {
|
||||
throw new UnprocessableEntityException("Expected answer and actual answer have incompatible types");
|
||||
}
|
||||
if (expectedAnswer instanceof Coding) {
|
||||
return compareCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer, questionnaireItemOperator);
|
||||
} else if ((expectedAnswer instanceof PrimitiveType)) {
|
||||
return comparePrimitiveAnswer((PrimitiveType<?>)actualAnswer, (PrimitiveType<?>)expectedAnswer, questionnaireItemOperator);
|
||||
} else if (expectedAnswer instanceof Quantity) {
|
||||
return compareQuantityAnswer((Quantity)actualAnswer, (Quantity)expectedAnswer, questionnaireItemOperator);
|
||||
}
|
||||
// TODO: Attachment, reference?
|
||||
throw new UnprocessableEntityException("Unimplemented answer type: " + expectedAnswer.getClass());
|
||||
}
|
||||
|
||||
|
||||
private boolean compareQuantityAnswer(Quantity actualAnswer, Quantity expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
return compareComparable(actualAnswer.getValue(), expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
}
|
||||
|
||||
|
||||
private boolean comparePrimitiveAnswer(PrimitiveType<?> actualAnswer, PrimitiveType<?> expectedAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
if (actualAnswer.getValue() instanceof Comparable){
|
||||
return compareComparable((Comparable)actualAnswer.getValue(), (Comparable) expectedAnswer.getValue(), questionnaireItemOperator);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return actualAnswer.equalsShallow(expectedAnswer);
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return !actualAnswer.equalsShallow(expectedAnswer);
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private boolean compareComparable(Comparable actual, Comparable expected,
|
||||
QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
int result = actual.compareTo(expected);
|
||||
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result != 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_OR_EQUAL){
|
||||
return result >= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_OR_EQUAL){
|
||||
return result <= 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_THAN){
|
||||
return result < 0;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){
|
||||
return result > 0;
|
||||
}
|
||||
|
||||
throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison");
|
||||
|
||||
}
|
||||
|
||||
private List<Element> findQuestionAnswers(Element questionnaireResponse, String question) {
|
||||
List<Element> matchingItems = questionnaireResponse.getChildren(ITEM_ELEMENT)
|
||||
.stream()
|
||||
.flatMap(i -> findSubItems(i).stream())
|
||||
.filter(i -> hasLinkId(i, question))
|
||||
.collect(Collectors.toList());
|
||||
return matchingItems
|
||||
.stream()
|
||||
.flatMap(e -> extractAnswer(e).stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<Element> extractAnswer(Element item) {
|
||||
return item.getChildrenByName(ANSWER_ELEMENT)
|
||||
.stream()
|
||||
.flatMap(c -> c.getChildren().stream())
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private boolean compareCodingAnswer(Coding expectedAnswer, Coding actualAnswer, QuestionnaireItemOperator questionnaireItemOperator) {
|
||||
boolean result = compareSystems(expectedAnswer, actualAnswer) && compareCodes(expectedAnswer, actualAnswer);
|
||||
if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){
|
||||
return result == true;
|
||||
} else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){
|
||||
return result == false;
|
||||
}
|
||||
throw new UnprocessableEntityException("Bad operator for Coding comparison");
|
||||
}
|
||||
|
||||
private boolean compareCodes(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasCode() != value.hasCode()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasCode()) {
|
||||
return expectedCoding.getCode().equals(value.getCode());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean compareSystems(Coding expectedCoding, Coding value) {
|
||||
if (expectedCoding.hasSystem() && !value.hasSystem()) {
|
||||
return false;
|
||||
}
|
||||
if (expectedCoding.hasSystem()) {
|
||||
return expectedCoding.getSystem().equals(value.getSystem());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
private List<Element> findSubItems(Element item) {
|
||||
List<Element> results = item.getChildren(LINKID_ELEMENT)
|
||||
.stream()
|
||||
.flatMap(i -> findSubItems(i).stream())
|
||||
.collect(Collectors.toList());
|
||||
results.add(item);
|
||||
return results;
|
||||
}
|
||||
|
||||
private boolean hasLinkId(Element item, String linkId) {
|
||||
Element linkIdChild = item.getNamedChild(LINKID_ELEMENT);
|
||||
if (linkIdChild != null && linkIdChild.getValue().equals(linkId)){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent;
|
||||
|
||||
public class EnableWhenResult {
|
||||
private final boolean enabled;
|
||||
private final QuestionnaireItemEnableWhenComponent enableWhenCondition;
|
||||
private final Element answerItem;
|
||||
private final String linkId;
|
||||
|
||||
/**
|
||||
* Evaluation result of enableWhen condition
|
||||
*
|
||||
* @param enabled
|
||||
* Evaluation result
|
||||
* @param linkId
|
||||
* LinkId of the questionnaire item
|
||||
* @param enableWhenCondition
|
||||
* Evaluated enableWhen condition
|
||||
* @param responseItem
|
||||
* item in QuestionnaireResponse
|
||||
*/
|
||||
public EnableWhenResult(boolean enabled, String linkId, QuestionnaireItemEnableWhenComponent enableWhenCondition,
|
||||
Element answerItem) {
|
||||
this.enabled = enabled;
|
||||
this.linkId = linkId;
|
||||
this.answerItem = answerItem;
|
||||
this.enableWhenCondition = enableWhenCondition;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getLinkId() {
|
||||
return linkId;
|
||||
}
|
||||
|
||||
public Element getAnswerItem() {
|
||||
return answerItem;
|
||||
}
|
||||
|
||||
public QuestionnaireItemEnableWhenComponent getEnableWhenCondition() {
|
||||
return enableWhenCondition;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
import org.hl7.fhir.r4.elementmodel.Element;
|
||||
import org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent;
|
||||
|
||||
public interface IEnableWhenEvaluator {
|
||||
public boolean isQuestionEnabled(QuestionnaireItemComponent questionnaireItem,
|
||||
Element questionnaireResponse);
|
||||
|
||||
}
|
|
@ -15,6 +15,8 @@ import java.util.UUID;
|
|||
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.exceptions.*;
|
||||
import org.hl7.fhir.convertors.VersionConvertorConstants;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
|
@ -255,6 +257,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
private boolean noExtensibleWarnings;
|
||||
private String serverBase;
|
||||
|
||||
private IEnableWhenEvaluator myEnableWhenEvaluator = new DefaultEnableWhenEvaluator();
|
||||
|
||||
/*
|
||||
* Keeps track of whether a particular profile has been checked or not yet
|
||||
*/
|
||||
|
@ -2465,6 +2469,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
this.allowXsiLocation = allowXsiLocation;
|
||||
}
|
||||
|
||||
public void setEnableWhenEvaluator(IEnableWhenEvaluator myEnableWhenEvaluator) {
|
||||
this.myEnableWhenEvaluator = myEnableWhenEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param element
|
||||
|
@ -2734,21 +2742,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
sdTime = sdTime + (System.nanoTime() - t);
|
||||
if (warning(errors, IssueType.REQUIRED, q.line(), q.col(), stack.getLiteralPath(), qsrc != null, "The questionnaire \""+questionnaire+"\" could not be resolved, so no validation can be performed against the base questionnaire")) {
|
||||
boolean inProgress = "in-progress".equals(element.getNamedChildValue("status"));
|
||||
validateQuestionannaireResponseItems(qsrc, qsrc.getItem(), errors, element, stack, inProgress);
|
||||
validateQuestionannaireResponseItems(qsrc, qsrc.getItem(), errors, element, stack, inProgress, element);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress) {
|
||||
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot) {
|
||||
String text = element.getNamedChildValue("text");
|
||||
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), Utilities.noString(text) || text.equals(qItem.getText()), "If text exists, it must match the questionnaire definition for linkId "+qItem.getLinkId());
|
||||
|
||||
List<Element> answers = new ArrayList<Element>();
|
||||
element.getNamedChildren("answer", answers);
|
||||
if (inProgress)
|
||||
warning(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), (answers.size() > 0) || !qItem.getRequired(), "No response answer found for required item "+qItem.getLinkId());
|
||||
warning(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), isAnswerRequirementFulfilled(qItem, answers), "No response answer found for required item "+qItem.getLinkId());
|
||||
else
|
||||
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), (answers.size() > 0) || !qItem.getRequired(), "No response answer found for required item "+qItem.getLinkId());
|
||||
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), isAnswerRequirementFulfilled(qItem, answers), "No response answer found for required item "+qItem.getLinkId());
|
||||
if (answers.size() > 1)
|
||||
rule(errors, IssueType.INVALID, answers.get(1).line(), answers.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response answer item with this linkId allowed");
|
||||
|
||||
|
@ -2823,7 +2831,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// no validation
|
||||
break;
|
||||
}
|
||||
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress);
|
||||
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress, questionnaireResponseRoot);
|
||||
}
|
||||
if (qItem.getType() == null) {
|
||||
fail(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, "Definition for item "+qItem.getLinkId() + " does not contain a type");
|
||||
|
@ -2832,16 +2840,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
element.getNamedChildren("item", items);
|
||||
rule(errors, IssueType.STRUCTURE, element.line(), element.col(), stack.getLiteralPath(), items.isEmpty(), "Items not of type DISPLAY should not have items - linkId {0}", qItem.getLinkId());
|
||||
} else {
|
||||
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, element, stack, inProgress);
|
||||
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, element, stack, inProgress, questionnaireResponseRoot);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<Element> elements, NodeStack stack, boolean inProgress) {
|
||||
private boolean isAnswerRequirementFulfilled(QuestionnaireItemComponent qItem, List<Element> answers) {
|
||||
return !answers.isEmpty() || !qItem.getRequired() || qItem.getType() == QuestionnaireItemType.GROUP;
|
||||
}
|
||||
|
||||
private void validateQuestionannaireResponseItem(Questionnaire qsrc, QuestionnaireItemComponent qItem, List<ValidationMessage> errors, List<Element> elements, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot) {
|
||||
if (elements.size() > 1)
|
||||
rule(errors, IssueType.INVALID, elements.get(1).line(), elements.get(1).col(), stack.getLiteralPath(), qItem.getRepeats(), "Only one response item with this linkId allowed - " + qItem.getLinkId());
|
||||
for (Element element : elements) {
|
||||
NodeStack ns = stack.push(element, -1, null, null);
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress);
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress, questionnaireResponseRoot);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2853,7 +2865,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
return -1;
|
||||
}
|
||||
|
||||
private void validateQuestionannaireResponseItems(Questionnaire qsrc, List<QuestionnaireItemComponent> qItems, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress) {
|
||||
private void validateQuestionannaireResponseItems(Questionnaire qsrc, List<QuestionnaireItemComponent> qItems, List<ValidationMessage> errors, Element element, NodeStack stack, boolean inProgress, Element questionnaireResponseRoot) {
|
||||
List<Element> items = new ArrayList<Element>();
|
||||
element.getNamedChildren("item", items);
|
||||
// now, sort into stacks
|
||||
|
@ -2866,9 +2878,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
if (index == -1) {
|
||||
QuestionnaireItemComponent qItem = findQuestionnaireItem(qsrc, linkId);
|
||||
if (qItem != null) {
|
||||
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index > -1, "Structural Error: item is in the wrong place");
|
||||
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index > -1, misplacedItemError(qItem));
|
||||
NodeStack ns = stack.push(item, -1, null, null);
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress);
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot);
|
||||
}
|
||||
else
|
||||
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, "LinkId \""+linkId+"\" not found in questionnaire");
|
||||
|
@ -2877,11 +2889,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
{
|
||||
rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index >= lastIndex, "Structural Error: items are out of order");
|
||||
lastIndex = index;
|
||||
List<Element> mapItem = map.get(linkId);
|
||||
if (mapItem == null) {
|
||||
mapItem = new ArrayList<Element>();
|
||||
map.put(linkId, mapItem);
|
||||
}
|
||||
|
||||
List<Element> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
|
||||
|
||||
mapItem.add(item);
|
||||
}
|
||||
}
|
||||
|
@ -2890,13 +2900,25 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
|
|||
// ok, now we have a list of known items, grouped by linkId. We"ve made an error for anything out of order
|
||||
for (QuestionnaireItemComponent qItem : qItems) {
|
||||
List<Element> mapItem = map.get(qItem.getLinkId());
|
||||
if (mapItem != null)
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress);
|
||||
else
|
||||
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), !qItem.getRequired(), "No response found for required item "+qItem.getLinkId());
|
||||
if (mapItem != null){
|
||||
rule(errors, IssueType.INVALID, element.line(), element.col(), stack.getLiteralPath(), myEnableWhenEvaluator.isQuestionEnabled(qItem, questionnaireResponseRoot), "Item has answer, even though it is not enabled "+qItem.getLinkId());
|
||||
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot);
|
||||
} else {
|
||||
//item is missing, is the question enabled?
|
||||
if (myEnableWhenEvaluator.isQuestionEnabled(qItem, questionnaireResponseRoot)) {
|
||||
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), !qItem.getRequired(), "No response found for required item "+qItem.getLinkId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String misplacedItemError(QuestionnaireItemComponent qItem) {
|
||||
return qItem.hasLinkId() ?
|
||||
String.format("Structural Error: item with linkid %s is in the wrong place", qItem.getLinkId())
|
||||
:
|
||||
"Structural Error: item is in the wrong place";
|
||||
}
|
||||
|
||||
private void validateQuestionnaireResponseItemQuantity( List<ValidationMessage> errors, Element answer, NodeStack stack) {
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
package org.hl7.fhir.dstu3.hapi.validation;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent;
|
||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
||||
|
||||
public class EnableWhenResult {
|
||||
private final boolean enabled;
|
||||
private final QuestionnaireItemEnableWhenComponent enableWhenCondition;
|
||||
private final QuestionnaireResponseItemComponent responseItem;
|
||||
private final String linkId;
|
||||
|
||||
/**
|
||||
* Evaluation result of enableWhen condition
|
||||
*
|
||||
* @param enabled
|
||||
* Evaluation result
|
||||
* @param linkId
|
||||
* LinkId of the questionnaire item
|
||||
* @param enableWhenCondition
|
||||
* Evaluated enableWhen condition
|
||||
* @param responseItem
|
||||
* item in QuestionnaireResponse
|
||||
*/
|
||||
public EnableWhenResult(boolean enabled, String linkId, QuestionnaireItemEnableWhenComponent enableWhenCondition,
|
||||
QuestionnaireResponseItemComponent responseItem) {
|
||||
this.enabled = enabled;
|
||||
this.linkId = linkId;
|
||||
this.responseItem = responseItem;
|
||||
this.enableWhenCondition = enableWhenCondition;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
public String getLinkId() {
|
||||
return linkId;
|
||||
}
|
||||
|
||||
public QuestionnaireResponseItemComponent getResponseItem() {
|
||||
return responseItem;
|
||||
}
|
||||
|
||||
public QuestionnaireItemEnableWhenComponent getEnableWhenCondition() {
|
||||
return enableWhenCondition;
|
||||
}
|
||||
}
|
|
@ -7,35 +7,37 @@ import ca.uhn.fhir.validation.FhirValidator;
|
|||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhir.validation.SingleValidationMessage;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.dstu3.context.IWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemOptionComponent;
|
||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
|
||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemAnswerComponent;
|
||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
import static org.hamcrest.Matchers.hasSize;
|
||||
import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.BOOLEAN;
|
||||
import static org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType.CHOICE;
|
||||
import static org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.ArgumentMatchers.contains;
|
||||
import static org.mockito.Matchers.any;
|
||||
import static org.mockito.Matchers.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
@ -43,23 +45,26 @@ import static org.mockito.Mockito.reset;
|
|||
import static org.mockito.Mockito.when;
|
||||
|
||||
public class QuestionnaireResponseValidatorDstu3Test {
|
||||
private static final String QUESTIONNAIRE_URL = "http://example.com/Questionnaire/q1";
|
||||
public static final IdType ID_ICC_QUESTIONNAIRE_SETUP = new IdType("Questionnaire/profile");
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(QuestionnaireResponseValidatorDstu3Test.class);
|
||||
private static final String CODE_ICC_SCHOOLTYPE_PT = "PT";
|
||||
private static final IdType ID_VS_SCHOOLTYPE = new IdType("ValueSet/schooltype");
|
||||
private static final String SYSTEMURI_ICC_SCHOOLTYPE = "http://ehealthinnovation/icc/ns/schooltype";
|
||||
private static DefaultProfileValidationSupport myDefaultValidationSupport = new DefaultProfileValidationSupport();
|
||||
private static FhirContext ourCtx = FhirContext.forDstu3();
|
||||
private static FhirContext ourCtx;
|
||||
private FhirInstanceValidator myInstanceVal;
|
||||
private FhirValidator myVal;
|
||||
private IValidationSupport myValSupport;
|
||||
private IWorkerContext myWorkerCtx;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myValSupport = mock(IValidationSupport.class);
|
||||
// new DefaultProfileValidationSupport();
|
||||
myWorkerCtx = new HapiWorkerContext(ourCtx, myValSupport);
|
||||
|
||||
myVal = ourCtx.newValidator();
|
||||
myVal.setValidateAgainstStandardSchema(false);
|
||||
|
@ -128,7 +133,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
answerValues[11] = new Coding().setSystem("http://codesystems.com/system").setCode("code0");
|
||||
answerValues[12] = new StringType("some value");
|
||||
answerValues[13] = new Attachment().setData("some data".getBytes()).setContentType("txt");
|
||||
answerValues[14] = new Reference("http://example.com/Questionnaire/q1");
|
||||
answerValues[14] = new Reference(QUESTIONNAIRE_URL);
|
||||
answerValues[15] = new Quantity(42);
|
||||
|
||||
for (int i = 0; i < itemCnt; i++) {
|
||||
|
@ -138,7 +143,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
reset(myValSupport);
|
||||
Questionnaire q = new Questionnaire();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class),
|
||||
eq("http://example.com/Questionnaire/q1"))).thenReturn(q);
|
||||
eq(QUESTIONNAIRE_URL))).thenReturn(q);
|
||||
when(myValSupport.fetchCodeSystem(any(FhirContext.class), eq("http://codesystems.com/system"))).thenReturn(codeSystem);
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(ValueSet.class), eq("http://somevalueset"))).thenReturn(options);
|
||||
myInstanceVal.flushCaches();
|
||||
|
@ -155,7 +160,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.INPROGRESS);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId(linkId).addAnswer().setValue(answerValues[i]);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
@ -171,7 +176,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(qa.getQuestionnaire().getReference()))).thenReturn(q);
|
||||
|
@ -184,11 +189,11 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testCodedAnswer() {
|
||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||
String questionnaireRef = QUESTIONNAIRE_URL;
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.CHOICE).setOptions(new Reference("http://somevalueset"));
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq("http://example.com/Questionnaire/q1"))).thenReturn(q);
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(QUESTIONNAIRE_URL))).thenReturn(q);
|
||||
|
||||
CodeSystem codeSystem = new CodeSystem();
|
||||
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
||||
|
@ -252,7 +257,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
QuestionnaireResponseItemComponent qaGroup = qa.addItem();
|
||||
qaGroup.addItem().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
|
@ -263,6 +268,43 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
assertThat(errors.toString(), containsString("No LinkId, so can't be validated"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingAnswerInNestedStructureIsReported() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setType(QuestionnaireItemType.GROUP).setRequired(true)
|
||||
.addItem().setType(QuestionnaireItemType.GROUP).setRequired(true)
|
||||
.addItem().setType(QuestionnaireItemType.BOOLEAN).setLinkId("link0").setRequired(true);
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(qa.getQuestionnaire().getReference()))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
assertThat(errors.toString(), Matchers.not(containsString("No issues")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupMarkedAsRequiredIsOk() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setType(QuestionnaireItemType.GROUP).setRequired(true).setLinkId("link1")
|
||||
.addItem().setType(QuestionnaireItemType.BOOLEAN).setLinkId("link0").setRequired(true);
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link1")
|
||||
.addItem().setLinkId("link0").addAnswer().setValue(new BooleanType(true));
|
||||
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(qa.getQuestionnaire().getReference()))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testItemWithNoType() {
|
||||
Questionnaire q = new Questionnaire();
|
||||
|
@ -272,7 +314,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
QuestionnaireResponseItemComponent qaGroup = qa.addItem().setLinkId("link0");
|
||||
qaGroup.addItem().setLinkId("link1").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
|
@ -293,7 +335,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link1").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
|
@ -304,9 +346,270 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
assertThat(errors.toString(), containsString("No response found for required item link0"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEnableWhenWithHasAnswerTrueDisablesQuestionWhenNoAnswerIsPresent() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING);
|
||||
q.addItem().setLinkId("link1").setRequired(true).addEnableWhen().setQuestion("link0").setHasAnswer(true);
|
||||
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredQuestionQuantityWithEnableWhenHidesQuestionHasAnswerTrue() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||
|
||||
//link1 question is enabled when link0 has answer
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
item1.setLinkId("link1").setRequired(true);
|
||||
q.addItem(item1);
|
||||
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||
item1.addEnableWhen(enable);
|
||||
enable.setQuestion("link0");
|
||||
enable.setHasAnswer(true);
|
||||
enable.setAnswer(new Quantity().setValue(1L));
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredQuestionQuantityWithEnableWhenHidesQuestionValue() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||
|
||||
//link1 question is enabled when link0 has answer
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
item1.setLinkId("link1").setRequired(true);
|
||||
q.addItem(item1);
|
||||
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||
item1.addEnableWhen(enable);
|
||||
enable.setQuestion("link0");
|
||||
enable.setAnswer(new Quantity().setValue(2L));
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link0").addAnswer().setValue(new Quantity().setValue(1L));
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredQuestionQuantityWithEnableWhenEnablesQuestionValue() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.QUANTITY);
|
||||
|
||||
//link1 question is enabled when link0 has answer
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
item1.setLinkId("link1").setRequired(true);
|
||||
q.addItem(item1);
|
||||
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||
item1.addEnableWhen(enable);
|
||||
enable.setQuestion("link0");
|
||||
enable.setAnswer(new Quantity().setValue(1L));
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link0").addAnswer().setValue(new Quantity().setValue(1L));
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No response found for required item link1"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRequiredQuestionWithEnableWhenHasAnswerTrueWithAnswer() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(true).setType(QuestionnaireItemType.STRING);
|
||||
|
||||
// create the questionnaire
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
item1.setLinkId("link1").setRequired(true).setType(QuestionnaireItemType.STRING);
|
||||
q.addItem(item1);
|
||||
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||
item1.addEnableWhen(enable);
|
||||
enable.setQuestion("link0");
|
||||
enable.setHasAnswer(true);
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
||||
qa.addItem().setLinkId("link1").addAnswer().setValue(new StringType("BAR"));
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testRequiredQuestionWithEnableWheHidesRequiredQuestionnHasAnswerFalse() {
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING);
|
||||
|
||||
// create the questionnaire
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
item1.setLinkId("link1").setRequired(true);
|
||||
q.addItem(item1);
|
||||
QuestionnaireItemEnableWhenComponent enable = new QuestionnaireItemEnableWhenComponent();
|
||||
item1.addEnableWhen(enable);
|
||||
enable.setQuestion("link0");
|
||||
enable.setHasAnswer(false);
|
||||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
|
||||
// link1 should be disabled, because the enableWhen enables it when link0 doesn't haven an answer
|
||||
qa.addItem().setLinkId("link0").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
String reference = qa.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
ValidationResult errors = myVal.validateWithResult(qa);
|
||||
|
||||
ourLog.info(errors.toString());
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGivenQuestionIsNotEnabledWithEnableWhenAnswersAreReportedAsErrors() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
q.addItem().setLinkId("link0").setRequired(false).setType(QuestionnaireItemType.STRING);
|
||||
q.addItem().setLinkId("link2").setRequired(false).setType(QuestionnaireItemType.STRING).addEnableWhen().setQuestion("link0").setHasAnswer(true);
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
|
||||
qr.addItem().setLinkId("link2").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
String reference = qr.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qr);
|
||||
|
||||
assertThat(errors.toString(), Matchers.not(containsString("No issues")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGivenQuestionnaireResponseHasSiblingItemsWhenTheyShouldBeChildItems() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
QuestionnaireItemComponent item = q.addItem().setLinkId("link0").setRequired(true).setType(QuestionnaireItemType.GROUP);
|
||||
item.addItem().setLinkId("link1").setRequired(true).setType(QuestionnaireItemType.STRING);
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qr.addItem().setLinkId("link0").setText("Text");
|
||||
qr.addItem().setLinkId("link1").addAnswer().setValue(new StringType("Answer"));
|
||||
String reference = qr.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qr);
|
||||
assertThat(errors.toString(), Matchers.not(containsString("No issues")));
|
||||
assertTrue("Must contain structural error about misplaced link1 item",
|
||||
errors.getMessages().stream().filter(vm -> vm.getMessage().contains("Structural Error"))
|
||||
.anyMatch(vm -> vm.getMessage().contains("link1")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAnswerIsValueCodingWithExtensionInside() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
Coding qcoding = new Coding();
|
||||
qcoding.setCode("1293");
|
||||
q.addItem().setLinkId("1B").setRequired(true).setType(CHOICE).addOption().setValue(qcoding);
|
||||
q.addItem().setLinkId("2B").setType(BOOLEAN).addEnableWhen().setQuestion("1B").setAnswer(qcoding);
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(COMPLETED);
|
||||
qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
QuestionnaireResponseItemComponent qrItem = qr.addItem().setLinkId("1B");
|
||||
Coding coding = new Coding();
|
||||
coding.setCode("1293");
|
||||
QuestionnaireResponseItemAnswerComponent answer = qrItem.addAnswer();
|
||||
answer.setValue(coding);
|
||||
coding.addExtension("http://hl7.org/fhir/StructureDefinition/questionnaire-hidden", new BooleanType(true));
|
||||
qr.addItem().setLinkId("2B").addAnswer().setValue(new BooleanType(true));
|
||||
|
||||
String reference = qr.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qr);
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testChoiceItemsEnableWhenHasNoSystemYetAnswerHasSystem() throws Exception {
|
||||
Questionnaire q = new Questionnaire();
|
||||
Coding qcoding = new Coding();
|
||||
qcoding.setCode("male");
|
||||
qcoding.setSystem("http://hl7.org/fhir/administrative-gender");
|
||||
q.addItem().setLinkId("1B").setRequired(true).setType(CHOICE).addOption().setValue(qcoding);
|
||||
Coding enablewhenCoding = new Coding();
|
||||
enablewhenCoding.setCode("male");
|
||||
q.addItem().setLinkId("2B").setType(BOOLEAN).addEnableWhen().setQuestion("1B").setAnswer(enablewhenCoding);
|
||||
|
||||
QuestionnaireResponse qr = new QuestionnaireResponse();
|
||||
qr.setStatus(COMPLETED);
|
||||
qr.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
QuestionnaireResponseItemComponent qrItem = qr.addItem().setLinkId("1B");
|
||||
Coding coding = new Coding();
|
||||
coding.setCode("male");
|
||||
coding.setSystem("http://hl7.org/fhir/administrative-gender");
|
||||
QuestionnaireResponseItemAnswerComponent answer = qrItem.addAnswer();
|
||||
answer.setValue(coding);
|
||||
qr.addItem().setLinkId("2B").addAnswer().setValue(new BooleanType(true));
|
||||
|
||||
String reference = qr.getQuestionnaire().getReference();
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference))).thenReturn(q);
|
||||
|
||||
ValidationResult errors = myVal.validateWithResult(qr);
|
||||
assertThat(errors.toString(), containsString("No issues"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmbeddedItemInChoice() {
|
||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||
String questionnaireRef = QUESTIONNAIRE_URL;
|
||||
String valueSetRef = "http://somevalueset";
|
||||
String codeSystemUrl = "http://codesystems.com/system";
|
||||
String codeValue = "code0";
|
||||
|
@ -362,7 +665,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testEmbeddedItemInOpenChoice() {
|
||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||
String questionnaireRef = QUESTIONNAIRE_URL;
|
||||
String valueSetRef = "http://somevalueset";
|
||||
String codeSystemUrl = "http://codesystems.com/system";
|
||||
String codeValue = "code0";
|
||||
|
@ -418,7 +721,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testEmbeddedItemInString() {
|
||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||
String questionnaireRef = QUESTIONNAIRE_URL;
|
||||
|
||||
// create the questionnaire
|
||||
QuestionnaireItemComponent item1 = new QuestionnaireItemComponent();
|
||||
|
@ -519,7 +822,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
.setType(QuestionnaireItemType.STRING)
|
||||
.setRequired(true);
|
||||
|
||||
String reference = "http://example.com/Questionnaire/q1";
|
||||
String reference = QUESTIONNAIRE_URL;
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(reference)))
|
||||
.thenReturn(q);
|
||||
|
||||
|
@ -543,7 +846,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
@Test
|
||||
public void testOpenchoiceAnswer() {
|
||||
String questionnaireRef = "http://example.com/Questionnaire/q1";
|
||||
String questionnaireRef = QUESTIONNAIRE_URL;
|
||||
|
||||
Questionnaire q = new Questionnaire();
|
||||
QuestionnaireItemComponent item = q.addItem();
|
||||
|
@ -666,7 +969,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link1").addAnswer().setValue(new StringType("FOO"));
|
||||
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(qa.getQuestionnaire().getReference()))).thenReturn(q);
|
||||
|
@ -684,7 +987,7 @@ public class QuestionnaireResponseValidatorDstu3Test {
|
|||
|
||||
QuestionnaireResponse qa = new QuestionnaireResponse();
|
||||
qa.setStatus(QuestionnaireResponseStatus.COMPLETED);
|
||||
qa.getQuestionnaire().setReference("http://example.com/Questionnaire/q1");
|
||||
qa.getQuestionnaire().setReference(QUESTIONNAIRE_URL);
|
||||
qa.addItem().setLinkId("link1").addItem().setLinkId("link2");
|
||||
|
||||
when(myValSupport.fetchResource(any(FhirContext.class), eq(Questionnaire.class), eq(qa.getQuestionnaire().getReference()))).thenReturn(q);
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -73,7 +73,7 @@
|
|||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
2
pom.xml
2
pom.xml
|
@ -6,7 +6,7 @@
|
|||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<name>HAPI-FHIR</name>
|
||||
<description>An open-source implementation of the FHIR specification in Java.</description>
|
||||
<url>https://hapifhir.io</url>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<title>HAPI FHIR Changelog</title>
|
||||
</properties>
|
||||
<body>
|
||||
<release version="3.7.0" date="TBD" description="Gale">
|
||||
<release version="3.7.0" date="2019-02-06" description="Gale">
|
||||
<action type="add">
|
||||
HAPI FHIR is now built using OpenJDK 11. Users are recommended to upgrade to this version
|
||||
of Java if this is feasible. We are not yet dropping support for Java 8 (aka 1.8), but
|
||||
|
@ -356,6 +356,10 @@
|
|||
A NullPointerException during validation was fixed. Thanks to GitHub
|
||||
user zilin375 for the pull request!
|
||||
</action>
|
||||
<action type="add" issue="1148">
|
||||
Support for validating enableWhen in Questionnaires has been added to the Validator. Thanks
|
||||
to Eeva Turkka and Matti Uutsitalo for the pull request!
|
||||
</action>
|
||||
</release>
|
||||
<release version="3.6.0" date="2018-11-12" description="Food">
|
||||
<action type="add">
|
||||
|
|
|
@ -67,6 +67,29 @@
|
|||
</section>
|
||||
|
||||
<section name="Announcements">
|
||||
<p>
|
||||
<b>Feb 6, 2019 - HAPI FHIR 3.7.0 (Gale) Released</b> -
|
||||
The next release of HAPI has now been uploaded to the Maven repos and
|
||||
GitHub's releases section.
|
||||
</p>
|
||||
<p>
|
||||
This release includes support for the now-completed FHIR R4 release (FHIR 4.0.0).
|
||||
It also brings support for Java 11, along with a big number of bugfixes and
|
||||
new features.
|
||||
</p>
|
||||
<p>
|
||||
As always, see the
|
||||
<a href="http://hapifhir.io/changes-report.html">changelog</a> for a full list
|
||||
of changes.
|
||||
</p>
|
||||
<p>
|
||||
Thanks to everyone who contributed to this release!
|
||||
</p>
|
||||
<p>
|
||||
- <a href="https://github.com/jamesagnew/">James Agnew</a>
|
||||
</p>
|
||||
<br/><br/>
|
||||
|
||||
<p>
|
||||
<b>Nov 12, 2018 - HAPI FHIR 3.6.0 (Food) Released</b> -
|
||||
The next release of HAPI has now been uploaded to the Maven repos and
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>3.7.0-SNAPSHOT</version>
|
||||
<version>3.7.0</version>
|
||||
<relativePath>../../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
Loading…
Reference in New Issue