001/*
002 * Copyright (c) 2007-2016 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
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  }