/*==========================================================================*\
| $Id: MutableStringBufferInputStream.java,v 1.3 2010/02/23 17:06:38 stedwar2 Exp $
|*-------------------------------------------------------------------------*|
| Copyright (C) 2007-2010 Virginia Tech
|
| This file is part of the Student-Library.
|
| The Student-Library is free software; you can redistribute it and/or
| modify it under the terms of the GNU Lesser General Public License as
| published by the Free Software Foundation; either version 3 of the
| License, or (at your option) any later version.
|
| The Student-Library 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 Lesser General Public License for more details.
|
| You should have received a copy of the GNU Lesser General Public License
| along with the Student-Library; if not, see <http://www.gnu.org/licenses/>.
\*==========================================================================*/
package student.testingsupport;
import java.io.IOException;
import java.io.InputStream;
//-------------------------------------------------------------------------
/**
* A custom input stream that takes its contents from a provided string
* literal, and that also supports dynamically resetting of its own contents.
* This class is designed to help write test cases involving input,
* particularly from <code>System.in</code>. It can be used as a
* "smart" replacement for <code>System.in</code> that allows the console
* input to be provided by string contents, and allows the console
* input to be reset whenever needed.
* <p>
* Note that it is possible to create a
* <code>MutableStringBufferInputStream</code> with null contents. Such
* a stream is in an "unusable" state where no {@link InputStream} methods
* can be called until actual contents have been provided at some later point.
* Any calls to <code>InputStream</code> methods when a stream is unusable
* are instead preempted, and a protected error handling method called
* {@link #handleMissingContents()} is invoked instead, usually producing
* an {@link IllegalStateException}. The <code>handleMissingContents()</code>
* method is protected, so that subclasses can override it to provide
* customized error responses if desired.
* </p><p>
* At any point in time, {@link #resetContents(String)} (or
* {@link #resetContents(InputStream)}) can be used to change the stream's
* contents to a new value. This completely resets the stream's state.
* </p>
*
* @author Stephen Edwards
* @author Last changed by $Author: stedwar2 $
* @version $Revision: 1.3 $, $Date: 2010/02/23 17:06:38 $
*/
@SuppressWarnings("deprecation")
public class MutableStringBufferInputStream
extends InputStream
{
//~ Instance/static variables .............................................
private InputStream src;
private String name = "an input stream";
//~ Constructors ..........................................................
// ----------------------------------------------------------
/**
* Create a new input stream with the specified contents. If null is
* provided, the stream is created in an "unusable" state where
* {@link InputStream} methods cannot be called until actual contents
* have been provided at some later point. Any attempt to access an
* unusable stream is preempted by a call to
* {@link #handleMissingContents()}, which typically produces an
* exception. Contents can be changed at any time using
* <code>resetContents()</code>.
* @param contents The complete contents of this input stream, provided
* as a <code>String</code>.
*/
public MutableStringBufferInputStream(String contents)
{
resetContents(contents);
}
// ----------------------------------------------------------
/**
* Create a new input stream with the specified contents. If null is
* provided, the stream is created in an "unusable" state where
* {@link InputStream} methods cannot be called until actual contents
* have been provided at some later point. Any attempt to access an
* unusable stream is preempted by a call to
* {@link #handleMissingContents()}, which typically produces an
* exception. Contents can be changed at any time using
* <code>resetContents()</code>.
* @param contents A second input stream to draw contents from. All
* stream operations will be delegated to this object,
* until <code>resetContents()</code> is called.
*/
public MutableStringBufferInputStream(InputStream contents)
{
resetContents(contents);
}
// ----------------------------------------------------------
/**
* Get the human-readable name of this input stream, for diagnostic or
* debugging purposes. The default name for each newly-created
* stream is simply "an input stream", but a specific name can be
* provided using {@link #setName(String)} where desired.
* @return This stream's name, for debugging purposes.
*/
public String getName()
{
return name;
}
// ----------------------------------------------------------
/**
* Set the human-readable name of this input stream, for diagnostic or
* debugging purposes. The default name is simply "an input stream".
* @param name The new name to use for this stream.
*/
public void setName(String name)
{
this.name = name;
}
// ----------------------------------------------------------
/**
* Reset this stream and replace its contents. If null is
* provided, the stream becomes "unusable" where
* {@link InputStream} methods cannot be called until actual contents
* have been provided at some later point. Any attempt to access an
* unusable stream is preempted by a call to
* {@link #handleMissingContents()}, which typically produces an
* exception. Contents can be changed again at any time using
* <code>resetContents()</code>.
* @param newContents The new contents (possibly null) for this stream.
*/
public void resetContents(String newContents)
{
if (newContents == null)
{
src = null;
}
else
{
src = new java.io.StringBufferInputStream(newContents);
}
}
// ----------------------------------------------------------
/**
* Reset this stream and replace its contents. If null is
* provided, the stream becomes "unusable" where
* {@link InputStream} methods cannot be called until actual contents
* have been provided at some later point. Any attempt to access an
* unusable stream is preempted by a call to
* {@link #handleMissingContents()}, which typically produces an
* exception. Contents can be changed again at any time using
* <code>resetContents()</code>.
* @param newContents The new contents (possibly null) for this stream.
*/
public void resetContents(InputStream newContents)
{
src = newContents;
}
// ----------------------------------------------------------
/**
* Handle access to an input stream that has not had its contents
* defined. The default behavior is to throw an
* <code>IllegalStateException</code> indicating that the stream
* has not had its contents set. Subclasses can override this
* method to provide custom error handling behaviors as needed.
*/
protected void handleMissingContents()
{
throw new IllegalStateException("The program attempted to read from "
+ getName()
+ ", but no contents have been set yet.");
}
// ----------------------------------------------------------
@Override
public int read()
throws IOException
{
if (src == null)
{
handleMissingContents();
}
return src.read();
}
// ----------------------------------------------------------
@Override
public int read(byte[] b, int off, int len)
throws IOException
{
if (src == null)
{
handleMissingContents();
}
return src.read(b, off, len);
}
// ----------------------------------------------------------
@Override
public long skip(long n)
throws IOException
{
if (src == null)
{
handleMissingContents();
}
return src.skip(n);
}
// ----------------------------------------------------------
@Override
public int available()
throws IOException
{
if (src == null)
{
handleMissingContents();
}
return src.available();
}
// ----------------------------------------------------------
@Override
public void reset()
throws IOException
{
if (src == null)
{
handleMissingContents();
}
src.reset();
}
}