2014-09-14 1 views
1

J'utilise Rhino pour interpréter javascripts par Java. Mon cas d'utilisation nécessite que ces javascripts effectuent des appels de service (multiples) (RESTful/Webservices/HTTP GET/POST). Certains de ces appels de service sont de nature asynchrone (avec 24 heures de SLA). Je veux pouvoir mettre en pause l'exécution de mon script dans de tels cas, sérialiser l'état (en le sauvegardant, disons S3 avec la clé transmise à la charge utile du service asynchrone que le service retourne en rappel) et reprendre l'exécution quand je reçois le résultat du service. Le défi auquel je fais face est que ContinuationPending (extension RuntimeException) n'est pas sérialisable (parce que Context n'est pas). Question: Existe-t-il un autre moyen de stocker l'état du script et de le récupérer à partir de sa forme sérialisée?Rhino: Possibilité de mettre en pause, de sauvegarder l'état et de reprendre le javascript

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

Répondre

2

J'ai trouvé la solution finalement. La clé consiste à utiliser ScriptableOutputStream (pour sérialiser) et ScriptableInputStream (pour désérialiser) Continuation and Scope.

Ci-dessous le code de fonctionnement.

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