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