package nl.ipo.cds.validation.flow; import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import nl.ipo.cds.validation.AbstractExpression; import nl.ipo.cds.validation.Expression; import nl.ipo.cds.validation.ValidationMessage; import nl.ipo.cds.validation.ValidatorContext; import nl.ipo.cds.validation.execute.Compiler; import nl.ipo.cds.validation.execute.CompilerException; import nl.ipo.cds.validation.execute.Executor; import nl.ipo.cds.validation.execute.ExecutorException; import nl.ipo.cds.validation.execute.ExpressionExecutor; public class IfExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>, ResultType> extends AbstractExpression<K, C, ResultType> { public final Expression<K, C, Boolean> condition; public final Expression<K, C, ResultType> a; public final Expression<K, C, ResultType> b; public IfExpression (final Expression<K, C, Boolean> condition, final Expression<K, C, ResultType> a, final Expression<K, C, ResultType> b) { if (condition == null) { throw new NullPointerException ("condition cannot be null"); } if (a == null) { throw new NullPointerException ("a cannot be null"); } if (b == null) { throw new NullPointerException ("b cannot be null"); } this.condition = condition; this.a = a; this.b = b; } @Override public Class<ResultType> getResultType() { return a.getResultType (); } @Override public String toString () { if (b == null) { return String.format ("(if %s then %s)", condition.toString (), a.toString ()); } else { return String.format ("(if %s then %s else %s)", condition.toString (), a.toString (), b.toString ()); } } @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { // Compile both branches: final Executor<C> aExecutor = compiler.compile (a); final Executor<C> bExecutor = compiler.compile (b); final MethodHandle handle = MethodHandles.insertArguments ( executeHandle, 4, aExecutor, bExecutor ).bindTo (this); return ExpressionExecutor.create ( this, condition, false, true, //executeHandle.bindTo (executor), handle, false ); } private final static MethodHandle executeHandle = Compiler .findMethod( IfExpression.class, "execute", MethodType.methodType(Object.class, Object[].class, ValidatorContext.class, Boolean.class, Executor.class, Executor.class) ); @SuppressWarnings("unchecked") public ResultType execute (final Object[] objects, final ValidatorContext<K, C> context, final Boolean conditionValue, final Executor<ValidatorContext<K, C>> aExecutor, final Executor<ValidatorContext<K, C>> bExecutor) throws ExecutorException { if (conditionValue != null && conditionValue) { return (ResultType)aExecutor.execute (context, objects); } else { return (ResultType)bExecutor.execute (context, objects); } } }