2. Qui avez-vous en face de vous ?
Moi
-nom = "SIMON"
-prenom = "Franck"
-formation = "Ingénieur"
-profession = {"développeur","formateur","consultant"}
-aime = {"coder","technologie","bandes dessinées","musique"}
-email = "franck.simon@free.fr"
-web = "http://www.franck-simon.com"
Franck SIMON Confoo 2012 - Java Scripting API 2 / 48
3. Qui avez-vous en face de vous ?
● Mes activités
● développement
– pour de petites structures
● formation / tutorat
● spécialisé dans la valorisation des tickets d'appels
– dans le monde des opérateurs telecom virtuels
● Passionné de code
● et toujours émerveillé
Franck SIMON Confoo 2012 - Java Scripting API 3 / 48
4. Langages de script
● Facilité d'utilisation
● typage dynamique, conversion de type automatique
● Développement rapide de prototypes
● Création d'extensions d'application
● script de configuration
● encapsulation de règles métiers
● programmation par l'utilisateur de l'application
Franck SIMON Confoo 2012 - Java Scripting API 4 / 48
5. Java Scripting API
● API apparue avec Java SE 6
● API développée sous la JSR 223
● JSR 223 : Scripting for the Java Platform
– JSR : Java Specification Request
● définit une interface d'interaction avec les moteurs de
scripts
● classes, interfaces et exceptions réunies dans le
package javax.script
Franck SIMON Confoo 2012 - Java Scripting API 5 / 48
6. Java Scripting API
● L'implémentation Sun utilise le projet Rhino de
Mozilla
● http://www.mozilla.org/rhino/
● certaines fonctionnalités de Rhino n'ont pas été
portées dans l'implémentation Sun
● L'utilitaire jrunscript permet de lancer des
scripts en mode console
● outil "expérimental" sous les versions 6 et 7 de
Java SE
Franck SIMON Confoo 2012 - Java Scripting API 6 / 48
7. Étapes d'utilisation en Java
● L'objectif est de faire interpréter un script
JavaScript par le moteur de script
● le JavaScript est un flux texte ou un String
● Pour évaluer le JavaScript en Java
● créer une instance de ScriptEngineManager
● récupérer un ScriptEngine
● faire évaluer le script par la méthode eval(...)
Franck SIMON Confoo 2012 - Java Scripting API 7 / 48
8. Premier exemple
● L'incontournable "Hello, world"
package confoo;
import javax.script.*;
public class HelloWorld
{
public static void main(String[] args) throws Exception
{
String javaScript = "print('Hello, world')";
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(javaScript);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 8 / 48
9. Les classes et interface de l'API
● L'ensemble des interfaces et classes qui
composent l'API fournit un framework d'utilisation
des moteurs de script en Java
● 6 interfaces
● 5 classes
● 1 classe d'exception
● Les plus utiles
● ScriptEngine : interaction avec le moteur de script
● ScriptEngineManager : point d'entrée de l'API
Franck SIMON Confoo 2012 - Java Scripting API 9 / 48
10. La classe ScriptEngineManager
● Point d'entrée de l'API
● Découvre et instancie les fabriques de script
● JavaScript en standard
● Possède des méthodes pour récupérer
● les méta données du moteur de script
– langage, version, etc.
● un moteur de script de script par le nom du langage, le
type MIME
● Maintient un un contexte global
● contient des entrées clé/valeur
Franck SIMON Confoo 2012 - Java Scripting API 10 / 48
11. La classe ScriptEngineManager
● Plusieurs méthodes permettent d'obtenir un
moteur de script (ScriptEngine)
● par l'extension : getEngineByExtension
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByExtension("js");
● par l'alias: getEngineByName
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("ECMAScript");
● par le type MIME : getEngineByMimeType
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByMimeType("application/javascript");
Franck SIMON Confoo 2012 - Java Scripting API 11 / 48
12. La classe ScriptEngineManager
● Des méthodes supplémentaire permettent
● d'inscrire dynamiquement de nouveaux moteurs de
script
– void registerEngineName(String name,
ScriptEngineFactory factory)
– void registerEngineMimeType(String name,
ScriptEngineFactory factory)
– void registerEngineExtension(String name,
ScriptEngineFactory factory)
● d'ajouter des paire clé/valeur au contexte global
Franck SIMON Confoo 2012 - Java Scripting API 12 / 48
13. La classe ScriptEngineFactory
● Il est possible pour chaque moteur de script de
récupérer
● le nom et la version du moteur
● l'extension
● le nom du langage et sa version
● les types MIME
● les alias
● Cf. ScriptEngineFactoryMetaDatas.java
Franck SIMON Confoo 2012 - Java Scripting API 13 / 48
14. La classe ScriptEngineFactory
...
ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> factories = manager.getEngineFactories();
for (ScriptEngineFactory factory : factories) {
System.out.println("Nom complet du moteur de script : " + factory.getEngineName());
System.out.println("Version du moteur de script : " + factory.getEngineVersion());
System.out.println("Extensions :");
List<String> extensions = factory.getExtensions();
for (String extension : extensions)
System.out.println(" " + extension);
System.out.println("Langage : " + factory.getLanguageName());
System.out.println("Version du langage : " + factory.getLanguageVersion());
System.out.println("Types MIME :");
List<String> mimetypes = factory.getMimeTypes();
for (String mimetype : mimetypes)
System.out.println(" " + mimetype);
System.out.println("Alias :");
List<String> shortnames = factory.getNames();
for (String shortname : shortnames)
System.out.println(" " + shortname);
System.out.println();
}
...
Franck SIMON Confoo 2012 - Java Scripting API 14 / 48
15. Évaluation du script
● L'évaluation du script est effectuée sur l'instance de
ScriptEngine récupérée
● Plusieurs signatures de la méthode eval(...)
permettent l'évaluation :
● du script en tant que String
● du script lu dans un flux de type Reader
● un contexte de script peut y être associé
● eval(...) retourne le résultat de l'évaluation sous
forme d'Object
● null si pas de résultat
Franck SIMON Confoo 2012 - Java Scripting API 15 / 48
16. Évaluation d'un String
● Exemple EvalString.java
public class EvalString {
public static void main(String[] args) throws ScriptException{
String script = "2+2";
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Object o = engine.eval(script);
System.out.println(o);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 16 / 48
17. Évaluation d'un Reader
● Exemple EvalReader.java
public class EvalReader {
public static void main(String[] args)
throws ScriptException,FileNotFoundException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("javascript_01.js"));
}
}
print("Hello, world");
Franck SIMON Confoo 2012 - Java Scripting API 17 / 48
18. Communication entre Java et
JavaScript
● Des objets Java peuvent être passés au script
● JavaScript peut alors utiliser les membres publiques
des objets exposés
● void put(String key, Object value)
passe un objet au moteur de script
– méthode de ScriptEngine
● la méthode Object get(String key) permet à
Java de récupérer des variable du script
– méthode de ScriptEngine
Franck SIMON Confoo 2012 - Java Scripting API 18 / 48
19. Utilisation d'un objet Java par
JavaScript
● Exemple UtilisationPoint_01.java
public class UtilisationPoint_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Point p = new Point(1,2);
engine.put("p1", p);
engine.eval(new FileReader("point_01.js")); association pour utilisation
} par JavaScript
}
var x = p1.getX();
var y = p1.getY();
print("le point se trouve en ("+x+","+y+")");
Franck SIMON Confoo 2012 - Java Scripting API 19 / 48
20. Utilisation d'un objet Java par
JavaScript
● JavaScript peut donc changer l'état de notre Point
● Exemple UtilisationPoint_02.java
public class UtilisationPoint_02 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Point p = new Point(1,2);
engine.put("p1", p);
engine.eval(new FileReader("point_02.js"));
System.out.println(p);
}
}
p1.setX(110) ;
Franck SIMON Confoo 2012 - Java Scripting API 20 / 48
21. Récupération de variables JavaScript
● Exemple RecuperationVariables_01.java
public class RecuperationVariables_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("variables_01.js"));
String message = (String) engine.get("message");
System.out.println("message : "+message);
double d = (Double) engine.get("dimension");
System.out.println("dimension : "+d);
List<String> liste = (List<String>) engine.get("liste");
for(String ville : liste)
System.out.println(ville);
}
}
var message = "Hello, world";
var dimension = 10.3;
var liste = ["Montréal","Saint-Malo","Paris"];
Franck SIMON Confoo 2012 - Java Scripting API 21 / 48
22. Invoquer des fonctions JavaScript en
Java
● Un des intérêts de d'utiliser JavaScript dans un
programme Java est d'utiliser des fonctions
JavaScript
● créées par d'autres développeur
● ou des "utilisateurs avertis"
● valable aussi pour des objets JavaScript
Franck SIMON Confoo 2012 - Java Scripting API 22 / 48
23. Invoquer des fonctions JavaScript en
Java
● Le moteur de script doit implémenter l'interface
Invocable de l'API
● rhino implémente Invocable
● Permet l'invocation depuis Java de fonctions du
script
● ou méthodes d'objet JavaScript
● Permet au script d'implémenter des interfaces
Java
● et là cela devient très intéressant
Franck SIMON Confoo 2012 - Java Scripting API 23 / 48
24. Invoquer des fonctions JavaScript en
Java
● Schéma de codage de l'invocation de fonctions
JavaScript en Java
● récupérer un ScriptEngine
● évaluer le script
● caster le ScriptEngine en Invocable
● appeler la méthode invokeFunction sur le
Invocable
– ou invokeMethod pour un objet JavaScript
– une exception NoSuchMethodException est susceptible
d'être levée
Franck SIMON Confoo 2012 - Java Scripting API 24 / 48
25. Invoquer des fonctions JavaScript en
Java
● Exemple InvoqueJavaScript_01.java
public class InvoqueJavaScript_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException, NoSuchMethodException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
double r = (Double) invocable.invokeFunction("somme", 10,20);
System.out.println("Résulat r : "+r);
}
}
function somme(i,j){
return i+j;
}
Franck SIMON Confoo 2012 - Java Scripting API 25 / 48
26. Invoquer des fonctions JavaScript en
Java
● Invoquer une fonction JavaScript avec un nombre
variable de paramètres
● Exemple InvoqueJavaScript_02.java
...
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
double r = (Double) invocable.invokeFunction("add", 10,20);
System.out.println("Résulat r : "+r);
...
function add(){
var res = 0;
for(var i=0 ; i<arguments.length; i++){
res = res + arguments[i];
}
return res;
}
Franck SIMON Confoo 2012 - Java Scripting API 26 / 48
27. Invoquer des méthodes d'objets
JavaScript en Java
● Exemples InvoqueJavaScript_03.java
...
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
Object voiture = engine.get("voiture");
invocable.invokeMethod(voiture, "rouler");
invocable.invokeMethod(voiture, "atteindre", 130);
System.out.println("Nb de chevaux : "+
invocable.invokeMethod(voiture, "getNbChevaux"));
...
var voiture = new Object();
voiture.getNbChevaux=function(){return 5;}
voiture.rouler = function(){println('Je roule !!!!');}
voiture.atteindre=function(vitesse){
println("Accélération jusqu'à "+vitesse+" km/h");}
Franck SIMON Confoo 2012 - Java Scripting API 27 / 48
28. Implémenter des interfaces Java en
JavaScript
● Les interfaces fournissent une couche abstraite
● Il peut être intéressant de sortir un traitement de la
couche Java pour l'implémenter en JavaScript
● code métier changeant
● Java fournit l'interface et JavaScript
l'implémentation
● par des fonctions
● par des méthodes d'objets
Franck SIMON Confoo 2012 - Java Scripting API 28 / 48
29. Implémenter des interfaces Java en
JavaScript
● Comme pour l'invocation depuis Java de fonctions
JavaScript, il faut que le moteur de script
implémente Invocable
● La méthode getInterface renvoie une
implémentation d'une interface Java avec les
fonctions trouvées par l'interpréteur
Franck SIMON Confoo 2012 - Java Scripting API 29 / 48
30. Implémenter des interfaces Java en
JavaScript
● L'interface Calculable
public interface Calculable {
int add(int a, int b);
}
● L'implémentation en JavaScript
● fichier implementations_01.js
function add(a,b){ return a+b;}
Franck SIMON Confoo 2012 - Java Scripting API 30 / 48
31. Implémenter des interfaces Java en
JavaScript
● L'utilisation de l'implémentation en Java
● fichier ImplementationJavaScript_01.java
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("implementations_01.js"));
Invocable invocable = (Invocable) engine;
Calculable calculable = invocable.getInterface(Calculable.class);
System.out.println(calculable.add(10,20));
Franck SIMON Confoo 2012 - Java Scripting API 31 / 48
32. Implémenter des interfaces Java en
JavaScript
● Si l'implémentation utilise un objet JavaScript il
faut d'abord le retrouver
● implémentation JavaScript
– fichier implementations_01.js
var calcul = new Object();
calcul.add = function(a,b){return a+b;}
● utilisation en Java
– fichier ImplementationJavaScript_01.java
engine.eval(new FileReader("implementations_01.js"));
Invocable invocable = (Invocable) engine;
Object obj = engine.get("calcul");
Calculable calculable = invocable.getInterface(obj,Calculable.class);
System.out.println(calculable.add(10,20));
Franck SIMON Confoo 2012 - Java Scripting API 32 / 48
33. Import Java dans JavaScript
● Par la fonction importPackage de JavaScript
● moteur rhino
● le nom du package correspond à son import entier
– importPackage(java.util) ;
● correspond à un
– import java.util.* ;
● java.lang n'est pas importé par défaut
● Par la fonction importClass de JavaScript
● Attention les noms de packages doivent suivre la
spécification Java
Franck SIMON Confoo 2012 - Java Scripting API 33 / 48
34. Import Java dans JavaScript
● Fichier JavaScript import_01.js
importPackage(java.awt);
var frame = new java.awt.Frame("Hello");
frame.setVisible(true);
● Exécution du fichier en Java
public class EvalReaderImport_01 {
public static void main(String[] args)
throws ScriptException, FileNotFoundException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("import_01.js"));
}
}
Franck SIMON Confoo 2012 - Java Scripting API 34 / 48
35. Import Java dans JavaScript
● le moteur de script rhino propose aussi un
JavaImporter
● fichier import_02.js
var gui = new JavaImporter(java.awt);
with(gui){
var frame = new Frame("Bonjour");
frame.setVisible(true);
}
Franck SIMON Confoo 2012 - Java Scripting API 35 / 48
36. Résolution de la surcharge
● Le langage Java supporte la surcharge par les
arguments d'une méthode
● signatures différentes d'un même nom de méthode
● la résolution de l'appel est alors effectuée lors de la
compilation
● Lors de l'appel de méthodes Java depuis un
JavaScript le moteur sélectionne la méthode
appropriée
● une exception est levée si aucune méthode n'est
trouvée
Franck SIMON Confoo 2012 - Java Scripting API 36 / 48
37. Utilisation de plusieurs contextes de
script
● Dans le exemples précédents les objets Java ont
étés exposés à JavaScript dans le contexte par
défaut
● Deux contextes existent par défaut
● un contexte global partagé par tous les moteurs qui
seront instanciés par le même EngineFactory
– ScriptContext.GLOBAL_SCOPE
● un contexte par moteur de script
– ScriptContext.ENGINE_SCOPE
Franck SIMON Confoo 2012 - Java Scripting API 37 / 48
38. Utilisation de plusieurs contextes de
script
● Exemple de manipulation de contexte
public class MultiScope {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine1 = factory.getEngineByName("javascript");
ScriptEngine engine2 = factory.getEngineByName("javascript");
ScriptContext context = new SimpleScriptContext();
Bindings globalScope = engine1.getBindings(ScriptContext.GLOBAL_SCOPE);
String script = "println('x : '+x)";
globalScope.put("x", "Bonjour");
… // suite page suivante
Franck SIMON Confoo 2012 - Java Scripting API 38 / 48
39. Utilisation de plusieurs contextes de
script
● Exemple de manipulation de contexte
… // cf. page précédente
globalScope.put("x", "Bonjour");
engine1.eval(script);
engine2.eval(script);
System.out.println("======================");
engine1.put("x", "Hello");
engine1.eval(script);
engine2.eval(script);
System.out.println("======================");
engine1.eval(script,engine1.getBindings(ScriptContext.GLOBAL_SCOPE));
engine2.eval(script);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 39 / 48
40. Exemple du "monde réel"
Et maintenant...
… un peu de code pour grande personne
Franck SIMON Confoo 2012 - Java Scripting API 40 / 48
41. Exemple : le pattern Visitor
● L'objectif du modèle de conception Visitor est de
séparer un modèle de données de ses traitements
● le modèle de données est souvent structuré en
composite
● les traitements peuvent être enrichis sans modifier le
modèle de données
● les données doivent "accepter" la visite d'un "visiteur"
● c'est le visiteur qui effectue le traitement en fonction du
type concret de la donnée
Franck SIMON Confoo 2012 - Java Scripting API 41 / 48
42. Exemple : le pattern Visitor
● Ce modèle de conception est très utile si
● la structure des données est stable
● la structure de données est figée
– les données et leurs traitements sont séparés
– l'évolution des traitements est indépendant des données
● Voici la structure extraite de l'ouvrage du GoF
● Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides
● "Design Patterns – Elemnts of Reusable Object-Oriented
Software" en 1995
Franck SIMON Confoo 2012 - Java Scripting API 42 / 48
43. Exemple : le pattern Visitor
● Diagramme issu du livre du GoF
Franck SIMON Confoo 2012 - Java Scripting API 43 / 48
44. Exemple : le pattern Visitor
● Le diagramme de notre exemple
Franck SIMON Confoo 2012 - Java Scripting API 44 / 48
45. Exemple : le pattern Visitor
● L'interface Visitor et son implémentation en
JavaScript
public interface Visitor { var visitor = new Object();
void visitText(Text t); visitor.visitText = function(objText){
void visitLine(Line l); println(objText.getText());
void visitPanel(Panel p); }
}
visitor.visitLine=function(objLine){
println(objLine.getLongueur());
}
visitor.visitPanel=function(objPanel){
println(objPanel.getType());
var liste =objPanel.getElements();
for(var i=0 ; i < liste.size() ; i++){
liste.get(i).accept(visitor)
}
}
Franck SIMON Confoo 2012 - Java Scripting API 45 / 48
46. Exemple : le pattern Visitor
● Mise en œuvre en Java
...
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("visitors.js"));
on récupère l'objet JavaScript
Object o = engine.get("visitor");
Invocable invocable = (Invocable) engine;
Visitor visitor = invocable.getInterface(o, Visitor.class);
engine.put("visitor", visitor);
p3.accept(visitor); Java voit l'objet JavaScript comme
... implémentation de Visitor
Pour que le moteur JavaScript
puisse caster l'objet en Visitor
Franck SIMON Confoo 2012 - Java Scripting API 46 / 48
47. Pour aller plus loin
● Web
● documentation officielle
– http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html
● documentation mozilla – projet rhino
–http://www.mozilla.org/rhino/
● Livres
● Beginning Java SE 6 Platform
– auteur : Jeff FRIESEN
– éditeur : Apress
Franck SIMON Confoo 2012 - Java Scripting API 47 / 48
50. Qui avez-vous en face de vous ?
Moi
-nom = "SIMON"
-prenom = "Franck"
-formation = "Ingénieur"
-profession = {"développeur","formateur","consultant"}
-aime = {"coder","technologie","bandes dessinées","musique"}
-email = "franck.simon@free.fr"
-web = "http://www.franck-simon.com"
Franck SIMON Confoo 2012 - Java Scripting API 2 / 48
51. Qui avez-vous en face de vous ?
● Mes activités
● développement
– pour de petites structures
● formation / tutorat
● spécialisé dans la valorisation des tickets d'appels
– dans le monde des opérateurs telecom virtuels
● Passionné de code
● et toujours émerveillé
Franck SIMON Confoo 2012 - Java Scripting API 3 / 48
52. Langages de script
● Facilité d'utilisation
● typage dynamique, conversion de type automatique
● Développement rapide de prototypes
● Création d'extensions d'application
● script de configuration
● encapsulation de règles métiers
● programmation par l'utilisateur de l'application
Franck SIMON Confoo 2012 - Java Scripting API 4 / 48
53. Java Scripting API
● API apparue avec Java SE 6
● API développée sous la JSR 223
● JSR 223 : Scripting for the Java Platform
– JSR : Java Specification Request
● définit une interface d'interaction avec les moteurs de
scripts
● classes, interfaces et exceptions réunies dans le
package javax.script
Franck SIMON Confoo 2012 - Java Scripting API 5 / 48
Il existait déjà des solution pour scrypter la plateforme Java avec des
langages de script : Groovy, JRuby, Jython, ...
54. Java Scripting API
● L'implémentation Sun utilise le projet Rhino de
Mozilla
● http://www.mozilla.org/rhino/
● certaines fonctionnalités de Rhino n'ont pas été
portées dans l'implémentation Sun
● L'utilitaire jrunscript permet de lancer des
scripts en mode console
● outil "expérimental" sous les versions 6 et 7 de
Java SE
Franck SIMON Confoo 2012 - Java Scripting API 6 / 48
Pour des raisons de sécurité et d'empreinte mémoire, les fonctionnalités
suivantes n'ont pas été portées
●le compilateur javascript vers byte-code ("optimizer") n'a pas été repris, le
javascript fonctionne donc toujours en mode interprété
●le JavaAdapter de Rhino a été remplacé par une implémentation Sun.
L'implémentation Rhino permet à une classe Java d'être étendue en
JavaScript et une interface Java d'être implémentée en JavaScript,
L'implémentation de Sun ne permet que l'implémentation d'une interface
Java en JavaScript
●E4X (ECMAScript for XML) a été excus
●l'outil de commande en ligne Rhino a été remplacé par jrunscript
55. Étapes d'utilisation en Java
● L'objectif est de faire interpréter un script
JavaScript par le moteur de script
● le JavaScript est un flux texte ou un String
● Pour évaluer le JavaScript en Java
● créer une instance de ScriptEngineManager
● récupérer un ScriptEngine
● faire évaluer le script par la méthode eval(...)
Franck SIMON Confoo 2012 - Java Scripting API 7 / 48
56. Premier exemple
● L'incontournable "Hello, world"
package confoo;
import javax.script.*;
public class HelloWorld
{
public static void main(String[] args) throws Exception
{
String javaScript = "print('Hello, world')";
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("JavaScript");
engine.eval(javaScript);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 8 / 48
57. Les classes et interface de l'API
● L'ensemble des interfaces et classes qui
composent l'API fournit un framework d'utilisation
des moteurs de script en Java
● 6 interfaces
● 5 classes
● 1 classe d'exception
● Les plus utiles
● ScriptEngine : interaction avec le moteur de script
● ScriptEngineManager : point d'entrée de l'API
Franck SIMON Confoo 2012 - Java Scripting API 9 / 48
58. La classe ScriptEngineManager
● Point d'entrée de l'API
● Découvre et instancie les fabriques de script
● JavaScript en standard
● Possède des méthodes pour récupérer
● les méta données du moteur de script
– langage, version, etc.
● un moteur de script de script par le nom du langage, le
type MIME
● Maintient un un contexte global
● contient des entrées clé/valeur
Franck SIMON Confoo 2012 - Java Scripting API 10 / 48
59. La classe ScriptEngineManager
● Plusieurs méthodes permettent d'obtenir un
moteur de script (ScriptEngine)
● par l'extension : getEngineByExtension
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByExtension("js");
● par l'alias: getEngineByName
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("ECMAScript");
● par le type MIME : getEngineByMimeType
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByMimeType("application/javascript");
Franck SIMON Confoo 2012 - Java Scripting API 11 / 48
60. La classe ScriptEngineManager
● Des méthodes supplémentaire permettent
● d'inscrire dynamiquement de nouveaux moteurs de
script
– void registerEngineName(String name,
ScriptEngineFactory factory)
– void registerEngineMimeType(String name,
ScriptEngineFactory factory)
– void registerEngineExtension(String name,
ScriptEngineFactory factory)
● d'ajouter des paire clé/valeur au contexte global
Franck SIMON Confoo 2012 - Java Scripting API 12 / 48
61. La classe ScriptEngineFactory
● Il est possible pour chaque moteur de script de
récupérer
● le nom et la version du moteur
● l'extension
● le nom du langage et sa version
● les types MIME
● les alias
● Cf. ScriptEngineFactoryMetaDatas.java
Franck SIMON Confoo 2012 - Java Scripting API 13 / 48
62. La classe ScriptEngineFactory
...
ScriptEngineManager manager = new ScriptEngineManager();
List<ScriptEngineFactory> factories = manager.getEngineFactories();
for (ScriptEngineFactory factory : factories) {
System.out.println("Nom complet du moteur de script : " + factory.getEngineName());
System.out.println("Version du moteur de script : " + factory.getEngineVersion());
System.out.println("Extensions :");
List<String> extensions = factory.getExtensions();
for (String extension : extensions)
System.out.println(" " + extension);
System.out.println("Langage : " + factory.getLanguageName());
System.out.println("Version du langage : " + factory.getLanguageVersion());
System.out.println("Types MIME :");
List<String> mimetypes = factory.getMimeTypes();
for (String mimetype : mimetypes)
System.out.println(" " + mimetype);
System.out.println("Alias :");
List<String> shortnames = factory.getNames();
for (String shortname : shortnames)
System.out.println(" " + shortname);
System.out.println();
}
...
Franck SIMON Confoo 2012 - Java Scripting API 14 / 48
63. Évaluation du script
● L'évaluation du script est effectuée sur l'instance de
ScriptEngine récupérée
● Plusieurs signatures de la méthode eval(...)
permettent l'évaluation :
● du script en tant que String
● du script lu dans un flux de type Reader
● un contexte de script peut y être associé
● eval(...) retourne le résultat de l'évaluation sous
forme d'Object
● null si pas de résultat
Franck SIMON Confoo 2012 - Java Scripting API 15 / 48
64. Évaluation d'un String
● Exemple EvalString.java
public class EvalString {
public static void main(String[] args) throws ScriptException{
String script = "2+2";
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Object o = engine.eval(script);
System.out.println(o);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 16 / 48
65. Évaluation d'un Reader
● Exemple EvalReader.java
public class EvalReader {
public static void main(String[] args)
throws ScriptException,FileNotFoundException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("javascript_01.js"));
}
}
print("Hello, world");
Franck SIMON Confoo 2012 - Java Scripting API 17 / 48
66. Communication entre Java et
JavaScript
● Des objets Java peuvent être passés au script
● JavaScript peut alors utiliser les membres publiques
des objets exposés
● void put(String key, Object value)
passe un objet au moteur de script
– méthode de ScriptEngine
● la méthode Object get(String key) permet à
Java de récupérer des variable du script
– méthode de ScriptEngine
Franck SIMON Confoo 2012 - Java Scripting API 18 / 48
67. Utilisation d'un objet Java par
JavaScript
● Exemple UtilisationPoint_01.java
public class UtilisationPoint_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Point p = new Point(1,2);
engine.put("p1", p);
engine.eval(new FileReader("point_01.js")); association pour utilisation
} par JavaScript
}
var x = p1.getX();
var y = p1.getY();
print("le point se trouve en ("+x+","+y+")");
Franck SIMON Confoo 2012 - Java Scripting API 19 / 48
68. Utilisation d'un objet Java par
JavaScript
● JavaScript peut donc changer l'état de notre Point
● Exemple UtilisationPoint_02.java
public class UtilisationPoint_02 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
Point p = new Point(1,2);
engine.put("p1", p);
engine.eval(new FileReader("point_02.js"));
System.out.println(p);
}
}
p1.setX(110) ;
Franck SIMON Confoo 2012 - Java Scripting API 20 / 48
69. Récupération de variables JavaScript
● Exemple RecuperationVariables_01.java
public class RecuperationVariables_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("variables_01.js"));
String message = (String) engine.get("message");
System.out.println("message : "+message);
double d = (Double) engine.get("dimension");
System.out.println("dimension : "+d);
List<String> liste = (List<String>) engine.get("liste");
for(String ville : liste)
System.out.println(ville);
}
}
var message = "Hello, world";
var dimension = 10.3;
var liste = ["Montréal","Saint-Malo","Paris"];
Franck SIMON Confoo 2012 - Java Scripting API 21 / 48
70. Invoquer des fonctions JavaScript en
Java
● Un des intérêts de d'utiliser JavaScript dans un
programme Java est d'utiliser des fonctions
JavaScript
● créées par d'autres développeur
● ou des "utilisateurs avertis"
● valable aussi pour des objets JavaScript
Franck SIMON Confoo 2012 - Java Scripting API 22 / 48
71. Invoquer des fonctions JavaScript en
Java
● Le moteur de script doit implémenter l'interface
Invocable de l'API
● rhino implémente Invocable
● Permet l'invocation depuis Java de fonctions du
script
● ou méthodes d'objet JavaScript
● Permet au script d'implémenter des interfaces
Java
● et là cela devient très intéressant
Franck SIMON Confoo 2012 - Java Scripting API 23 / 48
72. Invoquer des fonctions JavaScript en
Java
● Schéma de codage de l'invocation de fonctions
JavaScript en Java
● récupérer un ScriptEngine
● évaluer le script
● caster le ScriptEngine en Invocable
● appeler la méthode invokeFunction sur le
Invocable
– ou invokeMethod pour un objet JavaScript
– une exception NoSuchMethodException est susceptible
d'être levée
Franck SIMON Confoo 2012 - Java Scripting API 24 / 48
73. Invoquer des fonctions JavaScript en
Java
● Exemple InvoqueJavaScript_01.java
public class InvoqueJavaScript_01 {
public static void main(String[] args)
throws FileNotFoundException, ScriptException, NoSuchMethodException {
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
double r = (Double) invocable.invokeFunction("somme", 10,20);
System.out.println("Résulat r : "+r);
}
}
function somme(i,j){
return i+j;
}
Franck SIMON Confoo 2012 - Java Scripting API 25 / 48
74. Invoquer des fonctions JavaScript en
Java
● Invoquer une fonction JavaScript avec un nombre
variable de paramètres
● Exemple InvoqueJavaScript_02.java
...
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
double r = (Double) invocable.invokeFunction("add", 10,20);
System.out.println("Résulat r : "+r);
...
function add(){
var res = 0;
for(var i=0 ; i<arguments.length; i++){
res = res + arguments[i];
}
return res;
}
Franck SIMON Confoo 2012 - Java Scripting API 26 / 48
75. Invoquer des méthodes d'objets
JavaScript en Java
● Exemples InvoqueJavaScript_03.java
...
engine.eval(new FileReader("fonctions_01.js"));
Invocable invocable = (Invocable) engine;
Object voiture = engine.get("voiture");
invocable.invokeMethod(voiture, "rouler");
invocable.invokeMethod(voiture, "atteindre", 130);
System.out.println("Nb de chevaux : "+
invocable.invokeMethod(voiture, "getNbChevaux"));
...
var voiture = new Object();
voiture.getNbChevaux=function(){return 5;}
voiture.rouler = function(){println('Je roule !!!!');}
voiture.atteindre=function(vitesse){
println("Accélération jusqu'à "+vitesse+" km/h");}
Franck SIMON Confoo 2012 - Java Scripting API 27 / 48
76. Implémenter des interfaces Java en
JavaScript
● Les interfaces fournissent une couche abstraite
● Il peut être intéressant de sortir un traitement de la
couche Java pour l'implémenter en JavaScript
● code métier changeant
● Java fournit l'interface et JavaScript
l'implémentation
● par des fonctions
● par des méthodes d'objets
Franck SIMON Confoo 2012 - Java Scripting API 28 / 48
77. Implémenter des interfaces Java en
JavaScript
● Comme pour l'invocation depuis Java de fonctions
JavaScript, il faut que le moteur de script
implémente Invocable
● La méthode getInterface renvoie une
implémentation d'une interface Java avec les
fonctions trouvées par l'interpréteur
Franck SIMON Confoo 2012 - Java Scripting API 29 / 48
78. Implémenter des interfaces Java en
JavaScript
● L'interface Calculable
public interface Calculable {
int add(int a, int b);
}
● L'implémentation en JavaScript
● fichier implementations_01.js
function add(a,b){ return a+b;}
Franck SIMON Confoo 2012 - Java Scripting API 30 / 48
79. Implémenter des interfaces Java en
JavaScript
● L'utilisation de l'implémentation en Java
● fichier ImplementationJavaScript_01.java
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("implementations_01.js"));
Invocable invocable = (Invocable) engine;
Calculable calculable = invocable.getInterface(Calculable.class);
System.out.println(calculable.add(10,20));
Franck SIMON Confoo 2012 - Java Scripting API 31 / 48
80. Implémenter des interfaces Java en
JavaScript
● Si l'implémentation utilise un objet JavaScript il
faut d'abord le retrouver
● implémentation JavaScript
– fichier implementations_01.js
var calcul = new Object();
calcul.add = function(a,b){return a+b;}
● utilisation en Java
– fichier ImplementationJavaScript_01.java
engine.eval(new FileReader("implementations_01.js"));
Invocable invocable = (Invocable) engine;
Object obj = engine.get("calcul");
Calculable calculable = invocable.getInterface(obj,Calculable.class);
System.out.println(calculable.add(10,20));
Franck SIMON Confoo 2012 - Java Scripting API 32 / 48
81. Import Java dans JavaScript
● Par la fonction importPackage de JavaScript
● moteur rhino
● le nom du package correspond à son import entier
– importPackage(java.util) ;
● correspond à un
– import java.util.* ;
● java.lang n'est pas importé par défaut
● Par la fonction importClass de JavaScript
● Attention les noms de packages doivent suivre la
spécification Java
Franck SIMON Confoo 2012 - Java Scripting API 33 / 48
82. Import Java dans JavaScript
● Fichier JavaScript import_01.js
importPackage(java.awt);
var frame = new java.awt.Frame("Hello");
frame.setVisible(true);
● Exécution du fichier en Java
public class EvalReaderImport_01 {
public static void main(String[] args)
throws ScriptException, FileNotFoundException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine = factory.getEngineByName("javascript");
engine.eval(new FileReader("import_01.js"));
}
}
Franck SIMON Confoo 2012 - Java Scripting API 34 / 48
83. Import Java dans JavaScript
● le moteur de script rhino propose aussi un
JavaImporter
● fichier import_02.js
var gui = new JavaImporter(java.awt);
with(gui){
var frame = new Frame("Bonjour");
frame.setVisible(true);
}
Franck SIMON Confoo 2012 - Java Scripting API 35 / 48
84. Résolution de la surcharge
● Le langage Java supporte la surcharge par les
arguments d'une méthode
● signatures différentes d'un même nom de méthode
● la résolution de l'appel est alors effectuée lors de la
compilation
● Lors de l'appel de méthodes Java depuis un
JavaScript le moteur sélectionne la méthode
appropriée
● une exception est levée si aucune méthode n'est
trouvée
Franck SIMON Confoo 2012 - Java Scripting API 36 / 48
85. Utilisation de plusieurs contextes de
script
● Dans le exemples précédents les objets Java ont
étés exposés à JavaScript dans le contexte par
défaut
● Deux contextes existent par défaut
● un contexte global partagé par tous les moteurs qui
seront instanciés par le même EngineFactory
– ScriptContext.GLOBAL_SCOPE
● un contexte par moteur de script
– ScriptContext.ENGINE_SCOPE
Franck SIMON Confoo 2012 - Java Scripting API 37 / 48
86. Utilisation de plusieurs contextes de
script
● Exemple de manipulation de contexte
public class MultiScope {
public static void main(String[] args) throws ScriptException {
ScriptEngineManager factory = new ScriptEngineManager();
ScriptEngine engine1 = factory.getEngineByName("javascript");
ScriptEngine engine2 = factory.getEngineByName("javascript");
ScriptContext context = new SimpleScriptContext();
Bindings globalScope = engine1.getBindings(ScriptContext.GLOBAL_SCOPE);
String script = "println('x : '+x)";
globalScope.put("x", "Bonjour");
… // suite page suivante
Franck SIMON Confoo 2012 - Java Scripting API 38 / 48
87. Utilisation de plusieurs contextes de
script
● Exemple de manipulation de contexte
… // cf. page précédente
globalScope.put("x", "Bonjour");
engine1.eval(script);
engine2.eval(script);
System.out.println("======================");
engine1.put("x", "Hello");
engine1.eval(script);
engine2.eval(script);
System.out.println("======================");
engine1.eval(script,engine1.getBindings(ScriptContext.GLOBAL_SCOPE));
engine2.eval(script);
}
}
Franck SIMON Confoo 2012 - Java Scripting API 39 / 48
88. Exemple du "monde réel"
Et maintenant...
… un peu de code pour grande personne
Franck SIMON Confoo 2012 - Java Scripting API 40 / 48
89. Exemple : le pattern Visitor
● L'objectif du modèle de conception Visitor est de
séparer un modèle de données de ses traitements
● le modèle de données est souvent structuré en
composite
● les traitements peuvent être enrichis sans modifier le
modèle de données
● les données doivent "accepter" la visite d'un "visiteur"
● c'est le visiteur qui effectue le traitement en fonction du
type concret de la donnée
Franck SIMON Confoo 2012 - Java Scripting API 41 / 48
90. Exemple : le pattern Visitor
● Ce modèle de conception est très utile si
● la structure des données est stable
● la structure de données est figée
– les données et leurs traitements sont séparés
– l'évolution des traitements est indépendant des données
● Voici la structure extraite de l'ouvrage du GoF
● Erich Gamma, Richard Helm, Ralph Johnson et John Vlissides
● "Design Patterns – Elemnts of Reusable Object-Oriented
Software" en 1995
Franck SIMON Confoo 2012 - Java Scripting API 42 / 48
91. Exemple : le pattern Visitor
● Diagramme issu du livre du GoF
Franck SIMON Confoo 2012 - Java Scripting API 43 / 48
92. Exemple : le pattern Visitor
● Le diagramme de notre exemple
Franck SIMON Confoo 2012 - Java Scripting API 44 / 48
93. Exemple : le pattern Visitor
● L'interface Visitor et son implémentation en
JavaScript
public interface Visitor { var visitor = new Object();
void visitText(Text t); visitor.visitText = function(objText){
void visitLine(Line l); println(objText.getText());
void visitPanel(Panel p); }
}
visitor.visitLine=function(objLine){
println(objLine.getLongueur());
}
visitor.visitPanel=function(objPanel){
println(objPanel.getType());
var liste =objPanel.getElements();
for(var i=0 ; i < liste.size() ; i++){
liste.get(i).accept(visitor)
}
}
Franck SIMON Confoo 2012 - Java Scripting API 45 / 48
94. Exemple : le pattern Visitor
● Mise en œuvre en Java
...
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
engine.eval(new FileReader("visitors.js"));
on récupère l'objet JavaScript
Object o = engine.get("visitor");
Invocable invocable = (Invocable) engine;
Visitor visitor = invocable.getInterface(o, Visitor.class);
engine.put("visitor", visitor);
p3.accept(visitor); Java voit l'objet JavaScript comme
... implémentation de Visitor
Pour que le moteur JavaScript
puisse caster l'objet en Visitor
Franck SIMON Confoo 2012 - Java Scripting API 46 / 48
95. Pour aller plus loin
● Web
● documentation officielle
– http://docs.oracle.com/javase/6/docs/technotes/guides/scripting/programmer_guide/index.html
● documentation mozilla – projet rhino
–http://www.mozilla.org/rhino/
● Livres
● Beginning Java SE 6 Platform
– auteur : Jeff FRIESEN
– éditeur : Apress
Franck SIMON Confoo 2012 - Java Scripting API 47 / 48