package nl.ipo.cds.validation; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodType; import nl.ipo.cds.validation.execute.Compiler; import nl.ipo.cds.validation.execute.CompilerException; import nl.ipo.cds.validation.execute.ExpressionExecutor; /** * Binary tests must be deterministic. * * @author erik * * @param <K> * @param <TypeA> * @param <TypeB> */ public abstract class AbstractBinaryTestExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>, TypeA, TypeB> extends AbstractExpression<K, C, Boolean> implements BinaryExpression<K, C, Boolean, TypeA, TypeB> { public final String name; public final Expression<K, C, TypeA> a; public final Expression<K, C, TypeB> b; public AbstractBinaryTestExpression (final Expression<K, C, TypeA> a, final Expression<K, C, TypeB> b, final String name) { if (name == null) { throw new NullPointerException ("name cannot be null"); } if (a == null) { throw new NullPointerException ("a cannot be null"); } if (b == null) { throw new NullPointerException ("b cannot be null"); } this.name = name; this.a = a; this.b = b; } @Override public Class<Boolean> getResultType () { return Boolean.class; } public Boolean evaluate (final C context, final TypeA a, final TypeB b) { return test (a, b, context); } @Override public Class<TypeA> getTypeA () { return a.getResultType (); } @Override public Class<TypeB> getTypeB() { return b.getResultType (); } public abstract boolean test (TypeA a, TypeB b, C context); private final static MethodHandle evaluateHandle = Compiler .findMethod ( AbstractBinaryTestExpression.class, "evaluate", MethodType.methodType (Boolean.class, ValidatorContext.class, Object.class, Object.class) ); @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { return ExpressionExecutor.create ( this, a, b, false, true, evaluateHandle.bindTo (this), false ); } @Override public boolean equals (final Object o) { if (o == null || !(getClass ().equals (o.getClass ()))) { return false; } final AbstractBinaryTestExpression<?, ?, ?, ?> other = (AbstractBinaryTestExpression<?, ?, ?, ?>)o; return name.equals (other.name) && a.equals (other.a) && b.equals (other.b); } @Override public int hashCode () { return name.hashCode () ^ a.hashCode () ^ b.hashCode (); } @Override public String toString () { return String.format ("(%s %s %s)", a, name, b); } }