001 /* 002 * Copyright (c) 2007-2015 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.Function; 027 import cascading.operation.FunctionCall; 028 import cascading.tuple.Fields; 029 import cascading.tuple.Tuple; 030 031 /** 032 * Class ScriptTupleFunction dynamically resolves a given expression using argument {@link cascading.tuple.Tuple} values. 033 * This {@link cascading.operation.Function} is based on the <a href="http://www.janino.net/">Janino</a> compiler. 034 * <p/> 035 * This class is different from {@link ScriptFunction} in that it requires a new {@link Tuple} instance to be returned 036 * by the script. ScriptFunction allows only a single value to be returned, which is passed into a result Tuple instance 037 * internally. 038 * <p/> 039 * Specifically this function uses the {@link org.codehaus.janino.ScriptEvaluator}, 040 * thus the syntax from that class is inherited here. 041 * <p/> 042 * A script 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 script returns true: <br/> 046 * {@code boolean result = (a + b == $0 + $1);}<br/> 047 * {@code return cascading.tuple.Tuples.tuple( boolean );}<br/> 048 * <p/> 049 * Unlike an "expression" used by {@link ExpressionFunction}, a "script" requires each line to end in an semi-colon 050 * (@{code ;}) and the final line to be a {@code return} statement that returns a new {@link Tuple} instance. 051 * <p/> 052 * Since Janino does not support "varargs", see the {@link cascading.tuple.Tuples} class for helper methods. 053 * <p/> 054 * Further, the types of the tuple elements will be coerced into the given parameterTypes. Regardless of the actual 055 * tuple element values, they will be converted to the types expected by the script if possible. 056 */ 057 public class ScriptTupleFunction extends ScriptOperation implements Function<ScriptOperation.Context> 058 { 059 /** 060 * Constructor ScriptFunction creates a new ScriptFunction instance. 061 * <p/> 062 * This constructor will use the runtime {@link cascading.operation.OperationCall#getArgumentFields()} 063 * to source the {@code parameterNames} and {@code parameterTypes} required by the other constructors. 064 * <p/> 065 * The {@code returnType} will be retrieved from the given {@code fieldDeclaration.getTypeClass(0)}. 066 * 067 * @param fieldDeclaration of type Fields 068 * @param script of type String 069 */ 070 @ConstructorProperties({"fieldDeclaration", "script"}) 071 public ScriptTupleFunction( Fields fieldDeclaration, String script ) 072 { 073 super( ANY, fieldDeclaration, script, Tuple.class ); 074 } 075 076 /** 077 * Constructor ScriptFunction creates a new ScriptFunction 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 fieldDeclaration of type Fields 084 * @param script of type String 085 * @param expectedTypes of type Class[] 086 */ 087 @ConstructorProperties({"fieldDeclaration", "script", "expectedTypes"}) 088 public ScriptTupleFunction( Fields fieldDeclaration, String script, Class[] expectedTypes ) 089 { 090 super( expectedTypes.length, fieldDeclaration, script, Tuple.class, expectedTypes ); 091 } 092 093 /** 094 * Constructor ScriptFunction creates a new ScriptFunction instance. 095 * <p/> 096 * This constructor expects all parameter type names to be declared with their types. Positional parameters must 097 * be named the same as in the given script with the "$" sign prepended. 098 * 099 * @param fieldDeclaration of type Fields 100 * @param script of type String 101 * @param parameterNames of type String[] 102 * @param parameterTypes of type Class[] 103 */ 104 @ConstructorProperties({"fieldDeclaration", "script", "parameterNames", "parameterTypes"}) 105 public ScriptTupleFunction( Fields fieldDeclaration, String script, String[] parameterNames, Class[] parameterTypes ) 106 { 107 super( parameterTypes.length, fieldDeclaration, script, Tuple.class, parameterNames, parameterTypes ); 108 } 109 110 public String getScript() 111 { 112 return getBlock(); 113 } 114 115 @Override 116 public void operate( FlowProcess flowProcess, FunctionCall<Context> functionCall ) 117 { 118 functionCall.getOutputCollector().add( (Tuple) evaluate( functionCall.getContext(), functionCall.getArguments() ) ); 119 } 120 }