/*
* Copyright (c) 2005 Thomas Weise
*
* E-Mail : tweise@gmx.de
* Creation Date : 2005-07-25 16:33:11
* Original Filename: org.sfc.xml.ReferenceCountedStreamResult.java
* Version : 1.0.2
* Last modification: 2006-03-07
* by: Thomas Weise
*
* License : GNU LESSER GENERAL PUBLIC LICENSE
* Version 2.1, February 1999
* You should have received a copy of this license along
* with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307, USA or download the license under
* http://www.gnu.org/copyleft/lesser.html.
*
* Warranty : This software is provided "as is" 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.
*/
package org.sfc.xml;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamResult;
import org.sfc.io.IO;
import org.sfc.io.ReferenceCountedOutputStream;
import org.sfc.io.ReferenceCountedWriter;
import org.sfc.scoped.AlreadyDisposedException;
import org.sfc.scoped.IReferenceCounted;
/**
* A stream result implementing the IReferenceCounted
-
* interface.
*
* @author Thomas Weise
*/
public final class ReferenceCountedStreamResult
extends StreamResult
implements IReferenceCounted,
Source
{
/**
* The internal reference counter.
*/
private int m_ref_count ;
/**
* true
as long as this object is alive, false
if
* it died.
*/
private boolean m_living ;
/**
* Construct a new StreamResult
.
*
*/
public ReferenceCountedStreamResult()
{
super();
this.m_living = true;
this.m_ref_count = 1;
}
/**
* Increase the reference counter of this object by one.
* You must call add_ref
before you assign a variable to point
* on this object (except when calling the constructor and storing the
* result to exactly one variable).
* @throws AlreadyDisposedException If the object has already been disposed.
*/
public final void add_ref () throws AlreadyDisposedException
{
synchronized(this)
{
if(this.m_living)
{
this.m_ref_count++;
}
else
{
throw new AlreadyDisposedException();
}
}
}
/**
* Decrease the reference counter of this object by one.
* If the reference count reaches zero, the object will automatically
* perform cleanup operations. You must call release
whenever
* you don't need a variable pointing to this object anymore.
* @throws AlreadyDisposedException If the object has already been disposed.
*/
public final void release () throws AlreadyDisposedException
{
this.do_release();
}
/**
* Decrease the reference counter of this object by one.
* If the reference count reaches zero, the object will automatically
* perform cleanup operations. You must call release
whenever
* you don't need a variable pointing to this object anymore.
* @throws AlreadyDisposedException If the object has already been disposed.
* @return The IOException
that was thrown during closing of
* the object, or null
if everything was ok.
*/
final IOException do_release () throws AlreadyDisposedException
{
OutputStream l_is;
Writer l_r;
IOException l_ioe;
synchronized(this)
{
if(this.m_living)
{
if( (--this.m_ref_count) <= 0)
{
this.m_living = false;
l_ioe = null;
l_is = getOutputStream();
if(l_is != null)
{
try
{
l_is.close();
}
catch(IOException l_ioe2)
{
l_ioe = l_ioe2;
}
finally
{
super.setOutputStream(null);
}
}
l_r = getWriter();
if(l_r != null)
{
try
{
l_r.close();
}
catch(IOException l_ioe2)
{
l_ioe = l_ioe2;
}
finally
{
super.setWriter(null);
}
}
return l_ioe;
}
}
else
{
throw new AlreadyDisposedException();
}
}
return null;
}
/**
* Set the ByteStream that is to be written to. Normally,
* a stream should be used rather than a reader, so that
* the transformer may use instructions contained in the
* transformation instructions to control the encoding.
*
* @param p_output_stream A valid OutputStream reference.
*/
@Override
public final void setOutputStream(final OutputStream p_output_stream)
{
ReferenceCountedOutputStream l_x;
l_x = ((ReferenceCountedOutputStream)(this.getOutputStream()));
if(l_x != null) l_x = null;
super.setOutputStream(IO.get_output_stream(p_output_stream));
}
/**
* Assign this stream result from another one.
* @param p_result The other stream result to be the blueprint for this
* one.
*/
public final void set_stream_result(final StreamResult p_result)
{
OutputStream l_os;
Writer l_w;
l_os = p_result.getOutputStream();
l_w = p_result.getWriter();
if(p_result instanceof ReferenceCountedStreamResult)
{
if(l_os != null) ((ReferenceCountedOutputStream)l_os).add_ref();
if(l_w != null) ((ReferenceCountedWriter)l_w).add_ref();
}
this.setOutputStream(l_os);
this.setWriter(l_w);
this.setSystemId(p_result.getSystemId());
}
/**
* Set the writer that is to receive the result. Normally,
* a stream should be used rather than a writer, so that
* the transformer may use instructions contained in the
* transformation instructions to control the encoding. However,
* there are times when it is useful to write to a writer,
* such as when using a StringWriter.
*
* @param p_writer A valid Writer reference.
*/
@Override
public final void setWriter(final Writer p_writer)
{
ReferenceCountedWriter l_x;
l_x = ((ReferenceCountedWriter)p_writer);
if(l_x != null) l_x.release();
super.setWriter(IO.get_writer(p_writer,
XML.PREFERED_ENCODING));
}
/**
* Cleanup this input source.
* @throws Throwable From the super implementation.
*/
@Override
protected final void finalize () throws Throwable
{
synchronized(this)
{
if(this.m_living)
{
this.m_ref_count = 1;
this.do_release();
this.m_living = false;
}
this.m_ref_count = 0;
}
super.finalize();
}
}