/** * <a href="http://www.openolat.org"> * OpenOLAT - Online Learning and Training</a><br> * <p> * Licensed under the Apache License, Version 2.0 (the "License"); <br> * you may not use this file except in compliance with the License.<br> * You may obtain a copy of the License at the * <a href="http://www.apache.org/licenses/LICENSE-2.0">Apache homepage</a> * <p> * Unless required by applicable law or agreed to in writing,<br> * software distributed under the License is distributed on an "AS IS" BASIS, <br> * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. <br> * See the License for the specific language governing permissions and <br> * limitations under the License. * <p> * Initial code contributed and copyrighted by<br> * frentix GmbH, http://www.frentix.com * <p> */ package org.olat.ims.qti21.model.xml; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.olat.core.helpers.Settings; import org.olat.ims.qti21.QTI21Constants; import org.olat.ims.qti21.model.IdentifierGenerator; import uk.ac.ed.ph.jqtiplus.node.content.variable.RubricBlock; import uk.ac.ed.ph.jqtiplus.node.expression.ExpressionParent; import uk.ac.ed.ph.jqtiplus.node.expression.general.BaseValue; import uk.ac.ed.ph.jqtiplus.node.expression.general.Variable; import uk.ac.ed.ph.jqtiplus.node.expression.operator.And; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Gte; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Match; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Multiple; import uk.ac.ed.ph.jqtiplus.node.expression.operator.Sum; import uk.ac.ed.ph.jqtiplus.node.expression.outcome.TestVariables; import uk.ac.ed.ph.jqtiplus.node.outcome.declaration.OutcomeDeclaration; import uk.ac.ed.ph.jqtiplus.node.shared.FieldValue; import uk.ac.ed.ph.jqtiplus.node.shared.declaration.DefaultValue; import uk.ac.ed.ph.jqtiplus.node.test.AbstractPart; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentItemRef; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentSection; import uk.ac.ed.ph.jqtiplus.node.test.AssessmentTest; import uk.ac.ed.ph.jqtiplus.node.test.ItemSessionControl; import uk.ac.ed.ph.jqtiplus.node.test.NavigationMode; import uk.ac.ed.ph.jqtiplus.node.test.Ordering; import uk.ac.ed.ph.jqtiplus.node.test.SubmissionMode; import uk.ac.ed.ph.jqtiplus.node.test.TestFeedback; import uk.ac.ed.ph.jqtiplus.node.test.TestFeedbackAccess; import uk.ac.ed.ph.jqtiplus.node.test.TestPart; import uk.ac.ed.ph.jqtiplus.node.test.View; import uk.ac.ed.ph.jqtiplus.node.test.VisibilityMode; import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.OutcomeCondition; import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.OutcomeElse; import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.OutcomeIf; import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.OutcomeProcessing; import uk.ac.ed.ph.jqtiplus.node.test.outcome.processing.SetOutcomeValue; import uk.ac.ed.ph.jqtiplus.types.ComplexReferenceIdentifier; import uk.ac.ed.ph.jqtiplus.types.Identifier; import uk.ac.ed.ph.jqtiplus.value.BaseType; import uk.ac.ed.ph.jqtiplus.value.BooleanValue; import uk.ac.ed.ph.jqtiplus.value.Cardinality; import uk.ac.ed.ph.jqtiplus.value.FloatValue; import uk.ac.ed.ph.jqtiplus.value.IdentifierValue; /** * * Initial date: 04.06.2015<br> * @author srosse, stephane.rosse@frentix.com, http://www.frentix.com * */ public class AssessmentTestFactory { /** * Create an assessmentTest object but without items * * @param title * @return */ public static AssessmentTest createAssessmentTest(String title, String sectionTitle) { AssessmentTest assessmentTest = new AssessmentTest(); assessmentTest.setIdentifier(IdentifierGenerator.newAsString("test")); assessmentTest.setTitle(title); assessmentTest.setToolName(QTI21Constants.TOOLNAME); assessmentTest.setToolVersion(Settings.getVersion()); // outcome score OutcomeDeclaration scoreOutcomeDeclaration = new OutcomeDeclaration(assessmentTest); scoreOutcomeDeclaration.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); scoreOutcomeDeclaration.setCardinality(Cardinality.SINGLE); scoreOutcomeDeclaration.setBaseType(BaseType.FLOAT); assessmentTest.getOutcomeDeclarations().add(scoreOutcomeDeclaration); //test part TestPart part = createTestPart(assessmentTest); appendAssessmentSection(sectionTitle, part); //outcome processing OutcomeProcessing outcomeProcessing = new OutcomeProcessing(assessmentTest); assessmentTest.setOutcomeProcessing(outcomeProcessing); SetOutcomeValue outcomeRule = new SetOutcomeValue(outcomeProcessing); outcomeRule.setIdentifier(QTI21Constants.SCORE_IDENTIFIER); Sum sum = new Sum(outcomeRule); outcomeRule.getExpressions().add(sum); TestVariables testVariables = new TestVariables(sum); testVariables.setVariableIdentifier(QTI21Constants.SCORE_IDENTIFIER); sum.getExpressions().add(testVariables); outcomeProcessing.getOutcomeRules().add(outcomeRule); return assessmentTest; } public static OutcomeDeclaration createOutcomeDeclaration(AssessmentTest assessmentTest, Identifier identifier, Double defaultValue) { OutcomeDeclaration outcomeDeclaration = new OutcomeDeclaration(assessmentTest); outcomeDeclaration.setIdentifier(identifier); outcomeDeclaration.setCardinality(Cardinality.SINGLE); outcomeDeclaration.setBaseType(BaseType.FLOAT); DefaultValue defaultVal = new DefaultValue(outcomeDeclaration); outcomeDeclaration.setDefaultValue(defaultVal); FieldValue fieldValue = new FieldValue(defaultVal); FloatValue identifierValue = new FloatValue(defaultValue); fieldValue.setSingleValue(identifierValue); defaultVal.getFieldValues().add(fieldValue); return outcomeDeclaration; } public static void updateDefaultValue(OutcomeDeclaration outcomeDeclaration, Double defaultValue) { outcomeDeclaration.setBaseType(BaseType.FLOAT); DefaultValue defaultVal = outcomeDeclaration.getDefaultValue(); defaultVal.getFieldValues().clear(); FieldValue fieldValue = new FieldValue(defaultVal); FloatValue identifierValue = new FloatValue(defaultValue); fieldValue.setSingleValue(identifierValue); defaultVal.getFieldValues().add(fieldValue); } public static OutcomeDeclaration createOutcomeDeclaration(AssessmentTest assessmentTest, Identifier identifier, boolean defaultValue) { OutcomeDeclaration outcomeDeclaration = new OutcomeDeclaration(assessmentTest); outcomeDeclaration.setIdentifier(identifier); outcomeDeclaration.setCardinality(Cardinality.SINGLE); outcomeDeclaration.setBaseType(BaseType.BOOLEAN); DefaultValue defaultVal = new DefaultValue(outcomeDeclaration); outcomeDeclaration.setDefaultValue(defaultVal); FieldValue fieldValue = new FieldValue(defaultVal); BooleanValue booleanValue = defaultValue ? BooleanValue.TRUE : BooleanValue.FALSE; fieldValue.setSingleValue(booleanValue); defaultVal.getFieldValues().add(fieldValue); return outcomeDeclaration; } /* Passed <outcomeCondition> <outcomeIf> <gte> <sum> <testVariables variableIdentifier="SCORE" /> </sum> <baseValue baseType="float"> 1 </baseValue> </gte> <setOutcomeValue identifier="PASS"> <baseValue baseType="boolean"> true </baseValue> </setOutcomeValue> </outcomeIf> <outcomeElse> <setOutcomeValue identifier="PASS"> <baseValue baseType="boolean"> false </baseValue> </setOutcomeValue> </outcomeElse> </outcomeCondition> */ public static OutcomeCondition createCutValueRule(AssessmentTest assessmentTest, Double cutValue) { OutcomeCondition outcomeCondition = new OutcomeCondition(assessmentTest); //if { OutcomeIf outcomeIf = new OutcomeIf(outcomeCondition); outcomeCondition.setOutcomeIf(outcomeIf); Gte gte = new Gte(outcomeIf); outcomeIf.setExpression(gte); { appendSumOfTestVariables(gte); BaseValue passed = new BaseValue(gte); passed.setBaseTypeAttrValue(BaseType.FLOAT); passed.setSingleValue(new FloatValue(cutValue.floatValue())); gte.getExpressions().add(passed); } SetOutcomeValue passedOutcomeValue = new SetOutcomeValue(outcomeIf); passedOutcomeValue.setIdentifier(QTI21Constants.PASS_IDENTIFIER); outcomeIf.getOutcomeRules().add(passedOutcomeValue); BaseValue passed = new BaseValue(passedOutcomeValue); passed.setBaseTypeAttrValue(BaseType.BOOLEAN); passed.setSingleValue(BooleanValue.TRUE); passedOutcomeValue.setExpression(passed); } {//else OutcomeElse outcomeElse = new OutcomeElse(outcomeCondition); outcomeCondition.setOutcomeElse(outcomeElse); SetOutcomeValue notPassedOutcomeValue = new SetOutcomeValue(outcomeElse); notPassedOutcomeValue.setIdentifier(QTI21Constants.PASS_IDENTIFIER); outcomeElse.getOutcomeRules().add(notPassedOutcomeValue); BaseValue notPassed = new BaseValue(notPassedOutcomeValue); notPassed.setBaseTypeAttrValue(BaseType.BOOLEAN); notPassed.setSingleValue(BooleanValue.FALSE); notPassedOutcomeValue.setExpression(notPassed); } return outcomeCondition; } /* <sum> <testVariables variableIdentifier="SCORE" /> </sum> */ public static Sum appendSumOfTestVariables(ExpressionParent parent) { Sum sum = new Sum(parent); parent.getExpressions().add(sum); TestVariables testVariables = new TestVariables(sum); sum.getExpressions().add(testVariables); testVariables.setVariableIdentifier(QTI21Constants.SCORE_IDENTIFIER); return sum; } public static void appendAssessmentItem(AssessmentSection section, String itemFilename) throws URISyntaxException { AssessmentItemRef item = new AssessmentItemRef(section); item.setIdentifier(IdentifierGenerator.newAsIdentifier("ai")); item.setHref(new URI(itemFilename)); section.getSectionParts().add(item); } public static TestPart createTestPart(AssessmentTest assessmentTest) { TestPart part = new TestPart(assessmentTest); part.setIdentifier(IdentifierGenerator.newAsIdentifier("tp")); part.setNavigationMode(NavigationMode.NONLINEAR); part.setSubmissionMode(SubmissionMode.INDIVIDUAL); assessmentTest.getTestParts().add(part); // test par item session control ItemSessionControl itemSessionControl = new ItemSessionControl(part); itemSessionControl.setAllowComment(Boolean.TRUE); itemSessionControl.setAllowReview(Boolean.FALSE); itemSessionControl.setAllowSkipping(Boolean.TRUE);//default is true itemSessionControl.setShowFeedback(Boolean.FALSE); itemSessionControl.setShowSolution(Boolean.FALSE); itemSessionControl.setMaxAttempts(0); part.setItemSessionControl(itemSessionControl); return part; } /** * create an assessmentSection with an empty rubricBlock for candidate, * not shuffled but visible and fixed. * @param part * @return */ public static AssessmentSection appendAssessmentSection(String title, TestPart part) { return appendAssessmentSectionInternal(title, part); } public static AssessmentSection appendAssessmentSection(String title, AssessmentSection part) { return appendAssessmentSectionInternal(title, part); } private final static AssessmentSection appendAssessmentSectionInternal(String title, AbstractPart part) { // section AssessmentSection section = new AssessmentSection(part); section.setFixed(Boolean.TRUE); section.setVisible(Boolean.TRUE); section.setTitle(title); section.setIdentifier(IdentifierGenerator.newAsIdentifier("sect")); if(part instanceof TestPart) { ((TestPart)part).getAssessmentSections().add(section); } else if(part instanceof AssessmentSection) { ((AssessmentSection)part).getSectionParts().add(section); } // section ordering Ordering ordering = new Ordering(section); ordering.setShuffle(false); section.setOrdering(ordering); // section rubric block RubricBlock rubricBlock = new RubricBlock(section); rubricBlock.setViews(Collections.singletonList(View.CANDIDATE)); section.getRubricBlocks().add(rubricBlock); ItemSessionControl itemSessionControl = new ItemSessionControl(section); section.setItemSessionControl(itemSessionControl); return section; } /* <outcomeDeclaration identifier="FEEDBACKMODAL" cardinality="multiple" baseType="identifier" view="testConstructor" /> */ public final static OutcomeDeclaration createTestFeedbackModalOutcomeDeclaration(AssessmentTest assessmentTest) { OutcomeDeclaration feedbackOutcomeDeclaration = new OutcomeDeclaration(assessmentTest); feedbackOutcomeDeclaration.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER); feedbackOutcomeDeclaration.setCardinality(Cardinality.MULTIPLE); feedbackOutcomeDeclaration.setBaseType(BaseType.IDENTIFIER); List<View> views = new ArrayList<>(); views.add(View.TEST_CONSTRUCTOR); feedbackOutcomeDeclaration.setViews(views); return feedbackOutcomeDeclaration; } /* <testFeedback identifier="Feedback952020414" outcomeIdentifier="FEEDBACKMODAL" showHide="show" access="atEnd" title="Correct answer"> <p>This is the correct answer</p> </testFeedback> */ public final static TestFeedback createTestFeedbackModal(AssessmentTest assessmentTest, Identifier identifier, String title, String text) { TestFeedback testFeedback = new TestFeedback(assessmentTest); testFeedback.setOutcomeValue(identifier); testFeedback.setOutcomeIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER); testFeedback.setVisibilityMode(VisibilityMode.SHOW_IF_MATCH); testFeedback.setTestFeedbackAccess(TestFeedbackAccess.AT_END); testFeedback.setTitle(title); new AssessmentHtmlBuilder().appendHtml(testFeedback, text); return testFeedback; } /* <outcomeCondition> <outcomeIf> <and> <match> <baseValue baseType="boolean"> false </baseValue> <variable identifier="PASS" /> </match> </and> <setOutcomeValue identifier="FEEDBACKMODAL"> <multiple> <variable identifier="FEEDBACKMODAL" /> <baseValue baseType="identifier"> Feedback1757237693 </baseValue> </multiple> </setOutcomeValue> </outcomeIf> </outcomeCondition> */ public final static OutcomeCondition createTestFeedbackModalCondition(AssessmentTest assessmentTest, boolean condition, Identifier feedbackIdentifier) { OutcomeCondition outcomeCondition = new OutcomeCondition(assessmentTest); OutcomeIf outcomeIf = new OutcomeIf(outcomeCondition); outcomeCondition.setOutcomeIf(outcomeIf); {//condition And and = new And(outcomeIf); outcomeIf.getExpressions().add(and); Match match = new Match(and); and.getExpressions().add(match); BaseValue feedbackVal = new BaseValue(match); feedbackVal.setBaseTypeAttrValue(BaseType.BOOLEAN); feedbackVal.setSingleValue(condition ? BooleanValue.TRUE : BooleanValue.FALSE); match.getExpressions().add(feedbackVal); Variable variable = new Variable(match); variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.PASS)); match.getExpressions().add(variable); } {//outcome SetOutcomeValue setOutcomeValue = new SetOutcomeValue(outcomeIf); setOutcomeValue.setIdentifier(QTI21Constants.FEEDBACKMODAL_IDENTIFIER); outcomeIf.getOutcomeRules().add(setOutcomeValue); Multiple multiple = new Multiple(setOutcomeValue); setOutcomeValue.getExpressions().add(multiple); Variable variable = new Variable(multiple); variable.setIdentifier(ComplexReferenceIdentifier.parseString(QTI21Constants.FEEDBACKMODAL)); multiple.getExpressions().add(variable); BaseValue feedbackVal = new BaseValue(multiple); feedbackVal.setBaseTypeAttrValue(BaseType.IDENTIFIER); feedbackVal.setSingleValue(new IdentifierValue(feedbackIdentifier)); multiple.getExpressions().add(feedbackVal); } return outcomeCondition; } }