/*
* Copyright (c) 2007-2010 Concurrent, Inc. All Rights Reserved.
*
* Project and contact information: http://www.cascading.org/
*
* This file is part of the Cascading project.
*
* Cascading is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Cascading is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Cascading. If not, see <http://www.gnu.org/licenses/>.
*/
package cascading.operation;
import java.beans.ConstructorProperties;
import java.io.PrintStream;
import cascading.flow.FlowProcess;
/**
* Class Debug is a {@link Filter} that will never remove an item from a stream, but will print the Tuple to either
* stdout or stderr.
* <p/>
* Currently, if printFields is true, they will print every 10 Tuples.
* <p/>
* The frequency that fields and tuples are printed can be set via {@link #setPrintFieldsEvery(int)} and
* {@link #setPrintTupleEvery(int)} methods, respectively.
*/
public class Debug extends BaseOperation<Long> implements Filter<Long>, PlannedOperation<Long>
{
static public enum Output
{
STDOUT, STDERR
}
/** Field output */
private Output output = Output.STDERR;
/** Field prefix */
private String prefix = null;
/** Field printFields */
private boolean printFields = false;
/** Field printFieldsEvery */
private int printFieldsEvery = 10;
/** Field printTupleEvery */
private int printTupleEvery = 1;
/**
* Constructor Debug creates a new Debug instance that prints to stderr by default, and does not print
* the Tuple instance field names.
*/
public Debug()
{
}
/**
* Constructor Debug creates a new Debug instance that prints to stderr by default, and does not print
* the Tuple instance field names.
*
* @param prefix of type String
*/
@ConstructorProperties({"prefix"})
public Debug( String prefix )
{
this.prefix = prefix;
}
/**
* Constructor Debug creates a new Debug instance that prints to stderr and will print the current
* Tuple instance field names if printFields is true.
*
* @param prefix of type String
* @param printFields of type boolean
*/
@ConstructorProperties({"prefix", "printFields"})
public Debug( String prefix, boolean printFields )
{
this.prefix = prefix;
this.printFields = printFields;
}
/**
* Constructor Debug creates a new Debug instance that prints to stderr and will print the current
* Tuple instance field names if printFields is true.
*
* @param printFields of type boolean
*/
@ConstructorProperties({"printFields"})
public Debug( boolean printFields )
{
this.printFields = printFields;
}
/**
* Constructor Debug creates a new Debug instance that prints to the declared stream and does not print the Tuple
* field names.
*
* @param output of type Output
*/
@ConstructorProperties({"output"})
public Debug( Output output )
{
this.output = output;
}
/**
* Constructor Debug creates a new Debug instance that prints to the declared stream and does not print the Tuple
* field names.
*
* @param output of type Output
* @param prefix of type String
*/
@ConstructorProperties({"output", "prefix"})
public Debug( Output output, String prefix )
{
this.output = output;
this.prefix = prefix;
}
/**
* Constructor Debug creates a new Debug instance that prints to the declared stream and will print the Tuple instances
* field names if printFields is true.
*
* @param output of type Output
* @param prefix of type String
* @param printFields of type boolean
*/
@ConstructorProperties({"output", "prefix", "printFields"})
public Debug( Output output, String prefix, boolean printFields )
{
this.output = output;
this.prefix = prefix;
this.printFields = printFields;
}
/**
* Constructor Debug creates a new Debug instance that prints to the declared stream and will print the Tuple instances
* field names if printFields is true.
*
* @param output of type Output
* @param printFields of type boolean
*/
@ConstructorProperties({"output", "printFields"})
public Debug( Output output, boolean printFields )
{
this.output = output;
this.printFields = printFields;
}
/**
* Method getPrintFieldsEvery returns the printFieldsEvery interval value of this Debug object.
*
* @return the printFieldsEvery (type int) of this Debug object.
*/
public int getPrintFieldsEvery()
{
return printFieldsEvery;
}
/**
* Method setPrintFieldsEvery sets the printFieldsEvery interval value of this Debug object.
*
* @param printFieldsEvery the printFieldsEvery of this Debug object.
*/
public void setPrintFieldsEvery( int printFieldsEvery )
{
this.printFieldsEvery = printFieldsEvery;
}
/**
* Method getPrintTupleEvery returns the printTupleEvery interval value of this Debug object.
*
* @return the printTupleEvery (type int) of this Debug object.
*/
public int getPrintTupleEvery()
{
return printTupleEvery;
}
/**
* Method setPrintTupleEvery sets the printTupleEvery interval value of this Debug object.
*
* @param printTupleEvery the printTupleEvery of this Debug object.
*/
public void setPrintTupleEvery( int printTupleEvery )
{
this.printTupleEvery = printTupleEvery;
}
@Override
public boolean supportsPlannerLevel( PlannerLevel plannerLevel )
{
return plannerLevel instanceof DebugLevel;
}
@Override
public void prepare( FlowProcess flowProcess, OperationCall<Long> operationCall )
{
super.prepare( flowProcess, operationCall );
operationCall.setContext( 0L );
}
/** @see Filter#isRemove(cascading.flow.FlowProcess, FilterCall) */
public boolean isRemove( FlowProcess flowProcess, FilterCall<Long> filterCall )
{
PrintStream stream = output == Output.STDOUT ? System.out : System.err;
if( printFields && filterCall.getContext() % printFieldsEvery == 0 )
print( stream, filterCall.getArguments().getFields().print() );
if( filterCall.getContext() % printTupleEvery == 0 )
print( stream, filterCall.getArguments().getTuple().print() );
filterCall.setContext( filterCall.getContext() + 1 );
return false;
}
@Override
public void cleanup( FlowProcess flowProcess, OperationCall<Long> longOperationCall )
{
PrintStream stream = output == Output.STDOUT ? System.out : System.err;
print( stream, "tuples count: " + longOperationCall.getContext().toString() );
}
private void print( PrintStream stream, String message )
{
if( prefix != null )
{
stream.print( prefix );
stream.print( ": " );
}
stream.println( message );
}
@Override
public boolean equals( Object object )
{
if( this == object )
return true;
if( !( object instanceof Debug ) )
return false;
if( !super.equals( object ) )
return false;
Debug debug = (Debug) object;
if( printFields != debug.printFields )
return false;
if( printFieldsEvery != debug.printFieldsEvery )
return false;
if( printTupleEvery != debug.printTupleEvery )
return false;
if( output != debug.output )
return false;
if( prefix != null ? !prefix.equals( debug.prefix ) : debug.prefix != null )
return false;
return true;
}
@Override
public int hashCode()
{
int result = super.hashCode();
result = 31 * result + ( output != null ? output.hashCode() : 0 );
result = 31 * result + ( prefix != null ? prefix.hashCode() : 0 );
result = 31 * result + ( printFields ? 1 : 0 );
result = 31 * result + printFieldsEvery;
result = 31 * result + printTupleEvery;
return result;
}
}