/*
* 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.tuple;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import cascading.tuple.hadoop.TupleSerialization;
import org.apache.hadoop.io.WritableUtils;
import org.apache.log4j.Logger;
/** Class TupleOutputStream is used internally to write Tuples to storage. */
public class TupleOutputStream extends DataOutputStream
{
/** Field LOG */
private static final Logger LOG = Logger.getLogger( TupleInputStream.class );
/** Field WRITABLE_TOKEN */
public static final int WRITABLE_TOKEN = 32;
private interface TupleElementWriter
{
void write( TupleOutputStream stream, Object element ) throws IOException;
}
private static Map<Class, TupleElementWriter> tupleElementWriters = new IdentityHashMap<Class, TupleElementWriter>();
static
{
tupleElementWriters.put( String.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 1 );
WritableUtils.writeString( stream, (String) element );
}
} );
tupleElementWriters.put( Float.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 2 );
stream.writeFloat( (Float) element );
}
} );
tupleElementWriters.put( Double.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 3 );
stream.writeDouble( (Double) element );
}
} );
tupleElementWriters.put( Integer.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 4 );
WritableUtils.writeVInt( stream, (Integer) element );
}
} );
tupleElementWriters.put( Long.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 5 );
WritableUtils.writeVLong( stream, (Long) element );
}
} );
tupleElementWriters.put( Boolean.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 6 );
stream.writeBoolean( (Boolean) element );
}
} );
tupleElementWriters.put( Short.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 7 );
stream.writeShort( (Short) element );
}
} );
tupleElementWriters.put( Tuple.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 8 );
stream.writeTuple( (Tuple) element );
}
} );
tupleElementWriters.put( TuplePair.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 9 );
stream.writeTuplePair( (TuplePair) element );
}
} );
tupleElementWriters.put( IndexTuple.class, new TupleElementWriter()
{
@Override
public void write( TupleOutputStream stream, Object element ) throws IOException
{
WritableUtils.writeVInt( stream, 10 );
stream.writeIndexTuple( (IndexTuple) element );
}
} );
}
/** Field elementWriter */
ElementWriter elementWriter;
public interface ElementWriter
{
void write( DataOutputStream outputStream, Object object ) throws IOException;
void close();
}
public TupleOutputStream( OutputStream outputStream, ElementWriter elementWriter )
{
super( outputStream );
this.elementWriter = elementWriter;
}
public TupleOutputStream( OutputStream outputStream )
{
super( outputStream );
this.elementWriter = new TupleSerialization().getElementWriter();
}
public void writeTuple( Tuple tuple ) throws IOException
{
write( tuple );
}
public void writeTuplePair( TuplePair tuplePair ) throws IOException
{
Tuple[] tuples = TuplePair.tuples( tuplePair );
write( tuples[ 0 ] );
write( tuples[ 1 ] );
}
public void writeIndexTuple( IndexTuple indexTuple ) throws IOException
{
WritableUtils.writeVInt( this, indexTuple.getIndex() );
writeTuple( indexTuple.getTuple() );
}
/**
* Method write is used by Hadoop to write this Tuple instance out to a file.
*
* @throws java.io.IOException when
*/
private void write( Tuple tuple ) throws IOException
{
List<Object> elements = Tuple.elements( tuple );
WritableUtils.writeVInt( this, elements.size() );
for( Object element : elements )
{
if( element == null )
{
WritableUtils.writeVInt( this, 0 );
continue;
}
Class type = element.getClass();
TupleElementWriter tupleElementWriter = tupleElementWriters.get( type );
if( tupleElementWriter != null )
tupleElementWriter.write( this, element );
else
elementWriter.write( this, element );
}
}
@Override
public void close() throws IOException
{
if( LOG.isDebugEnabled() )
LOG.debug( "closing tuple output stream" );
try
{
super.close();
}
finally
{
if( elementWriter != null )
elementWriter.close();
}
}
}