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