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.expression; 023 024import java.beans.ConstructorProperties; 025 026import cascading.flow.FlowProcess; 027import cascading.operation.Filter; 028import cascading.operation.FilterCall; 029 030/** 031 * Class ScriptFilter dynamically resolves a given expression using argument {@link cascading.tuple.Tuple} values. 032 * This {@link cascading.operation.Filter} is based on the <a href="http://www.janino.net/">Janino</a> compiler. 033 * <p> 034 * Specifically this filter uses the {@link org.codehaus.janino.ScriptEvaluator}, 035 * thus the syntax from that class is inherited here. 036 * <p> 037 * A script may use field names directly as parameters in the expression, or field positions with the syntax 038 * "$n", where n is an integer. 039 * <p> 040 * Given an argument tuple with the fields "a" and "b", the following script returns true: <br> 041 * {@code boolean result = (a + b == $0 + $1);}<br> 042 * {@code return boolean;}<br> 043 * <p> 044 * Unlike an "expression" used by {@link ExpressionFilter}, a "script" requires each line to end in an semi-colon 045 * (@{code ;}) and the final line to be a {@code return} statement. 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 script if possible. 049 */ 050public class ScriptFilter extends ScriptOperation implements Filter<ScriptOperation.Context> 051 { 052 /** 053 * Constructor ScriptFilter creates a new ScriptFilter instance. 054 * 055 * @param script of type String 056 */ 057 @ConstructorProperties({"script"}) 058 public ScriptFilter( String script ) 059 { 060 super( ANY, script, Boolean.class ); 061 } 062 063 /** 064 * Constructor ScriptFilter creates a new ScriptFilter instance. 065 * 066 * @param script of type String 067 * @param parameterName of type String 068 * @param parameterType of type Class 069 */ 070 @ConstructorProperties({"script", "parameterName", "parameterType"}) 071 public ScriptFilter( String script, String parameterName, Class parameterType ) 072 { 073 super( 1, script, Boolean.class, new String[]{parameterName}, new Class[]{parameterType} ); 074 } 075 076 /** 077 * Constructor ScriptFilter creates a new ScriptFilter instance. 078 * <p> 079 * This constructor will use the runtime {@link cascading.operation.OperationCall#getArgumentFields()} 080 * to source the {@code parameterNames} and {@code parameterTypes} required by the other constructors, but 081 * use {@code expectedTypes} to coerce the incoming types to before passing as parameters to the expression. 082 * 083 * @param script of type String 084 * @param expectedTypes of type Class[] 085 */ 086 @ConstructorProperties({"script", "expectedTypes"}) 087 public ScriptFilter( String script, Class[] expectedTypes ) 088 { 089 super( expectedTypes.length, script, Boolean.class, expectedTypes ); 090 } 091 092 /** 093 * Constructor ScriptFilter creates a new ScriptFilter instance. 094 * 095 * @param script of type String 096 * @param parameterNames of type String[] 097 * @param parameterTypes of type Class[] 098 */ 099 @ConstructorProperties({"script", "parameterNames", "parameterTypes"}) 100 public ScriptFilter( String script, String[] parameterNames, Class[] parameterTypes ) 101 { 102 super( parameterTypes.length, script, Boolean.class, parameterNames, parameterTypes ); 103 } 104 105 public String getScript() 106 { 107 return getBlock(); 108 } 109 110 @Override 111 public boolean isRemove( FlowProcess flowProcess, FilterCall<Context> filterCall ) 112 { 113 return (Boolean) evaluate( filterCall.getContext(), filterCall.getArguments() ); 114 } 115 }