}
public static class Key extends Request {
- private String path, matcher;
+ protected String path, matcher;
public Key() {}
+
+ /** Expects a shell-path that uses '.' as a seperator and * for wildcard. */
public Key(String c) {
int pos = c.lastIndexOf('.');
path = c.substring(0, pos);
matcher = c.substring(pos + 1).replaceAll("\\*+", ".*");
}
+
public Key(String path, String matcher) {
this.path = path; this.matcher = matcher;
}
- public Response process(JSScope root) throws JSExn {
+ /** Returns the object referenced by path. */
+ protected Object path(JSScope root) throws JSExn {
String p = path == null ? "" : path.replaceAll("\\.+", "\\.");
if (p.length() > 0 && p.charAt(0) == '.')
p = p.substring(1);
if (p.length() > 0 && p.charAt(p.length() - 1) == '.')
p = p.substring(0, p.length() - 1);
- System.out.println("searching path '"+p+"' for pattern '"+matcher+"'");
-
- Object o = p.equals("") ? root : root.get(p);
- if (o == null || o instanceof JSDate ||
- o instanceof JSArray ||
- !(o instanceof JS)) {
- System.out.println("hit bad object: "+o+", class="+
- (o == null ? null : o.getClass().getName()));
- return new Key.Res();
- } else {
- Pattern pat = Pattern.compile(matcher);
- List keys = new ArrayList();
-
- Iterator i = ((JS)o).keys().iterator(); while(i.hasNext()) {
- String k = i.next().toString();
- if (pat.matcher(k).matches()) keys.add(k);
- }
+ return p.equals("") ? root : root.get(p);
+ }
+
+ /** Returns the keys in <tt>js</tt> that match <tt>matcher</tt>. */
+ protected List matches(JS js) throws JSExn {
+ String m = matcher;
- return new Res(keys);
+ Pattern pat = Pattern.compile(m);
+ List keys = new ArrayList();
+
+ Iterator i = js.keys().iterator(); while(i.hasNext()) {
+ String k = i.next().toString();
+ if (pat.matcher(k).matches()) keys.add(k);
}
+
+ return keys;
+ }
+
+ /** Returns <tt>o</tt> cast as a JS if it is such and has keys,
+ * otherwise returns null. */
+ protected JS keyed(Object o) {
+ // FIXME: replace this with a canHaveKeys() function in org.ibex.js.JS
+ return o == null || !(o instanceof JS) ||
+ o instanceof JSDate || o instanceof Directory ||
+ o instanceof Grammar || o instanceof JSMath ||
+ o instanceof JSReflection || o instanceof JSRegexp ?
+ null : (JS)o;
+ }
+
+ public Response process(JSScope root) throws JSExn {
+ JS js = keyed(path(root));
+
+ // if matcher is exact and a keyed object, return its keys
+ JS o = keyed(js.get(matcher));
+ if (o != null) { js = o; matcher = ".*"; }
+
+ return js == null ? new Res() : new Res(matches(js));
}
public static class Res extends Response {
}
}
+ public static class IsKey extends Key {
+ public IsKey() {}
+ public IsKey(String c) { super(c); }
+ public Response process(JSScope root) throws JSExn {
+ JS js = keyed(path(root));
+ return js == null ? new Res(false) : new Res(js.get(matcher) != null);
+ }
+
+ public static class Res extends Response {
+ private boolean exists;
+ public Res() {}
+ public Res(boolean e) { exists = e; }
+ public boolean exists() { return exists; }
+ }
+ }
+
+ public static class RemoveKey extends Key {
+ public RemoveKey(String c) { super(c); }
+ public RemoveKey(String p, String m) { super(p, m); }
+ public Response process(JSScope root) throws JSExn {
+ JS js = keyed(path(root));
+ if (js == null) throw new JSExn("no such path");
+ boolean rm = js.containsKey(matcher);
+ if (rm) js.remove(matcher);
+ return new Res(rm);
+ }
+
+ public static class Res extends Response {
+ private boolean removed;
+ public Res() { }
+ public Res(boolean rm) { removed = rm; }
+ public boolean removed() { return removed; }
+ }
+ }
+
+ public static class SetKey extends Key {
+ protected JS value;
+ public SetKey() {}
+ public SetKey(String p, String m, JS val) { super(p, m); this.value = val; }
+
+ public Response process(JSScope root) throws JSExn {
+ JS js = keyed(path(root));
+ if (js == null) throw new JSExn("no such path");
+
+ js.put(matcher, JS.eval(JS.cloneWithNewParentScope(
+ value, new JSResolve(root, js))));
+ return new Res(); // TODO: return put() value when it has one
+ }
+
+ public class Res extends Response {
+ }
+
+ public class JSResolve extends JSScope {
+ private JS path;
+ public JSResolve(JSScope parent, JS path) { super(parent); this.path = path; }
+ public Object get(Object key) throws JSExn {
+ if (key != null && key instanceof String) {
+ String k = (String)key;
+ if (k.startsWith(".")) k = k.substring(1);
+ else return path.get(k);
+ }
+ return super.get(key);
+ }
+ public void put(Object key, Object val) throws JSExn {
+ if (key != null && key instanceof String) {
+ String k = (String)key;
+ if (k.startsWith(".")) k = k.substring(1);
+ else { path.put(key, val); return; }
+ }
+ super.put(key, val);
+ }
+ }
+ }
+
+ /** Runs a series of requests. */
public static class Composite extends Request {
+ private boolean breakOnError = false;
private Request[] requests;
public Composite() {}
- public Composite(Request[] r) { requests = r; }
- public Composite(List r) {
+ public Composite(Request[] r, boolean breakOnError) {
+ requests = r;
+ this.breakOnError = breakOnError;
+ }
+ public Composite(List r, boolean breakOnError) {
Request[] req = new Request[r.size()];
r.toArray(req);
requests = req;
+ this.breakOnError = breakOnError;
}
public Response process(JSScope root) {
for (int i=0; i < requests.length; i++) {
try { res[i] = requests[i].process(root); }
- catch (JSExn e) { res[i] = new Response(e); }
+ catch (JSExn e) {
+ res[i] = new Response(e);
+
+ if (breakOnError) {
+ Response[] newres = new Response[i + 1];
+ System.arraycopy(res, 0, newres, 0, newres.length);
+ res = newres;
+ break;
+ }
+ }
}
return new Res(res);
public Res(Response[] r) { responses = r; }
public Response get(int i) { return responses[i]; }
public int size() { return responses.length; }
+ public Response[] responses() { return responses; }
}
}
}