001: /*
002: * Portions Copyright 2000-2007 Sun Microsystems, Inc. All Rights
003: * Reserved. Use is subject to license terms.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: /*
026: * SDPOutputStream.java
027: *
028: * Created on Feb 20, 2004
029: *
030: */
031: package gov.nist.microedition.sip;
032:
033: import gov.nist.siplite.message.Request;
034:
035: import java.io.ByteArrayOutputStream;
036: import java.io.IOException;
037: import java.io.OutputStream;
038:
039: import javax.microedition.sip.SipConnection;
040:
041: /**
042: * SDP output stream.
043: *
044: * <a href="{@docRoot}/uncopyright.html">This code is in the public domain.</a>
045: */
046:
047: public class SDPOutputStream extends OutputStream {
048:
049: /**
050: * Constructs a stream for the requested connection.
051: * @param connection the associated connection
052: */
053: public SDPOutputStream(SipConnection connection) {
054: this .connection = connection;
055: setOpen(true);
056: }
057:
058: /** The current connection. */
059: private SipConnection connection = null;
060:
061: /**
062: * the ByteArrayOutputStream object wrapped by this class.
063: * We cannot just inherit from the ByteArrayOutputStream class because
064: * ByteArrayOutputStream.write() does not throw an IOException.
065: * (Is it important? Yes. When the parent class does not throw an
066: * exception, the child class must not throw the exception, because
067: * the child class may be used everywhere in place of the parent class.
068: * If the child classes could throw exceptions not declared for parents,
069: * we would have undeclared exceptions thrown. And Java does not permit
070: * this. So we have to use a wrapper class.)
071: */
072: private final ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
073:
074: /** is the stream open? */
075: private boolean isOpen;
076:
077: /**
078: * Convert to a string containing debugging information.
079: * @return string containing: class name + hash value + isOpen state
080: */
081: public String toString() {
082: return super .toString() + " isOpen=" + isOpen;
083: }
084:
085: /**
086: * Return the ByteArrayOutputStream object wrapped by this class.
087: * The problem is that ByteArrayOutputStream methods do not throw
088: * IOException, while SDPOutputStream methods should.
089: * @return the ByteArrayOutputStream object
090: */
091: protected ByteArrayOutputStream getByteArrayOutputStream() {
092: return outputStream;
093: }
094:
095: /**
096: * check if the stream is open
097: * @throws IOException if the stream is closed
098: */
099: private void checkOpen() throws IOException {
100: if (!isOpen) {
101: throw new IOException("the output stream has been closed");
102: }
103: }
104:
105: /**
106: * Writes the specified byte to the wrapped byte array output stream.
107: *
108: * @param b the byte to be written.
109: * @exception IOException if the stream is closed.
110: */
111: public void write(int b) throws IOException {
112: checkOpen();
113: outputStream.write(b);
114: }
115:
116: /**
117: * Flushes this output stream and forces any buffered output bytes
118: * to be written out. The general contract of <code>flush</code> is
119: * that calling it is an indication that, if any bytes previously
120: * written have been buffered by the implementation of the output
121: * stream, such bytes should immediately be written to their
122: * intended destination.
123: * <p>
124: * The <code>flush</code> method of <code>OutputStream</code> does nothing.
125: *
126: * @exception IOException if the stream is closed.
127: */
128: public void flush() throws IOException {
129: outputStream.flush();
130: }
131:
132: /**
133: * Writes <code>b.length</code> bytes from the specified byte array to the
134: * wrapped output stream. The general contract for <code>write(b)</code>
135: * is that it should have exactly the same effect as the call
136: * <code>write(b, 0, b.length)</code>.
137: *
138: * @param b the data.
139: * @exception IOException if an I/O error occurs.
140: * @see java.io.OutputStream#write(byte[], int, int)
141: * @exception IOException if the stream is closed.
142: */
143: public void write(byte[] b) throws IOException {
144: checkOpen();
145: outputStream.write(b);
146: }
147:
148: /**
149: * Writes <code>len</code> bytes from the specified byte array
150: * starting at offset <code>off</code> to the wrapped byte
151: * array output stream.
152: *
153: * @param b the data.
154: * @param off the start offset in the data.
155: * @param len the number of bytes to write.
156: * @exception IOException if the stream is closed.
157: */
158: public void write(byte[] b, int off, int len) throws IOException {
159: checkOpen();
160: outputStream.write(b, off, len);
161: }
162:
163: /**
164: * Return the status of the output stream (open or closed).
165: * When the stream is closed, write() throws an IOException.
166: * The open or closed status does not affect the internal
167: * ByteArrayOutputStream object.
168: * @return true if the stream is open
169: */
170: public boolean isOpen() {
171: return isOpen;
172: }
173:
174: /**
175: * The send() functions use this function to toggle the stream state.
176: * (send() cannot call close() because it's done vice versa:
177: * close() calls send())
178: * @param newOpenState the new state
179: */
180: protected void setOpen(boolean newOpenState) {
181: isOpen = newOpenState;
182: }
183:
184: /**
185: * Close the SDPOutputStream and send the message held by the
186: * sip connection
187: */
188: public void close() throws IOException {
189: if (!isOpen) {
190: throw new IOException("stream already closed");
191: }
192: setOpen(false);
193: outputStream.close();
194:
195: if (connection instanceof SipClientConnectionImpl) {
196: SipClientConnectionImpl sipClientConnection = (SipClientConnectionImpl) connection;
197: // If the client connection is in a STREAM_OPEN state and
198: // the request is an ACK
199: // The connection goes into the COMPLETED state
200: if (sipClientConnection.state == SipClientConnectionImpl.STREAM_OPEN) {
201: if (sipClientConnection.getMethod().equals(Request.ACK)) {
202: sipClientConnection.state = SipClientConnectionImpl.COMPLETED;
203: try {
204: super .close();
205: } catch (IOException ioe) {
206: ioe.printStackTrace();
207: }
208: return;
209: }
210: }
211: }
212: try {
213: connection.send();
214: } catch (IOException ioe) {
215: ioe.printStackTrace();
216: }
217: try {
218: super .close();
219: } catch (IOException ioe) {
220: ioe.printStackTrace();
221: }
222: }
223: }
|