KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > util > IOHandlerNio


1 /***** BEGIN LICENSE BLOCK *****
2  * Version: CPL 1.0/GPL 2.0/LGPL 2.1
3  *
4  * The contents of this file are subject to the Common Public
5  * License Version 1.0 (the "License"); you may not use this file
6  * except in compliance with the License. You may obtain a copy of
7  * the License at http://www.eclipse.org/legal/cpl-v10.html
8  *
9  * Software distributed under the License is distributed on an "AS
10  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
11  * implied. See the License for the specific language governing
12  * rights and limitations under the License.
13  *
14  * Copyright (C) 2006 Evan Buswell <ebuswell@gmail.com>
15  * Copyright (C) 2007 Miguel Covarrubias <mlcovarrubias@gmail.com>
16  *
17  * Alternatively, the contents of this file may be used under the terms of
18  * either of the GNU General Public License Version 2 or later (the "GPL"),
19  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
20  * in which case the provisions of the GPL or the LGPL are applicable instead
21  * of those above. If you wish to allow use of your version of this file only
22  * under the terms of either the GPL or the LGPL, and not to allow others to
23  * use your version of this file under the terms of the CPL, indicate your
24  * decision by deleting the provisions above and replace them with the notice
25  * and other provisions required by the GPL or the LGPL. If you do not delete
26  * the provisions above, a recipient may use your version of this file under
27  * the terms of any one of the CPL, the GPL or the LGPL.
28  ***** END LICENSE BLOCK *****/

29
30 package org.jruby.util;
31
32 import org.jruby.Ruby;
33 import org.jruby.RubyString;
34 import org.jruby.RubyIO;
35
36 import java.nio.channels.Channel JavaDoc;
37 import java.nio.channels.FileChannel JavaDoc;
38 import java.nio.channels.ReadableByteChannel JavaDoc;
39 import java.nio.channels.SelectableChannel JavaDoc;
40 import java.nio.channels.WritableByteChannel JavaDoc;
41 import java.nio.channels.IllegalBlockingModeException JavaDoc;
42 import java.nio.ByteBuffer JavaDoc;
43
44 import java.io.IOException JavaDoc;
45 import java.io.EOFException JavaDoc;
46
47 public class IOHandlerNio extends IOHandler {
48     private Channel JavaDoc channel;
49
50     private static final int BLOCK_SIZE = 1024 * 16;
51     private ByteBuffer JavaDoc outBuffer;
52     private ByteBuffer JavaDoc inBuffer;
53     private boolean blocking = true;
54     private boolean bufferedIO = false;
55
56     public IOHandlerNio(Ruby runtime, Channel JavaDoc channel) throws IOException JavaDoc {
57         super(runtime);
58         String JavaDoc mode = "";
59         this.channel = channel;
60         if (channel instanceof ReadableByteChannel JavaDoc) {
61             mode += "r";
62             isOpen = true;
63         }
64         if (channel instanceof WritableByteChannel JavaDoc) {
65             mode += "w";
66             isOpen = true;
67         }
68         if ("rw".equals(mode)) {
69             modes = new IOModes(runtime, IOModes.RDWR);
70             isOpen = true;
71         } else {
72             if (!isOpen) {
73                 // Neither stream exists?
74
// throw new IOException("Opening nothing?");
75
// Hack to cover the ServerSocketChannel case
76
mode = "r";
77                 isOpen = true;
78             }
79             modes = new IOModes(runtime, mode);
80         }
81         fileno = RubyIO.getNewFileno();
82         outBuffer = ByteBuffer.allocate(BLOCK_SIZE);
83     }
84
85     public Channel JavaDoc getChannel() {
86         return channel;
87     }
88
89     // this seems wrong...
90
public IOHandler cloneIOHandler() throws IOException JavaDoc {
91         return new IOHandlerNio(getRuntime(), channel);
92     }
93
94     private void checkBuffered() throws IOException JavaDoc {
95         if (bufferedIO) {
96             throw new IOException JavaDoc("Can't mix buffered and unbuffered IO.");
97         }
98     }
99
100     /* Unbuffered operations */
101     
102     public void setBlocking(boolean block) throws IOException JavaDoc {
103         if (!(channel instanceof SelectableChannel JavaDoc)) {
104             return;
105         }
106         synchronized (((SelectableChannel JavaDoc) channel).blockingLock()) {
107             blocking = block;
108             try {
109                 ((SelectableChannel JavaDoc) channel).configureBlocking(block);
110             } catch (IllegalBlockingModeException JavaDoc e) {
111                 // ignore this; select() will set the correct mode when it is finished
112
}
113         }
114     }
115
116     public boolean getBlocking() {
117         return blocking;
118     }
119
120     public ByteList sysread(int length) throws EOFException JavaDoc, BadDescriptorException, IOException JavaDoc {
121         checkReadable();
122         checkBuffered();
123     
124         ByteBuffer JavaDoc buffer = ByteBuffer.allocate(length);
125         int bytes_read = 0;
126         bytes_read = ((ReadableByteChannel JavaDoc) channel).read(buffer);
127         if (bytes_read < 0) {
128             throw new EOFException JavaDoc();
129         }
130
131         byte[] ret;
132         if (buffer.hasRemaining()) {
133             buffer.flip();
134             ret = new byte[buffer.remaining()];
135             buffer.get(ret);
136         } else {
137             ret = buffer.array();
138         }
139         return new ByteList(ret,false);
140     }
141     
142     public int syswrite(ByteList string) throws BadDescriptorException, IOException JavaDoc {
143         checkWritable();
144         outBuffer.flip();
145         flushOutBuffer();
146     
147         ByteBuffer JavaDoc buffer = ByteBuffer.wrap(string.bytes,0,string.realSize);
148         while (buffer.hasRemaining()) {
149         if (((WritableByteChannel JavaDoc) channel).write(buffer) < 0) {
150             // does this ever happen??
151
throw new IOException JavaDoc("write returned less than zero");
152         }
153         }
154         return buffer.capacity();
155     }
156     
157     public int syswrite(int c) throws BadDescriptorException, IOException JavaDoc {
158         ByteBuffer JavaDoc buffer = ByteBuffer.allocate(1); // inefficient?
159
buffer.put((byte)c);
160         
161         return syswrite(new ByteList(buffer.array(),false));
162     }
163     
164     public ByteList recv(int length) throws EOFException JavaDoc, BadDescriptorException, IOException JavaDoc {
165         return sysread(length);
166     }
167
168     /* Buffered operations */
169     private void setupBufferedIO() {
170         if (bufferedIO) {
171             return;
172         }
173         inBuffer = ByteBuffer.allocate(BLOCK_SIZE);
174         flushInBuffer();
175         bufferedIO = true;
176     }
177
178     int ungotc = -1;
179
180     private ByteList consumeInBuffer(int length) {
181         int offset = 0;
182         if (ungotc > 0) {
183             length--;
184             offset = 1;
185         }
186         length = inBuffer.remaining() < length ? inBuffer.remaining() : length;
187         byte[] ret = new byte[length + offset];
188         inBuffer.get(ret, offset, length);
189         if (ungotc > 0) {
190             ret[0] = (byte) (ungotc & 0xff);
191             ungotc = -1;
192         }
193         return new ByteList(ret,false);
194     }
195
196     private int fillInBuffer() throws IOException JavaDoc {
197         inBuffer.clear();
198         int i = ((ReadableByteChannel JavaDoc) channel).read(inBuffer);
199         inBuffer.flip();
200         return i;
201     }
202
203     private void flushInBuffer() {
204         inBuffer.position(0);
205         inBuffer.limit(0);
206         ungotc = -1;
207     }
208
209     private void flushOutBuffer() throws IOException JavaDoc {
210         while (outBuffer.hasRemaining()) {
211             if (((WritableByteChannel JavaDoc) channel).write(outBuffer) < 0) {
212                 throw new IOException JavaDoc("write returned less than zero");
213             }
214         }
215         outBuffer.clear();
216     }
217    
218     /* unused but looks like it could be at some point
219     private int buffer_rindex(ByteBuffer haystack, byte[] needle) {
220         search_loop:
221         for (int i = haystack.limit() - needle.length; i >= haystack.position(); i--) {
222             for (int j = 0; j < needle.length; j++) {
223                 if (haystack.get(i + j) != needle[j]) {
224                     continue search_loop;
225                 }
226             }
227             return i;
228         }
229         return -1;
230     }*/

231
232     private int buffer_index(ByteBuffer JavaDoc haystack, ByteList needle) {
233         search_loop:
234         for (int i = haystack.position(); i + (needle.realSize - 1) < haystack.limit(); i++) {
235             for (int j = 0; j < needle.realSize; j++) {
236                 if (haystack.get(i + j) != needle.bytes[j]) {
237                     continue search_loop;
238                 }
239             }
240             return i;
241         }
242         return -1;
243     }
244
245     public ByteList readpartial(int length) throws IOException JavaDoc, BadDescriptorException, EOFException JavaDoc {
246         checkReadable();
247         setupBufferedIO();
248
249         if (!inBuffer.hasRemaining()) {
250             if (fillInBuffer() < 0) {
251                 throw new EOFException JavaDoc();
252             }
253         }
254         return consumeInBuffer(length);
255     }
256
257     public ByteList read(int length) throws IOException JavaDoc, BadDescriptorException, EOFException JavaDoc {
258         setupBufferedIO();
259         checkReadable();
260
261         boolean eof = false;
262         int remaining = length;
263         ByteList ret = new ByteList(length);
264         ret.append(consumeInBuffer(remaining));
265         remaining -= ret.length();
266         while (remaining > 0) {
267             int i = fillInBuffer();
268             if (i < 0) {
269                 eof = true;
270                 break;
271             }
272             ret.append(consumeInBuffer(remaining));
273             remaining -= i;
274         }
275         if (eof && ret.length() == 0) {
276             throw new EOFException JavaDoc();
277         }
278         return ret;
279     }
280
281     public int write(ByteList string) throws IOException JavaDoc, BadDescriptorException {
282         checkWritable();
283
284         ByteBuffer JavaDoc buffer = ByteBuffer.wrap(string.bytes,0,string.realSize);
285         do {
286             /* append data */
287             while (buffer.hasRemaining() && outBuffer.hasRemaining()) {
288                 outBuffer.put(buffer.get());
289             }
290
291             outBuffer.flip();
292             if ((buffer.hasRemaining() && !outBuffer.hasRemaining()) || isSync()) {
293                 flushOutBuffer();
294             }
295         } while (buffer.hasRemaining());
296         
297         if(!isSync()) {
298           flushOutBuffer();
299         }
300         return buffer.capacity();
301     }
302
303     public ByteList gets(ByteList separator) throws IOException JavaDoc, BadDescriptorException, EOFException JavaDoc {
304         setupBufferedIO();
305         checkReadable();
306
307         ByteList ret = new ByteList();
308         boolean eof = false;
309         ByteList trigger;
310         if (separator != null) {
311             trigger = separator;
312         } else {
313             trigger = ((RubyString) getRuntime().getGlobalVariables().get("$/")).getByteList();
314         }
315
316         int idx;
317         while ((idx = buffer_index(inBuffer, trigger)) < 0 && !eof) {
318             ret.append(consumeInBuffer(BLOCK_SIZE));
319             if (fillInBuffer() < 0) {
320                 eof = true;
321         }
322         }
323         if (eof && !inBuffer.hasRemaining() && ret.length() == 0) {
324             throw new EOFException JavaDoc();
325         }
326         if (idx >= 0) {
327             ret.append(consumeInBuffer((idx + trigger.realSize) - inBuffer.position()));
328         } else if (eof) {
329             ret.append(consumeInBuffer(BLOCK_SIZE));
330         }
331         return ret;
332     }
333
334     public ByteList getsEntireStream() throws IOException JavaDoc, BadDescriptorException, EOFException JavaDoc {
335         checkReadable();
336         setupBufferedIO();
337         ByteList ret = new ByteList();
338         boolean eof;
339
340         while (true) {
341             ret.append(consumeInBuffer(BLOCK_SIZE));
342             if (fillInBuffer() < 0) {
343                 eof = true;
344                 break;
345             }
346         }
347         if (eof && ret.length() == 0) {
348             throw new EOFException JavaDoc();
349         }
350         return ret;
351     }
352
353     public int getc() throws IOException JavaDoc, BadDescriptorException, EOFException JavaDoc {
354         checkReadable();
355         setupBufferedIO();
356
357         if (ungotc > 0) {
358             int i = ungotc;
359             ungotc = -1;
360             return i;
361         }
362
363         if (!inBuffer.hasRemaining()) {
364             if (fillInBuffer() < 0) {
365                 throw new EOFException JavaDoc();
366             }
367         }
368         return (int) (inBuffer.get() & 0xff);
369     }
370
371     public void ungetc(int c) {
372         setupBufferedIO();
373         ungotc = c;
374     }
375     
376     public void putc(int c) throws IOException JavaDoc, BadDescriptorException {
377         checkWritable();
378
379         if (!outBuffer.hasRemaining()) {
380             outBuffer.flip();
381             flushOutBuffer();
382         }
383
384         outBuffer.put((byte) (c & 0xff));
385     }
386
387     public void flush() throws IOException JavaDoc, BadDescriptorException {
388         checkWritable();
389         outBuffer.flip();
390         flushOutBuffer();
391     }
392
393     /* FIXME: what is the difference between sync() and flush()?
394      * does this difference make sense for nio? */

395     public void sync() throws IOException JavaDoc, BadDescriptorException {
396         flush();
397     }
398     
399     public boolean isEOF() throws IOException JavaDoc, BadDescriptorException {
400         setupBufferedIO();
401         checkReadable();
402
403         if (ungotc > 0) {
404         return false;
405     }
406         if (inBuffer.hasRemaining()) {
407             return false;
408         }
409         if (fillInBuffer() < 0) {
410             return true;
411     }
412         return false;
413     }
414
415     /* buffering independent */
416     public void close() throws IOException JavaDoc {
417     /* flush output buffer before close */
418     if (outBuffer.position() > 0) {
419         outBuffer.flip();
420         flushOutBuffer();
421     }
422
423         channel.close();
424     }
425     
426     public long pos() throws PipeException, IOException JavaDoc {
427         if (channel instanceof FileChannel JavaDoc) {
428             if (bufferedIO) {
429                 return ((FileChannel JavaDoc) channel).position() - (inBuffer.remaining() + (ungotc > 0 ? 1 : 0));
430             } else {
431                 return ((FileChannel JavaDoc) channel).position();
432             }
433         } else {
434             throw new IOHandler.PipeException();
435         }
436     }
437
438     public void seek(long offset, int type) throws IOException JavaDoc, InvalidValueException, PipeException {
439         checkOpen();
440         if (channel instanceof FileChannel JavaDoc) {
441             if (bufferedIO) {
442                 flushInBuffer();
443             }
444             try {
445                 switch (type) {
446                 case SEEK_SET:
447                     ((FileChannel JavaDoc) channel).position(offset);
448                     break;
449                 case SEEK_CUR:
450                     ((FileChannel JavaDoc) channel).position(((FileChannel JavaDoc) channel).position() + offset);
451                     break;
452                 case SEEK_END:
453                     ((FileChannel JavaDoc) channel).position(((FileChannel JavaDoc) channel).size() + offset);
454                     break;
455                 }
456             } catch (IllegalArgumentException JavaDoc e) {
457                 throw new InvalidValueException();
458             }
459         } else {
460             throw new IOHandler.PipeException();
461         }
462     }
463
464     public void resetByModes(IOModes newModes) throws IOException JavaDoc, InvalidValueException {
465         if (channel instanceof FileChannel JavaDoc) {
466             if (newModes.isAppendable()) {
467                 try {
468                     seek(0L, SEEK_END);
469                 } catch(PipeException e) {
470                 } catch(InvalidValueException e) {} // these won't be thrown.
471
} else if (newModes.isWritable()) {
472                 try {
473                     rewind();
474                 } catch(PipeException e) {} // won't be thrown.
475
}
476         }
477     }
478     
479     public void rewind() throws IOException JavaDoc, PipeException {
480         checkOpen();
481         checkBuffered();
482         if (channel instanceof FileChannel JavaDoc) {
483             try {
484                 seek(0, SEEK_SET);
485             } catch(InvalidValueException e) {} // won't be thrown
486
} else {
487             throw new IOHandler.PipeException();
488         }
489     }
490
491     public void truncate(long length) throws IOException JavaDoc, PipeException {
492         if (channel instanceof FileChannel JavaDoc) {
493             ((FileChannel JavaDoc) channel).truncate(length);
494         } else {
495             throw new IOHandler.PipeException();
496         }
497     }
498
499     /* invalid operation */
500     public int pid() {
501         return -1;
502     }
503
504     public FileChannel JavaDoc getFileChannel() {
505         // FIXME: Satisfied for IOHandler, but this should throw some unsupported operation?
506
return null;
507     }
508 }
509
Popular Tags