    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;
    022
    023import java.beans.ConstructorProperties;
    024import java.io.PrintStream;
    025
    026import cascading.flow.FlowProcess;
    027
    028/**
    029 * Class Debug is a {@link Filter} that will never remove an item from a stream, but will print the Tuple to either
    030 * stdout or stderr.
    031 * <p/>
    032 * Currently, if printFields is true, they will print every 10 Tuples.
    033 * <p/>
    034 * The frequency that fields and tuples are printed can be set via {@link #setPrintFieldsEvery(int)} and
    035 * {@link #setPrintTupleEvery(int)} methods, respectively.
    036 */
    037@SuppressWarnings({"UseOfSystemOutOrSystemErr"})
    038public class Debug extends BaseOperation<Long> implements Filter<Long>, PlannedOperation<Long>
    039  {
    040  static public enum Output
    041    {
    042      STDOUT, STDERR
    043    }
    044
    045  /** Field output */
    046  private Output output = Output.STDERR;
    047  /** Field prefix */
    048  private String prefix = null;
    049  /** Field printFields */
    050  private boolean printFields = false;
    051
    052  /** Field printFieldsEvery */
    053  private int printFieldsEvery = 10;
    054  /** Field printTupleEvery */
    055  private int printTupleEvery = 1;
    056
    057  /**
    058   * Constructor Debug creates a new Debug instance that prints to stderr by default, and does not print
    059   * the Tuple instance field names.
    060   */
    061  public Debug()
    062    {
    063    }
    064
    065  /**
    066   * Constructor Debug creates a new Debug instance that prints to stderr by default, and does not print
    067   * the Tuple instance field names.
    068   *
    069   * @param prefix of type String
    070   */
    071  @ConstructorProperties({"prefix"})
    072  public Debug( String prefix )
    073    {
    074    this.prefix = prefix;
    075    }
    076
    077  /**
    078   * Constructor Debug creates a new Debug instance that prints to stderr and will print the current
    079   * Tuple instance field names if printFields is true.
    080   *
    081   * @param prefix      of type String
    082   * @param printFields of type boolean
    083   */
    084  @ConstructorProperties({"prefix", "printFields"})
    085  public Debug( String prefix, boolean printFields )
    086    {
    087    this.prefix = prefix;
    088    this.printFields = printFields;
    089    }
    090
    091  /**
    092   * Constructor Debug creates a new Debug instance that prints to stderr and will print the current
    093   * Tuple instance field names if printFields is true.
    094   *
    095   * @param printFields of type boolean
    096   */
    097  @ConstructorProperties({"printFields"})
    098  public Debug( boolean printFields )
    099    {
    100    this.printFields = printFields;
    101    }
    102
    103  /**
    104   * Constructor Debug creates a new Debug instance that prints to the declared stream and does not print the Tuple
    105   * field names.
    106   *
    107   * @param output of type Output
    108   */
    109  @ConstructorProperties({"output"})
    110  public Debug( Output output )
    111    {
    112    this.output = output;
    113    }
    114
    115  /**
    116   * Constructor Debug creates a new Debug instance that prints to the declared stream and does not print the Tuple
    117   * field names.
    118   *
    119   * @param output of type Output
    120   * @param prefix of type String
    121   */
    122  @ConstructorProperties({"output", "prefix"})
    123  public Debug( Output output, String prefix )
    124    {
    125    this.output = output;
    126    this.prefix = prefix;
    127    }
    128
    129  /**
    130   * Constructor Debug creates a new Debug instance that prints to the declared stream and will print the Tuple instances
    131   * field names if printFields is true.
    132   *
    133   * @param output      of type Output
    134   * @param prefix      of type String
    135   * @param printFields of type boolean
    136   */
    137  @ConstructorProperties({"output", "prefix", "printFields"})
    138  public Debug( Output output, String prefix, boolean printFields )
    139    {
    140    this.output = output;
    141    this.prefix = prefix;
    142    this.printFields = printFields;
    143    }
    144
    145  /**
    146   * Constructor Debug creates a new Debug instance that prints to the declared stream and will print the Tuple instances
    147   * field names if printFields is true.
    148   *
    149   * @param output      of type Output
    150   * @param printFields of type boolean
    151   */
    152  @ConstructorProperties({"output", "printFields"})
    153  public Debug( Output output, boolean printFields )
    154    {
    155    this.output = output;
    156    this.printFields = printFields;
    157    }
    158
    159  public Output getOutput()
    160    {
    161    return output;
    162    }
    163
    164  public String getPrefix()
    165    {
    166    return prefix;
    167    }
    168
    169  public boolean isPrintFields()
    170    {
    171    return printFields;
    172    }
    173
    174  /**
    175   * Method getPrintFieldsEvery returns the printFieldsEvery interval value of this Debug object.
    176   *
    177   * @return the printFieldsEvery (type int) of this Debug object.
    178   */
    179  public int getPrintFieldsEvery()
    180    {
    181    return printFieldsEvery;
    182    }
    183
    184  /**
    185   * Method setPrintFieldsEvery sets the printFieldsEvery interval value of this Debug object.
    186   *
    187   * @param printFieldsEvery the printFieldsEvery of this Debug object.
    188   */
    189  public void setPrintFieldsEvery( int printFieldsEvery )
    190    {
    191    this.printFieldsEvery = printFieldsEvery;
    192    }
    193
    194  /**
    195   * Method getPrintTupleEvery returns the printTupleEvery interval value of this Debug object.
    196   *
    197   * @return the printTupleEvery (type int) of this Debug object.
    198   */
    199  public int getPrintTupleEvery()
    200    {
    201    return printTupleEvery;
    202    }
    203
    204  /**
    205   * Method setPrintTupleEvery sets the printTupleEvery interval value of this Debug object.
    206   *
    207   * @param printTupleEvery the printTupleEvery of this Debug object.
    208   */
    209  public void setPrintTupleEvery( int printTupleEvery )
    210    {
    211    this.printTupleEvery = printTupleEvery;
    212    }
    213
    214  @Override
    215  public boolean supportsPlannerLevel( PlannerLevel plannerLevel )
    216    {
    217    return plannerLevel instanceof DebugLevel;
    218    }
    219
    220  @Override
    221  public void prepare( FlowProcess flowProcess, OperationCall<Long> operationCall )
    222    {
    223    super.prepare( flowProcess, operationCall );
    224
    225    operationCall.setContext( 0L );
    226    }
    227
    228  /** @see Filter#isRemove(cascading.flow.FlowProcess, FilterCall) */
    229  public boolean isRemove( FlowProcess flowProcess, FilterCall<Long> filterCall )
    230    {
    231    PrintStream stream = output == Output.STDOUT ? System.out : System.err;
    232
    233    if( printFields && filterCall.getContext() % printFieldsEvery == 0 )
    234      print( stream, filterCall.getArguments().getFields().print() );
    235
    236    if( filterCall.getContext() % printTupleEvery == 0 )
    237      print( stream, filterCall.getArguments().getTuple().print() );
    238
    239    filterCall.setContext( filterCall.getContext() + 1 );
    240
    241    return false;
    242    }
    243
    244  @Override
    245  public void cleanup( FlowProcess flowProcess, OperationCall<Long> longOperationCall )
    246    {
    247    if( longOperationCall.getContext() == null )
    248      return;
    249
    250    PrintStream stream = output == Output.STDOUT ? System.out : System.err;
    251
    252    print( stream, "tuples count: " + longOperationCall.getContext().toString() );
    253    }
    254
    255  private void print( PrintStream stream, String message )
    256    {
    257    if( prefix != null )
    258      {
    259      stream.print( prefix );
    260      stream.print( ": " );
    261      }
    262
    263    stream.println( message );
    264    }
    265
    266  @Override
    267  public boolean equals( Object object )
    268    {
    269    if( this == object )
    270      return true;
    271    if( !( object instanceof Debug ) )
    272      return false;
    273    if( !super.equals( object ) )
    274      return false;
    275
    276    Debug debug = (Debug) object;
    277
    278    if( printFields != debug.printFields )
    279      return false;
    280    if( printFieldsEvery != debug.printFieldsEvery )
    281      return false;
    282    if( printTupleEvery != debug.printTupleEvery )
    283      return false;
    284    if( output != debug.output )
    285      return false;
    286    if( prefix != null ? !prefix.equals( debug.prefix ) : debug.prefix != null )
    287      return false;
    288
    289    return true;
    290    }
    291
    292  @Override
    293  public int hashCode()
    294    {
    295    int result = super.hashCode();
    296    result = 31 * result + ( output != null ? output.hashCode() : 0 );
    297    result = 31 * result + ( prefix != null ? prefix.hashCode() : 0 );
    298    result = 31 * result + ( printFields ? 1 : 0 );
    299    result = 31 * result + printFieldsEvery;
    300    result = 31 * result + printTupleEvery;
    301    return result;
    302    }
    303  }