r9635 - in helma-ng/trunk: modules/helma src/org/helma/jack src/org/helma/javascript src/org/helma/web

[email protected] Tue, 21 Apr 2009 10:37:57 +0200 (CEST)
Newsgroups gmane.comp.java.helma.cvs
Message-ID <20090421083757.2B5E53D0D6@mia>
Author: hannes
Date: 2009-04-21 10:37:57 +0200 (Tue, 21 Apr 2009)
New Revision: 9635

Removed:
   helma-ng/trunk/modules/helma/jack.js
   helma-ng/trunk/src/org/helma/web/HelmaServlet.java
   helma-ng/trunk/src/org/helma/web/Request.java
   helma-ng/trunk/src/org/helma/web/Response.java
   helma-ng/trunk/src/org/helma/web/Session.java
Modified:
   helma-ng/trunk/modules/helma/httpserver.js
   helma-ng/trunk/modules/helma/webapp.js
   helma-ng/trunk/src/org/helma/jack/JackEnv.java
   helma-ng/trunk/src/org/helma/jack/JackServlet.java
   helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java
   helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java
Log:
Make JackServlet the default and only servlet for Helma.
 * Move jack helper functions from helma/jack to helma/httpserver
 * Add constructor to JackServlet that allows to pass in a jack function
 * Add jack.servlet_request and jack.servlet_response properties to JackEnv
 * Remove org.helma.web package including HelmaServlet

Details at http://dev.helma.org/trac/helma/changeset/9635

Modified: helma-ng/trunk/modules/helma/httpserver.js
===================================================================
--- helma-ng/trunk/modules/helma/httpserver.js	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/modules/helma/httpserver.js	2009-04-21 08:37:57 UTC (rev 9635)
@@ -2,7 +2,7 @@
  * Module for starting and stopping the jetty http server.
  */
 
-export('start', 'stop');
+export('start', 'stop', 'initRequest', 'commitResponse');
 
 // mark this module as shared between all requests
 var __shared__ = true;
@@ -32,7 +32,7 @@
      *                      function: 'handleServletRequest' })</li>
      * </ul>
      */
-    this.start = function(config) {
+    this.start = function(config, func) {
         config = config || {};
         var configFile = config.configFile || 'config/jetty.xml';
         // var staticIndex = config.staticIndex || config.staticIndex == undefined;
@@ -44,7 +44,7 @@
             }
             var jetty = org.mortbay.jetty;
             var XmlConfiguration = org.mortbay.xml.XmlConfiguration;
-            var HelmaServlet = org.helma.web.HelmaServlet;
+            var Servlet = org.helma.jack.JackServlet;
             server = new jetty.Server();
             try {
                 var xmlconfig = new XmlConfiguration(jettyconfig.inputStream);
@@ -56,7 +56,7 @@
                 xmlconfig.configure(server);
                 //everything else is configured via idmap
                 var idMap = xmlconfig.getIdMap();
-                // java.lang.System.err.println("idmap: " + idMap);
+                // print("idmap: " + idMap);
                 var staticCtx = idMap.get('staticContext');
                 if (staticCtx && typeof config.staticDir == "string") {
                     staticCtx.setResourceBase(getResource(config.staticDir));
@@ -66,11 +66,11 @@
                 // set up helma servlet context
                 var helmaCtx = idMap.get('helmaContext');
                 if (helmaCtx) {
-                    var servlet = new HelmaServlet(engine);
+                    var servlet = func ? new Servlet(engine, func) : new Servlet(engine);
                     var servletHolder = new jetty.servlet.ServletHolder(servlet);
-                    var params = config.servletParams || {
-                        'module': 'helma/webapp',
-                        'function': 'handleServletRequest'
+                    var params = {
+                        'moduleName': config.moduleName || 'helma/webapp',
+                        'functionName': config.functionName || 'handleRequest'
                     };
                     for (var p in params) {
                         servletHolder.setInitParameter(p, params[p]);
@@ -101,3 +101,44 @@
     }
 
 })(this);
+
+/**
+ * Set up the IO related properties of a jack environment object.
+ * @param env a jack request object
+ */
+function initRequest(env) {
+    var IO = require('io').IO;
+    env['jack.input'] = new IO(env['jack.input'], null);
+    env['jack.error'] = new IO(null, env['jack.error']);
+}
+
+/**
+ * Apply the return value of a Jack application to a servlet response.
+ * This is used internally by the org.helma.jack.JackServlet class, so
+ * you won't need this unless you're implementing your own servlet
+ * based jack connector.
+ *
+ * @param env the jack env argument
+ * @param result the object returned by a jack application
+ */
+function commitResponse(env, result) {
+    var response = env['jack.servlet_response'];
+    if (response.isCommitted() || !(result instanceof Array))
+        return;
+	var [status, headers, body] = result;
+	response.status = status;
+	for (var name in headers) {
+		response.setHeader(name, headers[name]);
+	}
+	var writer = response.writer;
+	if (body && typeof body.forEach == "function") {
+		body.forEach(function(chunk) {
+			writer.write(String(chunk));
+			writer.flush();
+		})
+	} else {
+		writer.write(String(body));
+	}
+    writer.close();
+}
+

Deleted: helma-ng/trunk/modules/helma/jack.js

Modified: helma-ng/trunk/modules/helma/webapp.js
===================================================================
--- helma-ng/trunk/modules/helma/webapp.js	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/modules/helma/webapp.js	2009-04-21 08:37:57 UTC (rev 9635)
@@ -1,4 +1,4 @@
-11/*
+/*
  * The webapp module provides support for building web applications in Helma NG.
  */
 
@@ -17,26 +17,20 @@
 
 var log = logging.getLogger(__name__);
 
-function handleJackRequest(env) {}
+var __shared__ = true;
 
-// support old name
-function handleRequest(req, res) {
-    return handleServletRequest(req, res);
-}
-
 /**
- * Handler function called by the Helma servlet. 
+ * Handler function called by the Jack servlet.
  *
- * @param req
- * @param res
+ * @param env the jack environment argument
  */
-function handleServletRequest(servletRequest, servletResponse) {
+function handleRequest(env) {
     // get config and apply it to req, res
     var config = getConfig();
     if (log.debugEnabled) log.debug('got config: ' + config.toSource());
 
-    var req = new Request(servletRequest);
-    var res = new Response(servletResponse);
+    var req = new Request(env['jack.servlet_request']);
+    var res = new Response(env['jack.servlet_response']);
 
     req.charset = res.charset = config.charset || 'utf8';
     res.contentType = config.contentType || 'text/html';

Modified: helma-ng/trunk/src/org/helma/jack/JackEnv.java
===================================================================
--- helma-ng/trunk/src/org/helma/jack/JackEnv.java	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/src/org/helma/jack/JackEnv.java	2009-04-21 08:37:57 UTC (rev 9635)
@@ -19,24 +19,29 @@
 import org.mozilla.javascript.*;
 
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import java.util.Enumeration;
 import java.io.IOException;
 import java.lang.reflect.Method;
 
 public class JackEnv extends ScriptableObject {
 
-    HttpServletRequest req;
+    HttpServletRequest request;
+    HttpServletResponse response;
 
     public JackEnv() {}
 
-    public JackEnv(Object obj) {
-        if (!(obj instanceof HttpServletRequest)) {
-            throw new IllegalArgumentException("Wrong argument: " + obj);
+    public JackEnv(Object req, Object res) {
+        if (!(req instanceof HttpServletRequest)) {
+            throw new IllegalArgumentException("Wrong argument: " + req);
+        } else if (!(res instanceof HttpServletResponse)) {
+            throw new IllegalArgumentException("Wrong argument: " + res);
         }
-        req = (HttpServletRequest) obj;
-        for (Enumeration e = req.getHeaderNames(); e.hasMoreElements(); ) {
+        this.request = (HttpServletRequest) req;
+        this.response = (HttpServletResponse) res;
+        for (Enumeration e = request.getHeaderNames(); e.hasMoreElements(); ) {
             String name = (String) e.nextElement();
-            String value = req.getHeader(name);
+            String value = request.getHeader(name);
             name = name.replace('-', '_').toUpperCase();
             if (!"CONTENT_LENGTH".equals(value) && !"CONTENT_TYPE".equals(value)) {
                 name = "HTTP_" + name;
@@ -47,53 +52,61 @@
 
 
     public String getScriptName() {
-        return checkString(req.getServletPath());
+        return checkString(request.getServletPath());
     }
 
     public String getPathInfo() {
-        return checkString(req.getPathInfo());
+        return checkString(request.getPathInfo());
     }
 
     public String getRequestMethod() {
-        return checkString(req.getMethod());
+        return checkString(request.getMethod());
     }
 
     public String getServerName() {
-        return checkString(req.getServerName());
+        return checkString(request.getServerName());
     }
     
     public String getServerPort() {
-        return checkString(Integer.toString(req.getServerPort()));
+        return checkString(Integer.toString(request.getServerPort()));
     }
 
     public String getQueryString() {
-        return checkString(req.getQueryString());
+        return checkString(request.getQueryString());
     }
 
     public String getHttpVersion() {
-        return checkString(req.getProtocol());
+        return checkString(request.getProtocol());
     }
 
     public String getRemoteHost() {
-        return checkString(req.getRemoteHost());
+        return checkString(request.getRemoteHost());
     }
 
     public String getUrlScheme() {
-        return req.isSecure() ? "https" : "http";
+        return request.isSecure() ? "https" : "http";
     }
 
     public Object getInputStream() {
         try {
-            return req.getInputStream();
+            return Context.javaToJS(request.getInputStream(), this);
         } catch (IOException iox) {
             return Undefined.instance;
         }
     }
 
     public Object getErrorStream() {
-        return System.err;
+        return Context.javaToJS(System.err, this);
     }
 
+    public Object getServletRequest() {
+        return Context.javaToJS(request, this);
+    }
+
+    public Object getServletResponse() {
+        return Context.javaToJS(response, this);
+    }
+
     public static void finishInit(Scriptable scope, FunctionObject constructor, Scriptable prototype)
             throws NoSuchMethodException {
         int flags = PERMANENT;
@@ -115,6 +128,8 @@
         ScriptableObject.defineProperty(proto, "jack.multiprocess", Boolean.TRUE, flags);
         ScriptableObject.defineProperty(proto, "jack.run_once", Boolean.FALSE, flags);
         proto.defineProperty("jack.url_scheme", null, getMethod("getUrlScheme"), null, flags);
+        proto.defineProperty("jack.servlet_request", null, getMethod("getServletRequest"), null, flags);
+        proto.defineProperty("jack.servlet_response", null, getMethod("getServletResponse"), null, flags);
     }
 
     private static Method getMethod(String name) throws NoSuchMethodException {
@@ -130,7 +145,7 @@
         // FIXME: implement IO wrappers
         if ("jack.input".equals(name)) {
             try {
-                return Context.toObject(req.getInputStream(), this);
+                return Context.toObject(request.getInputStream(), this);
             } catch (IOException iox) {
                 return Undefined.instance;
             }

Modified: helma-ng/trunk/src/org/helma/jack/JackServlet.java
===================================================================
--- helma-ng/trunk/src/org/helma/jack/JackServlet.java	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/src/org/helma/jack/JackServlet.java	2009-04-21 08:37:57 UTC (rev 9635)
@@ -21,6 +21,7 @@
 import org.helma.repository.FileRepository;
 import org.helma.repository.WebappRepository;
 import org.helma.javascript.RhinoEngine;
+import org.mozilla.javascript.Callable;
 
 import javax.servlet.http.HttpServlet;
 import javax.servlet.http.HttpServletRequest;
@@ -34,9 +35,15 @@
 
     String module, function;
     RhinoEngine engine;
+    Callable callable;
 
     public JackServlet(RhinoEngine engine) throws ServletException {
+        this(engine, null);
+    }
+
+    public JackServlet(RhinoEngine engine, Callable callable) throws ServletException {
         this.engine = engine;
+        this.callable = callable;
         try {
             engine.defineHostClass(JackEnv.class);
         } catch (Exception x) {
@@ -47,11 +54,11 @@
     @Override
     public void init(ServletConfig config) throws ServletException {
         super.init(config);
-        module = getInitParam(config, "module", "app");
-        function = getInitParam(config, "function", "handler");
+        module = getInitParam(config, "moduleName", "app");
+        function = getInitParam(config, "functionName", "handler");
 
         if (engine == null) {
-            String helmaHome = getInitParam(config, "home", "WEB-INF");
+            String helmaHome = getInitParam(config, "helmaHome", "WEB-INF");
             String modulePath = getInitParam(config, "modulePath", "modules");
 
             Repository home = new WebappRepository(config.getServletContext(), helmaHome);
@@ -72,8 +79,12 @@
     protected void service(HttpServletRequest request, HttpServletResponse response)
             throws ServletException, IOException {
         try {
-            Object result = engine.invoke(module, function, new JackEnv(request));
-            engine.invoke("helma/jack", "applyResponse", response, result);
+            JackEnv env = new JackEnv(request, response);
+            engine.invoke("helma/httpserver", "initRequest", env);
+            Object result = callable == null ?
+                    engine.invoke(module, function, env) :
+                    engine.invoke(callable, env);
+            engine.invoke("helma/httpserver", "commitResponse", env, result);
         } catch (NoSuchMethodException x) {
             throw new ServletException("Method not found", x);
         }

Modified: helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java
===================================================================
--- helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/src/org/helma/javascript/ReloadableScript.java	2009-04-21 08:37:57 UTC (rev 9635)
@@ -190,7 +190,8 @@
     protected synchronized Scriptable load(Scriptable prototype, Context cx)
             throws JavaScriptException, IOException {
         // check if we already came across the module in the current context/request
-        Map<Trackable,Scriptable> modules = (Map<Trackable,Scriptable>) cx.getThreadLocal("modules");
+        Map<Trackable,Scriptable> modules =
+                (Map<Trackable,Scriptable>) cx.getThreadLocal("modules");
         if (modules.containsKey(source)) {
             return modules.get(source);
         }

Modified: helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java
===================================================================
--- helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java	2009-04-21 08:37:53 UTC (rev 9634)
+++ helma-ng/trunk/src/org/helma/javascript/RhinoEngine.java	2009-04-21 08:37:57 UTC (rev 9635)
@@ -199,7 +199,7 @@
                     Scriptable module = loadModule(cx, moduleName, null);
                     Object function = ScriptableObject.getProperty(module, method);
                     if ((function == ScriptableObject.NOT_FOUND) || !(function instanceof Function)) {
-                        throw new NoSuchMethodException("Function " + method + "() not defined");
+                        throw new NoSuchMethodException("Function " + method + " not defined");
                     }
                     retval = ((Function) function).call(cx, topLevelScope, module, args);
                     break;
@@ -226,6 +226,40 @@
         }
     }
 
+    public Object invoke(Callable callable, Object... args)
+            throws IOException, NoSuchMethodException {
+        Context cx = contextFactory.enterContext();
+        Object[] threadLocals = checkThreadLocals(cx);
+        try {
+            initArguments(args);
+            Object retval;
+            while (true) {
+                try {
+                    retval = callable.call(cx, topLevelScope, null, args);
+                    break;
+                } catch (JavaScriptException jsx) {
+                    Scriptable thrown = jsx.getValue() instanceof Scriptable ?
+                            (Scriptable) jsx.getValue() : null;
+                    if (thrown != null && thrown.get("retry", thrown) == Boolean.TRUE) {
+                        ((Map) cx.getThreadLocal("modules")).clear();
+                    } else {
+                        throw jsx;
+                    }
+                } catch (RetryException retry) {
+                    // request to try again
+                    ((Map) cx.getThreadLocal("modules")).clear();
+                }
+            }
+            if (retval instanceof Wrapper) {
+                return ((Wrapper) retval).unwrap();
+            }
+            return retval;
+        } finally {
+            Context.exit();
+            resetThreadLocals(cx, threadLocals);
+        }
+    }
+
     /**
      * Return a shell scope for interactive evaluation
      * @return a shell scope

Deleted: helma-ng/trunk/src/org/helma/web/HelmaServlet.java

Deleted: helma-ng/trunk/src/org/helma/web/Request.java

Deleted: helma-ng/trunk/src/org/helma/web/Response.java

Deleted: helma-ng/trunk/src/org/helma/web/Session.java