@Override protected Value evaluateValidSelf(final ProcessingContext context, final Value[] childValues, final int depth) { final Random randomGenerator = context.getRandomGenerator(); final int min = getMin().evaluateNotNull(this, context, "Computed value of min was NULL. Replacing with 0", 0); final int max = getMax().evaluateNotNull(this, context, "Computed value of max was NULL. Replacing with min+1", min+1); final int step = getStep().evaluateNotNull(this, context, "Computed value of step was NULL. Replacing with 1", 1); /* Validate computed numbers */ if (step < 1) { return NullValue.INSTANCE; } if (max < min) { return NullValue.INSTANCE; } final int randomNumber = randomGenerator.nextInt((max - min) / step + 1); final int randomInteger = min + randomNumber * step; return new IntegerValue(randomInteger); } }
@Override public void validateFigures(final ValidationContext context, final IntegerOrVariableRefAttribute attribute) { final IntegerOrVariableRef integerOrVariableRef = attribute.getValue(); if (integerOrVariableRef.isConstantInteger()) { final int intValue = integerOrVariableRef.getConstantIntegerValue().intValue(); if (intValue < 0) { context.fireAttributeValidationError(attribute, "Figures count (" + intValue + ") must be 0 or more."); } } }
@Override public void validateBasic(final ValidationContext context) { super.validateBasic(context); /* If variable reference, make sure it refers to the right type of variable */ if (value!=null && value.isVariableRef()) { final Identifier variableReferenceIdentifier = value.getIdentifier(); final VariableDeclaration variableDeclaration = context.checkLocalVariableReference(owner, variableReferenceIdentifier); if (variableDeclaration!=null) { context.checkVariableType(owner, variableDeclaration, VariableType.TEMPLATE, VariableType.OUTCOME); context.checkSignature(owner, variableDeclaration, Signature.SINGLE_INTEGER); } } }
/** * Wrapper for {@link #evaluate(Expression, ProcessingContext)} that substitutes a replacement value and emits a * runtime warning if the result was NULL. */ public int evaluateNotNull(final Expression expression, final ProcessingContext context, final String messageOnNull, final int replacementOnNull) { final Value evaluated = evaluate(expression, context); int result; if (evaluated.isNull()) { context.fireRuntimeWarning(expression, messageOnNull); result = replacementOnNull; } else { result = ((IntegerValue) evaluated).intValue(); } return result; } }
/** * Parses a new integerOrVariableRef from the given String, as defined in the QTI spec. * * @throws QtiParseException */ public static IntegerOrVariableRef parseString(final String string) { Assert.notNull(string); if (string.isEmpty()) { throw new QtiParseException("integerOrVariableRef must not be empty"); } try { /* Try to parse as in integer */ final int integer = DataTypeBinder.parseInteger(string); return new IntegerOrVariableRef(integer); } catch (final QtiParseException e) { /* Parse as a variable reference */ final Identifier variableReferenceIdentifier = Identifier.parseString(string); return new IntegerOrVariableRef(variableReferenceIdentifier); } }
@Override public IntegerOrVariableRef parseDomAttributeValue(final String domAttributeValue) { return IntegerOrVariableRef.parseString(domAttributeValue); }
@Override public String toDomAttributeValue(final IntegerOrVariableRef value) { return value.toString(); }
/** * Evaluates this holder. If this holds an explicit integer then its value is returned as-is. * Otherwise, the given {@link ProcessingContext} is used to look up the value of the variable * that this type refers to. The result will either be an {@link IntegerValue} or {@link NullValue} * <p> * If the variable cannot be successfully resolved or is of the wrong type then a runtime error * is recorded and a {@link NullValue} will be returned. */ public Value evaluate(final Expression owner, final ProcessingContext context) { if (isConstantInteger()) { return constantIntegerValue; } else { final Value result = context.evaluateVariableValue(variableReferenceValue, VariableType.TEMPLATE, VariableType.OUTCOME); if (result.hasSignature(Signature.SINGLE_INTEGER)) { return result; } else { context.fireRuntimeError(owner, "Variable referenced by " + variableReferenceValue + " was expected to be a single integer - returning NULL"); return NullValue.INSTANCE; } } }
@Override protected Value evaluateValidSelfAndChildren(final ProcessingContext context, final int depth) { /* Check runtime value of numberRepeats */ final Value numberRepeatsValue = getNumberRepeats().evaluate(this, context); if (numberRepeatsValue.isNull()) { context.fireRuntimeWarning(this, "numberRepeats evaluated to NULL. Returning NULL"); return NullValue.INSTANCE; } final int numberRepeats = ((IntegerValue) numberRepeatsValue).intValue(); if (numberRepeats < 1) { context.fireRuntimeWarning(this, "numberRepeats ended up being less than 1. Returning NULL"); return NullValue.INSTANCE; } /* Now evaluate child expression repeatedly and build up result */ final List<SingleValue> resultList = new ArrayList<SingleValue>(); for (int i=0; i<numberRepeats; i++) { final Value[] childValues = evaluateChildren(context, depth); if (isAnyChildNull(childValues)) { return NullValue.INSTANCE; } for (int j=0; j<childValues.length; j++) { resultList.add((SingleValue) childValues[j]); } } return OrderedValue.createOrderedValue(resultList); } }
protected RandomInteger(final ExpressionParent parent, final String qtiClassName) { super(parent, qtiClassName); getAttributes().add(new IntegerOrVariableRefAttribute(this, ATTR_MIN_NAME, true)); getAttributes().add(new IntegerOrVariableRefAttribute(this, ATTR_MAX_NAME, true)); getAttributes().add(new IntegerOrVariableRefAttribute(this, ATTR_STEP_NAME, new IntegerOrVariableRef(ATTR_STEP_DEFAULT_VALUE), false)); }
@Override public void validateFigures(final ValidationContext context, final IntegerOrVariableRefAttribute attribute) { final IntegerOrVariableRef integerOrVariableRef = attribute.getValue(); if (integerOrVariableRef.isConstantInteger()) { final int intValue = integerOrVariableRef.getConstantIntegerValue().intValue(); if (intValue < 1) { context.fireAttributeValidationError(attribute, "Figures count (" + intValue + ") must be 1 or more."); } } }
@Override protected Value evaluateValidSelf(final ProcessingContext context, final Value[] childValues, final int depth) { if (isAnyChildNull(childValues)) { return NullValue.INSTANCE; } final OrderedValue childOrderedValue = (OrderedValue) childValues[0]; final Value computedIndex = getIndex().evaluate(this, context); if (computedIndex.isNull()) { return NullValue.INSTANCE; } final int index = ((IntegerValue) computedIndex).intValue(); if (index < 1 || index > childOrderedValue.size()) { return NullValue.INSTANCE; } return childOrderedValue.get(index - 1); } }
public PrintedVariable(final QtiNode parent) { super(parent, QTI_CLASS_NAME); getAttributes().add(new IdentifierAttribute(this, ATTR_IDENTIFIER_NAME, true)); getAttributes().add(new StringAttribute(this, ATTR_FORMAT_NAME, false)); getAttributes().add(new BooleanAttribute(this, ATTR_POWER_FORM_NAME, false)); getAttributes().add(new IntegerOrVariableRefAttribute(this, ATTR_BASE_NAME, new IntegerOrVariableRef(ATTR_BASE_DEFAULT_VALUE), false)); getAttributes().add(new IntegerOrVariableRefAttribute(this, ATTR_INDEX_NAME, false)); getAttributes().add(new StringAttribute(this, ATTR_DELIMTER_NAME, ATTR_DELMITER_DEFAULT_VALUE, false)); getAttributes().add(new StringAttribute(this, ATTR_FIELD_NAME, false)); getAttributes().add(new StringAttribute(this, ATTR_MAPPING_INDICATOR_NAME, ATTR_MAPPING_INDICATOR_DEFAULT_VALUE, false)); }
final int min = getMin().evaluateNotNull(this, context, "Computed value of minimum was NULL. Replacing with 0", 0); final int max = getMax().evaluateNotNull(this, context, "Computed value of maximum was NULL. Replacing with 0", 0);
@Override protected void validateThis(final ValidationContext context) { super.validateThis(context); final IntegerOrVariableRef minComputer = getMin(); final IntegerOrVariableRef maxComputer = getMax(); if (minComputer.isConstantInteger()) { final int min = minComputer.getConstantIntegerValue().intValue(); if (min < 0) { context.fireValidationWarning(this, "Attribute " + ATTR_MINIMUM_NAME + " (" + min + ") should be positive."); } if (maxComputer.isConstantInteger()) { final int max = maxComputer.getConstantIntegerValue().intValue(); if (max < min) { context.fireValidationWarning(this, "Attribute " + ATTR_MAXIMUM_NAME + " (" + max + ") should be greater than " + ATTR_MINIMUM_NAME + " (" + min + ")."); } } } }
@Override protected Value evaluateValidSelf(final ProcessingContext context, final Value[] childValues, final int depth) { final Value childValue = childValues[0]; if (childValue.isNull()) { return NullValue.INSTANCE; } final double childNumber = ((NumberValue) childValue).doubleValue(); if (Double.isInfinite(childNumber) || Double.isNaN(childNumber)) { return childValue; } final Value computedFigures = getFigures().evaluate(this, context); if (computedFigures.isNull()) { context.fireRuntimeWarning(this, "Computed value of figures is NULL. Returning NULL"); return NullValue.INSTANCE; } final RoundingMode roundingMode = getRoundingMode(); final int figures = ((IntegerValue) computedFigures).intValue(); if (!roundingMode.isFiguresValid(figures)) { context.fireRuntimeWarning(this, "The computed value of figures (" + figures + ") was not compatible with the constraints of the rounding mode. Returning NULL"); return NullValue.INSTANCE; } final BigDecimal rounded = getRoundingMode().round(childNumber, figures); return new FloatValue(rounded.doubleValue()); } }
@Override protected void validateThis(final ValidationContext context) { super.validateThis(context); final IntegerOrVariableRef numberRepeatsTemplate = getNumberRepeats(); if (numberRepeatsTemplate.isConstantInteger()) { final int numberRepeats = numberRepeatsTemplate.getConstantIntegerValue().intValue(); if (numberRepeats < 1) { context.fireAttributeValidationError(getAttributes().get(ATTR_NUMBER_REPEATS_NAME), "Attribute " + ATTR_NUMBER_REPEATS_NAME + " (" + numberRepeats + ") must be at least 1"); } } }
@Override protected Value evaluateValidSelf(final ProcessingContext context, final Value[] childValues, final int depth) { if (isAnyChildNull(childValues)) { return NullValue.INSTANCE; } final double firstNumber = ((NumberValue) childValues[0]).doubleValue(); final double secondNumber = ((NumberValue) childValues[1]).doubleValue(); /* Handle NaN or infinite cases by just doing normal double comparison */ if (RoundingMode.isNaNOrInfinite(firstNumber) || RoundingMode.isNaNOrInfinite(secondNumber)) { return BooleanValue.valueOf(firstNumber==secondNumber); } final Value computedFigures = getFigures().evaluate(this, context); if (computedFigures.isNull()) { context.fireRuntimeWarning(this, "Computed value of figures was NULL. Returning NULL"); return NullValue.INSTANCE; } final RoundingMode roundingMode = getRoundingMode(); final int figures = ((IntegerValue) computedFigures).intValue(); if (!roundingMode.isFiguresValid(figures)) { context.fireRuntimeWarning(this, "The computed value of figures (" + figures + ") was not compatible with the constraints of the rounding mode. Returning NULL"); return NullValue.INSTANCE; } return BooleanValue.valueOf(roundingMode.isEqual(firstNumber, secondNumber, figures)); } }
@Override protected void validateThis(final ValidationContext context) { super.validateThis(context); final IntegerOrVariableRef maxComputer = getMax(); final IntegerOrVariableRef minComputer = getMin(); final IntegerOrVariableRef stepComputer = getStep(); if (maxComputer.isConstantInteger() && minComputer.isConstantInteger()) { final int max = maxComputer.getConstantIntegerValue().intValue(); final int min = minComputer.getConstantIntegerValue().intValue(); if (max < min) { context.fireAttributeValidationError(getAttributes().get(ATTR_MAX_NAME), "Attribute " + ATTR_MAX_NAME + " (" + max + ") cannot be lower than " + ATTR_MIN_NAME + " (" + min + ")"); } } if (stepComputer!=null && stepComputer.isConstantInteger()) { final int step = stepComputer.getConstantIntegerValue().intValue(); if (step < 1) { context.fireAttributeValidationError(getAttributes().get(ATTR_STEP_NAME), "Attribute " + ATTR_STEP_NAME + " (" + step + ") must be positive."); } } }
@Override protected void validateThis(final ValidationContext context) { super.validateThis(context); final IntegerOrVariableRef indexComputer = getIndex(); if (indexComputer.isConstantInteger()) { final int index = indexComputer.getConstantIntegerValue().intValue(); if (index < 1) { context.fireAttributeValidationError(getAttributes().get(ATTR_INDEX_NAME), "Attribute " + ATTR_INDEX_NAME + " (" + index + ") must be positive"); } if (getChildren().size() != 0 && getChildren().get(0) instanceof Ordered) { final Ordered ordered = (Ordered) getChildren().get(0); if (ordered.getChildren().size() > 0 && index > ordered.getChildren().size()) { context.fireAttributeValidationWarning(getAttributes().get(ATTR_INDEX_NAME), "Attribute " + ATTR_INDEX_NAME + " is too big. Expected at most: " + ordered.getChildren().size() + ", but found: " + index); } } } }