give xt.shell its own package
authorcrawshaw <crawshaw@ibex.org>
Sun, 28 Nov 2004 14:33:43 +0000 (14:33 +0000)
committercrawshaw <crawshaw@ibex.org>
Sun, 28 Nov 2004 14:33:43 +0000 (14:33 +0000)
darcs-hash:20041128143343-2eb37-d075ecaec3930c2f9fe9a39fcc136e1cb676b56f.gz

src/java/org/ibex/xt/Shell.java [deleted file]
src/java/org/ibex/xt/shell/Command.java [new file with mode: 0644]
src/java/org/ibex/xt/shell/Env.java [new file with mode: 0644]
src/java/org/ibex/xt/shell/Request.java [new file with mode: 0644]
src/java/org/ibex/xt/shell/Servlet.java [moved from src/java/org/ibex/xt/ShellServlet.java with 85% similarity]
src/java/org/ibex/xt/shell/Shell.java [new file with mode: 0644]

diff --git a/src/java/org/ibex/xt/Shell.java b/src/java/org/ibex/xt/Shell.java
deleted file mode 100644 (file)
index 4696869..0000000
+++ /dev/null
@@ -1,360 +0,0 @@
-package org.ibex.xt;
-
-import java.io.*;
-import java.net.*;
-import java.util.*;
-import java.util.regex.*;
-
-import org.ibex.util.*;
-import org.ibex.util.Collections;
-import org.ibex.js.*;
-
-public class Shell {
-
-    public static void main(String[] args) throws Exception {
-        if (args.length == 0 || args.length > 2||  !args[0].startsWith("http://")) {
-            printUsage(); return;
-        }
-        Shell shell = new Shell(new URL(args[0]));
-
-        if (args.length == 2) {
-            // FIXME
-        } else {
-            shell.listen(new InputStreamReader(System.in), new OutputStreamWriter(System.out));
-        }
-    }
-
-    private static void printUsage() {
-        System.out.println("Usage: xish url [command]");
-    }
-
-    protected Command[] commands = new Command[] {
-        new LsCommand(),
-        new PwdCommand(),
-        new CdCommand(),
-        new RmCommand(),
-        new HelpCommand()
-    };
-
-    /** URL of server. */
-    protected URL server;
-
-    /** Current JS path using '.' as a seperator. */
-    protected String pwd = ".";
-
-    /** Create a new Shell using the given url for the server. */
-    public Shell(URL url) { server = url; }
-
-    public void listen(Reader r, Writer w) throws IOException {
-        LineNumberReader in = new LineNumberReader(r);
-        PrintWriter out = new PrintWriter(w);
-
-        out.println("ibex xt shell: type help or exit");
-        out.print("xt: ");
-        out.flush();
-
-        String line;
-        String buffer = "";
-        while ((line = in.readLine()) != null) {
-            if (line.length() > 0) {
-                if (line.startsWith("exit")) return;
-                if (line.charAt(line.length() - 1) == '\\') {
-                    buffer += line.substring(0, line.length() - 1);
-                    out.print('>');
-                    out.flush(); continue;
-                }
-
-                buffer += line;
-            }
-
-            if (buffer.length() > 0) {
-                String[] c = buffer.split(" ");
-                int i=0; while (i < commands.length) {
-                    if (commands[i].name().equals(c[0])) {
-                        commands[i].execute(out, c); break;
-                    }
-                    i++;
-                }
-                if (i == commands.length) {
-                    out.write(c[0]);
-                    w.write(": command not found\n");
-                }
-                buffer = "";
-            }
-            out.print("xt: ");
-            out.flush();
-        }
-    }
-
-    /** Returns a path, based on console input. */
-    private String path(String c) {
-        if (c.equals("") || c.equals(".") || c.equals("/")) {
-            c = ".";
-        } else if (c.equals("..")) {
-            c = c.substring(0, c.lastIndexOf('.'));
-            if (c.equals("")) c = ".";
-        } else {
-            if (c.charAt(0) != '/') c = pwd + c;
-            c = c.replaceAll("/+", ".");
-            if (c.length() > 1 && c.charAt(c.length() - 1) == '.')
-                c = c.substring(0, c.length() - 1);
-        }
-
-        return c;
-    }
-
-    private String cookie = null;
-    public Object send(Request request) throws IOException {
-        URLConnection c = server.openConnection();
-        ((HttpURLConnection)c).setRequestMethod("POST");
-        c.setDoOutput(true);
-        if (cookie != null) c.setRequestProperty("Cookie", cookie);
-
-        c.connect();
-
-        ObjectOutputStream out = new ObjectOutputStream(c.getOutputStream());
-        out.writeObject(request);
-        out.close();
-
-        String cook = c.getHeaderField("Set-Cookie");
-        if (cook != null && !cook.equals("")) cookie = cook.substring(0, cook.indexOf(';'));
-
-        try {
-            return new ObjectInputStream(c.getInputStream()).readObject();
-        } catch (ClassNotFoundException e) {
-            e.printStackTrace();
-            throw new IOException("unexpected ClassNotFoundException");
-        }
-    }
-
-    public abstract class Command {
-        /** Returns the command name. */
-        public abstract String name();
-
-        /** Returns single-line of usage information, eg. <tt>pattern]</tt> */
-        public abstract String usage();
-
-        /** Returns single-line description of command. */
-        public abstract String summary();
-
-        /** Returns multi-line description. */
-        public abstract String help();
-
-        /** Writes result of execution, even if result is an error. */
-        public abstract void execute(Writer w, String[] args) throws IOException;
-    }
-
-    /** Returns the command matching the given name. */
-    protected Command command(String name) {
-        for (int i=0; i < commands.length; i++)
-            if (commands[i].name().equals(name)) return commands[i];
-        return null;
-    }
-
-    public class HelpCommand extends Command {
-        public String name() { return "help"; }
-        public String usage() { return "[command name]"; }
-        public String summary() { return "Lists available commands."; }
-        public String help() { return ""; }
-
-        public void execute(Writer w, String[] c) throws IOException {
-            if (c.length > 1) {
-                Command cmd = command(c[1]);
-                if (c == null) {
-                    w.write("help: ");
-                    w.write(c[1]);
-                    w.write(": command not found\n");
-                } else {
-                    w.write("usage: ");
-                    w.write(cmd.name());
-                    w.write(" ");
-                    w.write(cmd.usage());
-                    w.write("\n\n");
-                    w.write(cmd.help());
-                    w.write("\n");
-                }
-            } else {
-                int len = 3;
-                for (int i=0; i < commands.length; i++)
-                    len = Math.max(commands[i].name().length(), len);
-
-                w.write("Available commands:\n");
-                for (int i=0; i < commands.length; i++) {
-                    Command cmd = commands[i];
-                    w.write("  ");
-                    w.write(cmd.name());
-                    for (int j=len - cmd.name().length(); j >= 0; j--) w.write(" ");
-                    w.write(" - ");
-                    w.write(cmd.summary());
-                    w.write("\n");
-                }
-                w.write("\nFor usage details, type help [command name].\n");
-            }
-        }
-    }
-
-    public class LsCommand extends Command {
-        public String name() { return "ls"; }
-        public String usage() { return "[path]"; }
-        public String summary() { return "List object entries."; }
-        public String help() { return
-            "Lists the keys in an object. Modelled after the UNIX ls command.";
-        }
-
-        public void execute(Writer w, String[] c) throws IOException {
-            if (c.length > 2) { w.write(usage()); return; }
-
-            Object ret = send(new KeyRequest(path(c[1])));
-            if (ret == null) {
-                w.write("error: (unexpected) returned object is null\n");
-            } else if (ret instanceof JSExn) {
-                String e = ((JSExn)ret).getMessage();
-                // FIXME: messy way to get info from server
-                if (e.endsWith("does not exist")) {
-                    w.write("ls ");
-                    w.write(c[1]);
-                    w.write(": no such path\n");
-                } else {
-                    w.write("error: ");
-                    w.write(e);
-                    w.write("\n");
-                }
-            } else if (ret instanceof List) {
-                List l = (List)ret; Collections.sort(l);
-                Iterator i = l.iterator(); while (i.hasNext()) {
-                    w.write(i.next().toString());
-                    w.write("\n");
-                }
-            } else {
-                w.write("error: (unexpected) returned object is of unknown type: ");
-                w.write(ret.getClass().getName());
-                w.write("\n");
-            }
-        }
-    }
-
-    public class PwdCommand extends Command {
-        public String name() { return "pwd"; }
-        public String usage() { return ""; }
-        public String summary() { return "Path to current object."; }
-        public String help() { return "Print the path to the current object."; }
-        public void execute(Writer w, String[] c) throws IOException {
-            w.write(c.length == 1 ? pwd.replace('.', '/') : usage());
-            w.write("\n");
-        }
-    }
-
-    public class CdCommand extends Command {
-        public String name() { return "cd"; }
-        public String usage() { return "[path]"; }
-        public String summary() { return "Change current object."; }
-        public String help() { return
-            "Chnages the current object that all other commands use "+
-            "as the base for running.\n Pass either a relative path "+
-            "(e.g. in /prevalent, type cd myob, now in /prevalent/myob) "+
-            "or an absolute path (e.g. cd /prevalent/myob).\n\n" +
-            "To go up one level, cd .. can be used.";
-        }
-        public void execute(Writer w, String[] c) throws IOException {
-            if (c.length > 2) w.write(usage());
-            else if (c.length == 1 || c[1].equals("") || c[1].equals("/")) pwd = ".";
-            else if (c[1].equals("..")) {
-                String n = pwd.substring(0, pwd.lastIndexOf('.'));
-                pwd = n.equals("") ? "." : n;
-            } else {
-                String n = path(c[1]);
-                Object ret = send(new KeyRequest(n));
-
-                if (ret == null) {
-                    w.write("error: (unexpected) server returned null\n");
-                } else if (ret instanceof List && ((List)ret).size() == 1) {
-                    pwd = n;
-                } else if (ret instanceof JSExn ||
-                           (ret instanceof List && ((List)ret).size() == 0)) {
-                    w.write("cd ");
-                    w.write(c[1]);
-                    w.write(": no such path\n");
-                } else {
-                    w.write("error: (unexpected) server returned ");
-                    w.write(ret.toString());
-                    w.write("\n");
-                }
-            }
-        }
-    }
-
-    public class RmCommand extends Command {
-        public String name() { return "rm"; }
-        public String usage() { return "[options] [path]"; }
-        public String summary() { return "Removes objects."; }
-        public String help() { return "Removes objects."; } // FIXME
-        public void execute(Writer w, String[] c) throws IOException {
-            if (c.length == 1) { w.write(usage()); }
-
-            String[] r = new String[c.length - 1];
-            for (int i=0; i < r.length; i++) r[i] = path(c[i + 1]);
-            // Object ret = send(new KeyRequest( FIXME: CompositeRequest
-        }
-    }
-
-    public static abstract class Request implements Serializable {
-        public abstract Object process(JSScope root) throws JSExn;
-    }
-
-    public static class KeyRequest extends Request {
-        private String path, matcher;
-        public KeyRequest() {}
-        public KeyRequest(String c) {
-            int pos = c.lastIndexOf('.');
-            path = c.substring(0, pos);
-            matcher = c.substring(pos + 1).replaceAll("\\*+", ".*");
-        }
-        public KeyRequest(String path, String matcher) {
-            this.path = path; this.matcher = matcher;
-        }
-
-        /** Returns a List. */
-        public Object process(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()));
-                throw new JSExn("path /" + p + " does not exist");
-            } 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 keys;
-            }
-        }
-    }
-
-    public static class ExecRequest extends Request {
-        private JS exec;
-        public ExecRequest() {}
-        public ExecRequest(JS exec) { this.exec = exec; }
-        public ExecRequest(String source) throws IOException, JSExn {
-            this(new StringReader(source));
-        }
-        public ExecRequest(Reader source) throws IOException, JSExn {
-            exec = JS.fromReader("xsh", 0, source);
-        }
-
-        /** Returns the result of <tt>JS.eval()</tt>. */
-        public Object process(JSScope root) throws JSExn {
-            return JS.eval(JS.cloneWithNewParentScope(exec, root));
-        }
-    }
-}
diff --git a/src/java/org/ibex/xt/shell/Command.java b/src/java/org/ibex/xt/shell/Command.java
new file mode 100644 (file)
index 0000000..0ff2952
--- /dev/null
@@ -0,0 +1,160 @@
+package org.ibex.xt.shell;
+
+import java.util.*;
+
+import java.io.Writer;
+import java.io.IOException;
+
+public abstract class Command {
+    /** Returns the command name. */
+    public abstract String name();
+
+    /** Returns single-line of usage information, eg. <tt>pattern]</tt> */
+    public abstract String usage();
+
+    /** Returns single-line description of command. */
+    public abstract String summary();
+
+    /** Returns multi-line description. */
+    public abstract String help();
+
+    /** Writes result of execution, even if result is an error. */
+    public abstract void execute(Writer w, String[] args, Env env) throws IOException;
+
+    public static class Help extends Command {
+        public String name() { return "help"; }
+        public String usage() { return "[command name]"; }
+        public String summary() { return "Lists available commands."; }
+        public String help() { return ""; }
+
+        public void execute(Writer w, String[] c, Env env) throws IOException {
+            if (c.length > 1) {
+                Command cmd = env.command(c[1]);
+                if (c == null) {
+                    w.write("help: ");
+                    w.write(c[1]);
+                    w.write(": command not found\n");
+                } else {
+                    w.write("usage: ");
+                    w.write(cmd.name());
+                    w.write(" ");
+                    w.write(cmd.usage());
+                    w.write("\n\n");
+                    w.write(cmd.help());
+                    w.write("\n");
+                }
+            } else {
+                int len = 3;
+                for (int i=0; i < env.commands.length; i++)
+                    len = Math.max(env.commands[i].name().length(), len);
+
+                w.write("Available commands:\n");
+                for (int i=0; i < env.commands.length; i++) {
+                    Command cmd = env.commands[i];
+                    w.write("  ");
+                    w.write(cmd.name());
+                    for (int j=len - cmd.name().length(); j >= 0; j--) w.write(" ");
+                    w.write(" - ");
+                    w.write(cmd.summary());
+                    w.write("\n");
+                }
+                w.write("\nFor usage details, type help [command name].\n");
+            }
+        }
+    }
+
+    public static class Ls extends Command {
+        public String name() { return "ls"; }
+        public String usage() { return "[path]"; }
+        public String summary() { return "List object entries."; }
+        public String help() { return
+            "Lists the keys in an object. Modelled after the UNIX ls command.";
+        }
+
+        public void execute(Writer w, String[] c, Env env) throws IOException {
+            if (c.length > 2) { w.write(usage()); return; }
+            String p = env.path(c.length == 1 ? "*" : c[1]);
+
+            Request.Response ret = env.send(new Request.Key(p));
+            if (!(ret instanceof Request.Key.Res)) {
+                w.write("error: ");
+                w.write(ret.error().getMessage());
+                w.write("\n");
+            } else {
+                List l = ((Request.Key.Res)ret).keys();
+                Iterator i = l.iterator(); while (i.hasNext()) {
+                    w.write(i.next().toString());
+                    w.write("\n");
+                }
+            }
+        }
+    }
+
+    public static class Pwd extends Command {
+        public String name() { return "pwd"; }
+        public String usage() { return ""; }
+        public String summary() { return "Path to current object."; }
+        public String help() { return "Print the path to the current object."; }
+        public void execute(Writer w, String[] c, Env env) throws IOException {
+            if (c.length != 1) { w.write(usage()); return; }
+            w.write(env.path.equals("") ? "/" : env.path.replace('.', '/'));
+            w.write("\n");
+        }
+    }
+
+    public static class Cd extends Command {
+        public String name() { return "cd"; }
+        public String usage() { return "[path]"; }
+        public String summary() { return "Change current object."; }
+        public String help() { return
+            "Chnages the current object that all other commands use "+
+            "as the base for running.\n Pass either a relative path "+
+            "(e.g. in /prevalent, type cd myob, now in /prevalent/myob) "+
+            "or an absolute path (e.g. cd /prevalent/myob).\n\n" +
+            "To go up one level, cd .. can be used.";
+        }
+        public void execute(Writer w, String[] c, Env env) throws IOException {
+            if (c.length > 2) w.write(usage());
+            else if (c.length == 1 || c[1].equals("") || c[1].equals("/")) env.path = "";
+            else if (c[1].equals("..")) {
+                String n = env.path;
+                n = n.substring(0, n.lastIndexOf('.'));
+                env.path = n;
+            } else {
+                String n = env.path(c[1]);
+
+                Request.Response ret = env.send(new Request.Key(n));
+                if (!(ret instanceof Request.Key.Res)) {
+                    w.write("error: ");
+                    w.write(ret.error().getMessage());
+                    w.write("\n");
+                } else {
+                    List l = ((Request.Key.Res)ret).keys();
+                    if (l.size() == 0) {
+                        w.write("cd ");
+                        w.write(c[1]);
+                        w.write(": no such path\n");
+                    } else {
+                        env.path = n;
+                    }
+                }
+            }
+        }
+    }
+
+    public static class Rm extends Command {
+        public String name() { return "rm"; }
+        public String usage() { return "[options] [path]"; }
+        public String summary() { return "Removes objects."; }
+        public String help() { return "Removes objects."; } // FIXME
+        public void execute(Writer w, String[] c, Env env) throws IOException {
+            if (c.length == 1) { w.write(usage()); }
+
+            String[] r = new String[c.length - 1];
+            for (int i=0; i < r.length; i++) r[i] = env.path(c[i + 1]);
+            // Object ret = send(new KeyRequest( FIXME: CompositeRequest
+        }
+    }
+
+
+}
diff --git a/src/java/org/ibex/xt/shell/Env.java b/src/java/org/ibex/xt/shell/Env.java
new file mode 100644 (file)
index 0000000..6f37146
--- /dev/null
@@ -0,0 +1,35 @@
+package org.ibex.xt.shell;
+
+import java.io.IOException;
+
+public abstract class Env {
+    /** Current JS path using '.' as a seperator. */
+    public String path = "";
+
+    public Command[] commands = new Command[0];
+
+    /** Returns the command matching the given name. */
+    public Command command(String name) {
+        for (int i=0; i < commands.length; i++)
+            if (commands[i].name().equals(name)) return commands[i];
+        return null;
+    }
+
+    /** Returns a path, based on console-style representation. */
+    public String path(String c) {
+        if (c.equals("") || c.equals(".") || c.equals("/")) {
+            c = ".";
+        } else if (c.equals("..")) {
+            c = c.substring(0, c.lastIndexOf('.'));
+            if (c.equals("")) c = ".";
+        } else {
+            if (c.charAt(0) != '/') c = path + "." + c;
+            c = c.replaceAll("/+", ".");
+            if (c.length() > 1 && c.charAt(c.length() - 1) == '.')
+                c = c.substring(0, c.length() - 1);
+        }
+        return c;
+    }
+
+    public abstract Request.Response send(Request request) throws IOException;
+}
diff --git a/src/java/org/ibex/xt/shell/Request.java b/src/java/org/ibex/xt/shell/Request.java
new file mode 100644 (file)
index 0000000..eec18b7
--- /dev/null
@@ -0,0 +1,99 @@
+package org.ibex.xt.shell;
+
+import java.io.*;
+import java.util.*;
+import java.util.regex.*;
+
+import org.ibex.js.*;
+
+public abstract class Request implements Serializable {
+
+    public abstract Response process(JSScope root) throws JSExn;
+
+    public static class Response implements Serializable {
+        protected Exception ex;
+        public Response() { ex = null; }
+        public Response(Exception e) { ex = e; }
+        public Exception error() { return ex; }
+    }
+
+    public static class Key extends Request {
+        private String path, matcher;
+        public Key() {}
+        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 {
+            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 new Res(keys);
+            }
+        }
+
+        public static class Res extends Response {
+            private List keys;
+            public Res() { keys = null; }
+            public Res(List l) { keys = l; }
+            public List keys() { return keys; }
+            public boolean isPath() { return keys != null; }
+        }
+    }
+
+    public static class Composite extends Request {
+        private Request[] requests;
+        public Composite() {}
+        public Composite(Request[] r) { requests = r; }
+        public Composite(List r) {
+            Request[] req = new Request[r.size()];
+            r.toArray(req);
+            requests = req;
+        }
+
+        public Response process(JSScope root) {
+            Response[] res = new Response[requests.length];
+
+            for (int i=0; i < requests.length; i++) {
+                try { res[i] = requests[i].process(root); }
+                catch (JSExn e) { res[i] = new Response(e); }
+            }
+
+            return new Res(res);
+        }
+
+        public static class Res extends Response {
+            private Response[] responses;
+            public Res() {}
+            public Res(Response[] r) { responses = r; }
+            public Response get(int i) { return responses[i]; }
+            public int size() { return responses.length; }
+        }
+    }
+}
similarity index 85%
rename from src/java/org/ibex/xt/ShellServlet.java
rename to src/java/org/ibex/xt/shell/Servlet.java
index e9fc0a8..44cc346 100644 (file)
@@ -1,15 +1,15 @@
-package org.ibex.xt;
+package org.ibex.xt.shell;
 
 import java.io.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 
+import org.ibex.xt.Prevalence;
 import org.ibex.js.*;
 
 import org.prevayler.*;
 
-
-public class ShellServlet extends HttpServlet {
+public class Servlet extends HttpServlet {
     private ServletContext cx = null;
     private Prevayler prevayler;
     private JS prevalent;
@@ -22,8 +22,8 @@ public class ShellServlet extends HttpServlet {
     }
 
     public void doPost(HttpServletRequest rq, HttpServletResponse rs) throws IOException {
-        Shell.Request r;
-        try { r = (Shell.Request)new ObjectInputStream(rq.getInputStream()).readObject(); }
+        Request r;
+        try { r = (Request)new ObjectInputStream(rq.getInputStream()).readObject(); }
         catch (ClassNotFoundException e) {
             e.printStackTrace();
             throw new IOException("exception receiving request, class not found");
@@ -47,8 +47,8 @@ public class ShellServlet extends HttpServlet {
             }
             rq.getSession().setAttribute("scope", scope);
         }
-        Object ret;
-        try { ret = r.process(scope); } catch (JSExn e) { ret = e; }
+        Request.Response ret;
+        try { ret = r.process(scope); } catch (JSExn e) { ret = new Request.Response(e); }
         new ObjectOutputStream(rs.getOutputStream()).writeObject(ret);
     }
 }
diff --git a/src/java/org/ibex/xt/shell/Shell.java b/src/java/org/ibex/xt/shell/Shell.java
new file mode 100644 (file)
index 0000000..746479e
--- /dev/null
@@ -0,0 +1,110 @@
+package org.ibex.xt.shell;
+
+import java.io.*;
+import java.net.*;
+
+public class Shell extends Env {
+
+    public static void main(String[] args) throws Exception {
+        if (args.length == 0 || args.length > 2||  !args[0].startsWith("http://")) {
+            printUsage(); return;
+        }
+        Shell shell = new Shell(new URL(args[0]));
+
+        if (args.length == 2) {
+            // FIXME
+        } else {
+            shell.listen(new InputStreamReader(System.in), new OutputStreamWriter(System.out));
+        }
+    }
+
+    private static void printUsage() {
+        System.out.println("Usage: xish url [command]");
+    }
+
+    /** URL of server. */
+    protected URL server;
+
+    /** Server cookie. Reduces server load. */
+    private String cookie = null;
+
+    /** Create a new Shell using the given url for the server. */
+    public Shell(URL url) {
+        server = url;
+        commands = new Command[] {
+            new Command.Ls(),
+            new Command.Pwd(),
+            new Command.Cd(),
+            new Command.Rm(),
+            new Command.Help()
+        };
+    }
+
+    public void listen(Reader r, Writer w) throws IOException {
+        LineNumberReader in = new LineNumberReader(r);
+        PrintWriter out = new PrintWriter(w);
+
+        out.println("ibex xt shell: type help or exit");
+        out.print("xt: ");
+        out.flush();
+
+        String line;
+        String buffer = "";
+        while ((line = in.readLine()) != null) {
+            if (line.length() > 0) {
+                if (line.startsWith("exit")) return;
+                if (line.charAt(line.length() - 1) == '\\') {
+                    buffer += line.substring(0, line.length() - 1);
+                    out.print('>');
+                    out.flush(); continue;
+                }
+
+                buffer += line;
+            }
+
+            if (buffer.length() > 0) {
+                String[] c = buffer.split(" ");
+                Command cmd = command(c[0]);
+
+                if (cmd == null) {
+                    out.write(c[0]);
+                    w.write(": command not found\n");
+                } else cmd.execute(out, c, this);
+
+                buffer = "";
+            }
+            out.print("xt: ");
+            out.flush();
+        }
+    }
+
+    public Request.Response send(Request request) throws IOException {
+        URLConnection c = server.openConnection();
+        ((HttpURLConnection)c).setRequestMethod("POST");
+        c.setDoOutput(true);
+        if (cookie != null) c.setRequestProperty("Cookie", cookie);
+
+        c.connect();
+
+        ObjectOutputStream out = new ObjectOutputStream(c.getOutputStream());
+        out.writeObject(request);
+        out.close();
+
+        String cook = c.getHeaderField("Set-Cookie");
+        if (cook != null && !cook.equals("")) cookie = cook.substring(0, cook.indexOf(';'));
+
+        try {
+            Object o = new ObjectInputStream(c.getInputStream()).readObject();
+            if (o == null) {
+                throw new IOException("unexpected null object returned");
+            } else if (!(o instanceof Request.Response)) {
+                throw new IOException("unexpected object returned: "+o.getClass().getName());
+            } else {
+                return (Request.Response)o;
+            }
+        } catch (ClassNotFoundException e) {
+            e.printStackTrace();
+            throw new IOException("unexpected ClassNotFoundException");
+        }
+    }
+}