    001/*
    002 * Copyright (c) 2016-2017 Chris K Wensel <chris@wensel.net>. 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;
    023
    024import java.beans.ConstructorProperties;
    025import java.lang.reflect.Type;
    026import java.util.Arrays;
    027
    028import cascading.flow.FlowProcess;
    029import cascading.tuple.Fields;
    030import cascading.tuple.Tuple;
    031import cascading.tuple.TupleEntryCollector;
    032import cascading.util.Util;
    033
    034/**
    035 * The Identity function simply passes incoming arguments back out again. Optionally argument fields can be renamed, and/or
    036 * coerced into specific types.
    037 * <p/>
    038 * During coercion, if the given type is a primitive ({@code long}), and the tuple value is null, {@code 0} is returned.
    039 * If the type is an Object ({@code java.lang.Long}), and the tuple value is {@code null}, {@code null} is returned.
    040 */
    041public class Identity extends BaseOperation<Identity.Functor> implements Function<Identity.Functor>
    042  {
    043  /** Field types */
    044  private Type[] types = null;
    045
    046  /**
    047   * Constructor Identity creates a new Identity instance that will pass the argument values to its output. Use this
    048   * constructor for a simple copy Pipe.
    049   */
    050  public Identity()
    051    {
    052    super( Fields.ARGS );
    053    }
    054
    055  /**
    056   * Constructor Identity creates a new Identity instance that will coerce the values to the give types.
    057   *
    058   * @param types of type Class...
    059   */
    060  @ConstructorProperties({"types"})
    061  public Identity( Class... types )
    062    {
    063    super( Fields.ARGS );
    064
    065    if( types.length == 0 )
    066      throw new IllegalArgumentException( "number of types must not be zero" );
    067
    068    this.types = Arrays.copyOf( types, types.length );
    069    }
    070
    071  /**
    072   * Constructor Identity creates a new Identity instance that will rename the argument fields to the given
    073   * fieldDeclaration.
    074   *
    075   * @param fieldDeclaration of type Fields
    076   */
    077  @ConstructorProperties({"fieldDeclaration"})
    078  public Identity( Fields fieldDeclaration )
    079    {
    080    super( fieldDeclaration ); // don't need to set size, default is ANY
    081
    082    this.types = fieldDeclaration.getTypes();
    083    }
    084
    085  /**
    086   * Constructor Identity creates a new Identity instance that will rename the argument fields to the given
    087   * fieldDeclaration, and coerce the values to the give types.
    088   *
    089   * @param fieldDeclaration of type Fields
    090   * @param types            of type Class...
    091   */
    092  @ConstructorProperties({"fieldDeclaration", "types"})
    093  public Identity( Fields fieldDeclaration, Class... types )
    094    {
    095    super( fieldDeclaration );
    096    this.types = Arrays.copyOf( types, types.length );
    097
    098    if( !fieldDeclaration.isSubstitution() && fieldDeclaration.size() != types.length )
    099      throw new IllegalArgumentException( "fieldDeclaration and types must be the same size" );
    100    }
    101
    102  public Type[] getTypes()
    103    {
    104    return Util.copy( types );
    105    }
    106
    107  @Override
    108  public void prepare( FlowProcess flowProcess, OperationCall<Functor> operationCall )
    109    {
    110    Functor functor;
    111
    112    if( types != null )
    113      {
    114      Tuple result = Tuple.size( types.length );
    115
    116      functor = functionCall ->
    117      {
    118      TupleEntryCollector outputCollector = functionCall.getOutputCollector();
    119
    120      outputCollector.add( functionCall.getArguments().getCoercedTuple( types, result ) );
    121      };
    122      }
    123    else
    124      {
    125      functor = functionCall ->
    126      {
    127      TupleEntryCollector outputCollector = functionCall.getOutputCollector();
    128
    129      outputCollector.add( functionCall.getArguments().getTuple() );
    130      };
    131
    132      operationCall.setContext( functor );
    133      }
    134
    135    operationCall.setContext( functor );
    136    }
    137
    138  @Override
    139  public void operate( FlowProcess flowProcess, FunctionCall<Functor> functionCall )
    140    {
    141    functionCall.getContext().operate( functionCall );
    142    }
    143
    144  @Override
    145  public boolean equals( Object object )
    146    {
    147    if( this == object )
    148      return true;
    149    if( !( object instanceof Identity ) )
    150      return false;
    151    if( !super.equals( object ) )
    152      return false;
    153
    154    Identity identity = (Identity) object;
    155
    156    if( !Arrays.equals( types, identity.types ) )
    157      return false;
    158
    159    return true;
    160    }
    161
    162  @Override
    163  public int hashCode()
    164    {
    165    int result = super.hashCode();
    166    result = 31 * result + ( types != null ? Arrays.hashCode( types ) : 0 );
    167    return result;
    168    }
    169
    170  protected interface Functor
    171    {
    172    void operate( FunctionCall<Functor> functionCall );
    173    }
    174  }