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

« back to all changes in this revision

Viewing changes to src/main/org/jboss/remoting/stream/StreamHandler.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
package org.jboss.remoting.stream;
 
24
 
 
25
import org.jboss.logging.Logger;
 
26
import org.jboss.remoting.Client;
 
27
import org.jboss.remoting.InvokerLocator;
 
28
 
 
29
import java.io.IOException;
 
30
import java.io.InputStream;
 
31
 
 
32
/**
 
33
 * This is the server side proxy back to the orginal stream
 
34
 * on the client side.  It implements InputStream, so can be
 
35
 * passed and acted on by the server handler as a regular InputStream
 
36
 * type.  For all the InputStream methods, it should behave EXACTLY
 
37
 * like a local InputStream with the one exception being that it
 
38
 * will sometimes throw IOExceptions based on network exceptions
 
39
 * or in the case when the method does not throw an IOException, throwing
 
40
 * a RuntimeException if network problem (however none of the method
 
41
 * signatures are changed).
 
42
 * <p/>
 
43
 * Internally, it will use remoting to callback to the client.
 
44
 *
 
45
 * @author <a href="mailto:tom.elrod@jboss.com">Tom Elrod</a>
 
46
 */
 
47
public class StreamHandler extends InputStream //implements InvocationHandler
 
48
{
 
49
   private InvokerLocator streamServerLocator = null;
 
50
   private Client streamClient = null;
 
51
 
 
52
   private static final Logger log = Logger.getLogger(StreamHandler.class);
 
53
 
 
54
   // The remoting invocation methods the match the InputStream metnhods.
 
55
   public static final String READ = "read()";
 
56
   public static final String AVAILABLE = "available()";
 
57
   public static final String CLOSE = "close()";
 
58
   public static final String RESET = "reset()";
 
59
   public static final String MARKSUPPORTED = "markSupported()";
 
60
   public static final String MARKREADLIMIT = "mark(int readlimit)";
 
61
   public static final String SKIP = "skip(long n)";
 
62
   public static final String READBYTEARRAY = "read(byte b[])";
 
63
   public static final String READOFFSET = "read(byte b[], int off, int len)";
 
64
 
 
65
   /**
 
66
    * Constructor requiring the locator url back to the client's
 
67
    * StreamServer connector (actually the connector's server invoker).
 
68
    *
 
69
    * @param locatorURL
 
70
    * @throws Exception
 
71
    */
 
72
   //private StreamHandler(String locatorURL) throws Exception
 
73
   public StreamHandler(String locatorURL) throws Exception
 
74
   {
 
75
      streamServerLocator = new InvokerLocator(locatorURL);
 
76
      streamClient = new Client(streamServerLocator);
 
77
      streamClient.connect();
 
78
   }
 
79
 
 
80
   /**
 
81
    * Returns the number of bytes that can be read (or skipped over) from
 
82
    * this input stream without blocking by the next caller of a method for
 
83
    * this input stream.  The next caller might be the same thread or or
 
84
    * another thread.
 
85
    * <p/>
 
86
    * <p> The <code>available</code> method for class <code>InputStream</code>
 
87
    * always returns <code>0</code>.
 
88
    * <p/>
 
89
    * <p> This method should be overridden by subclasses.
 
90
    *
 
91
    * @return the number of bytes that can be read from this input stream
 
92
    *         without blocking.
 
93
    * @throws java.io.IOException if an I/O error occurs.
 
94
    */
 
95
   public int available() throws IOException
 
96
   {
 
97
      int readInt = 0;
 
98
 
 
99
      try
 
100
      {
 
101
         Integer retInt = (Integer) streamClient.invoke(new StreamCallPayload(AVAILABLE));
 
102
         if(retInt != null)
 
103
         {
 
104
            readInt = retInt.intValue();
 
105
         }
 
106
      }
 
107
      catch(Throwable throwable)
 
108
      {
 
109
         log.debug("Error getting available from client stream.", throwable);
 
110
         throw new IOException(throwable.getMessage());
 
111
      }
 
112
      return readInt;
 
113
   }
 
114
 
 
115
   /**
 
116
    * Closes this input stream and releases any system resources associated
 
117
    * with the stream.
 
118
    * <p/>
 
119
    * <p> The <code>close</code> method of <code>InputStream</code> does
 
120
    * nothing.
 
121
    *
 
122
    * @throws java.io.IOException if an I/O error occurs.
 
123
    */
 
124
   public void close() throws IOException
 
125
   {
 
126
      try
 
127
      {
 
128
         streamClient.invoke(new StreamCallPayload(CLOSE));
 
129
      }
 
130
      catch(Throwable throwable)
 
131
      {
 
132
         log.debug("Error closing client stream.", throwable);
 
133
         throw new IOException(throwable.getMessage());
 
134
      }
 
135
   }
 
136
 
 
137
   /**
 
138
    * Repositions this stream to the position at the time the
 
139
    * <code>mark</code> method was last called on this input stream.
 
140
    * <p/>
 
141
    * <p> The general contract of <code>reset</code> is:
 
142
    * <p/>
 
143
    * <p><ul>
 
144
    * <p/>
 
145
    * <li> If the method <code>markSupported</code> returns
 
146
    * <code>true</code>, then:
 
147
    * <p/>
 
148
    * <ul><li> If the method <code>mark</code> has not been called since
 
149
    * the stream was created, or the number of bytes read from the stream
 
150
    * since <code>mark</code> was last called is larger than the argument
 
151
    * to <code>mark</code> at that last call, then an
 
152
    * <code>IOException</code> might be thrown.
 
153
    * <p/>
 
154
    * <li> If such an <code>IOException</code> is not thrown, then the
 
155
    * stream is reset to a state such that all the bytes read since the
 
156
    * most recent call to <code>mark</code> (or since the start of the
 
157
    * file, if <code>mark</code> has not been called) will be resupplied
 
158
    * to subsequent callers of the <code>read</code> method, followed by
 
159
    * any bytes that otherwise would have been the next input data as of
 
160
    * the time of the call to <code>reset</code>. </ul>
 
161
    * <p/>
 
162
    * <li> If the method <code>markSupported</code> returns
 
163
    * <code>false</code>, then:
 
164
    * <p/>
 
165
    * <ul><li> The call to <code>reset</code> may throw an
 
166
    * <code>IOException</code>.
 
167
    * <p/>
 
168
    * <li> If an <code>IOException</code> is not thrown, then the stream
 
169
    * is reset to a fixed state that depends on the particular type of the
 
170
    * input stream and how it was created. The bytes that will be supplied
 
171
    * to subsequent callers of the <code>read</code> method depend on the
 
172
    * particular type of the input stream. </ul></ul>
 
173
    * <p/>
 
174
    * <p> The method <code>reset</code> for class <code>InputStream</code>
 
175
    * does nothing and always throws an <code>IOException</code>.
 
176
    *
 
177
    * @throws java.io.IOException if this stream has not been marked or if the
 
178
    *                             mark has been invalidated.
 
179
    * @see java.io.InputStream#mark(int)
 
180
    * @see java.io.IOException
 
181
    */
 
182
   public synchronized void reset() throws IOException
 
183
   {
 
184
      try
 
185
      {
 
186
         streamClient.invoke(new StreamCallPayload(RESET));
 
187
      }
 
188
      catch(Throwable throwable)
 
189
      {
 
190
         log.debug("Error reseting client stream.", throwable);
 
191
         throw new IOException(throwable.getMessage());
 
192
      }
 
193
   }
 
194
 
 
195
   /**
 
196
    * Tests if this input stream supports the <code>mark</code> and
 
197
    * <code>reset</code> methods. Whether or not <code>mark</code> and
 
198
    * <code>reset</code> are supported is an invariant property of a
 
199
    * particular input stream instance. The <code>markSupported</code> method
 
200
    * of <code>InputStream</code> returns <code>false</code>.
 
201
    *
 
202
    * @return <code>true</code> if this stream instance supports the mark
 
203
    *         and reset methods; <code>false</code> otherwise.
 
204
    * @see java.io.InputStream#mark(int)
 
205
    * @see java.io.InputStream#reset()
 
206
    */
 
207
   public boolean markSupported()
 
208
   {
 
209
      boolean supported = false;
 
210
 
 
211
      try
 
212
      {
 
213
         Boolean bSupported = (Boolean) streamClient.invoke(new StreamCallPayload(MARKSUPPORTED));
 
214
         if(bSupported != null)
 
215
         {
 
216
            supported = bSupported.booleanValue();
 
217
         }
 
218
      }
 
219
      catch(Throwable throwable)
 
220
      {
 
221
         log.debug("Error getting markSupported from client stream.", throwable);
 
222
         throw new RuntimeException(throwable.getMessage(), throwable);
 
223
      }
 
224
      return supported;
 
225
   }
 
226
 
 
227
   /**
 
228
    * Marks the current position in this input stream. A subsequent call to
 
229
    * the <code>reset</code> method repositions this stream at the last marked
 
230
    * position so that subsequent reads re-read the same bytes.
 
231
    * <p/>
 
232
    * <p> The <code>readlimit</code> arguments tells this input stream to
 
233
    * allow that many bytes to be read before the mark position gets
 
234
    * invalidated.
 
235
    * <p/>
 
236
    * <p> The general contract of <code>mark</code> is that, if the method
 
237
    * <code>markSupported</code> returns <code>true</code>, the stream somehow
 
238
    * remembers all the bytes read after the call to <code>mark</code> and
 
239
    * stands ready to supply those same bytes again if and whenever the method
 
240
    * <code>reset</code> is called.  However, the stream is not required to
 
241
    * remember any data at all if more than <code>readlimit</code> bytes are
 
242
    * read from the stream before <code>reset</code> is called.
 
243
    * <p/>
 
244
    * <p> The <code>mark</code> method of <code>InputStream</code> does
 
245
    * nothing.
 
246
    *
 
247
    * @param readlimit the maximum limit of bytes that can be read before
 
248
    *                  the mark position becomes invalid.
 
249
    * @see java.io.InputStream#reset()
 
250
    */
 
251
   public synchronized void mark(int readlimit)
 
252
   {
 
253
      try
 
254
      {
 
255
         StreamCallPayload payload = new StreamCallPayload(MARKREADLIMIT);
 
256
         payload.setParams(new Object[]{new Integer(readlimit)});
 
257
         streamClient.invoke(payload);
 
258
      }
 
259
      catch(Throwable throwable)
 
260
      {
 
261
         log.debug("Error marking with read limit on client stream.", throwable);
 
262
         throw new RuntimeException(throwable.getMessage(), throwable);
 
263
      }
 
264
   }
 
265
 
 
266
   /**
 
267
    * Skips over and discards <code>n</code> bytes of data from this input
 
268
    * stream. The <code>skip</code> method may, for a variety of reasons, end
 
269
    * up skipping over some smaller number of bytes, possibly <code>0</code>.
 
270
    * This may result from any of a number of conditions; reaching end of file
 
271
    * before <code>n</code> bytes have been skipped is only one possibility.
 
272
    * The actual number of bytes skipped is returned.  If <code>n</code> is
 
273
    * negative, no bytes are skipped.
 
274
    * <p/>
 
275
    * <p> The <code>skip</code> method of <code>InputStream</code> creates a
 
276
    * byte array and then repeatedly reads into it until <code>n</code> bytes
 
277
    * have been read or the end of the stream has been reached. Subclasses are
 
278
    * encouraged to provide a more efficient implementation of this method.
 
279
    *
 
280
    * @param n the number of bytes to be skipped.
 
281
    * @return the actual number of bytes skipped.
 
282
    * @throws java.io.IOException if an I/O error occurs.
 
283
    */
 
284
   public long skip(long n) throws IOException
 
285
   {
 
286
      long numSkipped = -1;
 
287
 
 
288
      try
 
289
      {
 
290
         StreamCallPayload payload = new StreamCallPayload(SKIP);
 
291
         payload.setParams(new Object[]{new Long(n)});
 
292
         Long ret = (Long) streamClient.invoke(payload);
 
293
         if(ret != null)
 
294
         {
 
295
            numSkipped = ret.longValue();
 
296
         }
 
297
      }
 
298
      catch(Throwable throwable)
 
299
      {
 
300
         log.debug("Error skipping on client stream.", throwable);
 
301
         throw new IOException(throwable.getMessage());
 
302
      }
 
303
 
 
304
      return numSkipped;
 
305
   }
 
306
 
 
307
   /**
 
308
    * Reads some number of bytes from the input stream and stores them into
 
309
    * the buffer array <code>b</code>. The number of bytes actually read is
 
310
    * returned as an integer.  This method blocks until input data is
 
311
    * available, end of file is detected, or an exception is thrown.
 
312
    * <p/>
 
313
    * <p> If <code>b</code> is <code>null</code>, a
 
314
    * <code>NullPointerException</code> is thrown.  If the length of
 
315
    * <code>b</code> is zero, then no bytes are read and <code>0</code> is
 
316
    * returned; otherwise, there is an attempt to read at least one byte. If
 
317
    * no byte is available because the stream is at end of file, the value
 
318
    * <code>-1</code> is returned; otherwise, at least one byte is read and
 
319
    * stored into <code>b</code>.
 
320
    * <p/>
 
321
    * <p> The first byte read is stored into element <code>b[0]</code>, the
 
322
    * next one into <code>b[1]</code>, and so on. The number of bytes read is,
 
323
    * at most, equal to the length of <code>b</code>. Let <i>k</i> be the
 
324
    * number of bytes actually read; these bytes will be stored in elements
 
325
    * <code>b[0]</code> through <code>b[</code><i>k</i><code>-1]</code>,
 
326
    * leaving elements <code>b[</code><i>k</i><code>]</code> through
 
327
    * <code>b[b.length-1]</code> unaffected.
 
328
    * <p/>
 
329
    * <p> If the first byte cannot be read for any reason other than end of
 
330
    * file, then an <code>IOException</code> is thrown. In particular, an
 
331
    * <code>IOException</code> is thrown if the input stream has been closed.
 
332
    * <p/>
 
333
    * <p> The <code>read(b)</code> method for class <code>InputStream</code>
 
334
    * has the same effect as: <pre><code> read(b, 0, b.length) </code></pre>
 
335
    *
 
336
    * @param b the buffer into which the data is read.
 
337
    * @return the total number of bytes read into the buffer, or
 
338
    *         <code>-1</code> is there is no more data because the end of
 
339
    *         the stream has been reached.
 
340
    * @throws java.io.IOException  if an I/O error occurs.
 
341
    * @throws NullPointerException if <code>b</code> is <code>null</code>.
 
342
    * @see java.io.InputStream#read(byte[], int, int)
 
343
    */
 
344
   public int read(byte b[]) throws IOException
 
345
   {
 
346
      if(b == null)
 
347
      {
 
348
         throw new NullPointerException("can not read for a null byte array.");
 
349
      }
 
350
      else
 
351
      {
 
352
         if(b.length == 0)
 
353
         {
 
354
            return 0;
 
355
         }
 
356
      }
 
357
 
 
358
      int retByte = -1;
 
359
 
 
360
      try
 
361
      {
 
362
         StreamCallPayload payload = new StreamCallPayload(READBYTEARRAY);
 
363
         payload.setParams(new Object[]{b});
 
364
         StreamCallPayload ret = (StreamCallPayload) streamClient.invoke(payload);
 
365
         if(ret != null)
 
366
         {
 
367
            Object[] retVals = ret.getParams();
 
368
            byte[] retBytes = (byte[]) retVals[0];
 
369
            Integer retInt = (Integer) retVals[1];
 
370
 
 
371
            retByte = retInt.intValue();
 
372
 
 
373
            if(retByte != -1)
 
374
            {
 
375
               System.arraycopy(retBytes, 0, b, 0, retByte);
 
376
            }
 
377
         }
 
378
      }
 
379
      catch(Throwable throwable)
 
380
      {
 
381
         log.debug("Error reading from client stream.", throwable);
 
382
         throw new IOException(throwable.getMessage());
 
383
      }
 
384
 
 
385
      return retByte;
 
386
   }
 
387
 
 
388
   /**
 
389
    * Reads up to <code>len</code> bytes of data from the input stream into
 
390
    * an array of bytes.  An attempt is made to read as many as
 
391
    * <code>len</code> bytes, but a smaller number may be read, possibly
 
392
    * zero. The number of bytes actually read is returned as an integer.
 
393
    * <p/>
 
394
    * <p> This method blocks until input data is available, end of file is
 
395
    * detected, or an exception is thrown.
 
396
    * <p/>
 
397
    * <p> If <code>b</code> is <code>null</code>, a
 
398
    * <code>NullPointerException</code> is thrown.
 
399
    * <p/>
 
400
    * <p> If <code>off</code> is negative, or <code>len</code> is negative, or
 
401
    * <code>off+len</code> is greater than the length of the array
 
402
    * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
 
403
    * thrown.
 
404
    * <p/>
 
405
    * <p> If <code>len</code> is zero, then no bytes are read and
 
406
    * <code>0</code> is returned; otherwise, there is an attempt to read at
 
407
    * least one byte. If no byte is available because the stream is at end of
 
408
    * file, the value <code>-1</code> is returned; otherwise, at least one
 
409
    * byte is read and stored into <code>b</code>.
 
410
    * <p/>
 
411
    * <p> The first byte read is stored into element <code>b[off]</code>, the
 
412
    * next one into <code>b[off+1]</code>, and so on. The number of bytes read
 
413
    * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
 
414
    * bytes actually read; these bytes will be stored in elements
 
415
    * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
 
416
    * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
 
417
    * <code>b[off+len-1]</code> unaffected.
 
418
    * <p/>
 
419
    * <p> In every case, elements <code>b[0]</code> through
 
420
    * <code>b[off]</code> and elements <code>b[off+len]</code> through
 
421
    * <code>b[b.length-1]</code> are unaffected.
 
422
    * <p/>
 
423
    * <p> If the first byte cannot be read for any reason other than end of
 
424
    * file, then an <code>IOException</code> is thrown. In particular, an
 
425
    * <code>IOException</code> is thrown if the input stream has been closed.
 
426
    * <p/>
 
427
    * <p> The <code>read(b,</code> <code>off,</code> <code>len)</code> method
 
428
    * for class <code>InputStream</code> simply calls the method
 
429
    * <code>read()</code> repeatedly. If the first such call results in an
 
430
    * <code>IOException</code>, that exception is returned from the call to
 
431
    * the <code>read(b,</code> <code>off,</code> <code>len)</code> method.  If
 
432
    * any subsequent call to <code>read()</code> results in a
 
433
    * <code>IOException</code>, the exception is caught and treated as if it
 
434
    * were end of file; the bytes read up to that point are stored into
 
435
    * <code>b</code> and the number of bytes read before the exception
 
436
    * occurred is returned.  Subclasses are encouraged to provide a more
 
437
    * efficient implementation of this method.
 
438
    *
 
439
    * @param b   the buffer into which the data is read.
 
440
    * @param off the start offset in array <code>b</code>
 
441
    *            at which the data is written.
 
442
    * @param len the maximum number of bytes to read.
 
443
    * @return the total number of bytes read into the buffer, or
 
444
    *         <code>-1</code> if there is no more data because the end of
 
445
    *         the stream has been reached.
 
446
    * @throws java.io.IOException  if an I/O error occurs.
 
447
    * @throws NullPointerException if <code>b</code> is <code>null</code>.
 
448
    * @see java.io.InputStream#read()
 
449
    */
 
450
   public int read(byte b[], int off, int len) throws IOException
 
451
   {
 
452
      if(b == null)
 
453
      {
 
454
         throw new NullPointerException("can not read for a null byte array.");
 
455
      }
 
456
      else
 
457
      {
 
458
         if(b.length == 0)
 
459
         {
 
460
            return 0;
 
461
         }
 
462
         else
 
463
         {
 
464
            if(off < 0 || len < 0 || off + len > b.length)
 
465
            {
 
466
               throw new IndexOutOfBoundsException("Either off or len is negative or off+len is greater than length of b.");
 
467
            }
 
468
            if(len == 0)
 
469
            {
 
470
               return 0;
 
471
            }
 
472
         }
 
473
      }
 
474
 
 
475
      int retByte = -1;
 
476
 
 
477
      try
 
478
      {
 
479
         byte[] payloadArray = new byte[len];
 
480
         StreamCallPayload payload = new StreamCallPayload(READBYTEARRAY);
 
481
         payload.setParams(new Object[]{payloadArray});
 
482
         StreamCallPayload ret = (StreamCallPayload) streamClient.invoke(payload);
 
483
         if(ret != null)
 
484
         {
 
485
            Object[] retVals = ret.getParams();
 
486
            byte[] retBytes = (byte[]) retVals[0];
 
487
            Integer retInt = (Integer) retVals[1];
 
488
 
 
489
            retByte = retInt.intValue();
 
490
 
 
491
            if(retByte != -1)
 
492
            {
 
493
               System.arraycopy(retBytes, 0, b, off, retByte);
 
494
            }
 
495
         }
 
496
      }
 
497
      catch(Throwable throwable)
 
498
      {
 
499
         log.debug("Error reading with offset from client stream.", throwable);
 
500
         throw new IOException(throwable.getMessage());
 
501
      }
 
502
 
 
503
      return retByte;
 
504
   }
 
505
 
 
506
   /**
 
507
    * Reads the next byte of data from the input stream. The value byte is
 
508
    * returned as an <code>int</code> in the range <code>0</code> to
 
509
    * <code>255</code>. If no byte is available because the end of the stream
 
510
    * has been reached, the value <code>-1</code> is returned. This method
 
511
    * blocks until input data is available, the end of the stream is detected,
 
512
    * or an exception is thrown.
 
513
    * <p/>
 
514
    * <p> A subclass must provide an implementation of this method.
 
515
    *
 
516
    * @return the next byte of data, or <code>-1</code> if the end of the
 
517
    *         stream is reached.
 
518
    * @throws java.io.IOException if an I/O error occurs.
 
519
    */
 
520
   public int read() throws IOException
 
521
   {
 
522
      int readInt = -1;
 
523
 
 
524
      try
 
525
      {
 
526
         Integer retInt = (Integer) streamClient.invoke(new StreamCallPayload(READ));
 
527
         if(retInt != null)
 
528
         {
 
529
            readInt = retInt.intValue();
 
530
         }
 
531
      }
 
532
      catch(Throwable throwable)
 
533
      {
 
534
         log.debug("Error reading from client stream.", throwable);
 
535
         throw new IOException(throwable.getMessage());
 
536
      }
 
537
      return readInt;
 
538
   }
 
539
 
 
540
}
 
 
b'\\ No newline at end of file'