    001/*
    002 * Copyright (c) 2007-2017 Xplenty, 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
    021package cascading.operation.expression;
    022
    023import java.beans.ConstructorProperties;
    024
    025import cascading.flow.FlowProcess;
    026import cascading.operation.Filter;
    027import 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 */
    049public 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  }