From 52246a8ce5f9574dcd77885bd36c3a2e950af7bd Mon Sep 17 00:00:00 2001 From: markiantorno Date: Mon, 24 Feb 2020 15:38:18 -0500 Subject: [PATCH] cleanup --- .../instance/EnableWhenEvaluator.java | 149 +++++++++--------- .../validation/profile/ProfileValidator.java | 1 - 2 files changed, 71 insertions(+), 79 deletions(-) diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java index 03ec83379..77e5495da 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/instance/EnableWhenEvaluator.java @@ -9,9 +9,9 @@ package org.hl7.fhir.validation.instance; * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -35,7 +35,6 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; /** * Evaluates Questionnaire.item.enableWhen against a QuestionnaireResponse. * Ignores possible modifierExtensions and extensions. - * */ public class EnableWhenEvaluator { public static final String LINKID_ELEMENT = "linkId"; @@ -46,26 +45,29 @@ public class EnableWhenEvaluator { public static class QuestionnaireAnswerPair { private QuestionnaireItemComponent q; private Element a; - + public QuestionnaireAnswerPair(QuestionnaireItemComponent q, Element a) { super(); this.q = q; this.a = a; } + public QuestionnaireItemComponent getQ() { return q; } + public Element getA() { return a; } - + } + public static class QStack extends ArrayList { private static final long serialVersionUID = 1L; private Questionnaire q; private Element a; - + public QStack(Questionnaire q, Element a) { super(); this.q = q; @@ -97,40 +99,30 @@ public class EnableWhenEvaluator { /** * 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 + * + * @param enabled Evaluation result + * @param enableWhenCondition Evaluated enableWhen condition */ public EnableWhenResult(boolean enabled, QuestionnaireItemEnableWhenComponent enableWhenCondition) { - this.enabled = enabled; - this.enableWhenCondition = enableWhenCondition; + this.enabled = enabled; + this.enableWhenCondition = enableWhenCondition; } public boolean isEnabled() { - return enabled; + return enabled; } public QuestionnaireItemEnableWhenComponent getEnableWhenCondition() { - return enableWhenCondition; + return enableWhenCondition; } -} + } + /** * the stack contains a set of QR items that represent the tree of the QR being validated, each tagged with the definition of the item from the Q for the QR being validated - * - * the itembeing validated is in the context of the stack. For root items, the stack is empty. - * + *

+ * the itembeing validated is in the context of the stack. For root items, the stack is empty. + *

* The context Questionnaire and QuestionnaireResponse are always available - * - * @param questionnaireItem - * @param questionnaireResponse - * @param qstack - * @return */ public boolean isQuestionEnabled(ValidatorHostContext hostContext, QuestionnaireItemComponent qitem, QStack qstack, FHIRPathEngine engine) { if (hasExpressionExtension(qitem)) { @@ -138,22 +130,22 @@ public class EnableWhenEvaluator { ExpressionNode node = engine.parse(expr); return engine.evaluateToBoolean(hostContext, qstack.a, qstack.a, qstack.a, node); } - + if (!qitem.hasEnableWhen()) { return true; } - + List evaluationResults = qitem.getEnableWhen() - .stream() - .map(enableCondition -> evaluateCondition(enableCondition, qitem, qstack)) - .collect(Collectors.toList()); + .stream() + .map(enableCondition -> evaluateCondition(enableCondition, qitem, qstack)) + .collect(Collectors.toList()); return checkConditionResults(evaluationResults, qitem); } private boolean hasExpressionExtension(QuestionnaireItemComponent qitem) { return qitem.hasExtension("http://phr.kanta.fi/StructureDefinition/fiphr-ext-questionnaire-enablewhen") || // finnish extension - qitem.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); // sdc extension + qitem.hasExtension("http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); // sdc extension } private String getExpression(QuestionnaireItemComponent qitem) { @@ -164,17 +156,18 @@ public class EnableWhenEvaluator { if ("text/fhirpath".equals(expr.getLanguage())) { return expr.getExpression(); } else { - throw new FHIRException("Unsupported language '"+expr.getLanguage()+"' for enableWhen extension http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); + throw new FHIRException("Unsupported language '" + expr.getLanguage() + "' for enableWhen extension http://hl7.org/fhir/uv/sdc/StructureDefinition/sdc-questionnaire-enableWhenExpression"); } } throw new Error("How did you get here?"); } - public boolean checkConditionResults(List evaluationResults, QuestionnaireItemComponent questionnaireItem) { - if ((questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY) || evaluationResults.size() == 1){ + public boolean checkConditionResults(List evaluationResults, QuestionnaireItemComponent questionnaireItem) { + if ((questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ANY) || evaluationResults.size() == 1) { return evaluationResults.stream().anyMatch(EnableWhenResult::isEnabled); - } if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ALL){ + } + if (questionnaireItem.hasEnableBehavior() && questionnaireItem.getEnableBehavior() == EnableWhenBehavior.ALL) { return evaluationResults.stream().allMatch(EnableWhenResult::isEnabled); } //TODO: Throw exception? enableBehavior is mandatory when there are multiple conditions @@ -183,18 +176,18 @@ public class EnableWhenEvaluator { protected EnableWhenResult evaluateCondition(QuestionnaireItemEnableWhenComponent enableCondition, QuestionnaireItemComponent qitem, QStack qstack) { - List answerItems = findQuestionAnswers(qstack, qitem, enableCondition); + List answerItems = findQuestionAnswers(qstack, qitem, enableCondition); QuestionnaireItemOperator operator = enableCondition.getOperator(); - if (operator == QuestionnaireItemOperator.EXISTS){ + if (operator == QuestionnaireItemOperator.EXISTS) { DataType answer = enableCondition.getAnswer(); - if (!(answer instanceof BooleanType)){ - throw new UnprocessableEntityException("Exists-operator requires answerBoolean"); + if (!(answer instanceof BooleanType)) { + throw new UnprocessableEntityException("Exists-operator requires answerBoolean"); } - return new EnableWhenResult(((BooleanType)answer).booleanValue() != answerItems.isEmpty(), enableCondition); - } + return new EnableWhenResult(((BooleanType) answer).booleanValue() != answerItems.isEmpty(), enableCondition); + } boolean result = answerItems - .stream() - .anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator())); + .stream() + .anyMatch(answer -> evaluateAnswer(answer, enableCondition.getAnswer(), enableCondition.getOperator())); return new EnableWhenResult(result, enableCondition); } @@ -235,71 +228,71 @@ public class EnableWhenEvaluator { } 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); + return compareCodingAnswer((Coding) expectedAnswer, (Coding) actualAnswer, questionnaireItemOperator); } else if ((expectedAnswer instanceof PrimitiveType)) { - return comparePrimitiveAnswer((PrimitiveType)actualAnswer, (PrimitiveType)expectedAnswer, questionnaireItemOperator); + return comparePrimitiveAnswer((PrimitiveType) actualAnswer, (PrimitiveType) expectedAnswer, questionnaireItemOperator); } else if (expectedAnswer instanceof Quantity) { - return compareQuantityAnswer((Quantity)actualAnswer, (Quantity)expectedAnswer, questionnaireItemOperator); + 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) { + 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){ + 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){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL) { return !actualAnswer.equalsShallow(expectedAnswer); } throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison"); } - @SuppressWarnings({ "rawtypes", "unchecked" }) + @SuppressWarnings({"rawtypes", "unchecked"}) private boolean compareComparable(Comparable actual, Comparable expected, - QuestionnaireItemOperator questionnaireItemOperator) { + QuestionnaireItemOperator questionnaireItemOperator) { int result = actual.compareTo(expected); - if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL){ + if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL) { return result == 0; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL) { return result != 0; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_OR_EQUAL){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_OR_EQUAL) { return result >= 0; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_OR_EQUAL){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_OR_EQUAL) { return result <= 0; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_THAN){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.LESS_THAN) { return result < 0; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.GREATER_THAN) { return result > 0; } - throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison: "+questionnaireItemOperator.toCode()); + throw new UnprocessableEntityException("Bad operator for PrimitiveType comparison: " + questionnaireItemOperator.toCode()); } /** * Recursively look for answers to questions with the given link id, working upwards given the context - * + *

* For discussion about this, see https://chat.fhir.org/#narrow/stream/179255-questionnaire/topic/enable-when - * - - given sourceQ - question that contains the enableWhen reference and targetQ - question that the enableWhen references in the Q and also sourceA - answer for sourceQ and targetA - answer for targetQ in the QR - - work up from sourceQ until you find the Q group that also contains targetQ - this is groupQ - - work up from sourceA until you find the QR group that matches groupQ - this is groupA - - any targetA in groupA are input for the enableWhen decision + *

+ * - given sourceQ - question that contains the enableWhen reference and targetQ - question that the enableWhen references in the Q and also sourceA - answer for sourceQ and targetA - answer for targetQ in the QR + * - work up from sourceQ until you find the Q group that also contains targetQ - this is groupQ + * - work up from sourceA until you find the QR group that matches groupQ - this is groupA + * - any targetA in groupA are input for the enableWhen decision */ private List findQuestionAnswers(QStack qstack, QuestionnaireItemComponent sourceQ, QuestionnaireItemEnableWhenComponent ew) { QuestionnaireItemComponent targetQ = qstack.getQ().getQuestion(ew.getQuestion()); - if (targetQ != null) { + if (targetQ != null) { QuestionnaireItemComponent groupQ = qstack.getQ().getCommonGroup(sourceQ, targetQ); if (groupQ == null) { // root is Q itself return findOnItem(qstack.getA(), ew.getQuestion()); @@ -341,16 +334,16 @@ public class EnableWhenEvaluator { private List extractAnswer(Element item) { return item.getChildrenByName(ANSWER_ELEMENT) - .stream() - .flatMap(c -> c.getChildren().stream()) - .collect(Collectors.toList()); + .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){ + if (questionnaireItemOperator == QuestionnaireItemOperator.EQUAL) { return result == true; - } else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL){ + } else if (questionnaireItemOperator == QuestionnaireItemOperator.NOT_EQUAL) { return result == false; } throw new UnprocessableEntityException("Bad operator for Coding comparison"); @@ -378,7 +371,7 @@ public class EnableWhenEvaluator { private boolean hasLinkId(Element item, String linkId) { Element linkIdChild = item.getNamedChild(LINKID_ELEMENT); - if (linkIdChild != null && linkIdChild.getValue().equals(linkId)){ + if (linkIdChild != null && linkIdChild.getValue().equals(linkId)) { return true; } return false; diff --git a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java index e1fb8a787..054adb258 100644 --- a/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java +++ b/org.hl7.fhir.validation/src/main/java/org/hl7/fhir/validation/profile/ProfileValidator.java @@ -20,7 +20,6 @@ package org.hl7.fhir.validation.profile; * #L% */ - import java.util.ArrayList; import java.util.Hashtable; import java.util.List;