Added a simple session manager for responders and used it in the bsh sample.
authorFredrik Tolf <fredrik@dolda2000.com>
Mon, 26 Oct 2009 16:32:54 +0000 (17:32 +0100)
committerFredrik Tolf <fredrik@dolda2000.com>
Mon, 26 Oct 2009 16:32:54 +0000 (17:32 +0100)
samples/bsh/src/dolda/bsvc/Main.java
samples/bsh/src/dolda/bsvc/ShellPage.java
src/dolda/jsvc/util/PerSession.java [new file with mode: 0644]

index a1687af..d6a83d2 100644 (file)
@@ -6,7 +6,7 @@ import dolda.jsvc.util.*;
 public class Main {
     public static Responder responder() {
        Multiplexer root = new Multiplexer();
-       root.file("sh", new ShellPage());
+       root.file("sh", new PerSession(ShellPage.class));
        root.file("css", new StaticContent(Main.class, "static/base.css", false, "text/css"));
        return(Misc.stdroot(root));
     }
index 29d0d3d..e7412ad 100644 (file)
@@ -6,6 +6,47 @@ import java.io.*;
 import bsh.Interpreter;
 
 public class ShellPage extends SimpleWriter {
+    private RConsole cons = new RConsole();
+    private Interpreter ip = new Interpreter(cons);
+    
+    private static class RConsole implements bsh.ConsoleInterface {
+       public Console back;
+       Reader in = new StringReader("");
+       
+       public void error(Object msg) {
+           if(back != null)
+               back.error(msg);
+       }
+       
+       public void print(Object msg) {
+           if(back != null)
+               back.print(msg);
+       }
+       
+       public void println(Object msg) {
+           if(back != null)
+               back.println(msg);
+       }
+       
+       public PrintStream getOut() {
+           if(back == null)
+               return(null);
+           return(back.getOut());
+       }
+       
+       public PrintStream getErr() {
+           if(back == null)
+               return(null);
+           return(back.getErr());
+       }
+       
+       public Reader getIn() {
+           if(back == null)
+               return(null);
+           return(in);
+       }
+    }
+    
     private static class Console implements bsh.ConsoleInterface {
        ByteArrayOutputStream obuf = new ByteArrayOutputStream();
        ByteArrayOutputStream ebuf = new ByteArrayOutputStream();
@@ -61,25 +102,31 @@ public class ShellPage extends SimpleWriter {
        out.println("<h1>Shell</h1>");
        if((req.method() == "POST") && (cmd != null)) {
            Console cons = new Console();
-           Interpreter ip = new Interpreter(cons);
-           Object resp;
-           try {
-               ip.set("req", req);
-               resp = ip.eval(cmd);
-               out.println("<pre>");
-               out.println(Misc.htmlq((resp == null)?"(null)":(resp.toString())));
-               out.println("</pre>");
-           } catch(bsh.EvalError exc) {
-               out.println("<h2>Evaluation error</h2>");
-               out.println("<pre>");
-               out.print(exc.toString());
-               out.println("</pre>");
-               if(exc instanceof bsh.TargetError) {
-                   bsh.TargetError te = (bsh.TargetError)exc;
-                   out.println("<h3>Target error</h3>");
-                   out.println("<pre>");
-                   te.getTarget().printStackTrace(out);
-                   out.println("</pre>");
+           synchronized(ip) {
+               this.cons.back = cons;
+               try {
+                   Object resp;
+                   try {
+                       ip.set("req", req);
+                       resp = ip.eval(cmd);
+                       out.println("<pre>");
+                       out.println(Misc.htmlq((resp == null)?"(null)":(resp.toString())));
+                       out.println("</pre>");
+                   } catch(bsh.EvalError exc) {
+                       out.println("<h2>Evaluation error</h2>");
+                       out.println("<pre>");
+                       out.print(exc.toString());
+                       out.println("</pre>");
+                       if(exc instanceof bsh.TargetError) {
+                           bsh.TargetError te = (bsh.TargetError)exc;
+                           out.println("<h3>Target error</h3>");
+                           out.println("<pre>");
+                           te.getTarget().printStackTrace(out);
+                           out.println("</pre>");
+                       }
+                   }
+               } finally {
+                   this.cons.back = null;
                }
            }
            String eo = new String(cons.obuf.toByteArray(), Misc.utf8);
diff --git a/src/dolda/jsvc/util/PerSession.java b/src/dolda/jsvc/util/PerSession.java
new file mode 100644 (file)
index 0000000..7973e0a
--- /dev/null
@@ -0,0 +1,100 @@
+package dolda.jsvc.util;
+
+import dolda.jsvc.*;
+import java.lang.reflect.*;
+
+public class PerSession implements Responder {
+    private final Class<?> rcl;
+    private final Class<?> dcl;
+    
+    public PerSession(Class<?> rcl, Class<?> dcl) {
+       this.rcl = rcl;
+       this.dcl = dcl;
+    }
+    
+    public PerSession(Class<?> rcl) {
+       this(rcl, null);
+    }
+    
+    private Object makedata(Session sess) {
+       try {
+           try {
+               return(dcl.getConstructor().newInstance());
+           } catch(NoSuchMethodException e) {
+           }
+           try {
+               return(dcl.getConstructor(Session.class).newInstance(sess));
+           } catch(NoSuchMethodException e) {
+           }
+       } catch(InstantiationException e) {
+           throw(new RuntimeException(e));
+       } catch(IllegalAccessException e) {
+           throw(new RuntimeException(e));
+       } catch(InvocationTargetException e) {
+           throw(new RuntimeException(e));
+       }
+       throw(new RuntimeException("Found no way to create an instance of " + dcl.getName()));
+    }
+
+    private Object getdata(Session sess) {
+       Object d = sess.get(dcl, null);
+       if(d == null) {
+           d = makedata(sess);
+           sess.put(dcl, d);
+       }
+       return(d);
+    }
+
+    private Responder create(Session sess) {
+       try {
+           if(dcl != null) {
+               try {
+                   return((Responder)rcl.getMethod("responder", dcl).invoke(null, getdata(sess)));
+               } catch(NoSuchMethodException e) {
+               }
+           }
+           try {
+               return((Responder)rcl.getMethod("responder", Session.class).invoke(null, sess));
+           } catch(NoSuchMethodException e) {
+           }
+           try {
+               return((Responder)rcl.getMethod("responder").invoke(null));
+           } catch(NoSuchMethodException e) {
+           }
+           if(dcl != null) {
+               try {
+                   return((Responder)rcl.getConstructor(dcl).newInstance(getdata(sess)));
+               } catch(NoSuchMethodException e) {
+               }
+           }
+           try {
+               return((Responder)rcl.getConstructor(Session.class).newInstance(sess));
+           } catch(NoSuchMethodException e) {
+           }
+           try {
+               return((Responder)rcl.getConstructor().newInstance());
+           } catch(NoSuchMethodException e) {
+           }
+       } catch(InstantiationException e) {
+           throw(new RuntimeException(e));
+       } catch(IllegalAccessException e) {
+           throw(new RuntimeException(e));
+       } catch(InvocationTargetException e) {
+           throw(new RuntimeException(e));
+       }
+       throw(new RuntimeException("Found no way to create a responder from the class " + rcl.getName()));
+    }
+
+    public void respond(Request req) {
+       Session sess = Session.get(req);
+       Responder resp;
+       synchronized(sess) {
+           resp = (Responder)sess.get(rcl, null);
+           if(resp == null) {
+               resp = create(sess);
+               sess.put(rcl, resp);
+           }
+       }
+       resp.respond(req);
+    }
+}