KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jruby > RubyFile


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

35 package org.jruby;
36
37 import java.io.File JavaDoc;
38 import java.io.FileInputStream JavaDoc;
39 import java.io.FileNotFoundException JavaDoc;
40 import java.io.IOException JavaDoc;
41 import java.io.InputStream JavaDoc;
42 import java.io.Reader JavaDoc;
43 import java.nio.channels.FileChannel JavaDoc;
44 import java.nio.channels.FileLock JavaDoc;
45
46 import org.jruby.exceptions.RaiseException;
47 import org.jruby.runtime.Block;
48 import org.jruby.runtime.builtin.IRubyObject;
49 import org.jruby.runtime.builtin.meta.FileMetaClass;
50 import org.jruby.util.IOHandler;
51 import org.jruby.util.IOHandlerNull;
52 import org.jruby.util.IOHandlerSeekable;
53 import org.jruby.util.IOHandlerUnseekable;
54 import org.jruby.util.IOModes;
55 import org.jruby.util.JRubyFile;
56 import org.jruby.util.IOHandler.InvalidValueException;
57
58 /**
59  * Ruby File class equivalent in java.
60  *
61  * @author jpetersen
62  **/

63 public class RubyFile extends RubyIO {
64     public static final int LOCK_SH = 1;
65     public static final int LOCK_EX = 2;
66     public static final int LOCK_NB = 4;
67     public static final int LOCK_UN = 8;
68     
69     protected String JavaDoc path;
70     private FileLock JavaDoc currentLock;
71     
72     public RubyFile(Ruby runtime, RubyClass type) {
73         super(runtime, type);
74     }
75
76     public RubyFile(Ruby runtime, String JavaDoc path) {
77         this(runtime, path, open(runtime, path));
78     }
79
80     // use static function because constructor call must be first statement in above constructor
81
private static InputStream JavaDoc open(Ruby runtime, String JavaDoc path) {
82         try {
83             return new FileInputStream JavaDoc(path);
84         } catch (FileNotFoundException JavaDoc e) {
85             throw runtime.newIOError(e.getMessage());
86         }
87     }
88     
89     // XXX This constructor is a hack to implement the __END__ syntax.
90
// Converting a reader back into an InputStream doesn't generally work.
91
public RubyFile(Ruby runtime, String JavaDoc path, final Reader JavaDoc reader) {
92         this(runtime, path, new InputStream JavaDoc() {
93             public int read() throws IOException JavaDoc {
94                 return reader.read();
95             }
96         });
97     }
98     
99     private RubyFile(Ruby runtime, String JavaDoc path, InputStream JavaDoc in) {
100         super(runtime, runtime.getClass("File"));
101         this.path = path;
102         try {
103             this.handler = new IOHandlerUnseekable(runtime, in, null);
104         } catch (IOException JavaDoc e) {
105             throw runtime.newIOError(e.getMessage());
106         }
107         this.modes = handler.getModes();
108         registerIOHandler(handler);
109     }
110     
111     public void openInternal(String JavaDoc newPath, IOModes newModes) {
112         this.path = newPath;
113         this.modes = newModes;
114         
115         try {
116             if (newPath.equals("/dev/null")) {
117                 handler = new IOHandlerNull(getRuntime(), newModes);
118             } else {
119                 handler = new IOHandlerSeekable(getRuntime(), newPath, newModes);
120             }
121             
122             registerIOHandler(handler);
123         } catch (InvalidValueException e) {
124             throw getRuntime().newErrnoEINVALError();
125         } catch (FileNotFoundException JavaDoc e) {
126             throw getRuntime().newErrnoENOENTError();
127         } catch (IOException JavaDoc e) {
128             throw getRuntime().newIOError(e.getMessage());
129         }
130     }
131     
132     public IRubyObject close() {
133         // Make sure any existing lock is released before we try and close the file
134
if (currentLock != null) {
135             try {
136                 currentLock.release();
137             } catch (IOException JavaDoc e) {
138                 throw getRuntime().newIOError(e.getMessage());
139             }
140         }
141         return super.close();
142     }
143
144     public IRubyObject flock(IRubyObject lockingConstant) {
145         FileChannel JavaDoc fileChannel = handler.getFileChannel();
146         int lockMode = (int) ((RubyFixnum) lockingConstant.convertToType("Fixnum", "to_int",
147             true)).getLongValue();
148
149         try {
150             switch(lockMode) {
151             case LOCK_UN:
152                 if (currentLock != null) {
153                     currentLock.release();
154                     currentLock = null;
155                     
156                     return getRuntime().newFixnum(0);
157                 }
158                 break;
159             case LOCK_EX:
160             case LOCK_EX | LOCK_NB:
161                 if (currentLock != null) {
162                     currentLock.release();
163                     currentLock = null;
164                 }
165                 currentLock = fileChannel.tryLock();
166                 if (currentLock != null) {
167                     return getRuntime().newFixnum(0);
168                 }
169
170                 break;
171             case LOCK_SH:
172             case LOCK_SH | LOCK_NB:
173                 if (currentLock != null) {
174                     currentLock.release();
175                     currentLock = null;
176                 }
177                 
178                 currentLock = fileChannel.tryLock(0L, Long.MAX_VALUE, true);
179                 if (currentLock != null) {
180                     return getRuntime().newFixnum(0);
181                 }
182
183                 break;
184             default:
185             }
186         } catch (IOException JavaDoc ioe) {
187             throw new RaiseException(new NativeException(getRuntime(), getRuntime().getClass("IOError"), ioe));
188         }
189         
190         return getRuntime().getFalse();
191     }
192
193     public IRubyObject initialize(IRubyObject[] args, Block block) {
194         if (args.length == 0) {
195             throw getRuntime().newArgumentError(0, 1);
196         }
197
198         args[0].checkSafeString();
199         path = args[0].toString();
200         modes = args.length > 1 ? getModes(args[1]) :
201             new IOModes(getRuntime(), IOModes.RDONLY);
202         
203         // One of the few places where handler may be null.
204
// If handler is not null, it indicates that this object
205
// is being reused.
206
if (handler != null) {
207             close();
208         }
209         openInternal(path, modes);
210         
211         if (block.isGiven()) {
212             // getRuby().getRuntime().warn("File::new does not take block; use File::open instead");
213
}
214         return this;
215     }
216
217     public IRubyObject chmod(IRubyObject[] args) {
218         checkArgumentCount(args, 1, 1);
219         
220         RubyInteger mode = args[0].convertToInteger();
221
222         if (!new File JavaDoc(path).exists()) {
223             throw getRuntime().newErrnoENOENTError("No such file or directory - " + path);
224         }
225             
226         try {
227             Process JavaDoc chown = Runtime.getRuntime().exec("chmod " + FileMetaClass.OCTAL_FORMATTER.sprintf(mode.getLongValue()) + " " + path);
228             chown.waitFor();
229         } catch (IOException JavaDoc ioe) {
230             // FIXME: ignore?
231
} catch (InterruptedException JavaDoc ie) {
232             // FIXME: ignore?
233
}
234         
235         return getRuntime().newFixnum(0);
236     }
237
238     public IRubyObject chown(IRubyObject[] args) {
239         checkArgumentCount(args, 1, 1);
240         
241         RubyInteger owner = args[0].convertToInteger();
242         if (!new File JavaDoc(path).exists()) {
243             throw getRuntime().newErrnoENOENTError("No such file or directory - " + path);
244         }
245             
246         try {
247             Process JavaDoc chown = Runtime.getRuntime().exec("chown " + owner + " " + path);
248             chown.waitFor();
249         } catch (IOException JavaDoc ioe) {
250             // FIXME: ignore?
251
} catch (InterruptedException JavaDoc ie) {
252             // FIXME: ignore?
253
}
254         
255         return getRuntime().newFixnum(0);
256     }
257
258     public IRubyObject ctime() {
259         return getRuntime().newTime(JRubyFile.create(getRuntime().getCurrentDirectory(),this.path).getParentFile().lastModified());
260     }
261
262     public RubyString path() {
263         return getRuntime().newString(path);
264     }
265
266     public IRubyObject stat() {
267         return getRuntime().newRubyFileStat(path);
268     }
269     
270     public IRubyObject truncate(IRubyObject arg) {
271         RubyFixnum newLength = (RubyFixnum) arg.convertToType("Fixnum", "to_int", true);
272         try {
273             handler.truncate(newLength.getLongValue());
274         } catch (IOHandler.PipeException e) {
275             throw getRuntime().newErrnoESPIPEError();
276         } catch (IOException JavaDoc e) {
277             // Should we do anything?
278
}
279         
280         return RubyFixnum.zero(getRuntime());
281     }
282     
283     public String JavaDoc toString() {
284         return "RubyFile(" + path + ", " + modes + ", " + fileno + ")";
285     }
286
287     // TODO: This is also defined in the MetaClass too...Consolidate somewhere.
288
private IOModes getModes(IRubyObject object) {
289         if (object instanceof RubyString) {
290             return new IOModes(getRuntime(), ((RubyString)object).toString());
291         } else if (object instanceof RubyFixnum) {
292             return new IOModes(getRuntime(), ((RubyFixnum)object).getLongValue());
293         }
294
295         throw getRuntime().newTypeError("Invalid type for modes");
296     }
297
298     public IRubyObject inspect() {
299         StringBuffer JavaDoc val = new StringBuffer JavaDoc();
300         val.append("#<File:").append(path);
301         if(!isOpen()) {
302             val.append(" (closed)");
303         }
304         val.append(">");
305         return getRuntime().newString(val.toString());
306     }
307 }
308
Popular Tags