/*
* @(#)NxObjectOutputStream.java 1.0
*
* Created on September 18, 2008, 12:59 PM
*
* Copyright 2008 NeXtreme Innovations, Inc. All rights reserved.
* "NeXtreme Innovations" PROPRIETARY/CONFIDENTIAL. Use is subject
* to license terms.
*/
package com.nextreme.opennxserialization.standard.io;
import com.nextreme.opennxserialization.core.io.NxBlockDataOutputStream;
import com.nextreme.opennxserialization.core.io.NxObjectOutput;
import com.nextreme.opennxserialization.core.io.NxSerializationContext;
import com.nextreme.opennxserialization.core.io.NxTypeSurrogateSelector;
import com.nextreme.opennxserialization.core.io.surrogates.NxSerializationSurrogate;
import java.io.IOException;
import java.io.OutputStream;
/**
* NxObjectOutputStream class.
*
* @version 1.0, September 18, 2008
*/
public class NxObjectOutputStream
extends OutputStream implements NxObjectOutput
{
/**
* working arrays initialized on demand by readUTF
*/
private NxBlockDataOutputStream mOutput;
private NxSerializationContext mContext;
private NxTypeSurrogateSelector mSelector;
/**
* Creates an ObjectOutputStream that writes to the specified OutputStream.
* This constructor writes the serialization stream header to the
* underlying stream; callers may wish to flush the stream immediately to
* ensure that constructors for receiving ObjectInputStreams will not block
* when reading the header.
*
* <p>If a security manager is installed, this constructor will check for
* the "enableSubclassImplementation" SerializablePermission when invoked
* directly or indirectly by the constructor of a subclass which overrides
* the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
* methods.
*
* @param out output stream to write to
* @throws IOException if an I/O error occurs while writing stream header
* @throws SecurityException if untrusted subclass illegally overrides
* security-sensitive methods
* @throws NullPointerException if <code>out</code> is <code>null</code>
*/
public NxObjectOutputStream(OutputStream out) throws IOException {
this.mOutput = new NxBlockDataOutputStream(out);
this.mSelector = NxTypeSurrogateSelectorImpl.getDefault();
this.mContext = new NxSerializationContext(this.mSelector);
this.mContext.putUserItem("__bout", this.mOutput);
}
/**
* Creates an ObjectOutputStream that writes to the specified OutputStream.
* This constructor writes the serialization stream header to the
* underlying stream; callers may wish to flush the stream immediately to
* ensure that constructors for receiving ObjectInputStreams will not block
* when reading the header.
*
* <p>If a security manager is installed, this constructor will check for
* the "enableSubclassImplementation" SerializablePermission when invoked
* directly or indirectly by the constructor of a subclass which overrides
* the ObjectOutputStream.putFields or ObjectOutputStream.writeUnshared
* methods.
*
* @param out output stream to write to
* @param selector type surrogate selector to use
* @throws IOException if an I/O error occurs while writing stream header
* @throws SecurityException if untrusted subclass illegally overrides
* security-sensitive methods
* @throws NullPointerException if <code>out</code> is <code>null</code>
*/
public NxObjectOutputStream(OutputStream out, NxTypeSurrogateSelector selector) throws IOException {
this.mOutput = new NxBlockDataOutputStream(out);
this.mContext = new NxSerializationContext(selector);
this.mSelector = this.mContext.getSurrogateSelector();
this.mContext.putUserItem("__bout", this.mOutput);
}
/**
* Returns the current <see cref="NxSerializationContext"/> object.
*
* @return the current serialzation context
*/
public NxSerializationContext getContext() {
return this.mContext;
}
/**
* Returns the underlying InputStream object.
*/
public OutputStream getBaseStream() {
return this.mOutput;
}
/**
* Writes the specified byte (the low eight bits of the argument
* <code>b</code>) to the underlying output stream. If no exception
* is thrown, the counter <code>written</code> is incremented by
* <code>1</code>.
* <p>
* Implements the <code>write</code> method of <code>OutputStream</code>.
*
* @param b the <code>byte</code> to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public synchronized void write(int b) throws IOException {
this.mOutput.write(b);
}
/**
* Writes <code>len</code> bytes from the specified byte array
* starting at offset <code>off</code> to the underlying output stream.
* If no exception is thrown, the counter <code>written</code> is
* incremented by <code>len</code>.
*
* @param b the data.
* @param off the start offset in the data.
* @param len the number of bytes to write.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
@Override
public synchronized void write(byte b[], int off, int len) throws IOException {
this.mOutput.write(b, off, len);
}
/**
* Flushes this data output stream. This forces any buffered output
* bytes to be written out to the stream.
* <p>
* The <code>flush</code> method of <code>DataOutputStream</code>
* calls the <code>flush</code> method of its underlying output stream.
*
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
this.mOutput.flush();
}
/**
* Writes a <code>boolean</code> to the underlying output stream as
* a 1-byte value. The value <code>true</code> is written out as the
* value <code>(byte)1</code>; the value <code>false</code> is
* written out as the value <code>(byte)0</code>. If no exception is
* thrown, the counter <code>written</code> is incremented by
* <code>1</code>.
*
* @param v a <code>boolean</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeBoolean(boolean v) throws IOException {
this.mOutput.writeBoolean(v);
}
/**
* Writes out a <code>byte</code> to the underlying output stream as
* a 1-byte value. If no exception is thrown, the counter
* <code>written</code> is incremented by <code>1</code>.
*
* @param v a <code>byte</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeByte(int v) throws IOException {
this.mOutput.writeByte(v);
}
/**
* Writes a <code>short</code> to the underlying output stream as two
* bytes, high byte first. If no exception is thrown, the counter
* <code>written</code> is incremented by <code>2</code>.
*
* @param v a <code>short</code> to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeShort(int v) throws IOException {
this.mOutput.writeShort(v);
}
/**
* Writes a <code>char</code> to the underlying output stream as a
* 2-byte value, high byte first. If no exception is thrown, the
* counter <code>written</code> is incremented by <code>2</code>.
*
* @param v a <code>char</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeChar(int v) throws IOException {
this.mOutput.writeChar(v);
}
/**
* Writes an <code>int</code> to the underlying output stream as four
* bytes, high byte first. If no exception is thrown, the counter
* <code>written</code> is incremented by <code>4</code>.
*
* @param v an <code>int</code> to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeInt(int v) throws IOException {
this.mOutput.writeInt(v);
}
/**
* Writes a <code>long</code> to the underlying output stream as eight
* bytes, high byte first. In no exception is thrown, the counter
* <code>written</code> is incremented by <code>8</code>.
*
* @param v a <code>long</code> to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeLong(long v) throws IOException {
this.mOutput.writeLong(v);
}
/**
* Converts the float argument to an <code>int</code> using the
* <code>floatToIntBits</code> method in class <code>Float</code>,
* and then writes that <code>int</code> value to the underlying
* output stream as a 4-byte quantity, high byte first. If no
* exception is thrown, the counter <code>written</code> is
* incremented by <code>4</code>.
*
* @param v a <code>float</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.lang.Float#floatToIntBits(float)
*/
public final void writeFloat(float v) throws IOException {
this.mOutput.writeFloat(v);
}
/**
* Converts the double argument to a <code>long</code> using the
* <code>doubleToLongBits</code> method in class <code>Double</code>,
* and then writes that <code>long</code> value to the underlying
* output stream as an 8-byte quantity, high byte first. If no
* exception is thrown, the counter <code>written</code> is
* incremented by <code>8</code>.
*
* @param v a <code>double</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
* @see java.lang.Double#doubleToLongBits(double)
*/
public final void writeDouble(double v) throws IOException {
this.mOutput.writeDouble(v);
}
/**
* Writes out the string to the underlying output stream as a
* sequence of bytes. Each character in the string is written out, in
* sequence, by discarding its high eight bits. If no exception is
* thrown, the counter <code>written</code> is incremented by the
* length of <code>s</code>.
*
* @param s a string of bytes to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.FilterOutputStream#out
*/
public final void writeBytes(String s) throws IOException {
this.mOutput.writeBytes(s);
}
/**
* Writes a string to the underlying output stream as a sequence of
* characters. Each character is written to the data output stream as
* if by the <code>writeChar</code> method. If no exception is
* thrown, the counter <code>written</code> is incremented by twice
* the length of <code>s</code>.
*
* @param s a <code>String</code> value to be written.
* @exception IOException if an I/O error occurs.
* @see java.io.DataOutputStream#writeChar(int)
* @see java.io.FilterOutputStream#out
*/
public final void writeChars(String s) throws IOException {
this.mOutput.writeChars(s);
}
/**
* Writes a string to the underlying output stream using
* <a href="DataInput.html#modified-utf-8">modified UTF-8</a>
* encoding in a machine-independent manner.
* <p>
* First, two bytes are written to the output stream as if by the
* <code>writeShort</code> method giving the number of bytes to
* follow. This value is the number of bytes actually written out,
* not the length of the string. Following the length, each character
* of the string is output, in sequence, using the modified UTF-8 encoding
* for the character. If no exception is thrown, the counter
* <code>written</code> is incremented by the total number of
* bytes written to the output stream. This will be at least two
* plus the length of <code>str</code>, and at most two plus
* thrice the length of <code>str</code>.
*
* @param str a string to be written.
* @exception IOException if an I/O error occurs.
*/
public final void writeUTF(String str) throws IOException {
this.mOutput.writeUTF(str);
}
/**
* Returns the current value of the counter <code>written</code>,
* the number of bytes written to this data output stream so far.
* If the counter overflows, it will be wrapped to Integer.MAX_VALUE.
*
* @return the value of the <code>written</code> field.
* @see java.io.DataOutputStream#written
*/
public final int size() {
return this.mOutput.size();
}
/**
* Write the specified object to the ObjectOutputStream. Objects referenced by this
* object are written transitively so that a complete equivalent graph of
* objects can be reconstructed by an ObjectInputStream.
*
* <p>Exceptions are thrown for problems with the OutputStream and for
* classes that should not be serialized. All exceptions are fatal to the
* OutputStream, which is left in an indeterminate state, and it is up to
* the caller to ignore or recover the stream state.
*
* @throws IOException Any exception thrown by the underlying
* OutputStream.
*/
public final void writeObject(Object obj)
throws IOException
{
try
{
// Find an appropriate surrogate for the object
NxSerializationSurrogate surrogate =
this.mSelector.getSurrogateForObject(obj);
// write type handle
surrogate.writeHandle(this, obj);
surrogate.writeObject(this, obj);
}
catch (Exception ex)
{
throw new IOException(ex);
}
}
/**
* Write the specified object to the ObjectOutputStream. Objects referenced by this
* object are written transitively so that a complete equivalent graph of
* objects can be reconstructed by an ObjectInputStream.
*
* <p>Exceptions are thrown for problems with the OutputStream and for
* classes that should not be serialized. All exceptions are fatal to the
* OutputStream, which is left in an indeterminate state, and it is up to
* the caller to ignore or recover the stream state.
*
* @param obj the object to be written
* @param objClass the class surrogate to use for writing the object.
* @exception IOException Any of the usual Input/Output related exceptions.
* @throws IOException Any exception thrown by the underlying
* OutputStream.
*/
public void writeObject(Object obj, Class objClass)
throws IOException
{
if (obj == null)
throw new NullPointerException("obj");
if (objClass == null)
throw new NullPointerException("objClass");
try
{
NxSerializationSurrogate surrogate = this.mSelector.getSurrogateForType(objClass);
surrogate.writeObject(this, obj);
}
catch (Exception ex)
{
throw new IOException(ex);
}
}
}