Last active
July 7, 2020 13:46
-
-
Save eleinadani/7cf4391bcbb55b45344a8ebb8b0be212 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// HTTP request handler | |
WebServer.create(configuration, route.get("/request", (req, res) -> { | |
// ( #1 ) An HTTP GET request is received. Get some request data | |
int requestId = getRequestId(req); | |
// Send the data to JavaScript. Perform computation in JS and | |
// send back to the HTTP client a response message when done. | |
executeJs(requestId).whenComplete((r, ex) -> { | |
if (ex != null) { | |
res.status(404) | |
.send("404 error"); | |
} else { | |
// ( #5 ) Client response. Result 'r' is a JSON string created in JavaScript | |
res.send(r); | |
} | |
}); | |
}); | |
// JavaScript code that will be executed (for each request) | |
private static final String jsSource = "(async function(requestId) {" + | |
" // ( #2 ) The request id is validated in JS" + | |
" if (!validate(requestId)) return 'Bad request!';" + | |
" // ( #3 ) Process the request in Java" + | |
" let data = await computeFromJava(requestId);" + | |
" // ( #4 ) Create a JSON object for the response " + | |
" return JSON.stringify({requestId:requestId,result:data});" + | |
"})"; | |
// Offload request handling to JavaScript | |
private CompletionStage<Object> executeJs(int requestId) { | |
CompletableFuture<Object> jsExecution = new CompletableFuture<>(); | |
Context cx = getCurrentPolyglotContext(); | |
// Access to a polyglot context should be synchronized. We use a lock here. | |
contextAccessLock.lock(); | |
try { | |
// Enter the context | |
cx.enter(); | |
Value jsAsyncFunction = cx.eval(JS, jsSource); | |
// Execute the JavaScript code. The `async` function returns a JS | |
// Promise object. The Java `then` reaction will be executed by | |
// the JavaScript engine when `await` completes. | |
jsAsyncFunction.execute(requestId) | |
.invokeMember(THEN, (Consumer<?>) jsExecution::complete) | |
.invokeMember(CATCH, (Consumer<Throwable>) jsExecution::completeExceptionally); | |
} finally { | |
cx.leave(); | |
contextAccessLock.unlock(); | |
} | |
return jsExecution; | |
} |
Great, thanks for the feedback :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @eleinadani, great article, I have just few notes for improvement of example:
As I presume we don't want anyone else to complete
jsAsyncFunction
's future:Also using Helidon's reactive api could make the example even cooler:
Thx for all the great features of Graal 🖖