First implementation of enableWhen evaluator
This commit is contained in:
parent
92936d6889
commit
0dcc4fa189
|
@ -1,36 +1,35 @@
|
||||||
package org.hl7.fhir.instance.validation;
|
package org.hl7.fhir.instance.validation;
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
|
import java.util.*;
|
||||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
|
|
||||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
||||||
|
import org.hl7.fhir.exceptions.FHIRException;
|
||||||
import org.hl7.fhir.r4.elementmodel.Element;
|
import org.hl7.fhir.r4.elementmodel.Element;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.hl7.fhir.r4.model.Questionnaire.*;
|
||||||
|
/**
|
||||||
|
* Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse.
|
||||||
|
* Ignores possible modifierExtensions and extensions.
|
||||||
|
*
|
||||||
|
*/
|
||||||
public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
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
|
@Override
|
||||||
public boolean isQuestionEnabled(QuestionnaireItemComponent item, List<QuestionnaireResponseItemComponent> resp) {
|
public boolean isQuestionEnabled(org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent item,
|
||||||
|
List<QuestionnaireResponseItemComponent> resp) {
|
||||||
boolean enabled = true;
|
boolean enabled = true;
|
||||||
|
|
||||||
if(item.hasEnableWhen()) {
|
if(item.hasEnableWhen()) {
|
||||||
|
|
||||||
enabled = false;
|
enabled = false;
|
||||||
|
for(org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemEnableWhenComponent enable : item.getEnableWhen()) {
|
||||||
for( QuestionnaireItemEnableWhenComponent enable : item.getEnableWhen()) {
|
|
||||||
|
|
||||||
if(enable.getHasAnswer()) {
|
if(enable.getHasAnswer()) {
|
||||||
// check if referenced question has answer
|
// check if referenced question has answer
|
||||||
|
|
||||||
String itemId = enable.getQuestion();
|
String itemId = enable.getQuestion();
|
||||||
|
|
||||||
for(QuestionnaireResponseItemComponent respItem : resp) {
|
for(QuestionnaireResponseItemComponent respItem : resp) {
|
||||||
if(respItem.getLinkId().equalsIgnoreCase(itemId) && respItem.hasAnswer()) {
|
if(respItem.getLinkId().equalsIgnoreCase(itemId) && respItem.hasAnswer()) {
|
||||||
|
|
||||||
//TODO check answer value
|
//TODO check answer value
|
||||||
enabled = true;
|
enabled = true;
|
||||||
}
|
}
|
||||||
|
@ -38,9 +37,7 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// and if not
|
// and if not
|
||||||
|
|
||||||
String itemId = enable.getQuestion();
|
String itemId = enable.getQuestion();
|
||||||
|
|
||||||
for(QuestionnaireResponseItemComponent respItem : resp) {
|
for(QuestionnaireResponseItemComponent respItem : resp) {
|
||||||
if(respItem.getLinkId().equalsIgnoreCase(itemId) && !respItem.hasAnswer()) {
|
if(respItem.getLinkId().equalsIgnoreCase(itemId) && !respItem.hasAnswer()) {
|
||||||
|
|
||||||
|
@ -52,59 +49,129 @@ public class DefaultEnableWhenEvaluator implements IEnableWhenEvaluator {
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return enabled;
|
return enabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isQuestionEnabled(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent item,
|
public boolean isQuestionEnabled(QuestionnaireItemComponent questionnaireItem, Element questionnaireResponse) {
|
||||||
Element element) {
|
if (!questionnaireItem.hasEnableWhen()) {
|
||||||
boolean enabled = true;
|
return true;
|
||||||
|
|
||||||
if(item.hasEnableWhen()) {
|
|
||||||
|
|
||||||
enabled = false;
|
|
||||||
|
|
||||||
for( org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemEnableWhenComponent enable : item.getEnableWhen()) {
|
|
||||||
|
|
||||||
if(enable.hasAnswer()) {
|
|
||||||
// check if referenced question has answer
|
|
||||||
|
|
||||||
String itemId = enable.getQuestion();
|
|
||||||
|
|
||||||
List<Element> items = new ArrayList<Element>();
|
|
||||||
element.getNamedChildren("item", items);
|
|
||||||
|
|
||||||
for(Element respItem : items) {
|
|
||||||
|
|
||||||
// TODO toteuta uudelleen
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
List<EnableWhenResult> evaluationResults = questionnaireItem.getEnableWhen()
|
||||||
} else {
|
.stream()
|
||||||
// and if not
|
.map(enableCondition -> evaluateCondition(enableCondition, questionnaireResponse,
|
||||||
|
questionnaireItem.getLinkId()))
|
||||||
String itemId = enable.getQuestion();
|
.collect(Collectors.toList());
|
||||||
|
return checkConditionResults(evaluationResults, questionnaireItem);
|
||||||
List<Element> items = new ArrayList<Element>();
|
|
||||||
element.getNamedChildren("item", items);
|
|
||||||
|
|
||||||
for(Element respItem : items) {
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return enabled;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition,
|
||||||
|
Element questionnaireResponse, String linkId) {
|
||||||
|
//TODO: Fix EnableWhenResult stuff
|
||||||
|
List<Element> answerItems = findQuestionAnswers(questionnaireResponse,
|
||||||
|
enableCondition.getQuestion());
|
||||||
|
if (enableCondition.hasAnswer()) {
|
||||||
|
boolean result = answerItems.stream().anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer()));
|
||||||
|
|
||||||
|
return new EnableWhenResult(result, linkId, enableCondition, questionnaireResponse);
|
||||||
|
|
||||||
|
}
|
||||||
|
return new EnableWhenResult(false, linkId, enableCondition, questionnaireResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean evaluateAnswer(Element answer, Type expectedAnswer) {
|
||||||
|
org.hl7.fhir.r4.model.Type actualAnswer;
|
||||||
|
try {
|
||||||
|
actualAnswer = answer.asType();
|
||||||
|
} catch (FHIRException e) {
|
||||||
|
throw new RuntimeException("Unexpected answer type", e);
|
||||||
|
}
|
||||||
|
if (!actualAnswer.getClass().isAssignableFrom(expectedAnswer.getClass())) {
|
||||||
|
throw new RuntimeException("Expected answer and actual answer have incompatible types");
|
||||||
|
}
|
||||||
|
if (expectedAnswer instanceof Coding) {
|
||||||
|
return validateCodingAnswer((Coding)expectedAnswer, (Coding)actualAnswer);
|
||||||
|
} else if (expectedAnswer instanceof PrimitiveType) {
|
||||||
|
return actualAnswer.equalsShallow(expectedAnswer);
|
||||||
|
}
|
||||||
|
// TODO: Quantity, Attachment, reference?
|
||||||
|
throw new RuntimeException("Unimplemented answer type: " + expectedAnswer.getClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
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 validateCodingAnswer(Coding expectedAnswer, Coding actualAnswer) {
|
||||||
|
return compareSystems(expectedAnswer, actualAnswer) && compareCodes(expectedAnswer, actualAnswer);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,16 +3,13 @@ package org.hl7.fhir.instance.validation;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
|
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemComponent;
|
||||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
|
|
||||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
import org.hl7.fhir.dstu3.model.QuestionnaireResponse.QuestionnaireResponseItemComponent;
|
||||||
import org.hl7.fhir.r4.elementmodel.Element;
|
import org.hl7.fhir.r4.elementmodel.Element;
|
||||||
|
|
||||||
public interface IEnableWhenEvaluator {
|
public interface IEnableWhenEvaluator {
|
||||||
|
public boolean isQuestionEnabled(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent questionnaireItem,
|
||||||
|
Element questionnaireResponse);
|
||||||
public boolean isQuestionEnabled(QuestionnaireItemComponent item, List<QuestionnaireResponseItemComponent> theResponseItems);
|
public boolean isQuestionEnabled(QuestionnaireItemComponent item, List<QuestionnaireResponseItemComponent> theResponseItems);
|
||||||
|
|
||||||
|
|
||||||
public boolean isQuestionEnabled(org.hl7.fhir.r4.model.Questionnaire.QuestionnaireItemComponent qItem,
|
|
||||||
Element element);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue