Piloter une tâche asynchrone Java/Groovy depuis un composant WebView JavaFX avec JavaScript
Le composant JavaFX WebView réunit deux mondes : celui de Java et d'HTML5, et offre une interaction Java/JavaScript à double sens. D'une part, il est possible d'exécuter du code JavaScript dans le contexte de la page web chargée par le composant WebView, et d'autre part, on peut exécuter du code Java présent dans l'application JavaFX à partir du code JavaScript (voir la documentation de la classe WebEngine).
Dans ce dernier cas, plus précisément, lorsque l'on appelle une méthode sur la référence de l'objet Java passé au travers d'une propriété de l'objet JavaScript window, l'appel est synchrone. Cependant, il pourrait être intéressant de pouvoir déclencher un traitement asynchrone côté Java, depuis du code JavaScript de la page web, et recevoir le résultat de ce traitement une fois celui-ci terminé.
C'est ce que je vais démontrer dans le reste de cet article, en utilisant GroovyFX pour créer l'application JavaFX sous la forme d'un script Groovy. Pour la partie web, qui consiste en un fichier .html chargé dans un composant JavaFX WebView, je recours à AngularJS et son service $q qui implémente les promises. Il serait tout à fait possible d'utiliser jQuery et son implémentation des promises à la place.
L'idée principale est celle-ci : à partir du code JavaScript, appeler une méthode d'objet Java et lui transmettant l'objet JavaScript deferred créé via le service $q. Dans l'implémentation de la méthode Java (ou Groovy), un objet de type Task est créé puis démarré pour réaliser le traitement asynchrone ; selon l'issu traitement, on appelle resolve
ou reject
sur l'objet deferred, ce qui fait que le code JavaScript de la page web n'est pas bloqué et peut réagir en fonction de la réalisation de la promesse.
Voici le script GroovyFX AngularFX.groovy (disponible en fichier joint) qui, exécuté via une commande groovy, permet de démarrer l'application JavaFX comprenant un composant WebView :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
|
Le code est relativement simple : tout d'abord, on charge la page web angularfx.html
supposée se trouver dans le même répertoire que le script. Lorsque le page est complétement chargée, on injecte la propriété FX dans l'objet JavaScript window avec une référence vers un objet de type FX. Cette classe comprend une seule méthode, process, qui sera invoquée depuis du code JavaScript de la page angularfx.html
. La méthode process a la responsabilité de créer la tâche -une instance de ProcessTask
héritant de la classe JavaFX Task
- dont l'exécution se fera dans un thread séparé, mais également, en fonction du résultat du traitement, de satisfaire et de rejeter la promesse (appel à resolve
ou reject
sur l'objet deferred JavaScript).
Notez qu'à titre d'exemple, la tâche asynchrone se contente d'évaluer le code Groovy qu'on lui transmet dans son constructeur, dans la méthode call
. En cas de réussite, on appelle resolve
sur l'objet deferred en transmettant le résultat de l'évaluation ; en cas d'échec, c'est reject
qui est appelé sur l'objet deferred, en passant le message de l'exception à l'origine de l'échec (méthode process
de la classe FX
).
La page web angularfx.html
comprend une application AngularJS permettant l'évaluation (asynchrone) de code Groovy saisi dans une zone d'édition, et d'en afficher le résultat dans la page web.
Voici le code source d'angularfx.html
(également disponible en fichier joint) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
|
Un click sur le bouton Evaluate déclenche l'exécution de la méthode process
du contrôleur MainCtrl
. Cette méthode crée un objet deferred au moyen du service injecté $q d'AngularJS, puis définit par deux fonctions JavaScript, se qui va se passer en cas de succès et d'échec (appel deferred.promise.then()
) : dans notre exemple, on se contente d'affecter la propriété message du contrôleur avec le résultat de l'évaluation opéré côté Java ou avec un message d'exception. La valeur de message sera automatiquement affichée dans l'élément h2
de la page du fait de la liaison sur la propriété ctrl.message
.
Le fait de pouvoir invoquer du code Java/Groovy, qu'il soit asynchrone ou non, depuis un composant WebView placé dans une scène JavaFX, ouvre des perspectives intéressantes. C'est un peu comme être dans une application hybride dans laquelle on peut combiner la puissance et l'étendue du langage Java avec la souplesse de JavaScript au sein d'une présentation HTML5.
Nul doute pour moi de continuer à explorer une telle combinaison... en allant par exemple plus loin avec cette idée d'évaluation de code Groovy.