import
authoradam <adam@megacz.com>
Thu, 23 Sep 2004 08:32:17 +0000 (08:32 +0000)
committeradam <adam@megacz.com>
Thu, 23 Sep 2004 08:32:17 +0000 (08:32 +0000)
darcs-hash:20040923083217-5007d-cacf91c75a5198038c2644983de979f738e59b6f.gz

src/org/ibex/xml/JSRewriter.java [new file with mode: 0644]
src/org/ibex/xml/Servlet.java [new file with mode: 0644]

diff --git a/src/org/ibex/xml/JSRewriter.java b/src/org/ibex/xml/JSRewriter.java
new file mode 100644 (file)
index 0000000..d87afb3
--- /dev/null
@@ -0,0 +1,48 @@
+package org.ibex.xml;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+
+public class JSRewriter extends XML.Node.Stream {
+
+    private XML.Node.Stream in;
+    private JSScope scope;
+
+    public JSRewriter(XML.Node.Stream in) { this.in = in; this.scope = new JSScope(null); }
+    public JSRewriter(XML.Node.Stream in, JSScope scope) { this.in = in; this.scope = scope; }
+
+    public boolean _next(int level, XML.Node n) {
+        if (!in.next(level, n)) return false;
+        if (n.cdata != null) n.cdata = eval(n.cdata);
+        else for(int i=1; i<n.numattrs; i+=2) n.attrs[i] = eval(n.attrs[i]);
+        return true;
+    }
+
+    private String eval(String s) {
+        if (s == null) return null;
+        StringBuffer ret = new StringBuffer();
+        while(s.indexOf("$[") != -1) {
+            ret.append(s.substring(0, s.indexOf("$[")));
+            s = s.substring(s.indexOf("$[")+2);
+            String s2 = "return (" + s.substring(0, s.indexOf(']')) + ");\n";
+            System.err.println("evaluating " + s2);
+            try {
+                JS js = JS.cloneWithNewParentScope(JS.fromReader("input", 0, new StringReader(s2)), scope);
+                Object r = js.call(null, null, null, null, 0);
+                System.err.println("output was " + r);
+                ret.append(r == null ? "null" : r.toString());
+            } catch (Exception e) {
+                e.printStackTrace();
+                ret.append(e.toString());
+            }
+            s = s.substring(s.indexOf(']') + 1);
+        }
+        ret.append(s);
+        return ret.toString();
+    }
+}
+
+
diff --git a/src/org/ibex/xml/Servlet.java b/src/org/ibex/xml/Servlet.java
new file mode 100644 (file)
index 0000000..833f8fc
--- /dev/null
@@ -0,0 +1,244 @@
+package org.ibex.xml;
+import org.ibex.js.*;
+import org.ibex.util.*;
+import org.ibex.io.*;
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import javax.servlet.*;
+import javax.servlet.http.*;
+import com.thoughtworks.xstream.*;
+import org.prevayler.*;
+import org.prevayler.implementation.snapshot.*;
+
+
+public class Servlet extends HttpServlet {
+
+    private ServletResolver resolver = new ServletResolver();
+    private class ServletResolver implements XML.Node.Stream.Resolver {
+        public XML.Node.Stream.Functor resolve(String uri) {
+            if (uri.indexOf(':') == -1) throw new RuntimeException("uri does not contain an method: " + uri);
+            String method = uri.substring(0, uri.indexOf(':'));
+            String rest = uri.substring(uri.indexOf(':'))+1;
+            //case "xtree":  return XTree.tag(rest);
+            //#switch(method)
+            case "webinf": return new Template(cx.getRealPath(rest));
+            case "java":   try { return (XML.Node.Stream.Functor)Class.forName(rest).newInstance(); }
+                           catch (Exception e) { throw new RuntimeException(e); }
+            //#end
+            throw new RuntimeException("unknown method " + method);    
+        }
+    }
+
+    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
+        JSScope scope = new ServletScope(request, response);
+        String path = cx.getRealPath(((HttpServletRequest)request).getServletPath());
+        Reader xmlreader = new InputStreamReader(new FileInputStream(path));
+        XML.Node.Stream s = new JSRewriter(XML.Node.Stream.in(xmlreader), scope);
+        s.out(response.getWriter());
+    }
+
+    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { doGet(request, response); }
+
+    public class ServletScope extends JSScope {
+        HttpServletRequest request;
+        HttpServletResponse response;
+        public ServletScope(ServletRequest request, ServletResponse response) {
+            super(null);
+            this.request = (HttpServletRequest)request;
+            this.response = (HttpServletResponse)response;
+        }
+        private JS params = new JS() {
+                public Object get(Object key) { return request.getParameter(JS.toString(key)); }
+                public Enumeration keys() { return request.getParameterNames(); }
+            };
+        private JS cookies = new JS() {
+                /*
+                public Object get(Object key) { return request.getCookie(JS.toString(key)); }
+                public Enumeration keys() { return request.getCookieNames(); }
+                */
+            };
+        private JS sessionAttributes = new JS() {
+                public Object get(Object key) { return request.getSession(true).getAttribute(JS.toString(key)); }
+                public void put(Object key, Object val) {
+                    if (val == null) request.getSession(true).removeAttribute(JS.toString(key));
+                    else request.setAttribute(JS.toString(key), val); }
+                public Enumeration keys() { return request.getSession(true).getAttributeNames(); }
+            };
+        private JS requestHeader = new JS() {
+                public Object get(Object key) { return request.getHeader(JS.toString(key)); }
+                public Enumeration keys() { return request.getHeaderNames(); }
+            };
+        private JS responseHeader = new JS() {
+                public void put(Object key, Object val) { response.setHeader(JS.toString(key), JS.toString(val)); }
+            };
+
+
+        /** lets us put multi-level get/put/call keys all in the same method */
+        private class Sub extends JS {
+            Object key;
+            Sub(Object key) { this.key = key; }
+            public void put(Object key, Object val) throws JSExn {
+                ServletScope.this.put(JS.toString(this.key) + "." + JS.toString(key), val); }
+            public Object get(Object key) throws JSExn {
+                return ServletScope.this.get(JS.toString(this.key) + "." + JS.toString(key)); }
+            public Object call(Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+                return ServletScope.this.callMethod(this.key, a0, a1, a2, rest, nargs);
+            }
+            public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
+                return ServletScope.this.callMethod(JS.toString(this.key) + "."
+                                                         + JS.toString(method), a0, a1, a2, rest, nargs);
+            }
+        }
+        private Sub getSub(String key) { return new Sub(key); }
+
+        public Object callMethod(Object method, final Object a, final Object b, Object c, Object[] rest, int nargs) throws JSExn {
+            //#switch(method)
+            case "prevalent.query":
+                try {
+                    return prevayler.execute(new JSQuery(JS.cloneWithNewParentScope((JS)a, null)));
+                } catch (Exception e) {
+                    e.printStackTrace();
+                    throw new RuntimeException(e); }
+
+            case "prevalent.execute":
+                try {
+                    prevayler.execute(new JSTransaction(JS.cloneWithNewParentScope((JS)a, null)));
+                } catch (Exception e) { 
+                    e.printStackTrace();
+                    throw new RuntimeException(e); }
+
+            case "session.invalidate":    request.getSession(true).invalidate(); return null;
+            //#end
+            return null;
+        }
+        public Object get(Object key) throws JSExn {
+            //#switch(key)
+            case "body":
+            case "arg":                   return null;
+            case "prevalent":             return getSub("prevalent");
+            case "prevalent.query":       return METHOD;
+            case "prevalent.execute":     return METHOD;
+            case "request":               return getSub("request");
+            case "request.user":          return request.getRemoteUser();
+            case "request.header":        return requestHeader;
+            case "request.method":        return request.getMethod();
+            case "request.remote":        return getSub("request.remote");
+            case "request.remote.ip":     return request.getRemoteAddr();
+            case "request.remote.host":   return request.getRemoteHost();
+            case "request.ssl":           return request.isSecure();
+            case "request.path":          return request.getPathInfo();
+            case "response":              return getSub("response");
+            case "response.header":       return responseHeader;
+            case "session":               return getSub("session");
+            case "session.attr":          return sessionAttributes;
+            case "session.created":       return new JSDate(request.getSession(true).getCreationTime());
+            case "session.accessed":      return new JSDate(request.getSession(true).getLastAccessedTime());
+            case "session.invalidate":    return METHOD;
+            case "params":                return params;
+            case "cookie":                return cookies;
+            //#end
+            return null;
+        }
+        public void put(Object key, Object val) throws JSExn {
+            try {
+            //#switch(JS.toString(key))
+            case "response.code":         response.setStatus(JS.toInt(val));
+            case "response.redirect":     response.sendRedirect(JS.toString(val));
+            case "response.contentType":  response.setContentType(JS.toString(val));
+            //#end
+            } catch (IOException e) {
+                throw new JSExn(e);
+            }
+        }
+    }
+
+    // Prevalence //////////////////////////////////////////////////////////////////////////////
+    
+    static final Hashtable prevaylers = new Hashtable();
+    private Prevayler prevayler;
+    private JS prevalent;
+    private ServletContext cx = null;
+    public void destroy() {
+        try {
+            synchronized(this.getClass()) {
+                Prevayler privatePrevayler = prevayler;
+                if (prevayler == null) return;
+                prevayler = null;
+                prevaylers.remove(cx);
+                prevayler.takeSnapshot();
+                prevayler.close();
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    private static class SnapshotThread extends Thread {
+        ServletContext cx;
+        public SnapshotThread(ServletContext cx) { this.cx = cx; }
+        public void run() {
+            try {
+                Thread.sleep(10000);
+                Prevayler privatePrevayler = (Prevayler)prevaylers.get(cx);
+                if (privatePrevayler == null) return;
+                privatePrevayler.takeSnapshot();
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    public void init(ServletConfig sc) throws ServletException {
+        try {
+            cx = sc.getServletContext();
+            synchronized(cx) {
+                prevayler = (Prevayler)prevaylers.get(cx);
+                if (prevalent == null) {
+                    PrevaylerFactory pf = new PrevaylerFactory();
+                    String base = cx.getRealPath("/") + "WEB-INF" + File.separatorChar + "prevalent";
+                    System.err.println("prevayling to " + base);
+                    pf.configurePrevalenceBase(base);
+                    XStreamSnapshotManager manager = new XStreamSnapshotManager(new JS(), base, null) {
+                            protected XStream createXStream() {
+                                XStream xstream = new XStream();
+                                xstream.alias("js", JS.class);
+                                xstream.alias("jsdate", JSDate.class);
+                                return xstream;
+                            }
+                        };
+                    System.err.println("configuring with " + manager);
+                    pf.configureSnapshotManager(manager);
+                    //pf.configureClassLoader(JSTransaction.class.getClassLoader());
+                    prevayler = pf.create();
+                    prevaylers.put(cx, prevayler);
+                    new SnapshotThread(cx).start();
+                }
+            }
+            prevalent = (JS)prevayler.prevalentSystem();
+        } catch (Exception e) {
+            throw new ServletException(e);
+        }
+    }
+
+    public static class JSTransaction implements Transaction {
+        private JS js;
+        public JSTransaction(JS js) { this.js = js; }
+        public void executeOn(Object o, Date now) {
+            try {
+                js.call(o, new JSDate(now.getTime()), null, null, 2);
+            } catch (Exception e) { throw new RuntimeException(e); }
+        }
+    }
+
+    public static class JSQuery implements Query {
+        private JS js;
+        public JSQuery(JS js) { this.js = js; }
+        public Object query(Object o, Date now) {
+            try {
+                return js.call(o, new JSDate(now.getTime()), null, null, 2);
+            } catch (Exception e) { throw new RuntimeException(e); }
+        }
+    }
+
+}