    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.function;
    022
    023import java.beans.ConstructorProperties;
    024import java.io.Serializable;
    025import java.util.Arrays;
    026
    027import cascading.flow.FlowProcess;
    028import cascading.management.annotation.Property;
    029import cascading.management.annotation.Visibility;
    030import cascading.operation.BaseOperation;
    031import cascading.operation.Filter;
    032import cascading.operation.FilterCall;
    033import cascading.operation.Function;
    034import cascading.operation.FunctionCall;
    035import cascading.operation.OperationCall;
    036import cascading.tuple.Fields;
    037import cascading.tuple.Tuple;
    038
    039/**
    040 * Class SetValue is a utility {@link Function} that allows for a Tuple value to be returned based on the outcome
    041 * of a given {@link Filter} operation.
    042 * <p/>
    043 * There are only two possible values, either {@link Filter#isRemove(cascading.flow.FlowProcess, cascading.operation.FilterCall)}
    044 * returns {@code true} or {@code false}.
    045 * <p/>
    046 * If {@code false} is returned, most commonly the {@link Filter} passed and the Tuple should be kept. SetValue will then return
    047 * the first value in the given values array, by default {@code true}. If the Filter returns {@code true}, the second
    048 * value in the values array will be returned, by default {@code false}.
    049 * <p/>
    050 */
    051public class SetValue extends BaseOperation implements Function
    052  {
    053  /** Field filter */
    054  private final Filter filter;
    055  /** Field values */
    056  private Tuple[] values = new Tuple[]{new Tuple( true ), new Tuple( false )};
    057
    058  /**
    059   * Constructor SetValue creates a new SetValue instance.
    060   *
    061   * @param fieldDeclaration of type Fields
    062   * @param filter           of type Filter
    063   */
    064  @ConstructorProperties({"fieldDeclaration", "filter"})
    065  public SetValue( Fields fieldDeclaration, Filter filter )
    066    {
    067    super( fieldDeclaration );
    068    this.filter = filter;
    069
    070    verify();
    071    }
    072
    073  /**
    074   * Constructor SetValue creates a new SetValue instance.
    075   *
    076   * @param fieldDeclaration of type Fields
    077   * @param filter           of type Filter
    078   * @param firstValue       of type Serializable
    079   * @param secondValue      of type Serializable
    080   */
    081  @ConstructorProperties({"fieldDeclaration", "filter", "firstValue", "secondValue"})
    082  public SetValue( Fields fieldDeclaration, Filter filter, Serializable firstValue, Serializable secondValue )
    083    {
    084    super( fieldDeclaration );
    085    this.filter = filter;
    086    this.values = new Tuple[]{new Tuple( firstValue ), new Tuple( secondValue )};
    087
    088    verify();
    089    }
    090
    091  @Property(name = "firstValue", visibility = Visibility.PRIVATE)
    092  public Serializable getFirstValue()
    093    {
    094    return (Serializable) values[ 0 ].getObject( 0 );
    095    }
    096
    097  @Property(name = "secondValue", visibility = Visibility.PRIVATE)
    098  public Serializable getSecondValue()
    099    {
    100    return (Serializable) values[ 1 ].getObject( 0 );
    101    }
    102
    103  private void verify()
    104    {
    105    if( fieldDeclaration.size() != 1 )
    106      throw new IllegalArgumentException( "fieldDeclaration may only declare one field, was " + fieldDeclaration.print() );
    107
    108    if( filter == null )
    109      throw new IllegalArgumentException( "filter may not be null" );
    110
    111    if( values == null || values.length != 2 )
    112      throw new IllegalArgumentException( "values argument must contain two values" );
    113    }
    114
    115  @Override
    116  public void prepare( FlowProcess flowProcess, OperationCall operationCall )
    117    {
    118    filter.prepare( flowProcess, operationCall );
    119    }
    120
    121  @Override
    122  public void operate( FlowProcess flowProcess, FunctionCall functionCall )
    123    {
    124    boolean isRemove = !filter.isRemove( flowProcess, (FilterCall) functionCall );
    125
    126    int pos = isRemove ? 0 : 1;
    127
    128    functionCall.getOutputCollector().add( values[ pos ] );
    129    }
    130
    131  @Override
    132  public void cleanup( FlowProcess flowProcess, OperationCall operationCall )
    133    {
    134    filter.cleanup( flowProcess, operationCall );
    135    }
    136
    137  @Override
    138  public boolean equals( Object object )
    139    {
    140    if( this == object )
    141      return true;
    142    if( !( object instanceof SetValue ) )
    143      return false;
    144    if( !super.equals( object ) )
    145      return false;
    146
    147    SetValue setValue = (SetValue) object;
    148
    149    if( filter != null ? !filter.equals( setValue.filter ) : setValue.filter != null )
    150      return false;
    151    if( !Arrays.equals( values, setValue.values ) )
    152      return false;
    153
    154    return true;
    155    }
    156
    157  @Override
    158  public int hashCode()
    159    {
    160    int result = super.hashCode();
    161    result = 31 * result + ( filter != null ? filter.hashCode() : 0 );
    162    result = 31 * result + ( values != null ? Arrays.hashCode( values ) : 0 );
    163    return result;
    164    }
    165  }