1 // Copyright 2004 Adam Megacz, see the COPYING file for licensing [GPL]
4 import org.ibex.util.*;
8 // FEATURE: support for move
9 // FEATURE: support for bytestreams
10 // FEATURE: cache directories so we can do equality checking on them?
11 // FEATURE: autoconvert "true" to true and "0.3" to 0.3 on readback
14 * A crude mechanism for using a filesystem as object storage.
16 * This object represents a directory; writing a string, number, or
17 * boolean to any of its properties will create a file with the
18 * (encoded) property name as its filename and the "stringified"
19 * value as its contents.
21 * Writing 'null' to one of this object's properties will
22 * [recursively if necessary] delete the corresponding directory
25 * Writing any other object to one of this object's properties will
26 * create a new Directory object and copy the other object's keys()
27 * into the new Directory. This means that assigning one directory
28 * to a property of another directory will <i>copy</i> the directory,
29 * not move it. There is currently no way to move directories.
31 * If an object is written to a property that already has an entry,
32 * the old one is deleted (equivalent to writing 'null') first.
34 * WARNING: when instantiating a Directory object with a file
35 * argument that points to a non-directory File, this class will
36 * delete that file and create a directory!
38 public class Directory extends JS {
43 * Create the directory object. Existing directories will be
44 * preserved; if a file is present it will be obliterated.
46 public Directory(File f) throws IOException {
48 if (!f.exists()) new Directory(new File(f.getParent()));
49 if (!f.isDirectory()) destroy(f);
53 private static void destroy(File f) throws IOException {
54 if (!f.exists()) return;
55 if (f.isDirectory()) {
56 String[] entries = f.list();
57 for(int i=0; i<entries.length; i++) destroy(new File(f.getAbsolutePath() + File.separatorChar + entries[i]));
62 public void put(Object key0, Object val) throws JSExn {
64 if (key0 == null) return;
65 String key = toString(key0);
66 File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
68 if (val == null) return;
69 if (val instanceof JS) {
70 Directory d2 = new Directory(f2);
71 Enumeration e = ((JS)val).keys();
72 while(e.hasMoreElements()) {
73 String k = (String)e.nextElement();
74 Object v = ((JS)val).get(k);
78 OutputStream out = new FileOutputStream(f2);
79 Writer w = new OutputStreamWriter(out);
80 w.write(toString(val));
84 } catch (IOException ioe) {
85 throw new JSExn.IO(ioe);
89 public Object get(Object key0) throws JSExn {
91 if (key0 == null) return null;
92 String key = toString(key0);
93 File f2 = new File(f.getAbsolutePath() + File.separatorChar + FileNameEncoder.encode(key));
94 if (!f2.exists()) return null;
95 if (f2.isDirectory()) return new Directory(f2);
96 char[] chars = new char[((int)f2.length()) * 2];
98 Reader r = new InputStreamReader(new FileInputStream(f2));
100 int numread = r.read(chars, numchars, chars.length - numchars);
101 if (numread == -1) return new String(chars, 0, numchars);
104 } catch (IOException ioe) {
105 throw new JSExn.IO(ioe);
109 public Enumeration keys() {
110 final String[] elements = f.list();
111 return new Enumeration() {
113 public boolean hasMoreElements() { return i < elements.length; }
114 public Object nextElement() { return FileNameEncoder.decode(elements[i++]); }