    001/*
    002 * Copyright (c) 2007-2017 Xplenty, Inc. All Rights Reserved.
    003 *
    004 * Project and contact information: http://www.cascading.org/
    005 *
    006 * This file is part of the Cascading project.
    007 *
    008 * Licensed under the Apache License, Version 2.0 (the "License");
    009 * you may not use this file except in compliance with the License.
    010 * You may obtain a copy of the License at
    011 *
    012 *     http://www.apache.org/licenses/LICENSE-2.0
    013 *
    014 * Unless required by applicable law or agreed to in writing, software
    015 * distributed under the License is distributed on an "AS IS" BASIS,
    016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    017 * See the License for the specific language governing permissions and
    018 * limitations under the License.
    019 */
    020
    021package cascading.operation.assertion;
    022
    023import java.beans.ConstructorProperties;
    024
    025import cascading.flow.FlowProcess;
    026import cascading.operation.AssertionLevel;
    027import cascading.operation.PlannerLevel;
    028import cascading.operation.ValueAssertion;
    029import cascading.operation.ValueAssertionCall;
    030import cascading.operation.expression.ExpressionOperation;
    031import cascading.tuple.Fields;
    032import cascading.tuple.TupleEntry;
    033
    034/**
    035 * Class AssertExpression dynamically resolves a given expression using argument {@link cascading.tuple.Tuple} values. Any Tuple that
    036 * returns true for the given expression pass the assertion. This {@link cascading.operation.Assertion}
    037 * is based on the <a href="http://www.janino.net/">Janino</a> compiler.
    038 * <p/>
    039 * Specifically this filter uses the {@link org.codehaus.janino.ExpressionEvaluator}, thus the syntax from that class is inherited here.
    040 * <p/>
    041 * An expression may use field names directly as parameters in the expression, or field positions with the syntax
    042 * "$n", where n is an integer.
    043 * <p/>
    044 * Given an argument tuple with the fields "a" and "b", the following expression returns true: <br/>
    045 * <code>a + b == $0 + $1</code><br/>
    046 * <p/>
    047 * Further, the types of the tuple elements will be coerced into the given parameterTypes. Regardless of the actual
    048 * tuple element values, they will be converted to the types expected by the expression.
    049 */
    050public class AssertExpression extends ExpressionOperation implements ValueAssertion<ExpressionOperation.Context>
    051  {
    052  /**
    053   * Constructor ExpressionFilter creates a new ExpressionFilter instance.
    054   *
    055   * @param expression    of type String
    056   * @param parameterType of type Class
    057   */
    058  @ConstructorProperties({"expression", "parameterType"})
    059  public AssertExpression( String expression, Class parameterType )
    060    {
    061    super( Fields.ALL, expression, parameterType );
    062    }
    063
    064  /**
    065   * Constructor AssertExpression creates a new AssertExpression instance.
    066   *
    067   * @param fieldDeclaration of type Fields
    068   * @param expression       of type String
    069   * @param parameterNames   of type String[]
    070   * @param parameterTypes   of type Class[]
    071   */
    072  @ConstructorProperties({"fieldDeclaration", "expression", "parameterNames", "parameterTypes"})
    073  public AssertExpression( Fields fieldDeclaration, String expression, String[] parameterNames, Class[] parameterTypes )
    074    {
    075    super( fieldDeclaration, expression, parameterNames, parameterTypes );
    076    }
    077
    078  @Override
    079  public boolean supportsPlannerLevel( PlannerLevel plannerLevel )
    080    {
    081    return plannerLevel instanceof AssertionLevel;
    082    }
    083
    084  @Override
    085  public void doAssert( FlowProcess flowProcess, ValueAssertionCall<Context> assertionCall )
    086    {
    087    TupleEntry input = assertionCall.getArguments();
    088
    089    if( !(Boolean) evaluate( assertionCall.getContext(), input ) )
    090      BaseAssertion.throwFail( "argument tuple: %s did not evaluate to true with expression: %s", input.getTuple().print(), block );
    091    }
    092  }