96
Java Scripting API v 1.0

Java scripting api

Embed Size (px)

DESCRIPTION

Présentation donnée par Franck SIMON dans le cadre de ConFoo 2012

Citation preview

Page 1: Java scripting api

Java Scripting API

v 1.0

Page 2: Java scripting api

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"

Page 3: Java scripting api

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é

Page 4: Java scripting api

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

Page 5: Java scripting api

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

Page 6: Java scripting api

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

Page 7: Java scripting api

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(...)

Page 8: Java scripting api

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

}

Page 9: Java scripting api

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

Page 10: Java scripting 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

Page 11: Java scripting api

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");

Page 12: Java scripting api

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

Page 13: Java scripting api

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

Page 14: Java scripting api

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();

}...

Page 15: Java scripting api

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

Page 16: Java scripting api

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);

}

}

Page 17: Java scripting api

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");

Page 18: Java scripting api

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

Page 19: Java scripting api

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

Page 20: Java scripting api

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) ;

Page 21: Java scripting api

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"];

Page 22: Java scripting api

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

Page 23: Java scripting api

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

Page 24: Java scripting api

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

Page 25: Java scripting api

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;

}

Page 26: Java scripting api

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;

}

Page 27: Java scripting api

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");}

Page 28: Java scripting api

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

Page 29: Java scripting api

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

Page 30: Java scripting api

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

Page 31: Java scripting api

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));

Page 32: Java scripting api

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));

Page 33: Java scripting api

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

Page 34: Java scripting api

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"));

}

}

Page 35: Java scripting api

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);

}

Page 36: Java scripting api

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

Page 37: Java scripting api

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

Page 38: Java scripting api

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

Page 39: Java scripting api

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);

}}

Page 40: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 40 / 48

Exemple du "monde réel"

Et maintenant...

… un peu de code pour grande personne

Page 41: Java scripting api

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

Page 42: Java scripting api

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

Page 43: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 43 / 48

Exemple : le pattern Visitor● Diagramme issu du livre du GoF

Page 44: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 44 / 48

Exemple : le pattern Visitor● Le diagramme de notre exemple

Page 45: Java scripting api

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

}

Page 46: Java scripting api

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

Page 47: Java scripting api

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

Page 48: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 48 / 48

Et voilà !!!

Page 49: Java scripting api

Java Scripting API

v 1.0

Page 50: Java scripting api

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"

Page 51: Java scripting api

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é

Page 52: Java scripting api

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

Page 53: Java scripting api

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, ...

Page 54: Java scripting api

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

Page 55: Java scripting api

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(...)

Page 56: Java scripting api

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

}

Page 57: Java scripting api

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

Page 58: Java scripting 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

Page 59: Java scripting api

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");

Page 60: Java scripting api

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

Page 61: Java scripting api

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

Page 62: Java scripting api

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();

}...

Page 63: Java scripting api

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

Page 64: Java scripting api

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);

}

}

Page 65: Java scripting api

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");

Page 66: Java scripting api

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

Page 67: Java scripting api

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

Page 68: Java scripting api

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) ;

Page 69: Java scripting api

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"];

Page 70: Java scripting api

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

Page 71: Java scripting api

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

Page 72: Java scripting api

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

Page 73: Java scripting api

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;

}

Page 74: Java scripting api

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;

}

Page 75: Java scripting api

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");}

Page 76: Java scripting api

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

Page 77: Java scripting api

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

Page 78: Java scripting api

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

Page 79: Java scripting api

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));

Page 80: Java scripting api

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));

Page 81: Java scripting api

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

Page 82: Java scripting api

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"));

}

}

Page 83: Java scripting api

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);

}

Page 84: Java scripting api

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

Page 85: Java scripting api

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

Page 86: Java scripting api

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

Page 87: Java scripting api

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);

}}

Page 88: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 40 / 48

Exemple du "monde réel"

Et maintenant...

… un peu de code pour grande personne

Page 89: Java scripting api

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

Page 90: Java scripting api

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

Page 91: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 43 / 48

Exemple : le pattern Visitor● Diagramme issu du livre du GoF

Page 92: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 44 / 48

Exemple : le pattern Visitor● Le diagramme de notre exemple

Page 93: Java scripting api

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

}

Page 94: Java scripting api

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

Page 95: Java scripting api

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

Page 96: Java scripting api

Franck SIMON Confoo 2012 - Java Scripting API 48 / 48

Et voilà !!!