r9639 - in helma-ng/trunk: apps/demo apps/filestore apps/googlestore modules/helma modules/helma/webapp
[email protected] Tue, 21 Apr 2009 16:01:10 +0200 (CEST)
| Newsgroups | gmane.comp.java.helma.cvs |
|---|---|
| Message-ID | <20090421140110.E303D3D0D6@mia> |
Author: hannes
Date: 2009-04-21 16:01:10 +0200 (Tue, 21 Apr 2009)
New Revision: 9639
Modified:
helma-ng/trunk/apps/demo/actions.js
helma-ng/trunk/apps/demo/webmodule.js
helma-ng/trunk/apps/filestore/main.js
helma-ng/trunk/apps/googlestore/main.js
helma-ng/trunk/modules/helma/buffer.js
helma-ng/trunk/modules/helma/webapp.js
helma-ng/trunk/modules/helma/webapp/response.js
Log:
Move to jack-based action handling in helma/webapp: actions are called with a single request argument and expected to return a response object. Add convenience Response constructors such as SkinnedResponse and RedirectResponse. Disable middleware for the time being.
Details at http://dev.helma.org/trac/helma/changeset/9639
Modified: helma-ng/trunk/apps/demo/actions.js
===================================================================
--- helma-ng/trunk/apps/demo/actions.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/apps/demo/actions.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -1,26 +1,25 @@
import('helma/logging');
+include('helma/webapp/response');
var log = helma.logging.getLogger(__name__);
export('index', 'extra_path', 'skins', 'logging', 'continuation');
// the main action is invoked for http://localhost:8080/
-function index(req, res) {
- res.render('skins/index.html', { title: 'Welcome to Helma NG' });
- // res.debug(req.cookies.toSource());
- // res.debug(req.params.toSource());
+function index(req) {
+ return new SkinnedResponse('skins/index.html', { title: 'Welcome to Helma NG' });
}
// additional path elements are passed to the action as arguments,
// e.g. /extra.path/2008/09
-function extra_path(req, res, year, month) {
- res.write("Extra arguments: ", year, month);
+function extra_path(req, year, month) {
+ return new Response("Extra arguments:", year, month);
}
// demo for skins, macros, filters
-function skins(req, res) {
- res.render('skins/skins.html', {
+function skins(req) {
+ return new SkinnedResponse('skins/skins.html', {
title: 'Skin Demo',
name: 'Luisa',
names: ['Benni', 'Emma', 'Luca', 'Selma']
@@ -28,7 +27,7 @@
}
// demo for log4j logging
-function logging(req, res) {
+function logging(req) {
if (req.params.info) {
log.info("Hello world!");
} else if (req.params.error) {
@@ -38,18 +37,17 @@
log.error(e, e.rhinoException);
}
}
- res.render('skins/logging.html', { title: "Logging Demo" });
+ return new SkinnedResponse('skins/logging.html', { title: "Logging Demo" });
}
// demo for continuation support
function continuation(req, res) {
- res.render('skins/continuation.html', {
+ return new SkinnedResponse('skins/continuation.html', {
title: "Continuations",
skin: "start",
note: "NOTE: Continuation support is currently broken, so I have disabled this demo for the time being."
});
- return;
// local data - this is the data that is shared between resuming and suspension
var data = {};
Modified: helma-ng/trunk/apps/demo/webmodule.js
===================================================================
--- helma-ng/trunk/apps/demo/webmodule.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/apps/demo/webmodule.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -1,4 +1,5 @@
// a simple web app/module
+include('helma/webapp/response');
export('index');
@@ -7,5 +8,5 @@
title: 'Module Demo',
href: req.path
};
- res.render('skins/modules.html', context);
+ return new SkinnedResponse('skins/modules.html', context);
}
Modified: helma-ng/trunk/apps/filestore/main.js
===================================================================
--- helma-ng/trunk/apps/filestore/main.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/apps/filestore/main.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -1,21 +1,21 @@
-import('helma/webapp', 'webapp');
-import('model');
+include('helma/webapp/response');
+include('model');
export('index');
// the main action is invoked for http://localhost:8080/
// this also shows simple skin rendering
-function index(req, res) {
+function index(req) {
if (req.params.save) {
- createBook(req, res);
+ return createBook(req);
}
if (req.params.remove) {
- removeBook(req, res);
+ return removeBook(req);
}
- res.render('skins/index.html', {
+ return SkinnedResponse('skins/index.html', {
title: 'Storage Demo',
books: function(/*tag, skin, context*/) {
- var books = model.Book.all();
+ var books = Book.all();
return books.map(function(book) {
return book.getFullTitle() + ' ' + getDeleteLink(book);
}).join('<br>\r\n');
@@ -23,19 +23,19 @@
});
}
-function createBook(req, res) {
- var author = new model.Author({name: req.params.author});
- var book = new model.Book({author: author, title: req.params.title});
+function createBook(req) {
+ var author = new Author({name: req.params.author});
+ var book = new Book({author: author, title: req.params.title});
// author is saved transitively
book.save();
- res.redirect('/');
+ return new RedirectResponse('/');
}
-function removeBook(req, res) {
- var book = model.Book.get(req.params.remove);
+function removeBook(req) {
+ var book = Book.get(req.params.remove);
// author is removed through cascading delete
book.remove();
- res.redirect('/');
+ return new RedirectResponse('/');
}
function getDeleteLink(book) {
@@ -43,5 +43,5 @@
}
if (__name__ == "__main__") {
- webapp.start();
+ require('helma/webapp').start();
}
Modified: helma-ng/trunk/apps/googlestore/main.js
===================================================================
--- helma-ng/trunk/apps/googlestore/main.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/apps/googlestore/main.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -1,3 +1,4 @@
+include('helma/webapp/response');
include('model');
export('index');
@@ -4,14 +5,14 @@
// the main action is invoked for http://localhost:8080/
// this also shows simple skin rendering
-function index(req, res) {
+function index(req) {
if (req.params.save) {
- createBook(req, res);
+ return createBook(req);
}
if (req.params.remove) {
- removeBook(req, res);
+ return removeBook(req);
}
- res.render('skins/index.html', {
+ return new SkinnedResponse('skins/index.html', {
title: 'Storage Demo',
books: function(/*tag, skin, context*/) {
return Book.all().map(function(book) {
@@ -21,20 +22,20 @@
});
}
-function createBook(req, res) {
+function createBook(req) {
var author = new Author({name: req.params.author});
author.save(); // no cascading save yet
var book = new Book({author: author, title: req.params.title});
book.save();
- res.redirect('/');
+ return new RedirectResponse('/');
}
-function removeBook(req, res) {
+function removeBook(req) {
var book = Book.get(req.params.remove);
// no cascading delete
book.author.remove();
book.remove();
- res.redirect('/');
+ return new RedirectResponse('/');
}
function getDeleteLink(book) {
Modified: helma-ng/trunk/modules/helma/buffer.js
===================================================================
--- helma-ng/trunk/modules/helma/buffer.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/modules/helma/buffer.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -31,6 +31,10 @@
return content.join('');
};
+ this.forEach = function(fn) {
+ content.forEach(fn);
+ }
+
// hack
this.toFirebugConsole = function() {
var enc = JSON.stringify(this.toString());
Modified: helma-ng/trunk/modules/helma/webapp/response.js
===================================================================
--- helma-ng/trunk/modules/helma/webapp/response.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/modules/helma/webapp/response.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -1,31 +1,35 @@
+include('hashp');
include('helma/buffer');
import('helma/system', 'system');
-export('Response');
+export('Response', 'SkinnedResponse', 'RedirectResponse' /*, 'NotFoundResponse', 'ServerErrorResponse'*/);
-// FIXME hack to get this to evaluate
-function Response(servletResponse) {
+function Response() {
- var writer;
var status = 200;
+ var charset;
+ var contentType;
+ var headers = {};
+ var buffer = new Buffer();
Object.defineProperty(this, 'write', {
value: function write() {
- writer = writer || servletResponse.getWriter();
var length = arguments.length;
for (var i = 0; i < length; i++) {
- writer.write(String(arguments[i]));
+ buffer.write(String(arguments[i]));
if (i < length - 1)
- writer.write(' ');
+ buffer.write(' ');
}
return this;
}
});
+ this.write.apply(this, arguments);
+
Object.defineProperty(this, 'writeln', {
value: function writeln() {
this.write.apply(this, arguments);
- this.write('\r\n');
+ buffer.write('\r\n');
return this;
}
});
@@ -33,14 +37,14 @@
/**
* Render a skin to the response's buffer
- * @param skin
- * @param context
- * @param scope
+ * @param skin path to skin resource
+ * @param context context object
+ * @param scope optional scope for relative resource paths
*/
Object.defineProperty(this, 'render', {
value: function render(skin, context, scope) {
var render = require('helma/skin').render;
- this.write(render(skin, context, scope));
+ buffer.write(render(skin, context, scope));
}
});
@@ -79,28 +83,27 @@
});
Object.defineProperty(this, 'redirect', {
- value: function(target) {
- servletResponse.sendRedirect(target);
- // fixme: temporary solution until webapp refactoring
- throw {redirect: target};
+ value: function(location) {
+ status = 303;
+ HashP.set(headers, 'Location', String(location));
}
});
Object.defineProperty(this, 'charset', {
get: function() {
- return servletResponse.getCharacterEncoding();
+ return charset;
},
- set: function(charset) {
- servletResponse.setCharacterEncoding(charset);
+ set: function(c) {
+ charset = c;
}
});
Object.defineProperty(this, 'contentType', {
get: function() {
- return servletResponse.getContentType();
+ return contentType;
},
- set: function(contentType) {
- servletResponse.setContentType(contentType);
+ set: function(c) {
+ contentType = c;
}
});
@@ -110,8 +113,41 @@
},
set: function(s) {
status = s;
- servletResponse.setStatus(s);
}
});
+ Object.defineProperty(this, 'getHeader', {
+ value: function(key) {
+ HashP.get(headers, String(key));
+ }
+ });
+
+ Object.defineProperty(this, 'setHeader', {
+ value: function(key, value) {
+ HashP.set(headers, String(key), String(value));
+ }
+ });
+
+ Object.defineProperty(this, 'close', {
+ value: function() {
+ if (charset) {
+ contentType = contentType || HashP.get('content-type') || "text/html";
+ contentType += "; charset=" + charset;
+ }
+ if (contentType) {
+ HashP.set(headers, "Content-Type", contentType);
+ }
+ return [status, headers, buffer];
+ }
+ })
+
}
+
+function SkinnedResponse(skin, context, scope) {
+ var render = require('helma/skin').render;
+ return [200, {}, render(skin, context, scope)];
+}
+
+function RedirectResponse(location) {
+ return [303, {Location: location}, "See other: " + location];
+}
Modified: helma-ng/trunk/modules/helma/webapp.js
===================================================================
--- helma-ng/trunk/modules/helma/webapp.js 2009-04-21 14:01:08 UTC (rev 9638)
+++ helma-ng/trunk/modules/helma/webapp.js 2009-04-21 14:01:10 UTC (rev 9639)
@@ -30,17 +30,17 @@
if (log.debugEnabled) log.debug('got config: ' + config.toSource());
var req = new Request(env['jack.servlet_request']);
- var res = new Response(env['jack.servlet_response']);
+ var res;
- req.charset = res.charset = config.charset || 'utf8';
- res.contentType = config.contentType || 'text/html';
+ req.charset = config.charset || 'utf8';
+ // res.contentType = config.contentType || 'text/html';
// invoke onRequest
- invokeMiddleware('onRequest', config.middleware, [req, res]);
+ // invokeMiddleware('onRequest', config.middleware, [req, res]);
// resume continuation?
- if (continuation.resume(req, res)) {
+ /* if (continuation.resume(req, res)) {
return;
- }
+ } */
// resolve path and invoke action
var path = req.path;
@@ -96,31 +96,35 @@
//split
path = path.split(/\/+/);
var action = getAction(module, path[0]);
- if (typeof action == "function" && path.length < action.length) {
+ if (typeof action == "function" && path.length <= action.length) {
// add remaining path elements as additional action arguments
var actionArgs = path.slice(1).map(decodeURIComponent);
- var args = [req, res].concat(actionArgs);
- invokeMiddleware('onAction',
+ var args = [req].concat(actionArgs);
+ /* invokeMiddleware('onAction',
config.middleware,
- [req, res, action, actionArgs]);
- action.apply(module, args);
- return;
+ [req, action, actionArgs]); */
+ res = action.apply(module, args);
}
break;
}
}
}
- notfound(req, res);
} catch (e) {
if (e.retry) {
throw e;
} else if (!e.redirect) {
- invokeMiddleware('onError', config.middleware, [req, res, e]);
- error(req, res, e);
+ // invokeMiddleware('onError', config.middleware, [req, res, e]);
+ res = error(req, e);
}
} finally {
- invokeMiddleware('onResponse', config.middleware, [req, res]);
+ // TODO
+ if (!res)
+ res = notfound(req);
+ if (!(res instanceof Array) && res.close)
+ res = res.close();
+ // invokeMiddleware('onResponse', config.middleware, [req, res]);
}
+ return res;
}
function invokeMiddleware(hook, middleware, args) {
@@ -146,7 +150,8 @@
* Standard error page
* @param e the error that happened
*/
-function error(req, res, e) {
+function error(req, e) {
+ var res = new Response();
res.status = 500;
res.contentType = 'text/html';
res.writeln('<h2>', e, '</h2>');
@@ -165,18 +170,19 @@
} else {
log.error(e.toString());
}
- return null;
+ return res.close();
}
/**
* Standard notfound page
*/
-function notfound(req, res) {
+function notfound(req) {
+ var res = new Response();
res.status = 404;
res.contentType = 'text/html';
res.writeln('<h1>Not Found</h1>');
res.writeln('The requested URL', req.path, 'was not found on the server.');
- return null;
+ return res.close();
}
/**