Merge branch 'master' into Snapshot-issue

This commit is contained in:
Lloyd McKenzie 2019-02-06 23:25:13 -07:00 committed by GitHub
commit a17754792b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 4966 additions and 4314 deletions

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -33,6 +33,7 @@ import org.hl7.fhir.dstu3.model.Parameters;
import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent; import org.hl7.fhir.dstu3.model.Parameters.ParametersParameterComponent;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.model.BooleanType; import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Questionnaire;
import org.hl7.fhir.r4.model.CodeableConcept; import org.hl7.fhir.r4.model.CodeableConcept;
import org.hl7.fhir.r4.model.Enumeration; import org.hl7.fhir.r4.model.Enumeration;
import org.hl7.fhir.r4.model.Expression.ExpressionLanguage; import org.hl7.fhir.r4.model.Expression.ExpressionLanguage;
@ -76,7 +77,7 @@ import org.hl7.fhir.utilities.Utilities;
public class VersionConvertor_30_40 { public class VersionConvertor_30_40 {
private static List<String> CANONICAL_URLS = new ArrayList<String>(); private static List<String> CANONICAL_URLS = new ArrayList<>();
static { static {
CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-conceptmap"); CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-conceptmap");
CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-valueset"); CANONICAL_URLS.add("http://hl7.org/fhir/StructureDefinition/11179-permitted-value-valueset");
@ -16013,6 +16014,7 @@ public class VersionConvertor_30_40 {
tgt.setType(convertQuestionnaireItemType(src.getType())); tgt.setType(convertQuestionnaireItemType(src.getType()));
for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent t : src.getEnableWhen()) for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent t : src.getEnableWhen())
tgt.addEnableWhen(convertQuestionnaireItemEnableWhenComponent(t)); tgt.addEnableWhen(convertQuestionnaireItemEnableWhenComponent(t));
tgt.setEnableBehavior(Questionnaire.EnableWhenBehavior.ANY);
if (src.hasRequired()) if (src.hasRequired())
tgt.setRequired(src.getRequired()); tgt.setRequired(src.getRequired());
if (src.hasRepeats()) if (src.hasRepeats())
@ -16029,6 +16031,9 @@ public class VersionConvertor_30_40 {
tgt.addInitial().setValue(convertType(src.getInitial())); tgt.addInitial().setValue(convertType(src.getInitial()));
for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent t : src.getItem()) for (org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent t : src.getItem())
tgt.addItem(convertQuestionnaireItemComponent(t)); tgt.addItem(convertQuestionnaireItemComponent(t));
for (org.hl7.fhir.dstu3.model.Extension t : src.getModifierExtension()) {
tgt.addModifierExtension(convertExtension(t));
}
return tgt; return tgt;
} }
@ -16131,8 +16136,10 @@ public class VersionConvertor_30_40 {
tgt.setOperator(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator.EXISTS); tgt.setOperator(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator.EXISTS);
tgt.setAnswer(convertType(src.getHasAnswerElement())); tgt.setAnswer(convertType(src.getHasAnswerElement()));
} }
else if (src.hasAnswer()) else if (src.hasAnswer()) {
tgt.setAnswer(convertType(src.getAnswer())); tgt.setOperator(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemOperator.EQUAL);
tgt.setAnswer(convertType(src.getAnswer()));
}
return tgt; return tgt;
} }

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -650,8 +650,14 @@ public class ProfileUtilities extends TranslatingUtilities {
} }
if (outcome.getType().size() > 1) if (outcome.getType().size() > 1)
for (TypeRefComponent t : outcome.getType()) { for (TypeRefComponent t : outcome.getType()) {
if (!t.getCode().equals("Reference")) if (!t.getCode().equals("Reference")) {
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName); boolean nonExtension = false;
for (ElementDefinition ed : diffMatches)
if (ed != diffMatches.get(0) && !ed.getPath().endsWith(".extension"))
nonExtension = true;
if (nonExtension)
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") and multiple types ("+typeCode(outcome.getType())+") in profile "+profileName);
}
} }
} }
int start = diffCursor; int start = diffCursor;
@ -668,7 +674,7 @@ public class ProfileUtilities extends TranslatingUtilities {
nbl++; nbl++;
processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, profileName, tgt.getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, redirectorStack(redirector, outcome, cpath)); processPaths(indent+" ", result, base, differential, nbc, start - 1, nbl-1, diffCursor - 1, url, profileName, tgt.getPath(), diffMatches.get(0).getPath(), trimDifferential, contextName, resultPathBase, false, redirectorStack(redirector, outcome, cpath));
} else { } else {
StructureDefinition dt = getProfileForDataType(outcome.getType().get(0)); StructureDefinition dt = outcome.getType().size() == 1 ? getProfileForDataType(outcome.getType().get(0)) : getProfileForDataType("Element");
if (dt == null) if (dt == null)
throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type"); throw new DefinitionException(diffMatches.get(0).getPath()+" has children ("+differential.getElement().get(diffCursor).getPath()+") for type "+typeCode(outcome.getType())+" in profile "+profileName+", but can't find type");
contextName = dt.getUrl(); contextName = dt.getUrl();
@ -1194,6 +1200,13 @@ public class ProfileUtilities extends TranslatingUtilities {
return sd; return sd;
} }
private StructureDefinition getProfileForDataType(String type) {
StructureDefinition sd = context.fetchTypeDefinition(type);
if (sd == null)
System.out.println("XX: failed to find profle for type: " + type); // debug GJM
return sd;
}
public static String typeCode(List<TypeRefComponent> types) { public static String typeCode(List<TypeRefComponent> types) {
StringBuilder b = new StringBuilder(); StringBuilder b = new StringBuilder();

View File

@ -153,6 +153,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
public static SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException { public static SimpleWorkerContext fromPackage(NpmPackage pi, IContextResourceLoader loader) throws FileNotFoundException, IOException, FHIRException {
SimpleWorkerContext res = new SimpleWorkerContext(); SimpleWorkerContext res = new SimpleWorkerContext();
res.setAllowLoadingDuplicates(true); res.setAllowLoadingDuplicates(true);
res.version = pi.getNpm().get("version").getAsString();
res.loadFromPackage(pi, loader); res.loadFromPackage(pi, loader);
return res; return res;
} }
@ -523,7 +524,7 @@ public class SimpleWorkerContext extends BaseWorkerContext implements IWorkerCon
@Override @Override
public String getVersion() { public String getVersion() {
return version+"-"+revision; return version;
} }

View File

@ -512,12 +512,12 @@ public class Element extends Base {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<ElementDecoration> decorations = (List<ElementDecoration>) getUserData("fhir.decorations"); List<ElementDecoration> decorations = (List<ElementDecoration>) getUserData("fhir.decorations");
if (decorations == null) { if (decorations == null) {
decorations = new ArrayList<ElementDecoration>(); decorations = new ArrayList<>();
setUserData("fhir.decorations", decorations); setUserData("fhir.decorations", decorations);
} }
decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getUserString("path"), definition.getPath())); decorations.add(new ElementDecoration(DecorationType.TYPE, profile.getUserString("path"), definition.getPath()));
if (tail(definition.getId()).contains(":")) { if (definition.getId() != null && tail(definition.getId()).contains(":")) {
String[] details = tail(definition.getId()).split("\\:"); String[] details = tail(definition.getId()).split(":");
decorations.add(new ElementDecoration(DecorationType.SLICE, null, details[1])); decorations.add(new ElementDecoration(DecorationType.SLICE, null, details[1]));
} }
} }

View File

@ -1906,8 +1906,10 @@ public class FHIRPathEngine {
} }
private List<Base> opIn(List<Base> left, List<Base> right) throws FHIRException { private List<Base> opIn(List<Base> left, List<Base> right) throws FHIRException {
if (left.size() == 0 || right.size() == 0) if (left.size() == 0)
return new ArrayList<Base>(); return new ArrayList<Base>();
if (right.size() == 0)
return makeBoolean(false);
boolean ans = true; boolean ans = true;
for (Base l : left) { for (Base l : left) {
boolean f = false; boolean f = false;

View File

@ -1,451 +1,464 @@
package org.hl7.fhir.r4.test; package org.hl7.fhir.r4.test;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.ParserConfigurationException;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.exceptions.FHIRFormatError; import org.hl7.fhir.exceptions.FHIRFormatError;
import org.hl7.fhir.exceptions.PathEngineException; import org.hl7.fhir.exceptions.PathEngineException;
import org.hl7.fhir.r4.conformance.ProfileUtilities; import org.hl7.fhir.r4.conformance.ProfileUtilities;
import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider; import org.hl7.fhir.r4.conformance.ProfileUtilities.ProfileKnowledgeProvider;
import org.hl7.fhir.r4.context.SimpleWorkerContext; import org.hl7.fhir.r4.context.SimpleWorkerContext;
import org.hl7.fhir.r4.formats.IParser.OutputStyle; import org.hl7.fhir.r4.formats.IParser.OutputStyle;
import org.hl7.fhir.r4.formats.XmlParser; import org.hl7.fhir.r4.formats.XmlParser;
import org.hl7.fhir.r4.model.Base; import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.Coding;
import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent; import org.hl7.fhir.r4.model.ElementDefinition.ElementDefinitionBindingComponent;
import org.hl7.fhir.r4.model.ExpressionNode.CollectionStatus; import org.hl7.fhir.r4.model.ExpressionNode.CollectionStatus;
import org.hl7.fhir.r4.model.MetadataResource; import org.hl7.fhir.r4.model.MetadataResource;
import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.Resource;
import org.hl7.fhir.r4.model.StructureDefinition; import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind; import org.hl7.fhir.r4.model.StructureDefinition.StructureDefinitionKind;
import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule; import org.hl7.fhir.r4.model.StructureDefinition.TypeDerivationRule;
import org.hl7.fhir.r4.model.TestScript; import org.hl7.fhir.r4.model.TestScript;
import org.hl7.fhir.r4.model.TestScript.SetupActionAssertComponent; import org.hl7.fhir.r4.model.TestScript.AssertionResponseTypes;
import org.hl7.fhir.r4.model.TestScript.SetupActionOperationComponent; import org.hl7.fhir.r4.model.TestScript.SetupActionAssertComponent;
import org.hl7.fhir.r4.model.TestScript.TestActionComponent; import org.hl7.fhir.r4.model.TestScript.SetupActionOperationComponent;
import org.hl7.fhir.r4.model.TestScript.TestScriptFixtureComponent; import org.hl7.fhir.r4.model.TestScript.TestActionComponent;
import org.hl7.fhir.r4.model.TestScript.TestScriptTestComponent; import org.hl7.fhir.r4.model.TestScript.TestScriptFixtureComponent;
import org.hl7.fhir.r4.test.utils.TestingUtilities; import org.hl7.fhir.r4.model.TestScript.TestScriptTestComponent;
import org.hl7.fhir.r4.model.TypeDetails; import org.hl7.fhir.r4.test.utils.TestingUtilities;
import org.hl7.fhir.r4.utils.CodingUtilities; import org.hl7.fhir.r4.model.TypeDetails;
import org.hl7.fhir.r4.utils.FHIRPathEngine; import org.hl7.fhir.r4.utils.CodingUtilities;
import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext; import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.hl7.fhir.r4.utils.IResourceValidator; import org.hl7.fhir.r4.utils.FHIRPathEngine.IEvaluationContext;
import org.hl7.fhir.r4.utils.NarrativeGenerator; import org.hl7.fhir.r4.utils.IResourceValidator;
import org.hl7.fhir.utilities.Utilities; import org.hl7.fhir.r4.utils.NarrativeGenerator;
import org.hl7.fhir.utilities.validation.ValidationMessage; import org.hl7.fhir.utilities.Utilities;
import org.junit.Test; import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.junit.runner.RunWith; import org.junit.Test;
import org.junit.runners.Parameterized; import org.junit.runner.RunWith;
import org.junit.runners.Parameterized.Parameters; import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import junit.framework.Assert;
import junit.framework.Assert;
@RunWith(Parameterized.class)
public class SnapShotGenerationTests { @RunWith(Parameterized.class)
public class SnapShotGenerationTests {
public class TestPKP implements ProfileKnowledgeProvider {
public class TestPKP implements ProfileKnowledgeProvider {
@Override
public boolean isDatatype(String name) { @Override
StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(name); public boolean isDatatype(String name) {
return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE || sd.getKind() == StructureDefinitionKind.COMPLEXTYPE); StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(name);
} return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.PRIMITIVETYPE || sd.getKind() == StructureDefinitionKind.COMPLEXTYPE);
}
@Override
public boolean isResource(String typeSimple) { @Override
StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(name); public boolean isResource(String typeSimple) {
return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.RESOURCE); StructureDefinition sd = TestingUtilities.context().fetchTypeDefinition(name);
} return (sd != null) && (sd.getDerivation() == TypeDerivationRule.SPECIALIZATION) && (sd.getKind() == StructureDefinitionKind.RESOURCE);
}
@Override
public boolean hasLinkFor(String typeSimple) { @Override
return isDatatype(name); public boolean hasLinkFor(String typeSimple) {
} return isDatatype(name);
}
@Override
public String getLinkFor(String corePath, String typeSimple) { @Override
return Utilities.pathURL(corePath, "datatypes.html#"+typeSimple); public String getLinkFor(String corePath, String typeSimple) {
} return Utilities.pathURL(corePath, "datatypes.html#"+typeSimple);
}
@Override
public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException { @Override
BindingResolution br = new BindingResolution(); public BindingResolution resolveBinding(StructureDefinition def, ElementDefinitionBindingComponent binding, String path) throws FHIRException {
br.url = path+"/something.html"; BindingResolution br = new BindingResolution();
br.display = "something"; br.url = path+"/something.html";
return br; br.display = "something";
} return br;
}
@Override
public String getLinkForProfile(StructureDefinition profile, String url) { @Override
StructureDefinition sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url); public String getLinkForProfile(StructureDefinition profile, String url) {
if (sd == null) StructureDefinition sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url);
return url+"|"+url; if (sd == null)
else return url+"|"+url;
return sd.getId()+".html|"+sd.present(); else
} return sd.getId()+".html|"+sd.present();
}
@Override
public boolean prependLinks() { @Override
return false; public boolean prependLinks() {
} return false;
}
}
}
private static class SnapShotGenerationTestsContext implements IEvaluationContext {
private Map<String, Resource> fixtures; private static class SnapShotGenerationTestsContext implements IEvaluationContext {
private Map<String, StructureDefinition> snapshots = new HashMap<String, StructureDefinition>(); private Map<String, Resource> fixtures;
public TestScript tests; private Map<String, StructureDefinition> snapshots = new HashMap<String, StructureDefinition>();
public TestScript tests;
public void checkTestsDetails() {
if (!"http://hl7.org/fhir/tests/snapshotgeneration".equals(tests.getUrl())) public void checkTestsDetails() {
throw new Error("Wrong URL on test script"); if (!"http://hl7.org/fhir/tests/snapshotgeneration".equals(tests.getUrl()))
if (!tests.getSetup().isEmpty()) throw new Error("Wrong URL on test script");
throw new Error("Setup is not supported"); if (!tests.getSetup().isEmpty())
if (!tests.getTeardown().isEmpty()) throw new Error("Setup is not supported");
throw new Error("Teardown is not supported"); if (!tests.getTeardown().isEmpty())
Set<String> ids = new HashSet<String>(); throw new Error("Teardown is not supported");
Set<String> urls = new HashSet<String>(); Set<String> ids = new HashSet<String>();
for (Resource r : tests.getContained()) { Set<String> urls = new HashSet<String>();
if (ids.contains(r.getId())) for (Resource r : tests.getContained()) {
throw new Error("Unsupported: duplicate contained resource on fixture id "+r.getId()); if (ids.contains(r.getId()))
ids.add(r.getId()); throw new Error("Unsupported: duplicate contained resource on fixture id "+r.getId());
if (r instanceof MetadataResource) { ids.add(r.getId());
MetadataResource md = (MetadataResource) r; if (r instanceof MetadataResource) {
if (urls.contains(md.getUrl())) MetadataResource md = (MetadataResource) r;
throw new Error("Unsupported: duplicate canonical url "+md.getUrl()+" on fixture id "+r.getId()); if (urls.contains(md.getUrl()))
urls.add(md.getUrl()); throw new Error("Unsupported: duplicate canonical url "+md.getUrl()+" on fixture id "+r.getId());
} urls.add(md.getUrl());
} }
for (TestScriptFixtureComponent r : tests.getFixture()) { }
if (ids.contains(r.getId())) for (TestScriptFixtureComponent r : tests.getFixture()) {
throw new Error("Unsupported: duplicate contained resource or fixture id "+r.getId()); if (ids.contains(r.getId()))
ids.add(r.getId()); throw new Error("Unsupported: duplicate contained resource or fixture id "+r.getId());
} ids.add(r.getId());
Set<String> names = new HashSet<String>(); }
for (TestScriptTestComponent test : tests.getTest()) { Set<String> names = new HashSet<String>();
if (names.contains(test.getName())) for (TestScriptTestComponent test : tests.getTest()) {
throw new Error("Unsupported: duplicate name "+test.getName()); if (names.contains(test.getName()))
names.add(test.getName()); throw new Error("Unsupported: duplicate name "+test.getName());
if (test.getAction().size() < 2) names.add(test.getName());
throw new Error("Unsupported: multiple actions required"); if (test.getAction().size() < 2)
if (!test.getActionFirstRep().hasOperation()) throw new Error("Unsupported: multiple actions required");
throw new Error("Unsupported: first action must be an operation"); if (!test.getActionFirstRep().hasOperation())
for (int i = 0; i < test.getAction().size(); i++) { throw new Error("Unsupported: first action must be an operation");
// if (!test.getAction().get(i).hasAssert()) for (int i = 0; i < test.getAction().size(); i++) {
// throw new Error("Unsupported: following actions must be an asserts"); // if (!test.getAction().get(i).hasAssert())
TestActionComponent action = test.getAction().get(i); // throw new Error("Unsupported: following actions must be an asserts");
if (action.hasOperation()) { TestActionComponent action = test.getAction().get(i);
SetupActionOperationComponent op = test.getActionFirstRep().getOperation(); if (action.hasOperation()) {
if (!CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "snapshot") SetupActionOperationComponent op = test.getActionFirstRep().getOperation();
&& !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential")) if (!CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "snapshot")
throw new Error("Unsupported action operation type "+CodingUtilities.present(op.getType())); && !CodingUtilities.matches(op.getType(), "http://hl7.org/fhir/testscript-operation-codes", "sortDifferential"))
if (!"StructureDefinition".equals(op.getResource())) throw new Error("Unsupported action operation type "+CodingUtilities.present(op.getType()));
throw new Error("Unsupported action operation resource "+op.getResource()); if (!"StructureDefinition".equals(op.getResource()))
if (!op.hasResponseId()) throw new Error("Unsupported action operation resource "+op.getResource());
throw new Error("Unsupported action operation: no response id"); if (!op.hasResponseId())
if (!op.hasSourceId()) throw new Error("Unsupported action operation: no response id");
throw new Error("Unsupported action operation: no source id"); if (!op.hasSourceId())
if (!hasSource(op.getSourceId())) throw new Error("Unsupported action operation: no source id");
throw new Error("Unsupported action operation: source id could not be resolved"); if (!hasSource(op.getSourceId()))
} else if (action.hasAssert()) { throw new Error("Unsupported action operation: source id could not be resolved");
SetupActionAssertComponent a = action.getAssert(); } else if (action.hasAssert()) {
if (!a.hasLabel()) SetupActionAssertComponent a = action.getAssert();
throw new Error("Unsupported: actions must have a label"); if (!a.hasLabel())
if (!a.hasDescription()) throw new Error("Unsupported: actions must have a label");
throw new Error("Unsupported: actions must have a description"); if (!a.hasDescription())
if (!a.hasExpression() && !(a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))) throw new Error("Unsupported: actions must have a description");
throw new Error("Unsupported: actions must have an expression or a response type of 'bad'"); if (!a.hasExpression() && !a.hasResponse())
} else { throw new Error("Unsupported: actions must have an expression or a response");
throw new Error("Unsupported: Unrecognized action type"); } else {
} throw new Error("Unsupported: Unrecognized action type");
} }
} }
} }
}
private boolean hasSource(String sourceId) {
for (TestScriptFixtureComponent ds : tests.getFixture()) { private boolean hasSource(String sourceId) {
if (sourceId.equals(ds.getId())) for (TestScriptFixtureComponent ds : tests.getFixture()) {
return true; if (sourceId.equals(ds.getId()))
} return true;
for (Resource r : tests.getContained()) { }
if (sourceId.equals(r.getId())) for (Resource r : tests.getContained()) {
return true; if (sourceId.equals(r.getId()))
} return true;
return false; }
} return false;
}
public Resource fetchFixture(String id) {
if (fixtures.containsKey(id)) public Resource fetchFixture(String id) {
return fixtures.get(id); if (fixtures.containsKey(id))
return fixtures.get(id);
for (TestScriptFixtureComponent ds : tests.getFixture()) {
if (id.equals(ds.getId())) for (TestScriptFixtureComponent ds : tests.getFixture()) {
throw new Error("not done yet"); if (id.equals(ds.getId()))
} throw new Error("not done yet");
for (Resource r : tests.getContained()) { }
if (id.equals(r.getId())) for (Resource r : tests.getContained()) {
return r; if (id.equals(r.getId()))
} return r;
return null; }
} return null;
}
// FHIRPath methods
@Override // FHIRPath methods
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException { @Override
return null; public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
} return null;
}
@Override
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException { @Override
return null; public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
} return null;
}
@Override
public boolean log(String argument, List<Base> focus) { @Override
System.out.println(argument+": "+fp.convertToString(focus)); public boolean log(String argument, List<Base> focus) {
return true; System.out.println(argument+": "+fp.convertToString(focus));
} return true;
}
@Override
public FunctionDetails resolveFunction(String functionName) { @Override
if ("fixture".equals(functionName)) public FunctionDetails resolveFunction(String functionName) {
return new FunctionDetails("Access a fixture defined in the testing context", 0, 1); if ("fixture".equals(functionName))
return null; return new FunctionDetails("Access a fixture defined in the testing context", 0, 1);
} return null;
}
@Override
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException { @Override
if ("fixture".equals(functionName)) public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
return new TypeDetails(CollectionStatus.SINGLETON, TestingUtilities.context().getResourceNamesAsSet()); if ("fixture".equals(functionName))
return null; return new TypeDetails(CollectionStatus.SINGLETON, TestingUtilities.context().getResourceNamesAsSet());
} return null;
}
@Override
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) { @Override
if ("fixture".equals(functionName)) { public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
String id = fp.convertToString(parameters.get(0)); if ("fixture".equals(functionName)) {
Resource res = fetchFixture(id); String id = fp.convertToString(parameters.get(0));
if (res != null) { Resource res = fetchFixture(id);
List<Base> list = new ArrayList<Base>(); if (res != null) {
list.add(res); List<Base> list = new ArrayList<Base>();
return list; list.add(res);
} return list;
} }
return null; }
} return null;
}
@Override
public Base resolveReference(Object appContext, String url) { @Override
// TODO Auto-generated method stub public Base resolveReference(Object appContext, String url) {
return null; // TODO Auto-generated method stub
} return null;
}
@Override
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException { @Override
IResourceValidator val = TestingUtilities.context().newValidator(); public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
List<ValidationMessage> valerrors = new ArrayList<ValidationMessage>(); IResourceValidator val = TestingUtilities.context().newValidator();
if (item instanceof Resource) { List<ValidationMessage> valerrors = new ArrayList<ValidationMessage>();
val.validate(appContext, valerrors, (Resource) item, url); if (item instanceof Resource) {
boolean ok = true; val.validate(appContext, valerrors, (Resource) item, url);
for (ValidationMessage v : valerrors) boolean ok = true;
ok = ok && v.getLevel().isError(); for (ValidationMessage v : valerrors)
return ok; ok = ok && v.getLevel().isError();
} return ok;
throw new NotImplementedException("Not done yet (IGPublisherHostServices.SnapShotGenerationTestsContext), when item is element"); }
} throw new NotImplementedException("Not done yet (IGPublisherHostServices.SnapShotGenerationTestsContext), when item is element");
}
}
}
private static FHIRPathEngine fp;
private static FHIRPathEngine fp;
@Parameters(name = "{index}: file {0}")
public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError { @Parameters(name = "{index}: file {0}")
SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext(); public static Iterable<Object[]> data() throws ParserConfigurationException, IOException, FHIRFormatError {
context.tests = (TestScript) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation-tests.xml"))); SnapShotGenerationTestsContext context = new SnapShotGenerationTestsContext();
context.tests = (TestScript) new XmlParser().parse(new FileInputStream(TestingUtilities.resourceNameToFile("snapshot-generation-tests.xml")));
context.checkTestsDetails();
context.checkTestsDetails();
List<Object[]> objects = new ArrayList<Object[]>(context.tests.getTest().size());
List<Object[]> objects = new ArrayList<Object[]>(context.tests.getTest().size());
for (TestScriptTestComponent e : context.tests.getTest()) {
objects.add(new Object[] { e.getName(), e, context }); for (TestScriptTestComponent e : context.tests.getTest()) {
} objects.add(new Object[] { e.getName(), e, context });
return objects; }
} return objects;
}
private final TestScriptTestComponent test;
private final String name; private final TestScriptTestComponent test;
private SnapShotGenerationTestsContext context; private final String name;
private SnapShotGenerationTestsContext context;
public SnapShotGenerationTests(String name, TestScriptTestComponent e, SnapShotGenerationTestsContext context) {
this.name = name; public SnapShotGenerationTests(String name, TestScriptTestComponent e, SnapShotGenerationTestsContext context) {
this.test = e; this.name = name;
this.context = context; this.test = e;
} this.context = context;
}
@SuppressWarnings("deprecation")
@Test @SuppressWarnings("deprecation")
public void test() throws FHIRException { @Test
try { public void test() throws FHIRException {
for (Resource cr : context.tests.getContained()) { try {
if (cr instanceof StructureDefinition) { for (Resource cr : context.tests.getContained()) {
StructureDefinition sd = (StructureDefinition) cr; if (cr instanceof StructureDefinition) {
if (sd.getType().equals("Extension")) { StructureDefinition sd = (StructureDefinition) cr;
if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) { if (sd.getType().equals("Extension")) {
sd.setUserData("path", "test-"+sd.getId()+".html"); if (TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getUrl()) == null) {
StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition()); sd.setUserData("path", "test-"+sd.getId()+".html");
new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), sd.getName()); StructureDefinition extd = TestingUtilities.context().fetchResource(StructureDefinition.class, sd.getBaseDefinition());
TestingUtilities.context().cacheResource(sd); new ProfileUtilities(TestingUtilities.context(), null, null).generateSnapshot(extd, sd, sd.getUrl(), sd.getName());
debugSaveResource(sd); TestingUtilities.context().cacheResource(sd);
} debugSaveResource(sd);
} }
} }
} }
if (fp == null) }
fp = new FHIRPathEngine(TestingUtilities.context()); if (fp == null)
fp.setHostServices(context); fp = new FHIRPathEngine(TestingUtilities.context());
fp.setHostServices(context);
resolveFixtures();
resolveFixtures();
for (int i = 0; i < test.getAction().size(); i++) {
TestActionComponent action = test.getAction().get(i); TestScript.AssertionResponseTypes lastOpOutcome = null;
try { for (int i = 0; i < test.getAction().size(); i++) {
if (action.hasOperation()) { TestActionComponent action = test.getAction().get(i);
SetupActionOperationComponent op = action.getOperation(); if (action.hasOperation()) {
Coding opType = op.getType(); lastOpOutcome = AssertionResponseTypes.OKAY;
if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) { try {
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId()); SetupActionOperationComponent op = action.getOperation();
StructureDefinition base = getSD(source.getBaseDefinition()); Coding opType = op.getType();
StructureDefinition output = source.copy(); if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("snapshot")) {
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, new TestPKP()); StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
pu.setIds(source, false); StructureDefinition base = getSD(source.getBaseDefinition());
if ("sort=true".equals(op.getParams())) { StructureDefinition output = source.copy();
List<String> errors = new ArrayList<String>(); ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, new TestPKP());
pu.sortDifferential(base, output, source.getName(), errors); pu.setIds(source, false);
if (errors.size() > 0) if ("sort=true".equals(op.getParams())) {
throw new FHIRException("Sort failed: "+errors.toString()); List<String> errors = new ArrayList<String>();
} pu.sortDifferential(base, output, source.getName(), errors);
pu.generateSnapshot(base, output, source.getUrl(), source.getName()); if (errors.size() > 0)
debugSaveResource(output); throw new FHIRException("Sort failed: "+errors.toString());
context.fixtures.put(op.getResponseId(), output); }
context.snapshots.put(output.getUrl(), output); pu.generateSnapshot(base, output, source.getUrl(), source.getName());
debugSaveResource(output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output); context.fixtures.put(op.getResponseId(), output);
if (output.getDifferential().hasElement()) context.snapshots.put(output.getUrl(), output);
new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+"-d.xml")), output); new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
if (output.getDifferential().hasElement())
} else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) { new NarrativeGenerator("", "http://hl7.org/fhir", TestingUtilities.context()).setPkp(new TestPKP()).generate(output, null);
StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId()); new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+"-d.xml")), output);
StructureDefinition base = getSD(source.getBaseDefinition()); } else if (opType.getSystem().equals("http://hl7.org/fhir/testscript-operation-codes") && opType.getCode().equals("sortDifferential")) {
StructureDefinition output = source.copy(); StructureDefinition source = (StructureDefinition) context.fetchFixture(op.getSourceId());
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null); StructureDefinition base = getSD(source.getBaseDefinition());
pu.setIds(source, false); StructureDefinition output = source.copy();
List<String> errors = new ArrayList<String>(); ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
pu.sortDifferential(base, output, output.getUrl(), errors); pu.setIds(source, false);
if (!errors.isEmpty()) List<String> errors = new ArrayList<String>();
throw new FHIRException(errors.get(0)); pu.sortDifferential(base, output, output.getUrl(), errors);
context.fixtures.put(op.getResponseId(), output); if (!errors.isEmpty())
context.snapshots.put(output.getUrl(), output); throw new FHIRException(errors.get(0));
context.fixtures.put(op.getResponseId(), output);
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output); context.snapshots.put(output.getUrl(), output);
} else { new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
} new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(Utilities.path(System.getProperty("java.io.tmpdir"), op.getResponseId()+".xml")), output);
} else if (action.hasAssert()) {
SetupActionAssertComponent a = action.getAssert(); } else {
if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD)) throw new Error("Unsupported operation: " + opType.getSystem() + " : " + opType.getCode());
Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription()); }
else { } else if (action.hasAssert()) {
boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression()); SetupActionAssertComponent a = action.getAssert();
Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok); if (a.hasResponse() && a.getResponse().equals(TestScript.AssertionResponseTypes.BAD))
} Assert.fail(action.getAssert().getLabel()+": "+action.getAssert().getDescription());
} else {
} catch (Exception e) { boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression());
boolean ok = false; Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
for (int j = i+1;i < test.getAction().size(); i++) { }
TestActionComponent followAction = test.getAction().get(j); }
if (followAction.hasAssert() && followAction.getAssert().hasResponse() && followAction.getAssert().getResponse().equals(TestScript.AssertionResponseTypes.BAD)) { } catch (Exception e) {
ok = true; boolean ok = false;
break; for (int j = i+1;i < test.getAction().size(); i++) {
} TestActionComponent followAction = test.getAction().get(j);
} if (followAction.hasAssert() && followAction.getAssert().hasResponse() && followAction.getAssert().getResponse().equals(TestScript.AssertionResponseTypes.BAD)) {
if (!ok) ok = true;
throw e; break;
else }
break; }
} } catch (Exception e) {
} lastOpOutcome = AssertionResponseTypes.BAD;
} catch (Exception e) { }
e.printStackTrace();
throw new FHIRException(e); } else if (action.hasAssert()) {
} SetupActionAssertComponent a = action.getAssert();
} if (a.getResponse() != null) {
Assert.assertTrue(a.getLabel()+" (response): "+a.getDescription(), a.getResponse() == lastOpOutcome);
}
private void debugSaveResource(Resource r) throws IOException { if (a.hasExpression()) {
String dir = System.getProperty("java.io.tmpdir"); boolean ok = fp.evaluateToBoolean(new StructureDefinition(), new StructureDefinition(), a.getExpression());
if (new File("c:\\temp").exists()) Assert.assertTrue(a.getLabel()+": "+a.getDescription(), ok);
dir = "c:\\temp"; }
String fn = Utilities.path(dir, r.fhirType()+"-"+r.getId()+".xml"); }
new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(fn), r); }
} } catch (Exception e) {
e.printStackTrace();
private StructureDefinition getSD(String url) throws DefinitionException, FHIRException, IOException { throw new FHIRException(e);
StructureDefinition sd = context.snapshots.get(url); }
if (sd == null) }
sd = findContainedProfile(url);
if (sd == null)
sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url); private void debugSaveResource(Resource r) throws IOException {
return sd; String dir = System.getProperty("java.io.tmpdir");
} if (new File("c:\\temp").exists())
dir = "c:\\temp";
private StructureDefinition findContainedProfile(String url) throws DefinitionException, FHIRException, IOException { String fn = Utilities.path(dir, r.fhirType()+"-"+r.getId()+".xml");
for (Resource r : context.tests.getContained()) { new XmlParser().setOutputStyle(OutputStyle.PRETTY).compose(new FileOutputStream(fn), r);
if (r instanceof StructureDefinition) { }
StructureDefinition sd = (StructureDefinition) r;
if (sd.getUrl().equals(url)) { private StructureDefinition getSD(String url) throws DefinitionException, FHIRException, IOException {
StructureDefinition p = sd.copy(); StructureDefinition sd = context.snapshots.get(url);
ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null); if (sd == null)
pu.setIds(p, false); sd = findContainedProfile(url);
List<String> errors = new ArrayList<String>(); if (sd == null)
pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors); sd = TestingUtilities.context().fetchResource(StructureDefinition.class, url);
if (!errors.isEmpty()) return sd;
throw new FHIRException(errors.get(0)); }
pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), p.getName());
debugSaveResource(p); private StructureDefinition findContainedProfile(String url) throws DefinitionException, FHIRException, IOException {
return p; for (Resource r : context.tests.getContained()) {
} if (r instanceof StructureDefinition) {
} StructureDefinition sd = (StructureDefinition) r;
} if (sd.getUrl().equals(url)) {
return null; StructureDefinition p = sd.copy();
} ProfileUtilities pu = new ProfileUtilities(TestingUtilities.context(), null, null);
pu.setIds(p, false);
private void resolveFixtures() { List<String> errors = new ArrayList<String>();
if (context.fixtures == null) { pu.sortDifferential(getSD(p.getBaseDefinition()), p, url, errors);
context.fixtures = new HashMap<String, Resource>(); if (!errors.isEmpty())
for (TestScriptFixtureComponent fd : context.tests.getFixture()) { throw new FHIRException(errors.get(0));
Resource r = TestingUtilities.context().fetchResource(Resource.class, fd.getResource().getReference()); pu.generateSnapshot(getSD(p.getBaseDefinition()), p, p.getUrl(), p.getName());
context.fixtures.put(fd.getId(), r); debugSaveResource(p);
} return p;
} }
}
} }
} return null;
}
private void resolveFixtures() {
if (context.fixtures == null) {
context.fixtures = new HashMap<String, Resource>();
for (TestScriptFixtureComponent fd : context.tests.getFixture()) {
Resource r = TestingUtilities.context().fetchResource(Resource.class, fd.getResource().getReference());
context.fixtures.put(fd.getId(), r);
}
}
}
}

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>
@ -55,28 +55,63 @@
<build> <build>
<plugins> <plugins>
<!--
Build a fatjar containing all depenedncies
-->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-dependency-plugin</artifactId>
<version>3.2.1</version>
<executions> <executions>
<execution> <execution>
<phase>package</phase> <id>unpack-dependencies</id>
<phase>process-classes</phase>
<goals> <goals>
<goal>shade</goal> <goal>unpack-dependencies</goal>
</goals> </goals>
<configuration> <configuration>
<shadedClassifierName/> <excludes>**/module-info.class</excludes>
<transformers> <outputDirectory>${project.build.directory}/classes</outputDirectory>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <overWriteReleases>false</overWriteReleases>
<mainClass>org.hl7.fhir.r4.validation.Validator</mainClass> <overWriteSnapshots>true</overWriteSnapshots>
</transformer> <excludeScope>test</excludeScope>
</transformers> <includeScope>compile</includeScope>
<shadedArtifactAttached>true</shadedArtifactAttached>
</configuration> </configuration>
</execution> </execution>
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>org.hl7.fhir.r4.validation.Validator</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!--
These two plugins provide quality checks that don't make sense to perform
on a fatjar.
-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>animal-sniffer-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@ -1,52 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<classpath> <classpath>
<classpathentry kind="src" path="src/test/java" output="target/test-classes" including="**/*.java"/> <classpathentry including="**/*.java" kind="src" output="target/test-classes" path="src/test/java"/>
<classpathentry kind="src" path="src/test/resources" output="target/test-classes" excluding="**/*.java"/> <classpathentry excluding="**/*.java" kind="src" output="target/test-classes" path="src/test/resources"/>
<classpathentry kind="src" path="src/main/java" including="**/*.java"/> <classpathentry including="**/*.java" kind="src" path="src/main/java"/>
<classpathentry kind="src" path="src/main/resources" excluding="**/*.java"/> <classpathentry kind="var" path="M2_REPO/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar" sourcepath="M2_REPO/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1-sources.jar"/>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="var" path="M2_REPO/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar" sourcepath="M2_REPO/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1.jar" sourcepath="M2_REPO/javax/xml/bind/jaxb-api/2.3.1/jaxb-api-2.3.1-sources.jar"/> <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="var" path="M2_REPO/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0.jar" sourcepath="M2_REPO/javax/activation/javax.activation-api/1.2.0/javax.activation-api-1.2.0-sources.jar"/> <classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-base/3.7.0-SNAPSHOT/hapi-fhir-base-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-base/3.7.0-SNAPSHOT/hapi-fhir-base-3.7.0-SNAPSHOT-sources.jar"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/> <classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.8.5/gson-2.8.5.jar" sourcepath="M2_REPO/com/google/code/gson/gson/2.8.5/gson-2.8.5-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-base/3.7.0-SNAPSHOT/hapi-fhir-base-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-base/3.7.0-SNAPSHOT/hapi-fhir-base-3.7.0-SNAPSHOT-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/google/code/gson/gson/2.8.5/gson-2.8.5.jar" sourcepath="M2_REPO/com/google/code/gson/gson/2.8.5/gson-2.8.5-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-text/1.6/commons-text-1.6.jar" sourcepath="M2_REPO/org/apache/commons/commons-text/1.6/commons-text-1.6-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar" sourcepath="M2_REPO/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1-sources.jar"/> <classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/apache/commons/commons-text/1.6/commons-text-1.6.jar" sourcepath="M2_REPO/org/apache/commons/commons-text/1.6/commons-text-1.6-sources.jar"/> <classpathentry kind="var" path="M2_REPO/commons-io/commons-io/2.6/commons-io-2.6.jar" sourcepath="M2_REPO/commons-io/commons-io/2.6/commons-io-2.6-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11.jar" sourcepath="M2_REPO/commons-codec/commons-codec/1.11/commons-codec-1.11-sources.jar"/> <classpathentry kind="var" path="M2_REPO/com/google/guava/guava/25.0-jre/guava-25.0-jre.jar" sourcepath="M2_REPO/com/google/guava/guava/25.0-jre/guava-25.0-jre-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/commons-io/commons-io/2.6/commons-io-2.6.jar" sourcepath="M2_REPO/commons-io/commons-io/2.6/commons-io-2.6-sources.jar"/> <classpathentry kind="var" path="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar"/>
<classpathentry kind="var" path="M2_REPO/com/google/guava/guava/25.0-jre/guava-25.0-jre.jar" sourcepath="M2_REPO/com/google/guava/guava/25.0-jre/guava-25.0-jre-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0.jar" sourcepath="M2_REPO/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/google/code/findbugs/jsr305/1.3.9/jsr305-1.3.9.jar"/> <classpathentry kind="var" path="M2_REPO/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar" sourcepath="M2_REPO/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0.jar" sourcepath="M2_REPO/org/checkerframework/checker-compat-qual/2.0.0/checker-compat-qual-2.0.0-sources.jar"/> <classpathentry kind="var" path="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" sourcepath="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3.jar" sourcepath="M2_REPO/com/google/errorprone/error_prone_annotations/2.1.3/error_prone_annotations-2.1.3-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" sourcepath="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1.jar" sourcepath="M2_REPO/com/google/j2objc/j2objc-annotations/1.1/j2objc-annotations-1.1-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14.jar" sourcepath="M2_REPO/org/codehaus/mojo/animal-sniffer-annotations/1.14/animal-sniffer-annotations-1.14-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25.jar" sourcepath="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar" sourcepath="M2_REPO/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25-sources.jar"/> <classpathentry kind="src" path="/org.hl7.fhir.utilities"/>
<classpathentry kind="var" path="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25.jar" sourcepath="M2_REPO/org/slf4j/jcl-over-slf4j/1.7.25/jcl-over-slf4j-1.7.25-sources.jar"/> <classpathentry kind="src" path="/org.hl7.fhir.convertors"/>
<classpathentry kind="src" path="/org.hl7.fhir.utilities"/> <classpathentry kind="src" path="/org.hl7.fhir.dstu2"/>
<classpathentry kind="src" path="/org.hl7.fhir.convertors"/> <classpathentry kind="src" path="/org.hl7.fhir.dstu2016may"/>
<classpathentry kind="src" path="/org.hl7.fhir.dstu2"/> <classpathentry kind="src" path="/org.hl7.fhir.dstu3"/>
<classpathentry kind="src" path="/org.hl7.fhir.dstu2016may"/> <classpathentry kind="src" path="/org.hl7.fhir.r4"/>
<classpathentry kind="src" path="/org.hl7.fhir.dstu3"/> <classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-structures-r4/3.7.0-SNAPSHOT/hapi-fhir-structures-r4-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-structures-r4/3.7.0-SNAPSHOT/hapi-fhir-structures-r4-3.7.0-SNAPSHOT-sources.jar"/>
<classpathentry kind="src" path="/org.hl7.fhir.r4"/> <classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-utilities/3.7.0-SNAPSHOT/hapi-fhir-utilities-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-utilities/3.7.0-SNAPSHOT/hapi-fhir-utilities-3.7.0-SNAPSHOT-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-structures-r4/3.7.0-SNAPSHOT/hapi-fhir-structures-r4-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-structures-r4/3.7.0-SNAPSHOT/hapi-fhir-structures-r4-3.7.0-SNAPSHOT-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1.jar" sourcepath="M2_REPO/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-utilities/3.7.0-SNAPSHOT/hapi-fhir-utilities-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-utilities/3.7.0-SNAPSHOT/hapi-fhir-utilities-3.7.0-SNAPSHOT-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1.jar" sourcepath="M2_REPO/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1.jar" sourcepath="M2_REPO/org/glassfish/jaxb/jaxb-runtime/2.3.1/jaxb-runtime-2.3.1-sources.jar"/> <classpathentry kind="var" path="M2_REPO/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7.jar" sourcepath="M2_REPO/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1.jar" sourcepath="M2_REPO/org/glassfish/jaxb/txw2/2.3.1/txw2-2.3.1-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.jar" sourcepath="M2_REPO/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7.jar" sourcepath="M2_REPO/com/sun/istack/istack-commons-runtime/3.0.7/istack-commons-runtime-3.0.7-sources.jar"/> <classpathentry kind="var" path="M2_REPO/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15.jar" sourcepath="M2_REPO/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8.jar" sourcepath="M2_REPO/org/jvnet/staxex/stax-ex/1.8/stax-ex-1.8-sources.jar"/> <classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-validation-resources-r4/3.7.0-SNAPSHOT/hapi-fhir-validation-resources-r4-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-validation-resources-r4/3.7.0-SNAPSHOT/hapi-fhir-validation-resources-r4-3.7.0-SNAPSHOT-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15.jar" sourcepath="M2_REPO/com/sun/xml/fastinfoset/FastInfoset/1.2.15/FastInfoset-1.2.15-sources.jar"/> <classpathentry kind="var" path="M2_REPO/net/sf/saxon/Saxon-HE/9.5.1-5/Saxon-HE-9.5.1-5.jar" sourcepath="M2_REPO/net/sf/saxon/Saxon-HE/9.5.1-5/Saxon-HE-9.5.1-5-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-validation-resources-r4/3.7.0-SNAPSHOT/hapi-fhir-validation-resources-r4-3.7.0-SNAPSHOT.jar" sourcepath="M2_REPO/ca/uhn/hapi/fhir/hapi-fhir-validation-resources-r4/3.7.0-SNAPSHOT/hapi-fhir-validation-resources-r4-3.7.0-SNAPSHOT-sources.jar"/> <classpathentry kind="var" path="M2_REPO/xpp3/xpp3/1.1.4c/xpp3-1.1.4c.jar" sourcepath="M2_REPO/xpp3/xpp3/1.1.4c/xpp3-1.1.4c-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/net/sf/saxon/Saxon-HE/9.5.1-5/Saxon-HE-9.5.1-5.jar" sourcepath="M2_REPO/net/sf/saxon/Saxon-HE/9.5.1-5/Saxon-HE-9.5.1-5-sources.jar"/> <classpathentry kind="var" path="M2_REPO/xpp3/xpp3_xpath/1.1.4c/xpp3_xpath-1.1.4c.jar" sourcepath="M2_REPO/xpp3/xpp3_xpath/1.1.4c/xpp3_xpath-1.1.4c-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/xpp3/xpp3/1.1.4c/xpp3-1.1.4c.jar" sourcepath="M2_REPO/xpp3/xpp3/1.1.4c/xpp3-1.1.4c-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/everit/json/org.everit.json.schema/1.1.0/org.everit.json.schema-1.1.0.jar"/>
<classpathentry kind="var" path="M2_REPO/xpp3/xpp3_xpath/1.1.4c/xpp3_xpath-1.1.4c.jar" sourcepath="M2_REPO/xpp3/xpp3_xpath/1.1.4c/xpp3_xpath-1.1.4c-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/everit/osgi/bundles/org.everit.osgi.bundles.org.json/1.0.0-v20140107/org.everit.osgi.bundles.org.json-1.0.0-v20140107.jar"/>
<classpathentry kind="var" path="M2_REPO/org/everit/json/org.everit.json.schema/1.1.0/org.everit.json.schema-1.1.0.jar"/> <classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/everit/osgi/bundles/org.everit.osgi.bundles.org.json/1.0.0-v20140107/org.everit.osgi.bundles.org.json-1.0.0-v20140107.jar"/> <classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3.jar" sourcepath="M2_REPO/ch/qos/logback/logback-classic/1.2.3/logback-classic-1.2.3-sources.jar"/> <classpathentry kind="var" path="M2_REPO/junit/junit/4.12/junit-4.12.jar" sourcepath="M2_REPO/junit/junit/4.12/junit-4.12-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3.jar" sourcepath="M2_REPO/ch/qos/logback/logback-core/1.2.3/logback-core-1.2.3-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/hamcrest/java-hamcrest/2.0.0.0/java-hamcrest-2.0.0.0.jar" sourcepath="M2_REPO/org/hamcrest/java-hamcrest/2.0.0.0/java-hamcrest-2.0.0.0-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/junit/junit/4.12/junit-4.12.jar" sourcepath="M2_REPO/junit/junit/4.12/junit-4.12-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/mockito/mockito-core/2.23.4/mockito-core-2.23.4.jar" sourcepath="M2_REPO/org/mockito/mockito-core/2.23.4/mockito-core-2.23.4-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/hamcrest/java-hamcrest/2.0.0.0/java-hamcrest-2.0.0.0.jar" sourcepath="M2_REPO/org/hamcrest/java-hamcrest/2.0.0.0/java-hamcrest-2.0.0.0-sources.jar"/> <classpathentry kind="var" path="M2_REPO/net/bytebuddy/byte-buddy/1.9.3/byte-buddy-1.9.3.jar" sourcepath="M2_REPO/net/bytebuddy/byte-buddy/1.9.3/byte-buddy-1.9.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/org/mockito/mockito-core/2.23.4/mockito-core-2.23.4.jar" sourcepath="M2_REPO/org/mockito/mockito-core/2.23.4/mockito-core-2.23.4-sources.jar"/> <classpathentry kind="var" path="M2_REPO/net/bytebuddy/byte-buddy-agent/1.9.3/byte-buddy-agent-1.9.3.jar" sourcepath="M2_REPO/net/bytebuddy/byte-buddy-agent/1.9.3/byte-buddy-agent-1.9.3-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/net/bytebuddy/byte-buddy/1.9.3/byte-buddy-1.9.3.jar" sourcepath="M2_REPO/net/bytebuddy/byte-buddy/1.9.3/byte-buddy-1.9.3-sources.jar"/> <classpathentry kind="var" path="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6.jar" sourcepath="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6-sources.jar"/>
<classpathentry kind="var" path="M2_REPO/net/bytebuddy/byte-buddy-agent/1.9.3/byte-buddy-agent-1.9.3.jar" sourcepath="M2_REPO/net/bytebuddy/byte-buddy-agent/1.9.3/byte-buddy-agent-1.9.3-sources.jar"/> <classpathentry kind="output" path="target/classes"/>
<classpathentry kind="var" path="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6.jar" sourcepath="M2_REPO/org/objenesis/objenesis/2.6/objenesis-2.6-sources.jar"/> </classpath>
</classpath>

View File

@ -5,7 +5,7 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>org.hl7.fhir.core</artifactId> <artifactId>org.hl7.fhir.core</artifactId>
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath> <relativePath>../pom.xml</relativePath>
</parent> </parent>

View File

@ -72,8 +72,8 @@ public class BaseValidator {
*/ */
protected boolean fail(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) { protected boolean fail(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.FATAL)); addValidationMessage(errors, type, line, col, path, msg, IssueSeverity.FATAL);
} }
return thePass; return thePass;
} }
@ -87,8 +87,8 @@ public class BaseValidator {
protected boolean fail(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String msg) { protected boolean fail(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.FATAL)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.FATAL);
} }
return thePass; return thePass;
} }
@ -102,8 +102,8 @@ public class BaseValidator {
protected boolean fail(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) { protected boolean fail(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String theMessage, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
errors.add(new ValidationMessage(source, type, -1, -1, path, formatMessage(theMessage, theMessageArguments), IssueSeverity.FATAL)); addValidationMessage(errors, type, -1, -1, path, formatMessage(theMessage, theMessageArguments), IssueSeverity.FATAL);
} }
return thePass; return thePass;
} }
@ -116,8 +116,8 @@ public class BaseValidator {
*/ */
protected boolean fail(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { protected boolean fail(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.FATAL)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.FATAL);
} }
return thePass; return thePass;
} }
@ -145,8 +145,8 @@ public class BaseValidator {
*/ */
protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) { protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, line, col, path, msg, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -160,15 +160,16 @@ public class BaseValidator {
protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { protected boolean hint(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
protected boolean txHint(List<ValidationMessage> errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { protected boolean txHint(List<ValidationMessage> errors, String txLink, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(Source.TerminologyEngine, type, line, col, path, message, IssueSeverity.INFORMATION).setTxLink(txLink)); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.INFORMATION, Source.TerminologyEngine)
.setTxLink(txLink);
} }
return thePass; return thePass;
} }
@ -184,8 +185,8 @@ public class BaseValidator {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -198,8 +199,8 @@ public class BaseValidator {
*/ */
protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { protected boolean hint(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -213,8 +214,8 @@ public class BaseValidator {
protected boolean rule(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) { protected boolean rule(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String theMessage, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, line, col, path, message, IssueSeverity.ERROR)); addValidationMessage(errors, type, line, col, path, message, IssueSeverity.ERROR);
} }
return thePass; return thePass;
} }
@ -236,8 +237,8 @@ public class BaseValidator {
protected boolean rule(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String msg) { protected boolean rule(List<ValidationMessage> errors, IssueType type, List<String> pathParts, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.ERROR);
} }
return thePass; return thePass;
} }
@ -252,8 +253,8 @@ public class BaseValidator {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.ERROR)); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.ERROR);
} }
return thePass; return thePass;
} }
@ -266,15 +267,15 @@ public class BaseValidator {
*/ */
protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.ERROR);
} }
return thePass; return thePass;
} }
static public boolean rule(List<ValidationMessage> errors, Source source, IssueType type, String path, boolean thePass, String msg) { public boolean rule(List<ValidationMessage> errors, Source source, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.ERROR)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.ERROR, source);
} }
return thePass; return thePass;
} }
@ -287,8 +288,8 @@ public class BaseValidator {
*/ */
protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { protected boolean rule(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.ERROR)); addValidationMessage(errors, type, path, msg, html, IssueSeverity.ERROR);
} }
return thePass; return thePass;
} }
@ -330,13 +331,25 @@ public class BaseValidator {
protected boolean warning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { protected boolean warning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
msg = formatMessage(msg, theMessageArguments); msg = formatMessage(msg, theMessageArguments);
errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.WARNING)); IssueSeverity severity = IssueSeverity.WARNING;
} addValidationMessage(errors, type, line, col, path, msg, severity);
}
return thePass; return thePass;
} }
/** protected void addValidationMessage(List<ValidationMessage> errors, IssueType type, int line, int col, String path, String msg, IssueSeverity theSeverity) {
Source source = this.source;
addValidationMessage(errors, type, line, col, path, msg, theSeverity, source);
}
protected ValidationMessage addValidationMessage(List<ValidationMessage> errors, IssueType type, int line, int col, String path, String msg, IssueSeverity theSeverity, Source theSource) {
ValidationMessage validationMessage = new ValidationMessage(theSource, type, line, col, path, msg, theSeverity);
errors.add(validationMessage);
return validationMessage;
}
/**
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
* *
* @param thePass * @param thePass
@ -355,8 +368,8 @@ public class BaseValidator {
protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { protected boolean warningOrError(boolean isError, List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
msg = formatMessage(msg, theMessageArguments); msg = formatMessage(msg, theMessageArguments);
errors.add(new ValidationMessage(source, type, line, col, path, msg, isError ? IssueSeverity.ERROR : IssueSeverity.WARNING)); addValidationMessage(errors, type, line, col, path, msg, isError ? IssueSeverity.ERROR : IssueSeverity.WARNING);
} }
return thePass; return thePass;
} }
@ -372,8 +385,8 @@ public class BaseValidator {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.WARNING)); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.WARNING);
} }
return thePass; return thePass;
} }
@ -386,8 +399,8 @@ public class BaseValidator {
*/ */
protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.WARNING)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.WARNING);
} }
return thePass; return thePass;
} }
@ -400,8 +413,8 @@ public class BaseValidator {
*/ */
protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.WARNING)); addValidationMessage(errors, type, path, msg, html, IssueSeverity.WARNING);
} }
return thePass; return thePass;
} }
@ -415,8 +428,8 @@ public class BaseValidator {
protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { protected boolean warning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
msg = formatMessage(msg, theMessageArguments); msg = formatMessage(msg, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.WARNING)); addValidationMessage(errors, type, path, msg, html, IssueSeverity.WARNING);
} }
return thePass; return thePass;
} }
@ -431,8 +444,8 @@ public class BaseValidator {
protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) { protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, int line, int col, String path, boolean thePass, String msg, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
msg = formatMessage(msg, theMessageArguments); msg = formatMessage(msg, theMessageArguments);
errors.add(new ValidationMessage(source, type, line, col, path, msg, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, line, col, path, msg, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -448,8 +461,8 @@ public class BaseValidator {
if (!thePass) { if (!thePass) {
String path = toPath(pathParts); String path = toPath(pathParts);
String message = formatMessage(theMessage, theMessageArguments); String message = formatMessage(theMessage, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, message, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, -1, -1, path, message, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -462,8 +475,8 @@ public class BaseValidator {
*/ */
protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) { protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, -1, -1, path, msg, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }
@ -476,12 +489,17 @@ public class BaseValidator {
*/ */
protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) { protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html) {
if (!thePass) { if (!thePass) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.INFORMATION)); IssueSeverity severity = IssueSeverity.INFORMATION;
} addValidationMessage(errors, type, path, msg, html, severity);
}
return thePass; return thePass;
} }
/** protected void addValidationMessage(List<ValidationMessage> errors, IssueType type, String path, String msg, String html, IssueSeverity theSeverity) {
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, theSeverity));
}
/**
* Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails * Test a rule and add a {@link IssueSeverity#WARNING} validation message if the validation fails
* *
* @param thePass * @param thePass
@ -491,8 +509,8 @@ public class BaseValidator {
protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) { protected boolean suppressedwarning(List<ValidationMessage> errors, IssueType type, String path, boolean thePass, String msg, String html, Object... theMessageArguments) {
if (!thePass) { if (!thePass) {
msg = formatMessage(msg, theMessageArguments); msg = formatMessage(msg, theMessageArguments);
errors.add(new ValidationMessage(source, type, -1, -1, path, msg, html, IssueSeverity.INFORMATION)); addValidationMessage(errors, type, path, msg, html, IssueSeverity.INFORMATION);
} }
return thePass; return thePass;
} }

View File

@ -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) throws FHIRException {
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;
}
}

View File

@ -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;
}
}

View File

@ -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);
}

View File

@ -35,6 +35,8 @@ import java.util.UUID;
import org.apache.commons.lang3.NotImplementedException; import org.apache.commons.lang3.NotImplementedException;
import org.apache.commons.lang3.StringUtils; 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.convertors.VersionConvertorConstants;
import org.hl7.fhir.exceptions.DefinitionException; import org.hl7.fhir.exceptions.DefinitionException;
import org.hl7.fhir.exceptions.FHIRException; import org.hl7.fhir.exceptions.FHIRException;
@ -274,6 +276,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
private IEvaluationContext externalHostServices; private IEvaluationContext externalHostServices;
private boolean noExtensibleWarnings; private boolean noExtensibleWarnings;
private String serverBase; private String serverBase;
private IEnableWhenEvaluator myEnableWhenEvaluator = new DefaultEnableWhenEvaluator();
/* /*
* Keeps track of whether a particular profile has been checked or not yet * Keeps track of whether a particular profile has been checked or not yet
@ -2498,6 +2502,10 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
public void setAllowXsiLocation(boolean allowXsiLocation) { public void setAllowXsiLocation(boolean allowXsiLocation) {
this.allowXsiLocation = allowXsiLocation; this.allowXsiLocation = allowXsiLocation;
} }
public void setEnableWhenEvaluator(IEnableWhenEvaluator myEnableWhenEvaluator) {
this.myEnableWhenEvaluator = myEnableWhenEvaluator;
}
/** /**
* *
@ -2776,21 +2784,21 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
sdTime = sdTime + (System.nanoTime() - t); 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")) { 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")); 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"); 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()); 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>(); List<Element> answers = new ArrayList<Element>();
element.getNamedChildren("answer", answers); element.getNamedChildren("answer", answers);
if (inProgress) 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 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) 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"); 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");
@ -2865,7 +2873,7 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
// no validation // no validation
break; break;
} }
validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress); validateQuestionannaireResponseItems(qsrc, qItem.getItem(), errors, answer, stack, inProgress, questionnaireResponseRoot);
} }
if (qItem.getType() == null) { 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"); fail(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), false, "Definition for item "+qItem.getLinkId() + " does not contain a type");
@ -2874,16 +2882,20 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
element.getNamedChildren("item", items); 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()); 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 { } 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) 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()); 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) { for (Element element : elements) {
NodeStack ns = stack.push(element, -1, null, null); NodeStack ns = stack.push(element, -1, null, null);
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress); validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress, questionnaireResponseRoot);
} }
} }
@ -2894,8 +2906,8 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
} }
return -1; 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>(); List<Element> items = new ArrayList<Element>();
element.getNamedChildren("item", items); element.getNamedChildren("item", items);
// now, sort into stacks // now, sort into stacks
@ -2908,9 +2920,9 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
if (index == -1) { if (index == -1) {
QuestionnaireItemComponent qItem = findQuestionnaireItem(qsrc, linkId); QuestionnaireItemComponent qItem = findQuestionnaireItem(qsrc, linkId);
if (qItem != null) { 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); NodeStack ns = stack.push(item, -1, null, null);
validateQuestionannaireResponseItem(qsrc, qItem, errors, element, ns, inProgress); validateQuestionannaireResponseItem(qsrc, qItem, errors, item, ns, inProgress, questionnaireResponseRoot);
} }
else else
rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, "LinkId \""+linkId+"\" not found in questionnaire"); rule(errors, IssueType.NOTFOUND, item.line(), item.col(), stack.getLiteralPath(), index > -1, "LinkId \""+linkId+"\" not found in questionnaire");
@ -2919,11 +2931,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"); rule(errors, IssueType.STRUCTURE, item.line(), item.col(), stack.getLiteralPath(), index >= lastIndex, "Structural Error: items are out of order");
lastIndex = index; lastIndex = index;
List<Element> mapItem = map.get(linkId);
if (mapItem == null) { List<Element> mapItem = map.computeIfAbsent(linkId, key -> new ArrayList<>());
mapItem = new ArrayList<Element>();
map.put(linkId, mapItem);
}
mapItem.add(item); mapItem.add(item);
} }
} }
@ -2932,13 +2942,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 // 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) { for (QuestionnaireItemComponent qItem : qItems) {
List<Element> mapItem = map.get(qItem.getLinkId()); List<Element> mapItem = map.get(qItem.getLinkId());
if (mapItem != null) if (mapItem != null){
validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress); 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());
else validateQuestionannaireResponseItem(qsrc, qItem, errors, mapItem, stack, inProgress, questionnaireResponseRoot);
rule(errors, IssueType.REQUIRED, element.line(), element.col(), stack.getLiteralPath(), !qItem.getRequired(), "No response found for required item "+qItem.getLinkId()); } 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) { private void validateQuestionnaireResponseItemQuantity( List<ValidationMessage> errors, Element answer, NodeStack stack) {
} }
@ -3009,8 +3031,11 @@ public class InstanceValidator extends BaseValidator implements IResourceValidat
long t = System.nanoTime(); long t = System.nanoTime();
ValidationResult res = context.validateCode(c, vs); ValidationResult res = context.validateCode(c, vs);
txTime = txTime + (System.nanoTime() - t); txTime = txTime + (System.nanoTime() - t);
if (!res.isOk()) if (!res.isOk()) {
txRule(errors, res.getTxLink(), IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "The value provided ("+c.getSystem()+"::"+c.getCode()+") is not in the options value set in the questionnaire"); txRule(errors, res.getTxLink(), IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "The value provided (" + c.getSystem() + "::" + c.getCode() + ") is not in the options value set in the questionnaire");
} else if (res.getSeverity() != null) {
super.addValidationMessage(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), res.getMessage(), res.getSeverity(), Source.TerminologyEngine);
}
} catch (Exception e) { } catch (Exception e) {
warning(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "Error " + e.getMessage() + " validating Coding against Questionnaire Options"); warning(errors, IssueType.CODEINVALID, value.line(), value.col(), stack.getLiteralPath(), false, "Error " + e.getMessage() + " validating Coding against Questionnaire Options");
} }

View File

@ -13,7 +13,7 @@
each other. It is fine to bump the point version of this POM without affecting each other. It is fine to bump the point version of this POM without affecting
HAPI FHIR. HAPI FHIR.
--> -->
<version>3.7.3-SNAPSHOT</version> <version>3.7.4-SNAPSHOT</version>
<properties> <properties>
<hapi_fhir_version>3.7.0-SNAPSHOT</hapi_fhir_version> <hapi_fhir_version>3.7.0-SNAPSHOT</hapi_fhir_version>