    001    /*
    002     * Copyright (c) 2007-2014 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;
    022
    023    import java.beans.ConstructorProperties;
    024    import java.io.PrintStream;
    025
    026    import 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"})
    038    public 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      }