package org.yamcs.xtceproc; import java.util.Comparator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.yamcs.parameter.ParameterValue; import org.yamcs.parameter.ParameterValueList; import org.yamcs.parameter.Value; import org.yamcs.protobuf.Yamcs.Value.Type; import org.yamcs.xtce.CriteriaEvaluator; import org.yamcs.xtce.OperatorType; import org.yamcs.xtce.ParameterInstanceRef; import com.google.common.primitives.UnsignedBytes; import com.google.common.primitives.UnsignedLongs; public class CriteriaEvaluatorImpl implements CriteriaEvaluator { private static Logger LOG = LoggerFactory.getLogger(CriteriaEvaluatorImpl.class.getName()); ParameterValueList params; public CriteriaEvaluatorImpl(ParameterValueList params) { this.params = params; } @Override public boolean evaluate(OperatorType op, Object lValueRef, Object rValueRef) { ResolvedValue lValue = resolveValue(lValueRef); ResolvedValue rValue = resolveValue(rValueRef); if ((lValue == null) || (rValue == null)) { return false; } if (lValue.evaluator == rValue.evaluator) { return lValue.evaluator.evaluate(op, lValue, rValue); } else { if ((lValue.evaluator == intEvaluator) && (lValue.evaluator == floatEvaluator)) { lValue.value = (double)((long)lValue.value); return floatEvaluator.evaluate(op, lValue, rValue); } else if ((lValue.evaluator == floatEvaluator) && (lValue.evaluator == intEvaluator)) { rValue.value = (double)((long)rValue.value); return floatEvaluator.evaluate(op, lValue, rValue); } else { LOG.error("Comparing values of incompatible types: " + lValue.evaluator.getComparedType() + " vs. " + rValue.evaluator.getComparedType()); } } return false; } private ResolvedValue resolveValue(Object valueRef) { if (valueRef instanceof ParameterInstanceRef) { return resolveParameter((ParameterInstanceRef)valueRef); } else if(valueRef instanceof Integer) { return new ResolvedValue(((Integer)valueRef).longValue(), false, intEvaluator); } else if(valueRef instanceof Long) { return new ResolvedValue((Long)valueRef, false, intEvaluator); } else if (valueRef instanceof Float) { return new ResolvedValue(((Float)valueRef).doubleValue(), false, floatEvaluator); } else if (valueRef instanceof Double) { return new ResolvedValue((Double)valueRef, false, floatEvaluator); } else if (valueRef instanceof String) { return new ResolvedValue((String)valueRef, false, stringEvaluator); } else if (valueRef instanceof byte[]) { return new ResolvedValue((byte[])valueRef, false, binaryEvaluator); } else if (valueRef instanceof Boolean) { return new ResolvedValue((Boolean)valueRef, false, booleanEvaluator); } else { LOG.error("Unknown value type '" + valueRef.getClass() + "' while evaluating condition"); return null; } } private ResolvedValue resolveParameter(ParameterInstanceRef paramRef) { ParameterValue pv = params.getLastInserted((paramRef).getParameter()); if(pv==null) { return null; } Value v; if(paramRef.useCalibratedValue()) { v = pv.getEngValue(); } else { v = pv.getRawValue(); } switch (v.getType().getNumber()) { case Type.SINT32_VALUE: return new ResolvedValue((long)v.getSint32Value(), false, intEvaluator); case Type.SINT64_VALUE: return new ResolvedValue(v.getSint64Value(), false, intEvaluator); case Type.UINT32_VALUE: return new ResolvedValue((long)v.getUint32Value() & 0xFFFFFFFFFFFFFFFFL, true, intEvaluator); case Type.UINT64_VALUE: return new ResolvedValue(v.getUint64Value(), true, intEvaluator); case Type.FLOAT_VALUE: return new ResolvedValue((double)v.getFloatValue(), false, floatEvaluator); case Type.DOUBLE_VALUE: return new ResolvedValue(v.getDoubleValue(), false, floatEvaluator); case Type.STRING_VALUE: return new ResolvedValue(v.getStringValue(), false, stringEvaluator); case Type.BINARY_VALUE: return new ResolvedValue(v.getBinaryValue(), false, binaryEvaluator); case Type.BOOLEAN_VALUE: return new ResolvedValue(v.getBooleanValue(), false, booleanEvaluator); } return null; } static interface Evaluator { String getComparedType(); boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue); } static class ResolvedValue { Object value; boolean unsigned; Evaluator evaluator; public ResolvedValue(Object value, boolean unsigned, Evaluator evaluator) { super(); this.value = value; this.unsigned = unsigned; this.evaluator = evaluator; } @Override public String toString() { return "Value(" + value + ") Signed(" + unsigned + ") " + "EvaluatorType(" + evaluator.getComparedType() + ")"; } } // Some specific evaluators // Integer evaluator private static final Evaluator intEvaluator = new Evaluator() { @Override public boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue) { boolean unsigned = lValue.unsigned &rValue.unsigned; // FIXME: signed/unsigned comparison should be warned, but frequently seen in 'Parameter op value' long lval = (long)lValue.value; long rval = (long)rValue.value; if(unsigned) { switch (op) { case EQUALITY: return (lval == rval); case INEQUALITY: return (lval != rval); case LARGERTHAN: return UnsignedLongs.compare(lval, rval)>0; case LARGEROREQUALTHAN: return UnsignedLongs.compare(lval, rval)>=0; case SMALLERTHAN: return UnsignedLongs.compare(lval, rval)<0; case SMALLEROREQUALTHAN: return UnsignedLongs.compare(lval, rval)<=0; } } else { switch (op) { case EQUALITY: return (lval == rval); case INEQUALITY: return (lval != rval); case LARGERTHAN: return (lval > rval); case LARGEROREQUALTHAN: return (lval >= rval); case SMALLERTHAN: return (lval < rval); case SMALLEROREQUALTHAN: return (lval <= rval); } } return false; } @Override public String getComparedType() { return "Integer"; } }; // Float evaluator private static final Evaluator floatEvaluator = new Evaluator() { @Override public boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue) { double lval = (double)lValue.value; double rval = (double)rValue.value; switch (op) { case EQUALITY: return (lval == rval); case INEQUALITY: return (lval != rval); case LARGERTHAN: return (lval > rval); case LARGEROREQUALTHAN: return (lval >= rval); case SMALLERTHAN: return (lval < rval); case SMALLEROREQUALTHAN: return (lval <= rval); } return false; } @Override public String getComparedType() { return "Float"; } }; // String evaluator private static final Evaluator stringEvaluator = new Evaluator() { @Override public boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue) { String lval = (String)lValue.value; String rval = (String)rValue.value; switch (op) { case EQUALITY: return (lval.compareTo(rval) == 0); case INEQUALITY: return (lval.compareTo(rval) != 0); case LARGERTHAN: return (lval.compareTo(rval) > 0); case LARGEROREQUALTHAN: return (lval.compareTo(rval) >= 0); case SMALLERTHAN: return (lval.compareTo(rval) < 0); case SMALLEROREQUALTHAN: return (lval.compareTo(rval) <= 0); } return false; } @Override public String getComparedType() { return "String"; } }; // Binary evaluator private static final Evaluator binaryEvaluator = new Evaluator() { @Override public boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue) { byte[] lval = (byte[])lValue.value; byte[] rval = (byte[])rValue.value; Comparator<byte[]> comparator=UnsignedBytes.lexicographicalComparator(); switch (op) { case EQUALITY: return (comparator.compare(lval, rval) == 0); case INEQUALITY: return (comparator.compare(lval, rval) != 0); case LARGERTHAN: return (comparator.compare(lval, rval) > 0); case LARGEROREQUALTHAN: return (comparator.compare(lval, rval) >= 0); case SMALLERTHAN: return (comparator.compare(lval, rval) < 0); case SMALLEROREQUALTHAN: return (comparator.compare(lval, rval) <= 0); } return false; } @Override public String getComparedType() { return "Binary"; } }; // Binary evaluator private static final Evaluator booleanEvaluator = new Evaluator() { @Override public boolean evaluate(OperatorType op, ResolvedValue lValue, ResolvedValue rValue) { boolean lval = (boolean)lValue.value; boolean rval = (boolean)rValue.value; switch (op) { case EQUALITY: return lval== rval; case INEQUALITY: return lval!=rval; case LARGERTHAN: return Boolean.compare(lval, rval) > 0; case LARGEROREQUALTHAN: return Boolean.compare(lval, rval) >= 0; case SMALLERTHAN: return Boolean.compare(lval, rval) < 0; case SMALLEROREQUALTHAN: return Boolean.compare(lval, rval) <= 0; } return false; } @Override public String getComparedType() { return "Boolean"; } }; }