~ubuntu-branches/ubuntu/oneiric/libjboss-remoting-java/oneiric

« back to all changes in this revision

Viewing changes to src/main/org/jboss/remoting/transport/multiplex/MultiplexingOutputStream.java

  • Committer: Package Import Robot
  • Author(s): Torsten Werner
  • Date: 2011-09-09 14:01:03 UTC
  • mfrom: (1.1.6 upstream)
  • Revision ID: package-import@ubuntu.com-20110909140103-hqokx61534tas9rg
Tags: 2.5.3.SP1-1
* Newer but not newest upstream release. Do not build samples.
* Change debian/watch to upstream's svn repo.
* Add patch to fix compile error caused by tomcat update.
  (Closes: #628303)
* Switch to source format 3.0.
* Switch to debhelper level 7.
* Remove useless Depends.
* Update Standards-Version: 3.9.2.
* Update README.source.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
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.
 
6
*
 
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.
 
11
*
 
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.
 
16
*
 
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.
 
21
*/
 
22
 
 
23
/*
 
24
 * Created on Jul 22, 2005
 
25
 */
 
26
 
 
27
package org.jboss.remoting.transport.multiplex;
 
28
 
 
29
import java.io.IOException;
 
30
import java.io.OutputStream;
 
31
import java.net.SocketException;
 
32
 
 
33
import org.jboss.logging.Logger;
 
34
 
 
35
/**
 
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>.
 
41
 * <p>
 
42
 * Copyright (c) 2005
 
43
 * <p>
 
44
 * @author <a href="mailto:r.sigal@computer.org">Ron Sigal</a>
 
45
 * 
 
46
 * @deprecated As of release 2.4.0 the multiplex transport will no longer be actively supported.
 
47
 */
 
48
public class MultiplexingOutputStream extends OutputStream
 
49
{
 
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;
 
58
   
 
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;
 
63
 
 
64
   private byte[] oneByte = new byte[1];
 
65
   private byte[] fourBytes = new byte[4];
 
66
   
 
67
/**
 
68
 * 
 
69
 * @param manager
 
70
 * @param socketId
 
71
 */
 
72
   public MultiplexingOutputStream(MultiplexingManager manager, SocketId socketId)
 
73
   {
 
74
      this(manager, null, socketId);
 
75
   }
 
76
   
 
77
   
 
78
/**
 
79
 * 
 
80
 * @param manager
 
81
 * @param virtualSocket
 
82
 * @param socketId
 
83
 */
 
84
   public MultiplexingOutputStream(MultiplexingManager manager, VirtualSocket virtualSocket, SocketId socketId)
 
85
   {
 
86
      this.manager = manager;
 
87
      this.virtualSocket = virtualSocket;
 
88
      this.socketId = socketId;
 
89
      this.outputMultiplexor = manager.getOutputMultiplexor();
 
90
   }
 
91
   
 
92
//////////////////////////////////////////////////////////////////////////////////////////////////
 
93
///                  The following methods are required of all OutputStreams                  '///
 
94
//////////////////////////////////////////////////////////////////////////////////////////////////
 
95
 
 
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
 *************************************************************************************************/
 
103
 
 
104
   
 
105
/**
 
106
 * See superclass javadoc.
 
107
 */
 
108
   public void close() throws IOException
 
109
   {
 
110
      log.debug("MultiplexingOutputStream.close() entered");
 
111
      
 
112
      if (closed)
 
113
         return;
 
114
         
 
115
      closed = true;
 
116
      
 
117
      if (virtualSocket != null)
 
118
         virtualSocket.close();
 
119
   }
 
120
   
 
121
   
 
122
/**
 
123
 * See superclass javadoc.
 
124
 */
 
125
   public void flush() throws IOException
 
126
   {
 
127
      // Could use flush() to raise priority of messages waiting in OutputMultiplexor's write queue.
 
128
   }
 
129
   
 
130
   
 
131
/**
 
132
 * See superclass javadoc.
 
133
 */
 
134
   public void write(int i) throws IOException
 
135
   {
 
136
      checkStatus();
 
137
      oneByte[0] = (byte) i;
 
138
      outputMultiplexor.write(manager, socketId, oneByte);
 
139
   }
 
140
   
 
141
/**
 
142
 * See superclass javadoc.
 
143
 */
 
144
   public void write(byte[] array) throws IOException, NullPointerException
 
145
   { 
 
146
      checkStatus();
 
147
      outputMultiplexor.write(manager, socketId, array);
 
148
   }
 
149
   
 
150
   
 
151
/**
 
152
 * See superclass javadoc.
 
153
 */
 
154
   public void write(byte[] array, int off, int len)
 
155
   throws IOException, NullPointerException, IndexOutOfBoundsException
 
156
   { 
 
157
      checkStatus();
 
158
 
 
159
      if (array == null)
 
160
         throw new NullPointerException();
 
161
      
 
162
      if (off < 0 || len < 0 || off + len > array.length)
 
163
         throw new IndexOutOfBoundsException();
 
164
      
 
165
      byte[] subArray = new byte[len];
 
166
      
 
167
      for (int i = 0; i < len; i++)
 
168
         subArray[i] = array[off + i];
 
169
 
 
170
      outputMultiplexor.write(manager, socketId, subArray);
 
171
   }
 
172
   
 
173
  
 
174
//////////////////////////////////////////////////////////////////////////////////////////////////
 
175
///              The following methods are specific to MultiplexingOutputStream               '///
 
176
//////////////////////////////////////////////////////////////////////////////////////////////////
 
177
 
 
178
   protected void setWriteException(IOException e)
 
179
   {
 
180
      writeException = e;
 
181
   }
 
182
   
 
183
   
 
184
/**
 
185
 * <code>writeInt()</code> is borrowed from <code>DataOutputStream</code>.
 
186
 * It saves the extra expense of creating a <code>DataOutputStream</code>. 
 
187
 * @param i
 
188
 * @throws IOException
 
189
 */
 
190
   public void writeInt(int i) throws IOException
 
191
   {
 
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);
 
197
   }
 
198
   
 
199
/**
 
200
 * Determines how to handle a write request depending on what this socket knows about the state
 
201
 * of the peer socket.
 
202
 * <p>
 
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.
 
205
 * <p>
 
206
 * <ol>
 
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.
 
212
 * </ol>
 
213
 * <p>
 
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").
 
219
 * <p>
 
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");
 
223
 * <p>
 
224
 * Note.  This discussion is based on empirical observation on a linux system, not on examination of code.
 
225
 * Your mileage may vary.
 
226
 */
 
227
   protected void checkStatus() throws IOException
 
228
   {
 
229
      if (closed)
 
230
         throw new SocketException("Socket closed");
 
231
      
 
232
      if (outputShutdown)
 
233
         throw new SocketException("Broken pipe");
 
234
      
 
235
      if (writeException != null)
 
236
         throw writeException;
 
237
      
 
238
      switch (connectionState)
 
239
      {
 
240
         case OPEN:
 
241
            return;
 
242
 
 
243
         case CONNECTION_RESET:
 
244
            connectionState = CLOSED;
 
245
            return;
 
246
            
 
247
         case CLOSED:
 
248
            throw new SocketException("Broken pipe");
 
249
            
 
250
         default:
 
251
            log.error("unrecognized connection state: " + connectionState);
 
252
      }
 
253
   }
 
254
   
 
255
   
 
256
/**
 
257
 * 
 
258
 */
 
259
   protected void handleRemoteDisconnect()
 
260
   {
 
261
      log.debug("entering handleRemoteDisconnect()");
 
262
      
 
263
      switch (connectionState)
 
264
      {
 
265
         case OPEN:
 
266
            connectionState = CONNECTION_RESET;
 
267
            return;
 
268
            
 
269
         default:
 
270
            connectionState = CLOSED;
 
271
            log.error("invalid connection state in handleRemoteDisconnect(): " + connectionState);
 
272
      }
 
273
   }
 
274
   
 
275
   
 
276
/**
 
277
 * 
 
278
 */
 
279
   protected void shutdown()
 
280
   {
 
281
      outputShutdown = true;
 
282
   }
 
283
   
 
284
   
 
285
/**
 
286
 * @param i
 
287
 * @param brackets
 
288
 * @throws IOException
 
289
 */
 
290
   protected void write(int i, int brackets) throws IOException
 
291
   {
 
292
      log.debug("brackets: " + brackets);
 
293
      oneByte[0] = (byte) i;
 
294
      outputMultiplexor.write(manager, socketId, oneByte, brackets);
 
295
   }
 
296
   
 
297
   
 
298
/**
 
299
 * @param i
 
300
 * @param brackets
 
301
 * @throws IOException
 
302
 */
 
303
   protected void writeInt(int i, int brackets) throws IOException
 
304
   {
 
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);
 
311
   }
 
312
}