2014-09-14 4 views
1

Я использую Rhino для интерпретации javascripts Java. Мой вариант использования требует, чтобы эти javascript выполняли (несколько) служебных вызовов (RESTful/Webservices/HTTP GET/POST). Некоторые из этих вызовов службы носят асинхронный характер (с 24 часами SLA).Rhino: Возможность приостановить, сохранить состояние и возобновить javascript

Я хочу, чтобы в таких случаях приостанавливать выполнение моего сценария, сериализуйте состояние (сохраняя его, скажем, S3 с ключом, переданным в полезную нагрузку службы асинхронного обслуживания, возвращаемой службой обратно на обратный вызов) и возобновите выполнение когда я получаю результат от службы.

Задача, с которой я столкнулся, заключается в том, что ContinuationPending (расширение RuntimeException) не является сериализуемым (поскольку контекст не является).

Вопрос: Есть ли способ сохранить состояние скрипта и вернуть его из его сериализованной формы?

Javascript:

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

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

Java:

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 
    } 
} 

ответ

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 (..) { 
     .. 
    } 
} 

Java:

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 
    } 
}