package org.marketcetera.util.file;
import java.io.Closeable;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.Writer;
import org.marketcetera.util.misc.ClassVersion;
import org.marketcetera.util.unicode.SignatureCharset;
import org.marketcetera.util.unicode.UnicodeFileWriter;
import org.marketcetera.util.unicode.UnicodeOutputStreamWriter;
import static org.marketcetera.util.file.SpecialNames.*;
/**
* A wrapped writer. It may wrap a regular file, the standard output
* or error stream, or any other {@link Writer} instance. This wrapper
* is intended to wrap {@link Writer} instances for use with {@link
* CloseableRegistry}, hence such instances should not be closed
* directly, that is, without going through the wrapper's {@link
* #close()} method.
*
* @author tlerios@marketcetera.com
* @since 0.5.0
* @version $Id: WriterWrapper.java 16154 2012-07-14 16:34:05Z colin $
*/
/* $License$ */
@ClassVersion("$Id: WriterWrapper.java 16154 2012-07-14 16:34:05Z colin $")
public class WriterWrapper
implements Closeable
{
// INSTANCE DATA.
private Writer mWriter;
private boolean mSkipClose;
// CONSTRUCTORS.
/**
* Creates a new wrapped writer that wraps:
*
* <ul>
* <li>the regular file with the given name (data is appended to the
* file if the name is prefixed by {@link SpecialNames#PREFIX_APPEND}),
* or</li>
* <li>the standard output stream (if the name is {@link
* SpecialNames#STANDARD_OUTPUT}), or</li>
* <li>the standard error stream (if the name is {@link
* SpecialNames#STANDARD_ERROR}).</li>
* </ul>
*
* A writer that can inject unicode BOMs is used as a proxy; that
* writer uses the given signature/charset.
*
* @param name The file name.
* @param requestedSignatureCharset The signature/charset. It may
* be null to use the default JVM charset.
*
* @throws FileNotFoundException Thrown if the name represents a
* regular file, and it cannot be opened for writing.
*/
public WriterWrapper
(String name,
SignatureCharset requestedSignatureCharset)
throws FileNotFoundException
{
if (name.equals(STANDARD_OUTPUT)) {
mWriter=new UnicodeOutputStreamWriter
(System.out,requestedSignatureCharset);
mSkipClose=true;
return;
}
if (name.equals(STANDARD_ERROR)) {
mWriter=new UnicodeOutputStreamWriter
(System.err,requestedSignatureCharset);
mSkipClose=true;
return;
}
if (!name.startsWith(PREFIX_APPEND)) {
mWriter=new UnicodeFileWriter(name,requestedSignatureCharset);
return;
}
mWriter=new UnicodeFileWriter
(name.substring(PREFIX_APPEND.length()),true,
requestedSignatureCharset);
}
/**
* Creates a new wrapped writer that wraps:
*
* <ul>
* <li>the regular file with the given name (data is appended to the
* file if the name is prefixed by {@link SpecialNames#PREFIX_APPEND}),
* or</li>
* <li>the standard output stream (if the name is {@link
* SpecialNames#STANDARD_OUTPUT}), or</li>
* <li>the standard error stream (if the name is {@link
* SpecialNames#STANDARD_ERROR}).</li>
* </ul>
*
* The default JVM charset is used to convert characters into
* bytes.
*
* @param name The file name.
*
* @throws FileNotFoundException Thrown if the name represents a
* regular file, and it cannot be opened for writing.
*/
public WriterWrapper
(String name)
throws FileNotFoundException
{
this(name,null);
}
/**
* Creates a new wrapped writer that wraps the given regular
* file. A writer that can inject unicode BOMs is used as a proxy;
* that writer uses the given signature/charset.
*
* @param file The file.
* @param requestedSignatureCharset The signature/charset. It may
* be null to use the default JVM charset.
*
* @throws FileNotFoundException Thrown if the file cannot be
* opened for writing.
*/
public WriterWrapper
(File file,
SignatureCharset requestedSignatureCharset)
throws FileNotFoundException
{
mWriter=new UnicodeFileWriter(file,requestedSignatureCharset);
}
/**
* Creates a new wrapped writer that wraps the given regular file.
* The default JVM charset is used to convert characters into
* bytes.
*
* @param file The file.
*
* @throws FileNotFoundException Thrown if the file cannot be
* opened for writing.
*/
public WriterWrapper
(File file)
throws FileNotFoundException
{
this(file,null);
}
/**
* Creates a new wrapped writer that wraps the given writer. The
* writer may or may not be closed when {@link #close()} is called
* depending on the given flag.
*
* @param writer The writer.
* @param skipClose True if the underlying writer should not be
* closed.
*/
public WriterWrapper
(Writer writer,
boolean skipClose)
{
mWriter=writer;
mSkipClose=skipClose;
}
/**
* Creates a new wrapped writer that wraps the given writer. The
* underlying writer will be closed when {@link #close()} is
* called; hence the given writer should not wrap the standard
* output or error stream.
*
* @param writer The writer.
*/
public WriterWrapper
(Writer writer)
{
this(writer,false);
}
// Closeable.
@Override
public void close()
throws IOException
{
if (getWriter()==null) {
return;
}
// All writers (closeable or not) are flushed.
getWriter().flush();
if (getSkipClose()) {
return;
}
getWriter().close();
// Prevent future closures per {@link Closeable}.
mWriter=null;
}
// INSTANCE METHODS.
/**
* Returns the receiver's underlying writer.
*
* @return The writer.
*/
public Writer getWriter()
{
return mWriter;
}
/**
* Returns true if the receiver's underlying writer will not be
* closed when {@link #close()} is called.
*
* @return True if so.
*/
public boolean getSkipClose()
{
return mSkipClose;
}
}