Upload
franck-simon
View
1.812
Download
6
Embed Size (px)
DESCRIPTION
Présentation donnée par Franck SIMON dans le cadre de ConFoo 2012
Citation preview
Java Scripting API
v 1.0
Franck SIMON Confoo 2012 - Java Scripting API 2 / 48
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 = "[email protected]"-web = "http://www.franck-simon.com"
Franck SIMON Confoo 2012 - Java Scripting API 3 / 48
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 4 / 48
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 5 / 48
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 6 / 48
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 7 / 48
É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 8 / 48
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 9 / 48
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 10 / 48
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 11 / 48
La classe ScriptEngineManager● Plusieurs méthodes permettent d'obtenir un
moteur de script (ScriptEngine)● par l'extension : getEngineByExtension
● par l'alias: getEngineByName
● par le type MIME : getEngineByMimeTypeScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByName("ECMAScript");
ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByExtension("js");
ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByMimeType("application/javascript");
Franck SIMON Confoo 2012 - Java Scripting API 12 / 48
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 13 / 48
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 14 / 48
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 15 / 48
É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 16 / 48
É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 17 / 48
É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 18 / 48
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 19 / 48
Utilisation d'un objet Java par JavaScript
● Exemple UtilisationPoint_01.javapublic 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"));
}}
var x = p1.getX();var y = p1.getY();print("le point se trouve en ("+x+","+y+")");
association pour utilisationpar JavaScript
Franck SIMON Confoo 2012 - Java Scripting API 20 / 48
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 21 / 48
Récupération de variables JavaScript● Exemple RecuperationVariables_01.javapublic 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 22 / 48
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 23 / 48
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 24 / 48
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 25 / 48
Invoquer des fonctions JavaScript en Java
● Exemple InvoqueJavaScript_01.javapublic 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 26 / 48
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 27 / 48
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 28 / 48
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 29 / 48
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 30 / 48
Implémenter des interfaces Java en JavaScript
● L'interface Calculable
● L'implémentation en JavaScript● fichier implementations_01.js
public interface Calculable {int add(int a, int b);
}
function add(a,b){ return a+b;}
Franck SIMON Confoo 2012 - Java Scripting API 31 / 48
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 32 / 48
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
● utilisation en Java– fichier ImplementationJavaScript_01.java
var calcul = new Object();calcul.add = function(a,b){return a+b;}
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 33 / 48
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 34 / 48
Import Java dans JavaScript● Fichier JavaScript import_01.js
● Exécution du fichier en Java
importPackage(java.awt);var frame = new java.awt.Frame("Hello");frame.setVisible(true);
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 35 / 48
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 36 / 48
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 37 / 48
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 38 / 48
Utilisation de plusieurs contextes de script
● Exemple de manipulation de contextepublic 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 39 / 48
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 40 / 48
Exemple du "monde réel"
Et maintenant...
… un peu de code pour grande personne
Franck SIMON Confoo 2012 - Java Scripting API 41 / 48
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 42 / 48
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 43 / 48
Exemple : le pattern Visitor● Diagramme issu du livre du GoF
Franck SIMON Confoo 2012 - Java Scripting API 44 / 48
Exemple : le pattern Visitor● Le diagramme de notre exemple
Franck SIMON Confoo 2012 - Java Scripting API 45 / 48
Exemple : le pattern Visitor● L'interface Visitor et son implémentation en
JavaScriptpublic interface Visitor {
void visitText(Text t);void visitLine(Line l);void visitPanel(Panel p);
}
var visitor = new Object();visitor.visitText = function(objText){
println(objText.getText());}
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 46 / 48
Exemple : le pattern Visitor● Mise en œuvre en Java
...ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("javascript");engine.eval(new FileReader("visitors.js"));
Object o = engine.get("visitor");Invocable invocable = (Invocable) engine;Visitor visitor = invocable.getInterface(o, Visitor.class);engine.put("visitor", visitor);p3.accept(visitor);...
on récupère l'objet JavaScript
Java voit l'objet JavaScript commeimplémentation de Visitor
Pour que le moteur JavaScriptpuisse caster l'objet en Visitor
Franck SIMON Confoo 2012 - Java Scripting API 47 / 48
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 48 / 48
Et voilà !!!
Java Scripting API
v 1.0
Franck SIMON Confoo 2012 - Java Scripting API 2 / 48
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 = "[email protected]"-web = "http://www.franck-simon.com"
Franck SIMON Confoo 2012 - Java Scripting API 3 / 48
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 4 / 48
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 5 / 48
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
Il existait déjà des solution pour scrypter la plateforme Java avec des langages de script : Groovy, JRuby, Jython, ...
Franck SIMON Confoo 2012 - Java Scripting API 6 / 48
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
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
Franck SIMON Confoo 2012 - Java Scripting API 7 / 48
É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 8 / 48
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 9 / 48
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 10 / 48
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 11 / 48
La classe ScriptEngineManager● Plusieurs méthodes permettent d'obtenir un
moteur de script (ScriptEngine)● par l'extension : getEngineByExtension
● par l'alias: getEngineByName
● par le type MIME : getEngineByMimeTypeScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByName("ECMAScript");
ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByExtension("js");
ScriptEngineManager factory = new ScriptEngineManager();ScriptEngine engine = factory.getEngineByMimeType("application/javascript");
Franck SIMON Confoo 2012 - Java Scripting API 12 / 48
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 13 / 48
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 14 / 48
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 15 / 48
É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 16 / 48
É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 17 / 48
É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 18 / 48
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 19 / 48
Utilisation d'un objet Java par JavaScript
● Exemple UtilisationPoint_01.javapublic 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"));
}}
var x = p1.getX();var y = p1.getY();print("le point se trouve en ("+x+","+y+")");
association pour utilisationpar JavaScript
Franck SIMON Confoo 2012 - Java Scripting API 20 / 48
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 21 / 48
Récupération de variables JavaScript● Exemple RecuperationVariables_01.javapublic 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 22 / 48
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 23 / 48
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 24 / 48
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 25 / 48
Invoquer des fonctions JavaScript en Java
● Exemple InvoqueJavaScript_01.javapublic 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 26 / 48
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 27 / 48
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 28 / 48
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 29 / 48
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 30 / 48
Implémenter des interfaces Java en JavaScript
● L'interface Calculable
● L'implémentation en JavaScript● fichier implementations_01.js
public interface Calculable {int add(int a, int b);
}
function add(a,b){ return a+b;}
Franck SIMON Confoo 2012 - Java Scripting API 31 / 48
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 32 / 48
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
● utilisation en Java– fichier ImplementationJavaScript_01.java
var calcul = new Object();calcul.add = function(a,b){return a+b;}
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 33 / 48
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 34 / 48
Import Java dans JavaScript● Fichier JavaScript import_01.js
● Exécution du fichier en Java
importPackage(java.awt);var frame = new java.awt.Frame("Hello");frame.setVisible(true);
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 35 / 48
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 36 / 48
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 37 / 48
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 38 / 48
Utilisation de plusieurs contextes de script
● Exemple de manipulation de contextepublic 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 39 / 48
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 40 / 48
Exemple du "monde réel"
Et maintenant...
… un peu de code pour grande personne
Franck SIMON Confoo 2012 - Java Scripting API 41 / 48
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 42 / 48
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 43 / 48
Exemple : le pattern Visitor● Diagramme issu du livre du GoF
Franck SIMON Confoo 2012 - Java Scripting API 44 / 48
Exemple : le pattern Visitor● Le diagramme de notre exemple
Franck SIMON Confoo 2012 - Java Scripting API 45 / 48
Exemple : le pattern Visitor● L'interface Visitor et son implémentation en
JavaScriptpublic interface Visitor {
void visitText(Text t);void visitLine(Line l);void visitPanel(Panel p);
}
var visitor = new Object();visitor.visitText = function(objText){
println(objText.getText());}
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 46 / 48
Exemple : le pattern Visitor● Mise en œuvre en Java
...ScriptEngineManager manager = new ScriptEngineManager();ScriptEngine engine = manager.getEngineByName("javascript");engine.eval(new FileReader("visitors.js"));
Object o = engine.get("visitor");Invocable invocable = (Invocable) engine;Visitor visitor = invocable.getInterface(o, Visitor.class);engine.put("visitor", visitor);p3.accept(visitor);...
on récupère l'objet JavaScript
Java voit l'objet JavaScript commeimplémentation de Visitor
Pour que le moteur JavaScriptpuisse caster l'objet en Visitor
Franck SIMON Confoo 2012 - Java Scripting API 47 / 48
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 48 / 48
Et voilà !!!