FileDocCategorySizeDatePackage
SDPOutputStream.javaAPI DocphoneME MR2 API (J2ME)7687Wed May 02 18:00:42 BST 2007gov.nist.microedition.sip

SDPOutputStream.java

/*
 * Portions Copyright  2000-2007 Sun Microsystems, Inc. All Rights
 * Reserved.  Use is subject to license terms.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 only, as published by the Free Software Foundation.
 * 
 * This program 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
 * General Public License version 2 for more details (a copy is
 * included at /legal/license.txt).
 * 
 * You should have received a copy of the GNU General Public License
 * version 2 along with this work; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * 
 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */
/*
 * SDPOutputStream.java
 *
 * Created on Feb 20, 2004
 *
 */
package gov.nist.microedition.sip;

import gov.nist.siplite.message.Request;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;

import javax.microedition.sip.SipConnection;

/**
 * SDP output stream.
 *
 * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
 */

public class SDPOutputStream extends OutputStream {

    /**
     * Constructs a stream for the requested connection.
     * @param connection the associated connection
     */
    public SDPOutputStream(SipConnection connection) {
        this.connection = connection;
        setOpen(true);
    }

    /** The current connection. */
    private SipConnection connection = null;

    /**
     * the ByteArrayOutputStream object wrapped by this class.
     * We cannot just inherit from the ByteArrayOutputStream class because
     * ByteArrayOutputStream.write() does not throw an IOException.
     * (Is it important? Yes. When the parent class does not throw an
     * exception, the child class must not throw the exception, because
     * the child class may be used everywhere in place of the parent class.
     * If the child classes could throw exceptions not declared for parents,
     * we would have undeclared exceptions thrown. And Java does not permit
     * this. So we have to use a wrapper class.)
     */
    private final ByteArrayOutputStream outputStream =
            new ByteArrayOutputStream();

    /** is the stream open? */
    private boolean isOpen;

    /**
     * Convert to a string containing debugging information.
     * @return string containing: class name + hash value + isOpen state
     */
    public String toString() {
        return super.toString()+" isOpen="+isOpen;
    }

    /**
     * Return the ByteArrayOutputStream object wrapped by this class.
     * The problem is that ByteArrayOutputStream methods do not throw
     * IOException, while SDPOutputStream methods should.
     * @return the ByteArrayOutputStream object
     */
    protected ByteArrayOutputStream getByteArrayOutputStream() {
        return outputStream;
    }

    /**
     * check if the stream is open
     * @throws IOException if the stream is closed
     */
    private void checkOpen() throws IOException {
        if (!isOpen) {
            throw new IOException("the output stream has been closed");
        }
    }

    /**
     * Writes the specified byte to the wrapped byte array output stream.
     *
     * @param   b   the byte to be written.
     * @exception  IOException  if the stream is closed.
     */
    public void write(int b) throws IOException {
        checkOpen();
        outputStream.write(b);
    }

    /**
     * Flushes this output stream and forces any buffered output bytes
     * to be written out. The general contract of <code>flush</code> is
     * that calling it is an indication that, if any bytes previously
     * written have been buffered by the implementation of the output
     * stream, such bytes should immediately be written to their
     * intended destination.
     * <p>
     * The <code>flush</code> method of <code>OutputStream</code> does nothing.
     *
     * @exception  IOException  if the stream is closed.
     */
    public void flush() throws IOException {
        outputStream.flush();
    }

    /**
     * Writes <code>b.length</code> bytes from the specified byte array to the
     * wrapped output stream. The general contract for <code>write(b)</code>
     * is that it should have exactly the same effect as the call
     * <code>write(b, 0, b.length)</code>.
     *
     * @param      b   the data.
     * @exception  IOException  if an I/O error occurs.
     * @see        java.io.OutputStream#write(byte[], int, int)
     * @exception  IOException  if the stream is closed.
     */
    public void write(byte[] b) throws IOException {
        checkOpen();
        outputStream.write(b);
    }

    /**
     * Writes <code>len</code> bytes from the specified byte array
     * starting at offset <code>off</code> to the wrapped byte
     * array output stream.
     *
     * @param   b     the data.
     * @param   off   the start offset in the data.
     * @param   len   the number of bytes to write.
     * @exception  IOException  if the stream is closed.
     */
    public void write(byte[] b, int off, int len) throws IOException {
        checkOpen();
        outputStream.write(b, off, len);
    }

    /**
     * Return the status of the output stream (open or closed).
     * When the stream is closed, write() throws an IOException.
     * The open or closed status does not affect the internal
     * ByteArrayOutputStream object.
     * @return true if the stream is open
     */
    public boolean isOpen() {
        return isOpen;
    }

    /**
     * The send() functions use this function to toggle the stream state.
     * (send() cannot call close() because it's done vice versa:
     * close() calls send())
     * @param newOpenState the new state
     */
    protected void setOpen(boolean newOpenState) {
        isOpen = newOpenState;
    }

    /**
     * Close the SDPOutputStream and send the message held by the
     * sip connection
     */
    public void close() throws IOException {
        if (!isOpen) {
            throw new IOException("stream already closed");
        }
        setOpen(false);
        outputStream.close();

        if (connection instanceof SipClientConnectionImpl) {
            SipClientConnectionImpl sipClientConnection =
                    (SipClientConnectionImpl)connection;
            // If the client connection is in a STREAM_OPEN state and
            // the request is an ACK
            // The connection goes into the COMPLETED state
            if (sipClientConnection.state ==
                    SipClientConnectionImpl.STREAM_OPEN) {
                if (sipClientConnection.getMethod().equals(Request.ACK)) {
                    sipClientConnection.state =
                            SipClientConnectionImpl.COMPLETED;
                    try {
                        super.close();
                    } catch (IOException ioe) {
                        ioe.printStackTrace();
                    }
                    return;
                }
            }
        }
        try {
            connection.send();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
        try {
            super.close();
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }
}