6 import java.util.regex.*;
8 import org.ibex.util.*;
9 import org.ibex.util.Collections;
14 public static void main(String[] args) throws Exception {
15 if (args.length == 0 || args.length > 2|| !args[0].startsWith("http://")) {
18 Shell shell = new Shell(new URL(args[0]));
20 if (args.length == 2) {
23 shell.listen(new InputStreamReader(System.in), new OutputStreamWriter(System.out));
27 private static void printUsage() {
28 System.out.println("Usage: xish url [command]");
31 protected Command[] commands = new Command[] {
40 /** Current JS path using '.' as a seperator. */
41 protected String pwd = ".";
43 /** Create a new Shell using the given url for the server. */
44 public Shell(URL url) { server = url; }
46 public void listen(Reader r, Writer w) throws IOException {
47 LineNumberReader in = new LineNumberReader(r);
48 PrintWriter out = new PrintWriter(w);
50 out.println("ibex xt shell: type help or exit");
56 while ((line = in.readLine()) != null) {
57 if (line.length() > 0) {
58 if (line.startsWith("exit")) return;
59 if (line.charAt(line.length() - 1) == '\\') {
60 buffer += line.substring(0, line.length() - 1);
62 out.flush(); continue;
68 if (buffer.length() > 0) {
69 String[] c = buffer.split(" ");
70 int i=0; while (i < commands.length) {
71 if (commands[i].name().equals(c[0])) {
72 commands[i].execute(out, c);
73 out.write('\n'); break;
77 if (i == commands.length) {
79 w.write(": command not found\n");
88 private String cookie = null;
89 public Object send(Request request) throws IOException {
90 URLConnection c = server.openConnection();
91 ((HttpURLConnection)c).setRequestMethod("POST");
93 if (cookie != null) c.setRequestProperty("Cookie", cookie);
97 ObjectOutputStream out = new ObjectOutputStream(c.getOutputStream());
98 out.writeObject(request);
101 String cook = c.getHeaderField("Set-Cookie");
102 if (cook != null && !cook.equals("")) cookie = cook.substring(0, cook.indexOf(';'));
105 return new ObjectInputStream(c.getInputStream()).readObject();
106 } catch (ClassNotFoundException e) {
108 throw new IOException("unexpected ClassNotFoundException");
112 public abstract class Command {
113 /** Returns the command name. */
114 public abstract String name();
116 /** Returns single-line of usage information, eg. <tt>pattern]</tt> */
117 public abstract String usage();
119 /** Returns single-line description of command. */
120 public abstract String summary();
122 /** Returns multi-line description. */
123 public abstract String help();
125 /** Writes result of execution, even if result is an error. */
126 public abstract void execute(Writer w, String[] args) throws IOException;
129 /** Returns the command matching the given name. */
130 protected Command command(String name) {
131 for (int i=0; i < commands.length; i++)
132 if (commands[i].name().equals(name)) return commands[i];
136 public class HelpCommand extends Command {
137 public String name() { return "help"; }
138 public String usage() { return "[command name]"; }
139 public String summary() { return "Lists available commands."; }
140 public String help() { return ""; }
142 public void execute(Writer w, String[] c) throws IOException {
144 Command cmd = command(c[1]);
148 w.write(": command not found");
153 w.write(cmd.usage());
160 for (int i=0; i < commands.length; i++)
161 len = Math.max(commands[i].name().length(), len);
163 w.write("Available commands:\n");
164 for (int i=0; i < commands.length; i++) {
165 Command cmd = commands[i];
168 for (int j=len - cmd.name().length(); j >= 0; j--) w.write(" ");
170 w.write(cmd.summary());
173 w.write("\nFor usage details, type help [command name].");
178 public class LsCommand extends Command {
179 public String name() { return "ls"; }
180 public String usage() { return "[path]"; }
181 public String summary() { return "List object entries."; }
182 public String help() { return
183 "The ls command, modelled after the UNIX ls command lists the " +
184 "keys in an object. ";
187 public void execute(Writer w, String[] c) throws IOException {
188 if (c.length > 2) { w.write(usage()); return; }
191 String matcher = ".*";
193 int pos = c[1].lastIndexOf('/') + 1;
194 path += c[1].substring(0, pos);
195 path = path.replaceAll("/", "\\.");
196 if (pos < c[1].length()) {
197 matcher = c[1].substring(pos);
198 matcher = matcher.replaceAll("\\.", "\\.");
199 matcher = matcher.replaceAll("\\*", ".*");
203 Object ret = send(new KeyRequest(path, matcher));
205 w.write("error: (unexpected) returned object is null");
206 } else if (ret instanceof JSExn) {
208 w.write(((JSExn)ret).getMessage());
209 } else if (ret instanceof List) {
210 List l = (List)ret; Collections.sort(l);
211 w.write("total items: ");
212 w.write(l.size()+"");
213 Iterator i = l.iterator(); while (i.hasNext()) {
215 w.write(i.next().toString());
218 w.write("error: (unexpected) returned object is of unknown type: ");
219 w.write(ret.getClass().getName());
224 public class PwdCommand extends Command {
225 public String name() { return "pwd"; }
226 public String usage() { return ""; }
227 public String summary() { return "Path to current object."; }
228 public String help() { return "Print the path to the current object."; }
229 public void execute(Writer w, String[] c) throws IOException {
230 w.write(c.length == 1 ? pwd.replace('.', '/') : usage());
234 public static abstract class Request implements Serializable {
235 public abstract Object process(JSScope root) throws JSExn;
238 public static class KeyRequest extends Request {
239 private String path, matcher;
240 public KeyRequest() {}
241 public KeyRequest(String path, String matcher) {
242 this.path = path; this.matcher = matcher;
245 /** Returns a List. */
246 public Object process(JSScope root) throws JSExn {
247 String p = path == null ? "" : path.replaceAll("\\.+", "\\.");
248 if (p.length() > 0 && p.charAt(0) == '.') p = p.substring(1);
249 if (p.length() > 0 && p.charAt(p.length() - 1) == '.') p = p.substring(0, p.length() - 1);
250 System.out.println("searching path '"+p+"' for pattern '"+matcher+"'");
252 Object o = p.equals("") ? root : root.get(p);
253 if (o == null || o instanceof JSDate ||
254 o instanceof JSArray ||
255 !(o instanceof JS)) {
256 System.out.println("hit bad object: "+o+", class="+
257 (o == null ? null : o.getClass().getName()));
258 throw new JSExn("path /" + p + " does not exist");
260 Pattern pat = Pattern.compile(matcher);
261 List keys = new ArrayList();
263 Iterator i = ((JS)o).keys().iterator(); while(i.hasNext()) {
264 String k = i.next().toString();
265 if (pat.matcher(k).matches()) keys.add(k);
273 public static class ExecRequest extends Request {
275 public ExecRequest() {}
276 public ExecRequest(JS exec) { this.exec = exec; }
277 public ExecRequest(String source) throws IOException, JSExn {
278 this(new StringReader(source));
280 public ExecRequest(Reader source) throws IOException, JSExn {
281 exec = JS.fromReader("xsh", 0, source);
284 /** Returns the result of <tt>JS.eval()</tt>. */
285 public Object process(JSScope root) throws JSExn {
286 return JS.eval(JS.cloneWithNewParentScope(exec, root));