package nl.ipo.cds.validation; import java.lang.invoke.MethodType; import org.deegree.commons.tom.ows.CodeType; import nl.ipo.cds.validation.execute.Compiler; import nl.ipo.cds.validation.execute.CompilerException; import nl.ipo.cds.validation.execute.ExpressionExecutor; import nl.ipo.cds.validation.gml.CodeExpression; import nl.ipo.cds.validation.gml.CodeExpression.GetCodeSpaceExpression; public class AttributeExpression<K extends Enum<K> & ValidationMessage<K, C>, C extends ValidatorContext<K, C>, T> extends AbstractExpression<K, C, T> { public final String name; public final Class<T> type; public final String label; public AttributeExpression (final String name, final Class<T> type) { this (name, type, null); } public AttributeExpression (final String name, final Class<T> type, final String label) { if (name == null) { throw new NullPointerException ("name cannot be null"); } if (type == null) { throw new NullPointerException ("type cannot be null"); } this.name = name; this.type = type; this.label = label; } public AttributeExpression<K, C, T> label (final String label) { return new AttributeExpression<K, C, T> (name, type, label); } @Override public Class<T> getResultType () { return type; } public GetValueExpression value() { return new GetValueExpression(); } @Override public String toString () { return name; } public Expression<K, C, Boolean> is (final Class<? extends T> compareType) { return new AbstractUnaryTestExpression<K, C, T> (this, "Is") { @Override public boolean test(T value, C context) { if (value == null) { return false; } return compareType.isAssignableFrom (value.getClass ()); } @Override public boolean equals (final Object o) { return o == this; } }; } public <NewT> Expression<K, C, NewT> as (final Class<NewT> cls) { assert cls != null : "cls cannot be null"; assert cls.isAssignableFrom (getResultType ()) : String.format ("%s must be a superclass of %s", cls, getResultType ()); return new AbstractExpression<K, C, NewT>() { @Override public Class<NewT> getResultType () { return cls; } @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { final ExpressionExecutor<C> executor = AttributeExpression.this.getExecutor (compiler); return ExpressionExecutor.create ( this, executor.isConstant, executor.isDeterministic, executor.methodHandle.asType ( executor.methodHandle.type ().changeReturnType (cls) ), false ); } }; } public Expression<K, C, Boolean> isNull () { return new AbstractUnaryTestExpression<K, C, T> (this, "IsNull") { @Override public boolean test (final T value, final C context) { return value == null; } }; } @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { return compiler.createGetAttributeExecutor (name, this); } @Override public boolean equals (final Object o) { if (o == null) { return false; } if (!(o instanceof AttributeExpression)) { return false; } final AttributeExpression<?, ?, ?> other = (AttributeExpression<?, ?, ?>)o; return name.equals (other.name) && type.equals (other.type); } @Override public int hashCode () { return name.hashCode () ^ type.hashCode (); } public class GetValueExpression extends AbstractExpression<K, C, T> { @Override public Class<T> getResultType () { return type; } public T evaluate (final C context, final T input) { return input; } @Override public ExpressionExecutor<C> getExecutor (final Compiler<C> compiler) throws CompilerException { return ExpressionExecutor.create ( this, AttributeExpression.this, false, true, Compiler.findMethod (GetValueExpression.class, "evaluate", MethodType.methodType (type, ValidatorContext.class, type)).bindTo (this), false ); } public Expression<K, C, Boolean> isNull () { return new AbstractUnaryTestExpression<K, C, T> (this, "IsNull") { @Override public boolean test (final T value, final C context) { return value == null; } }; } } }