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 }