blob: 2508788282aa1c3bfd5328d4775fd0fe0a315698 [file] [log] [blame]
/*
* Copyright (c) 2010, Rickard Öberg. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.qi4j.io;
import java.io.BufferedOutputStream;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.Collection;
import java.util.zip.GZIPOutputStream;
/**
* Utility methods for creating standard Outputs
*/
public class Outputs
{
// START SNIPPET: method
/**
* Write lines to a text file with UTF-8 encoding. Separate each line with a newline ("\n" character). If the writing or sending fails,
* the file is deleted.
* <p>
* If the filename ends with .gz, then the data is automatically GZipped.
* </p>
* @param file the file to save the text to
*
* @return an Output for storing text in a file
*/
public static Output<String, IOException> text( final File file )
// END SNIPPET: method
{
return text( file, "UTF-8" );
}
// START SNIPPET: method
/**
* Write lines to a text file. Separate each line with a newline ("\n" character). If the writing or sending fails,
* the file is deleted.
* <p>
* If the filename ends with .gz, then the data is automatically GZipped.
* </p>
* @param file the file to save the text to
*
* @return an Output for storing text in a file
*/
public static Output<String, IOException> text( final File file, final String encoding )
// END SNIPPET: method
{
return new Output<String, IOException>()
{
@Override
@SuppressWarnings( "unchecked" )
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends String, SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
File tmpFile = Files.createTemporayFileOf( file );
OutputStream stream = new FileOutputStream( tmpFile );
// If file should be gzipped, do that automatically
if( file.getName().endsWith( ".gz" ) )
{
stream = new GZIPOutputStream( stream );
}
final BufferedWriter writer = new BufferedWriter( new OutputStreamWriter( stream, encoding ) );
try
{
sender.sendTo( new Receiver<String, IOException>()
{
@Override
public void receive( String item )
throws IOException
{
writer.append( item ).append( '\n' );
}
} );
writer.close();
// Replace file with temporary file
if( !file.exists() || file.delete() )
{
if( ! tmpFile.renameTo( file ) )
{
// TODO: What?? Throw an Exception?
System.err.println( "Unable to rename file: " + tmpFile + " to " + file );
}
}
}
catch( IOException e )
{
// We failed writing - close and delete
writer.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
}
catch( Throwable senderThrowableType )
{
// We failed writing - close and delete
writer.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
throw (SenderThrowableType) senderThrowableType;
}
}
};
}
// START SNIPPET: method
/**
* Write lines to a Writer. Separate each line with a newline ("\n" character).
*
* @param writer the Writer to write the text to
* @return an Output for storing text in a Writer
*/
public static Output<String, IOException> text( final Writer writer )
// END SNIPPET: method
{
return new Output<String, IOException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends String, SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
sender.sendTo( new Receiver<String, IOException>()
{
@Override
public void receive( String item )
throws IOException
{
writer.append( item ).append( "\n" );
}
} );
}
};
}
// START SNIPPET: method
/**
* Write lines to a StringBuilder. Separate each line with a newline ("\n" character).
*
* @param builder the StringBuilder to append the text to
* @return an Output for storing text in a StringBuilder
*/
public static Output<String, IOException> text( final StringBuilder builder )
// END SNIPPET: method
{
return new Output<String, IOException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends String, SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
sender.sendTo( new Receiver<String, IOException>()
{
@Override
public void receive( String item )
throws IOException
{
builder.append( item ).append( "\n" );
}
} );
}
};
}
// START SNIPPET: method
/**
* Write ByteBuffer data to a file. If the writing or sending of data fails the file will be deleted.
*
* @param file The destination file.
*
* @return The Output ByteBuffer instance backed by a File.
*/
public static Output<ByteBuffer, IOException> byteBuffer( final File file )
// END SNIPPET: method
{
return new Output<ByteBuffer, IOException>()
{
@Override
@SuppressWarnings( "unchecked" )
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends ByteBuffer, SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
File tmpFile = Files.createTemporayFileOf( file );
FileOutputStream stream = new FileOutputStream( tmpFile );
final FileChannel fco = stream.getChannel();
try
{
sender.sendTo( new Receiver<ByteBuffer, IOException>()
{
@Override
public void receive( ByteBuffer item )
throws IOException
{
fco.write( item );
}
} );
stream.close();
// Replace file with temporary file
if( !file.exists() || file.delete() )
{
if( ! tmpFile.renameTo( file ) )
{
// TODO: What can be done in this case?
System.err.println( "Unable to rename file: " + tmpFile + " to " + file );
}
}
}
catch( IOException e )
{
// We failed writing - close and delete
stream.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
}
catch( Throwable senderThrowableType )
{
// We failed writing - close and delete
stream.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
throw (SenderThrowableType) senderThrowableType;
}
}
};
}
// START SNIPPET: method
/**
* Write ByteBuffer data to an OutputStream.
*
* @param stream Destination OutputStream
*
* @return The Output of ByteBuffer that will be backed by the OutputStream.
*/
public static Output<ByteBuffer, IOException> byteBuffer( final OutputStream stream )
// END SNIPPET: method
{
return new Output<ByteBuffer, IOException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends ByteBuffer, SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
try
{
sender.sendTo( new Receiver<ByteBuffer, IOException>()
{
@Override
public void receive( ByteBuffer item )
throws IOException
{
if( item.hasArray() )
{
stream.write( item.array(), item.arrayOffset(), item.limit() );
}
else
{
for( int i = 0; i < item.limit(); i++ )
{
stream.write( item.get( i ) );
}
}
}
} );
}
finally
{
stream.close();
}
}
};
}
// START SNIPPET: method
/**
* Write byte array data to a file. If the writing or sending of data fails the file will be deleted.
*
* @param file The File to be written to.
* @param bufferSize The size of the ByteBuffer.
*
* @return An Output instance that will write to the given File.
*/
public static Output<byte[], IOException> bytes( final File file, final int bufferSize )
// END SNIPPET: method
{
return new Output<byte[], IOException>()
{
@Override
@SuppressWarnings( "unchecked" )
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends byte[], SenderThrowableType> sender )
throws IOException, SenderThrowableType
{
File tmpFile = Files.createTemporayFileOf( file );
final OutputStream stream = new BufferedOutputStream( new FileOutputStream( tmpFile ), bufferSize );
try
{
sender.sendTo( new Receiver<byte[], IOException>()
{
@Override
public void receive( byte[] item )
throws IOException
{
stream.write( item );
}
} );
stream.close();
// Replace file with temporary file
if( !file.exists() || file.delete() )
{
if( ! tmpFile.renameTo( file ) )
{
// TODO: WHAT???
System.err.println( "Unable to rename " + tmpFile + " to " + file );
}
}
}
catch( IOException e )
{
// We failed writing - close and delete
stream.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
}
catch( Throwable senderThrowableType )
{
// We failed writing - close and delete
stream.close();
if( ! tmpFile.delete() )
{
System.err.println("Unable to delete temporary file." );
tmpFile.deleteOnExit();
}
throw (SenderThrowableType) senderThrowableType;
}
}
};
}
// START SNIPPET: method
/**
* Do nothing. Use this if you have all logic in filters and/or specifications
*
* @param <T> The item type.
*
* @return An Output instance that ignores all data.
*/
public static <T> Output<T, RuntimeException> noop()
// END SNIPPET: method
{
return withReceiver( new Receiver<T, RuntimeException>()
{
@Override
public void receive( T item )
throws RuntimeException
{
// Do nothing
}
} );
}
// START SNIPPET: method
/**
* Use given receiver as Output. Use this if there is no need to create a "transaction" for each transfer, and no need
* to do batch writes or similar.
*
* @param <T> The item type
* @param receiver receiver for this Output
*
* @return An Output instance backed by a Receiver of items.
*/
public static <T, ReceiverThrowableType extends Throwable> Output<T, ReceiverThrowableType> withReceiver( final Receiver<T, ReceiverThrowableType> receiver )
// END SNIPPET: method
{
return new Output<T, ReceiverThrowableType>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends T, SenderThrowableType> sender )
throws ReceiverThrowableType, SenderThrowableType
{
sender.sendTo( receiver );
}
};
}
// START SNIPPET: method
/**
* Write objects to System.out.println.
*
* @return An Output instance that is backed by System.out
*/
public static Output<Object, RuntimeException> systemOut()
// END SNIPPET: method
{
return new Output<Object, RuntimeException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<?, SenderThrowableType> sender )
throws RuntimeException, SenderThrowableType
{
sender.sendTo( new Receiver<Object, RuntimeException>()
{
@Override
public void receive( Object item )
{
System.out.println( item );
}
} );
}
};
}
// START SNIPPET: method
/**
* Write objects to System.err.println.
*
* @return An Output instance backed by System.in
*/
@SuppressWarnings( "UnusedDeclaration" )
public static Output<Object, RuntimeException> systemErr()
// END SNIPPET: method
{
return new Output<Object, RuntimeException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<?, SenderThrowableType> sender )
throws RuntimeException, SenderThrowableType
{
sender.sendTo( new Receiver<Object, RuntimeException>()
{
@Override
public void receive( Object item )
{
System.err.println( item );
}
} );
}
};
}
// START SNIPPET: method
/**
* Add items to a collection
*/
public static <T> Output<T, RuntimeException> collection( final Collection<T> collection )
// END SNIPPET: method
{
return new Output<T, RuntimeException>()
{
@Override
public <SenderThrowableType extends Throwable> void receiveFrom( Sender<? extends T, SenderThrowableType> sender )
throws RuntimeException, SenderThrowableType
{
sender.sendTo( new Receiver<T, RuntimeException>()
{
@Override
public void receive( T item )
throws RuntimeException
{
collection.add( item );
}
} );
}
};
}
private Outputs()
{
}
}