2
* JBoss, Home of Professional Open Source
3
* Copyright 2005, JBoss Inc., and individual contributors as indicated
4
* by the @authors tag. See the copyright.txt in the distribution for a
5
* full listing of individual contributors.
7
* This is free software; you can redistribute it and/or modify it
8
* under the terms of the GNU Lesser General Public License as
9
* published by the Free Software Foundation; either version 2.1 of
10
* the License, or (at your option) any later version.
12
* This software is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this software; if not, write to the Free
19
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
24
* Created on Jul 22, 2005
27
package org.jboss.remoting.transport.multiplex;
29
import java.io.IOException;
30
import java.io.OutputStream;
31
import java.net.SocketException;
33
import org.jboss.logging.Logger;
36
* <code>MultiplexingOutputStream</code> is the class returned by
37
* <code>VirtualSocket.getOutputStream()</code>.
38
* It supports the methods and behavior implemented by the <code>OutputStream</code> returned by
39
* <code>java.net.Socket.getOutputStream()</code>. For more information about the behavior
40
* of the methods, see the javadoc for <code>java.io.OutputStream</code>.
44
* @author <a href="mailto:r.sigal@computer.org">Ron Sigal</a>
46
* @deprecated As of release 2.4.0 the multiplex transport will no longer be actively supported.
48
public class MultiplexingOutputStream extends OutputStream
50
protected static final Logger log = Logger.getLogger(MultiplexingOutputStream.class);
51
private MultiplexingManager manager;
52
private OutputMultiplexor outputMultiplexor;
53
private VirtualSocket virtualSocket;
54
private SocketId socketId;
55
private boolean outputShutdown = false;
56
private boolean closed = false;
57
private IOException writeException;
59
private static final int OPEN = 0;
60
private static final int CONNECTION_RESET = 1;
61
private static final int CLOSED = 2;
62
private int connectionState = OPEN;
64
private byte[] oneByte = new byte[1];
65
private byte[] fourBytes = new byte[4];
72
public MultiplexingOutputStream(MultiplexingManager manager, SocketId socketId)
74
this(manager, null, socketId);
81
* @param virtualSocket
84
public MultiplexingOutputStream(MultiplexingManager manager, VirtualSocket virtualSocket, SocketId socketId)
86
this.manager = manager;
87
this.virtualSocket = virtualSocket;
88
this.socketId = socketId;
89
this.outputMultiplexor = manager.getOutputMultiplexor();
92
//////////////////////////////////////////////////////////////////////////////////////////////////
93
/// The following methods are required of all OutputStreams '///
94
//////////////////////////////////////////////////////////////////////////////////////////////////
96
/*************************************************************************************************
97
ok: public void write(int b) throws IOException;
98
ok: public void write(byte b[]) throws IOException;
99
ok: public void write(byte b[], int off, int len) throws IOException;
100
public void flush() throws IOException;
101
ok: public void close() throws IOException;
102
*************************************************************************************************/
106
* See superclass javadoc.
108
public void close() throws IOException
110
log.debug("MultiplexingOutputStream.close() entered");
117
if (virtualSocket != null)
118
virtualSocket.close();
123
* See superclass javadoc.
125
public void flush() throws IOException
127
// Could use flush() to raise priority of messages waiting in OutputMultiplexor's write queue.
132
* See superclass javadoc.
134
public void write(int i) throws IOException
137
oneByte[0] = (byte) i;
138
outputMultiplexor.write(manager, socketId, oneByte);
142
* See superclass javadoc.
144
public void write(byte[] array) throws IOException, NullPointerException
147
outputMultiplexor.write(manager, socketId, array);
152
* See superclass javadoc.
154
public void write(byte[] array, int off, int len)
155
throws IOException, NullPointerException, IndexOutOfBoundsException
160
throw new NullPointerException();
162
if (off < 0 || len < 0 || off + len > array.length)
163
throw new IndexOutOfBoundsException();
165
byte[] subArray = new byte[len];
167
for (int i = 0; i < len; i++)
168
subArray[i] = array[off + i];
170
outputMultiplexor.write(manager, socketId, subArray);
174
//////////////////////////////////////////////////////////////////////////////////////////////////
175
/// The following methods are specific to MultiplexingOutputStream '///
176
//////////////////////////////////////////////////////////////////////////////////////////////////
178
protected void setWriteException(IOException e)
185
* <code>writeInt()</code> is borrowed from <code>DataOutputStream</code>.
186
* It saves the extra expense of creating a <code>DataOutputStream</code>.
188
* @throws IOException
190
public void writeInt(int i) throws IOException
192
fourBytes[0] = (byte) ((i >>> 24) & 0xff);
193
fourBytes[1] = (byte) ((i >>> 16) & 0xff);
194
fourBytes[2] = (byte) ((i >>> 8) & 0xff);
195
fourBytes[3] = (byte) ((i >>> 0) & 0xff);
196
outputMultiplexor.write(manager, socketId, fourBytes);
200
* Determines how to handle a write request depending on what this socket knows about the state
201
* of the peer socket.
203
* Once this socket knows that the peer socket has closed, no more write requests will be honored.
204
* There seem to be two ways for a socket A to learn that its peer socket B has closed.
207
* <li>If socket A has executed a write, but no subsequent write is performed on B,
208
* then the acknowledgement of the write will carry back the information that B has closed.
209
* <li>If socket B has no pending acknowledgements to send at the time it closes, and then socket A
210
* does a write after B has closed, the (negative) acknowledgement of the write will carry back
211
* the information that B has closed.
214
* Java seems to respond differently to the two cases. The first write after this socket has learned
215
* of the peer's closing through the first scenario will result in a SocketException("Connection reset").
216
* In the second scenario, the first write by this socket after the peer has closed
217
* will quietly fail (no exception is thrown). All subsequent writes after either of these two
218
* scenarios will result in a SocketException("Broken pipe").
220
* Currently, MultiplexingOutputStream implements only a simplified version of this behavior. In
221
* particular, it allows in all cases one write to silently fail, after which all writes result in a
222
* SocketException("Broken pipe");
224
* Note. This discussion is based on empirical observation on a linux system, not on examination of code.
225
* Your mileage may vary.
227
protected void checkStatus() throws IOException
230
throw new SocketException("Socket closed");
233
throw new SocketException("Broken pipe");
235
if (writeException != null)
236
throw writeException;
238
switch (connectionState)
243
case CONNECTION_RESET:
244
connectionState = CLOSED;
248
throw new SocketException("Broken pipe");
251
log.error("unrecognized connection state: " + connectionState);
259
protected void handleRemoteDisconnect()
261
log.debug("entering handleRemoteDisconnect()");
263
switch (connectionState)
266
connectionState = CONNECTION_RESET;
270
connectionState = CLOSED;
271
log.error("invalid connection state in handleRemoteDisconnect(): " + connectionState);
279
protected void shutdown()
281
outputShutdown = true;
288
* @throws IOException
290
protected void write(int i, int brackets) throws IOException
292
log.debug("brackets: " + brackets);
293
oneByte[0] = (byte) i;
294
outputMultiplexor.write(manager, socketId, oneByte, brackets);
301
* @throws IOException
303
protected void writeInt(int i, int brackets) throws IOException
305
log.debug("brackets: " + brackets);
306
fourBytes[0] = (byte) ((i >>> 24) & 0xff);
307
fourBytes[1] = (byte) ((i >>> 16) & 0xff);
308
fourBytes[2] = (byte) ((i >>> 8) & 0xff);
309
fourBytes[3] = (byte) ((i >>> 0) & 0xff);
310
outputMultiplexor.write(manager, socketId, fourBytes, brackets);