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      }