Rhino:能够暂停,保存状态和恢复javascript

时间:2014-09-14 19:59:12

标签: javascript rhino java-scripting-engine

我正在使用Rhino来解释Java的javascripts。我的用例需要这些javascripts进行(多个)服务调用(RESTful / Webservices / HTTP GET / POST)。其中一些服务调用本质上是异步的(具有24小时的SLA)。

我希望能够在这种情况下暂停执行我的脚本,序列化状态(将其保存,例如S3,将密钥传递给服务在回调时返回的异步服务的有效负载)并在恢复时执行我从服务中得到了结果。

我面临的挑战是ContinuationPending(扩展RuntimeException)不可序列化(因为Context不是)。

问题:是否有其他方法可以存储脚本状态并从序列化表单中恢复?

使用Javascript:

function invokeFooService(arg) {
    return foo.bar.Helper.invokeFooServiceAsync(arg);
}

function main() {
    // Main JS function
    ..
    var response = invokeFooService(arg);
    if (..) {
        ..
    }
}

爪哇:

package foo.bar;

public class Helper {

    public static final void invokeFooServiceAsync(String arg) {
        Context cx = getContext();
        ContinuationPending pending = cx.captureContinuation();
        // At this point the script is paused
        // Serialize the state of script
        invokeFooService(arg, key);
    }

    public static final void returnResponse(FooResponse response, String key) {
        // De serialize the state of script
        ContinuationPending pending = ..
        Context cx = getContext();
        cx.resumeContinuation(pending.getContinuation(), getScope(), response);
        // Script is resumed
    }
}

1 个答案:

答案 0 :(得分:2)

我终于找到了解决方案。关键是使用ScriptableOutputStream(序列化)和ScriptableInputStream(反序列化)Continuation和Scope。

以下是工作代码。

使用Javascript:

function invokeFooService(arg) {
    return foo.bar.Helper.invokeFooServiceAsync(arg);
}

function main() {
    // Main JS function
    ..
    var response = invokeFooService(arg);
    if (..) {
        ..
    }
}

爪哇:

package foo.bar;

public class Helper {

    public static final void invokeFooServiceAsync(String arg) {
        Context cx = getContext();
        ContinuationPending pending = cx.captureContinuation();
        // Script is paused here
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ScriptableOutputStream sos = new ScriptableOutputStream(baos, getScope());
        sos.writeObject(pending.getContinuation());
        sos.writeObject(getScope());
        String servicePayload = Base64.encodeBase64String(baos.toByteArray());
        invokeFooServiceForReal(arg, servicePayload); // This method invokes the async service
    }

    public static final void returnFooServiceResponse(FooResponse response, String servicePayload) {
        // De serialize the state of script
        byte[] continuationAndScope = Base64.decodeBase64(servicePayload);
        ScriptableInputStream sis = new ScriptableInputStream(new ByteArrayInputStream(continuationAndScope), getScope());
        Scriptable continuation = (Scriptable) sis.readObject();
        Scriptable scope = (Scriptable) sis.readObject();
        getContext().resumeContinuation(continuation, scope, response);
        // Script resumed
    }
}