KickJava   Java API By Example, From Geeks To Geeks.

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


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) 2004 Anders Bengtsson <ndrsbngtssn@yahoo.se>
15  * Copyright (C) 2004-2005 Thomas E Enebo <enebo@acm.org>
16  * Copyright (C) 2004 Jan Arne Petersen <jpetersen@uni-bonn.de>
17  * Copyright (C) 2004 Stefan Matthias Aust <sma@3plus4.de>
18  * Copyright (C) 2005 Charles O Nutter <headius@headius.com>
19  *
20  * Alternatively, the contents of this file may be used under the terms of
21  * either of the GNU General Public License Version 2 or later (the "GPL"),
22  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
23  * in which case the provisions of the GPL or the LGPL are applicable instead
24  * of those above. If you wish to allow use of your version of this file only
25  * under the terms of either the GPL or the LGPL, and not to allow others to
26  * use your version of this file under the terms of the CPL, indicate your
27  * decision by deleting the provisions above and replace them with the notice
28  * and other provisions required by the GPL or the LGPL. If you do not delete
29  * the provisions above, a recipient may use your version of this file under
30  * the terms of any one of the CPL, the GPL or the LGPL.
31  ***** END LICENSE BLOCK *****/

32 package org.jruby.util;
33
34 import java.io.BufferedInputStream JavaDoc;
35 import java.io.BufferedOutputStream JavaDoc;
36 import java.io.FileNotFoundException JavaDoc;
37 import java.io.IOException JavaDoc;
38 import java.io.InputStream JavaDoc;
39 import java.io.OutputStream JavaDoc;
40 import java.io.RandomAccessFile JavaDoc;
41 import java.nio.channels.FileChannel JavaDoc;
42
43 import org.jruby.Ruby;
44 import org.jruby.RubyIO;
45
46 /**
47  * <p>This file implements a seekable IO file.</p>
48  *
49  * @author Thomas E Enebo (enebo@acm.org)
50  */

51 public class IOHandlerSeekable extends IOHandlerJavaIO {
52     protected RandomAccessFile JavaDoc file;
53     protected String JavaDoc path;
54     protected String JavaDoc cwd;
55
56     
57     public IOHandlerSeekable(Ruby runtime, String JavaDoc path, IOModes modes)
58         throws IOException JavaDoc, InvalidValueException {
59         super(runtime);
60         
61         this.path = path;
62         this.modes = modes;
63         this.cwd = runtime.getCurrentDirectory();
64         JRubyFile theFile = JRubyFile.create(cwd,path);
65         
66         if (theFile.exists()) {
67             if (modes.shouldTruncate()) {
68                 // If we only want to open for writing we should remove
69
// the old file before opening the fresh one. If it fails
70
// to remove it we should do something?
71
if (!theFile.delete()) {
72                 }
73             }
74         } else {
75             if (modes.isReadable() && !modes.isWriteable()) {
76                 throw new FileNotFoundException JavaDoc();
77             }
78         }
79
80         // Do not open as 'rw' if we don't need to since a file with permissions for read-only
81
// will barf if opened 'rw'.
82
String JavaDoc javaMode = "r";
83         if (modes.isWriteable()) {
84             javaMode += "w";
85         }
86         
87         // We always open this rw since we can only open it r or rw.
88
file = new RandomAccessFile JavaDoc(theFile, javaMode);
89         isOpen = true;
90         
91         if (modes.isAppendable()) {
92             seek(0, SEEK_END);
93         }
94
95         // We give a fileno last so that we do not consume these when
96
// we have a problem opening a file.
97
fileno = RubyIO.getNewFileno();
98     }
99
100     private void reopen() throws IOException JavaDoc {
101         long pos = pos();
102
103         String JavaDoc javaMode = "r";
104         if (modes.isWriteable()) {
105             javaMode += "w";
106         }
107         
108         JRubyFile theFile = JRubyFile.create(cwd,path);
109         file.close();
110         file = new RandomAccessFile JavaDoc(theFile, javaMode);
111         isOpen = true;
112
113         try {
114             seek(pos,SEEK_SET);
115         } catch(Exception JavaDoc e) {
116             throw new IOException JavaDoc();
117         }
118     }
119
120     private void checkReopen() throws IOException JavaDoc {
121         if(file.length() != new java.io.File JavaDoc(path).length()) {
122             reopen();
123         }
124     }
125     
126     public ByteList getsEntireStream() throws IOException JavaDoc {
127         int c;
128
129         checkReopen();
130         
131         int left = (int)(file.length() - file.getFilePointer());
132         byte[] buf = new byte[left];
133         file.readFully(buf);
134
135         // We are already at EOF
136
if (buf.length == 0) {
137             return null;
138         }
139         
140         return new ByteList(buf,false);
141     }
142
143
144     public IOHandler cloneIOHandler() throws IOException JavaDoc, PipeException, InvalidValueException {
145         IOHandler newHandler = new IOHandlerSeekable(getRuntime(), path, modes);
146             
147         newHandler.seek(pos(), SEEK_CUR);
148             
149         return newHandler;
150     }
151     
152     /**
153      * <p>Close IO handler resources.</p>
154      * @throws IOException
155      * @throws BadDescriptorException
156      *
157      * @see org.jruby.util.IOHandler#close()
158      */

159     public void close() throws IOException JavaDoc, BadDescriptorException {
160         if (!isOpen()) {
161             throw new BadDescriptorException();
162         }
163         
164         isOpen = false;
165
166         file.close();
167     }
168
169     /**
170      * @throws IOException
171      * @throws BadDescriptorException
172      * @see org.jruby.util.IOHandler#flush()
173      */

174     public void flush() throws IOException JavaDoc, BadDescriptorException {
175         checkWriteable();
176
177         // No flushing a random access file.
178
}
179
180     /**
181      * @see org.jruby.util.IOHandler#getInputStream()
182      */

183     public InputStream JavaDoc getInputStream() {
184         return new BufferedInputStream JavaDoc(new DataInputBridgeStream(file));
185     }
186
187     /**
188      * @see org.jruby.util.IOHandler#getOutputStream()
189      */

190     public OutputStream JavaDoc getOutputStream() {
191         return new BufferedOutputStream JavaDoc(new DataOutputBridgeStream(file));
192     }
193     
194     /**
195      * @throws IOException
196      * @throws BadDescriptorException
197      * @see org.jruby.util.IOHandler#isEOF()
198      */

199     public boolean isEOF() throws IOException JavaDoc, BadDescriptorException {
200         checkReadable();
201
202         int c = file.read();
203         if (c == -1) {
204             return true;
205         }
206         file.seek(file.getFilePointer() - 1);
207         return false;
208     }
209     
210     /**
211      * @see org.jruby.util.IOHandler#pid()
212      */

213     public int pid() {
214         // A file is not a process.
215
return -1;
216     }
217     
218     /**
219      * @throws IOException
220      * @see org.jruby.util.IOHandler#pos()
221      */

222     public long pos() throws IOException JavaDoc {
223         checkOpen();
224         
225         return file.getFilePointer();
226     }
227     
228     public void resetByModes(IOModes newModes) throws IOException JavaDoc, InvalidValueException {
229         if (newModes.isAppendable()) {
230             seek(0L, SEEK_END);
231         } else if (newModes.isWriteable()) {
232             rewind();
233         }
234     }
235
236     /**
237      * @throws IOException
238      * @throws InvalidValueException
239      * @see org.jruby.util.IOHandler#rewind()
240      */

241     public void rewind() throws IOException JavaDoc, InvalidValueException {
242         seek(0, SEEK_SET);
243     }
244     
245     /**
246      * @throws IOException
247      * @throws InvalidValueException
248      * @see org.jruby.util.IOHandler#seek(long, int)
249      */

250     public void seek(long offset, int type) throws IOException JavaDoc, InvalidValueException {
251         checkOpen();
252
253         // TODO: This seems wrong...Invalid value should be for switch..not any IOError?
254
try {
255             switch (type) {
256             case SEEK_SET:
257                 file.seek(offset);
258                 break;
259             case SEEK_CUR:
260                 file.seek(file.getFilePointer() + offset);
261                 break;
262             case SEEK_END:
263                 file.seek(file.length() + offset);
264                 break;
265             }
266         } catch (IOException JavaDoc e) {
267             throw new InvalidValueException();
268         }
269     }
270
271     /**
272      * @see org.jruby.util.IOHandler#sync()
273      */

274     public void sync() throws IOException JavaDoc {
275         file.getFD().sync();
276         // RandomAccessFile is always synced?
277
}
278
279     public ByteList sysread(int number) throws IOException JavaDoc, BadDescriptorException {
280         if (!isOpen()) {
281             throw new IOException JavaDoc("File not open");
282         }
283         checkReadable();
284         byte[] buf = new byte[number];
285         int read = 0;
286         int n;
287         while(read < number) {
288             n = file.read(buf,read,number-read);
289             if(n == -1) {
290                 if(read == 0) {
291                     throw new java.io.EOFException JavaDoc();
292                 } else {
293                     break;
294                 }
295             }
296             read += n;
297         }
298         
299         return new ByteList(buf,0,read,false);
300     }
301     
302     /**
303      * @see org.jruby.util.IOHandler#sysread()
304      */

305     public int sysread() throws IOException JavaDoc {
306         return file.read();
307     }
308     
309     /**
310      * @throws IOException
311      * @throws BadDescriptorException
312      * @see org.jruby.util.IOHandler#syswrite(String buf)
313      */

314     public int syswrite(ByteList buf) throws IOException JavaDoc, BadDescriptorException {
315         getRuntime().secure(4);
316         checkWriteable();
317         
318         // Ruby ignores empty syswrites
319
if (buf == null || buf.realSize == 0) {
320             return 0;
321         }
322         
323         file.write(buf.bytes,0,buf.realSize);
324             
325         if (isSync()) {
326             sync();
327         }
328             
329         return buf.realSize;
330     }
331     
332     /**
333      * @throws IOException
334      * @throws BadDescriptorException
335      * @see org.jruby.util.IOHandler#syswrite(String buf)
336      */

337     public int syswrite(int c) throws IOException JavaDoc, BadDescriptorException {
338         getRuntime().secure(4);
339         checkWriteable();
340         
341         file.write(c);
342             
343         if (isSync()) {
344             sync();
345         }
346             
347         return 1;
348     }
349     
350     public void truncate(long newLength) throws IOException JavaDoc {
351         file.setLength(newLength);
352     }
353     
354     public FileChannel JavaDoc getFileChannel() {
355         return file.getChannel();
356     }
357 }
358
Popular Tags