1 // Copyright 2000-2005 the Contributors, as shown in the revision logs.
2 // Licensed under the Apache Public Source License 2.0 ("the License").
3 // You may not use this file except in compliance with the License.
7 import org.ibex.util.*;
11 // FEATURE: support for move
12 // FEATURE: support for bytestreams
13 // FEATURE: cache directories so we can do equality checking on them?
14 // FEATURE: autoconvert "true" to true and "0.3" to 0.3 on readback
17 * A crude mechanism for using a filesystem as object storage.
19 * This object represents a directory; writing a string, number, or
20 * boolean to any of its properties will create a file with the
21 * (encoded) property name as its filename and the "stringified"
22 * value as its contents.
24 * Writing 'null' to one of this object's properties will
25 * [recursively if necessary] delete the corresponding directory
28 * Writing any other object to one of this object's properties will
29 * create a new Directory object and copy the other object's keys()
30 * into the new Directory. This means that assigning one directory
31 * to a property of another directory will <i>copy</i> the directory,
32 * not move it. There is currently no way to move directories.
34 * If an object is written to a property that already has an entry,
35 * the old one is deleted (equivalent to writing 'null') first.
37 * WARNING: when instantiating a Directory object with a file
38 * argument that points to a non-directory File, this class will
39 * delete that file and create a directory!
41 public class Directory extends JS.Immutable {
46 * Create the directory object. Existing directories will be
47 * preserved; if a file is present it will be obliterated.
50 public Directory(File f) throws IOException {
52 if (!f.exists()) new Directory(new File(f.getParent()));
53 if (!f.isDirectory()) destroy(f);
57 private static void destroy(File f) throws IOException {
58 if (!f.exists()) return;
59 if (f.isDirectory()) {
60 String[] entries = f.list();
61 for(int i=0; i<entries.length; i++) destroy(new File(f.getAbsolutePath() + File.separatorChar + entries[i]));
66 public void put(JS key0, JS val) throws JSExn {
68 if (key0 == null) return;
69 String key = JSU.toString(key0);
70 File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
72 if (val == null) return;
73 if (val instanceof org.ibex.io.Fountain) {
74 Stream stream = ((org.ibex.io.Fountain)val).getStream();
75 Stream out = new Stream(null, new FileOutputStream(f2));
76 stream.transcribe(out);
78 } else if (val instanceof JSPrimitive) {
79 OutputStream out = new FileOutputStream(f2);
80 Writer w = new OutputStreamWriter(out);
81 w.write(JSU.toString(val));
85 Directory d2 = new Directory(f2);
86 JS.Enumeration e = val.keys();
93 } catch (IOException ioe) {
94 throw new JSExn.IO(ioe);
98 public JS get(JS key0) throws JSExn {
100 if (key0 == null) return null;
101 String key = JSU.toString(key0);
102 File f2 = new File(f.getAbsolutePath() + File.separatorChar + Encode.toFilename(key));
103 if (!f2.exists()) return null;
104 if (f2.isDirectory()) return new Directory(f2);
105 char[] chars = new char[((int)f2.length()) * 4 + 10];
107 Reader r = new InputStreamReader(new FileInputStream(f2));
109 int numread = r.read(chars, numchars, chars.length - numchars);
110 if (numread == -1) return JSU.S(new String(chars, 0, numchars));
113 } catch (IOException ioe) {
114 throw new JSExn.IO(ioe);
118 public JS.Enumeration keys() {
119 final String[] elements = f.list();
120 return new JS.Enumeration(null) {
122 public boolean _hasNext() { return i < elements.length; }
123 public JS _next() { return JSU.S(Encode.fromFilename(elements[i++])); }