bugfixes and working rm command
[org.ibex.xt-crawshaw.git] / src / java / org / ibex / xt / shell / Request.java
1 package org.ibex.xt.shell;
2
3 import java.io.*;
4 import java.util.*;
5 import java.util.regex.*;
6
7 import org.ibex.js.*;
8
9 public abstract class Request implements Serializable {
10
11     public abstract Response process(JSScope root) throws JSExn;
12
13     public static class Response implements Serializable {
14         protected Exception ex;
15         public Response() { ex = null; }
16         public Response(Exception e) { ex = e; }
17         public Exception error() { return ex; }
18     }
19
20     public static class Key extends Request {
21         protected String path, matcher;
22         public Key() {}
23
24         /** Expects a shell-path that uses '.' as a seperator and * for wildcard. */
25         public Key(String c) {
26             int pos = c.lastIndexOf('.');
27             path = c.substring(0, pos);
28             matcher = c.substring(pos + 1).replaceAll("\\*+", ".*");
29         }
30
31         public Key(String path, String matcher) {
32             this.path = path; this.matcher = matcher;
33         }
34
35         /** Returns the object referenced by path. */
36         protected Object path(JSScope root) throws JSExn {
37             String p = path == null ? "" : path.replaceAll("\\.+", "\\.");
38             if (p.length() > 0 && p.charAt(0) == '.')
39                 p = p.substring(1);
40             if (p.length() > 0 && p.charAt(p.length() - 1) == '.')
41                 p = p.substring(0, p.length() - 1);
42
43             return p.equals("") ? root : root.get(p);
44         }
45
46         /** Returns the keys in <tt>js</tt> that match <tt>matcher</tt>. */
47         protected List matches(JS js) throws JSExn {
48             Pattern pat = Pattern.compile(matcher);
49             List keys = new ArrayList();
50
51             Iterator i = js.keys().iterator(); while(i.hasNext()) {
52                 String k = i.next().toString();
53                 if (pat.matcher(k).matches()) keys.add(k);
54             }
55
56             return keys;
57         }
58
59         /** Returns <tt>o</tt> cast as a JS if it is such and has keys,
60          *  otherwise returns null. */
61         protected JS keyed(Object o) {
62             // FIXME: replace this with a canHaveKeys() function in org.ibex.js.JS
63             return o == null || !(o instanceof JS) ||
64                        o instanceof JSDate || o instanceof Directory ||
65                        o instanceof Grammar || o instanceof JSMath ||
66                        o instanceof JSReflection || o instanceof JSRegexp ?
67                    null : (JS)o;
68         }
69
70         public Response process(JSScope root) throws JSExn {
71             JS js = keyed(path(root));
72             return js == null ? new Res() : new Res(matches(js));
73         }
74
75         public static class Res extends Response {
76             private List keys;
77             public Res() { keys = null; }
78             public Res(List l) { keys = l; }
79             public List keys() { return keys; }
80             public boolean isPath() { return keys != null; }
81         }
82     }
83
84     public static class RemoveKey extends Key {
85         public RemoveKey(String c) { super(c); }
86         public RemoveKey(String p, String m) { super(p, m); }
87         public Response process(JSScope root) throws JSExn {
88             JS js = keyed(path(root));
89             if (js == null) throw new JSExn("no such path");
90             boolean rm = js.containsKey(matcher);
91             if (rm) js.remove(matcher);
92             return new Res(rm);
93         }
94
95         public static class Res extends Response {
96             private boolean removed;
97             public Res() { }
98             public Res(boolean rm) { removed = rm; }
99             public boolean removed() { return removed; }
100         }
101     }
102
103     /** Runs a series of requests. */
104     public static class Composite extends Request {
105         private boolean breakOnError = false;
106         private Request[] requests;
107         public Composite() {}
108         public Composite(Request[] r, boolean breakOnError) {
109             requests = r;
110             this.breakOnError = breakOnError;
111         }
112         public Composite(List r, boolean breakOnError) {
113             Request[] req = new Request[r.size()];
114             r.toArray(req);
115             requests = req;
116             this.breakOnError = breakOnError;
117         }
118
119         public Response process(JSScope root) {
120             Response[] res = new Response[requests.length];
121
122             for (int i=0; i < requests.length; i++) {
123                 try { res[i] = requests[i].process(root); }
124                 catch (JSExn e) {
125                     res[i] = new Response(e);
126
127                     if (breakOnError) {
128                         Response[] newres = new Response[i + 1];
129                         System.arraycopy(res, 0, newres, 0,  newres.length);
130                         res = newres;
131                         break;
132                     }
133                 }
134             }
135
136             return new Res(res);
137         }
138
139         public static class Res extends Response {
140             private Response[] responses;
141             public Res() {}
142             public Res(Response[] r) { responses = r; }
143             public Response get(int i) { return responses[i]; }
144             public int size() { return responses.length; }
145             public Response[] responses() { return responses; }
146         }
147     }
148 }