どうもスクリプトをコンパイルすると継続がうまく動かないようなので、Javaのサーブレット+JavaScript(未コンパイル)の2段構えにしてみた。
サーブレットは以下の通り。
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import org.mozilla.javascript.*;
import org.mozilla.javascript.tools.shell.*;public class RhinoServlet extends HttpServlet {
protected void service(HttpServletRequest req,
HttpServletResponse res) throws ServletException, IOException {
ServletContext app = getServletContext();
ServletConfig conf = getServletConfig();
String filename = req.getPathInfo();
InputStream in = app.getResourceAsStream("/WEB-INF/js/" + filename);
InputStreamReader reader = new InputStreamReader(in);try {
runScript(reader, filename, app, conf, req, res);
} finally {
reader.close();
in.close();
}
}private void runScript(Reader in, String filename,
ServletContext app, ServletConfig conf,
HttpServletRequest req, HttpServletResponse res)
throws IOException {
Context cx = Context.enter();
cx.setOptimizationLevel(-1);try {
Script script = cx.compileReader(in, filename, 1, null);
Global global = new Global();
ShellContextFactory factory = new ShellContextFactory();
global.init(factory);putProperty(app, "application", global);
putProperty(conf, "config", global);
putProperty(res.getWriter(), "out", global);
putProperty(req, "request", global);
putProperty(res, "response", global);
putProperty(req.getSession(), "session", global);Object result = script.exec(cx, global);
if (result != Context.getUndefinedValue())
System.err.println(Context.toString(result));
} finally {
Context.exit();
}
}private void putProperty(Object obj, String name, Scriptable scope) {
Object jsObj = Context.javaToJS(obj, scope);
ScriptableObject.putProperty(scope, name, jsObj);
}}
「cx.setOptimizationLevel(-1)」で、継続が使えるようになる。
スクリプトは以下の通り。
例外をキャッチしたら、例外がContinuationかどうかの判定を入れたほうがいいかも…
function pause() {
throw new Continuation();
}function mainloop() {
while(true) {
output("haru");
pause();
output("natu");
pause();
output("aki");
pause();
output("fuyu");
pause();
}
}function output(season) {
out.println("<html><body>" + season
+ "<br /><form action='/servlet_continuation/continuation.js'>"
+ "<input type='submit' method='post' /><form></body></html>");
}var kout = session.getAttribute("kout");
try {
if(kout) {
kout();
} else {
mainloop();
}
} catch(c) {
session.setAttribute("kout", c);
}
http://localhost:8080/servlet_continuation/continuation.jsにアクセスして送信ボタンを押すと…おぉ、ちゃんと「haru→natu→aki→fuyu」と循環している。なかなか感動。
でも、しばらくたつと動かなくなる…タイムアウト?
次は、コンパイルしたスクリプトで動かせるようにしたいなぁ。
追記
1.6 R3 preでテストしたけど、1.6 R2だと挙動違うかも。