package nl.ipo.cds.validation.flow;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodType;
import java.util.Arrays;
import nl.ipo.cds.validation.AbstractExpression;
import nl.ipo.cds.validation.Expression;
import nl.ipo.cds.validation.ValidationMessage;
import nl.ipo.cds.validation.Validator;
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 SplitExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>> extends AbstractExpression<K, C, Boolean> implements Expression<K, C, Boolean> {
final Expression<K, C, String> input;
final Expression<K, C, String> splitter;
final Validator<K, C> validator;
public SplitExpression (final Expression<K, C, String> input, final Expression<K, C, String> splitter, final Validator<K, C> validator) {
if (input == null) {
throw new NullPointerException ("input cannot be null");
}
if (splitter == null) {
throw new NullPointerException ("splitter cannot be null");
}
if (validator == null) {
throw new NullPointerException ("validator cannot be null");
}
this.input = input;
this.splitter = splitter;
this.validator = validator;
}
@Override
public Class<Boolean> getResultType () {
return Boolean.class;
}
@Override
public ExpressionExecutor<C> getExecutor(final Compiler<C> compiler) throws CompilerException {
// Compile the validator:
final Executor<C> validatorExecutor = compiler
.addBean ("splitResult", SplitBean.class)
.compile (validator);
// Create an executor for the split operation:
final SplitExecutor<K, C> executor = new SplitExecutor<K, C> () {
@Override
public Boolean execute (final Object[] objects, final C context, final String input, final String splitter) throws ExecutorException {
final String inputValue = input;
final String splitterValue = splitter;
final String[] list;
// Create a list of strings:
if (inputValue == null) {
list = new String[0];
} else if (splitterValue == null) {
list = new String[] { inputValue };
} else {
list = inputValue.split (splitterValue);
}
final Object[] contextObjects = Arrays.copyOf (objects, objects.length + 1);
contextObjects[contextObjects.length - 1] = new SplitBean<K> (list);
return (Boolean)validatorExecutor.execute (context, contextObjects);
}
};
return ExpressionExecutor.create (
this,
input,
splitter,
false,
false,
executeHandle.bindTo (executor),
false
);
}
public static class SplitBean<K extends Enum<K>> {
private final String[] values;
public SplitBean (final String[] values) {
this.values = values;
}
public Integer getLength () {
return values.length;
}
public String[] getValues () {
return values;
}
public String get (int i) {
return i >= 0 && i < values.length ? values[i] : null;
}
}
private final static MethodHandle executeHandle = Compiler
.findMethod (
SplitExecutor.class,
"execute",
MethodType.methodType (Boolean.class, Object[].class, ValidatorContext.class, String.class, String.class)
);
public static interface SplitExecutor<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>> {
Boolean execute (Object[] objects, C context, String input, String splitter) throws ExecutorException;
}
}