cerca
JavaScript in Java
modifica cronologia stampa login logout

Wiki

Tools

Categorie

Help

edit SideBar

Return to JavaScript in Java  (Edit)

Utenti.JavaScriptInJava History

Hide minor edits - Show changes to output

Added lines 145-212:


!Usare la distribuzione di Rhino
Nel caso non si voglia utilizzare il Rhino incluso nella JDK, è sempre possibile scaricare da [[qui -> http://www.mozilla.org/rhino/]] l'ultima distribuzione di Rhino. Del contenuto dello zip a noi serve solo il '''js.jar''', il quale va messo nel classpath. Per ottenere ciò, occorre mettere nelle proprietà di esecuzione del progetto la seguente riga:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
-Djava.library.path=/percorso/di/rhino
>><<

Nelle varie IDE c'è naturalmente l'opzione per selezionare le librerie da importare nel progetto, ma la riga sopra va comunque specificata nelle opzioni di esecuzione.

!!Utilizzo di Rhino
La procedura per far partire l'interprete è diversa, perché la distribuzione separata di Rhino non viene inclusa nell'interfaccia generica degli script che Java offre.

Nella classe che ospiterà Rhino, occorre avere almeno queste tre variabili, che metto '''private''' per conformità all'OOP:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
private Context myContext;
private ScriptableObject myScope;
private Script script;
>><<

Ed ecco poi quello che ci serve:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
// Creo il contesto per Rhino
ContextFactory cf = new ContextFactory();
myContext = cf.enterContext();

// Recupero lo scope
myScope = new ImporterTopLevel(myContext);

// Inizializzo gli oggetti standard
myContext.initStandardObjects(myScope);
>><<

Per eseguire effettivamente gli script, posso scegliere se compilarli oppure valutarli direttamente (compilati dovrebbero essere un po' più performanti). Ecco quello che si fa per compilarli:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
script = myContext.compileReader(new FileReader("./scripts/main.js"), "main.js", 0, null);

script.exec(myContext, myScope);
>><<

Analizziamo un po' i parametri di '''compileReader''':
* '''new FileReader("./scripts/main.js")''' è il reader da cui prendere il file
* '''"main.js"''' è il nome che quello script avrà all'interno del motore Rhino. Ad esempio, eventuali errori di interpretazioni saranno presentati come appartenenti al file "main.js"
* '''0''': numero di riga da cui partire a contare le righe del file
* '''null''': è il '''SecurityDomain''' a cui dovrà appartenere lo script. Se ce ne disinteressiamo, come in questo caso, allora lasciamo null.

Ed ecco invece quello che si fa per eseguirli al volo:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
myContext.evaluateReader(myScope, new FileReader("blabla.js"), "blabla", 0, null);
>><<

Simile a prima, ma con la differenza che lo '''scope''' viene indicato direttamente nella chiamata.

!!Bind di classi
Per esportare classi da Java a JavaScript, invece di usare il sistema dei '''Bindings''' visto sopra, si fa così:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
// Wrapping di System.out
Object wrappedOut = Context.javaToJS(System.out, myScope);
ScriptableObject.putProperty(myScope, "out", wrappedOut);
>><<

Con questo esempio ho voluto esportare nel contesto di JavaScript la gerarchia '''System.out''', così da poter scrivere in JS cose come "out.println("Valore = " + numero)".
Added lines 13-15:
!!OpenJDK
Può darsi che si tratti di un problema circostanziato, ma a quanto pare se si usa la OpenJDK occorre installare a parte il package Rhino, perché per qualche oscura ragione il Classpath non include le classi specifiche di Rhino.
Changed line 50 from:
Bindings b = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
to:
Bindings b = engine.getBindings(ScriptContext.ENGINE_SCOPE);
Changed line 53 from:
Questa riga prende i bindings del contesto GLOBAL_SCOPE (ovvero globali), e li restituisce come un oggetto di tipo '''Bindings'''.
to:
Questa riga prende i bindings del contesto ENGINE_SCOPE (ovvero relativi all'engine corrente), e li restituisce come un oggetto di tipo '''Bindings'''.
Changed lines 17-18 from:
ScriptEngineManager manager = new ScriptEngineManager();\\
ScriptEngine engine = manager.getEngineByName("JavaScript");
to:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("JavaScript");
Changed line 30 from:
engine.eval("println("Ciao:)");
to:
engine.eval("println("Ciao:)");
Changed line 36 from:
engine.eval(new FileReader("nomefile.js"));
to:
engine.eval(new FileReader("nomefile.js"));
Changed line 47 from:
Bindings b = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
to:
Bindings b = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
Changed line 55 from:
b.put("Valore", 20);
to:
b.put("Valore", 20);
Changed line 63 from:
println("Valore = " + Valore)
to:
println("Valore = " + Valore)
Changed line 70 from:
Valore = 132; // Ora la variabile Valore vale 132, sia dentro che fuori lo script
to:
Valore = 132; // Ora la variabile Valore vale 132, sia dentro che fuori lo script
Changed line 76 from:
System.out.println("Valore = " + (Double)b.get("Valore"));
to:
System.out.println("Valore = " + (Double)b.get("Valore"));
Changed line 108 from:
b.put("e", new Esperimento());
to:
b.put("e", new Esperimento());
Changed lines 114-115 from:
e.setA(400)
println("e.A = " + e.A)
to:
e.setA(400)
println("e.A = " + e.A)
Changed line 124 from:
importPackage(Packages.provarhino)
to:
importPackage(Packages.provarhino)
Changed lines 130-132 from:
var brao = new Esperimento()
brao.setA(10)
println("A = " + brao.getA())
to:
var brao = new Esperimento()
brao.setA(10)
println("A = " + brao.getA())
Changed line 138 from:
importClass(Packages.provarhino.Esperimento)
to:
importClass(Packages.provarhino.Esperimento)
Added lines 85-86:
package provarhino;
Added lines 117-141:

!!Creare istanze di una classe all'interno dello script
Nel caso appena visto, la classe viene create in Java, e viene resa visibile allo script. Posso però anche volere che una classe Java sia istanziabile direttamente nello script.

La mia classe Esperimento, come si può vedere sopra, fa parte del package '''provarhino'''. Ecco come si rende visibile questo package allo script

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
importPackage(Packages.provarhino)
>><<

In questo modo, tutti i membri del package '''provarhino''' saranno visibili allo script. Sarà quindi possibile scrivere del codice javascript così:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
var brao = new Esperimento()
brao.setA(10)
println("A = " + brao.getA())
>><<

Se, invece di importare l'intero package '''provarhino''', voglio importare solo una sua classe, allora uso questa istruzione:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
importClass(Packages.provarhino.Esperimento)
>><<

e solo la classe Esperimento sarà visibile all'interno dello script.
Changed line 13 from:
!!Primi passi
to:
!!Creare lo ScriptEngine
Added lines 15-114:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
ScriptEngineManager manager = new ScriptEngineManager();\\
ScriptEngine engine = manager.getEngineByName("JavaScript");
>><<


Con queste due righe, creo innanzitutto uno '''ScriptEngineManager''' che gestisce tutti i motori che voglio creare, e poi tiro fuori da esso un motore, istanza di '''ScriptEngine''', e glielo faccio recuperare per nome: JavaScript. Aaah che bello:)

Posso anche creare diversi ScriptEngine dallo stesso ScriptEngineManager, volendo, però ora non interessa nessuno.

!!Eseguire codice JavaScript
Siamo già al passo fondamentale: come far eseguire codice JavaScript al nostro ScriptEngine fresco di fabbrica! Ecco come:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
engine.eval("println("Ciao:)");
>><<

Se invece voglio fargli eseguire un intero files, glielo posso passare in questo modo:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
engine.eval(new FileReader("nomefile.js"));
>><<

Very easy!

!!Portare valori dentro lo script
Quando eseguo lo script, posso desiderare che ad esso siano visibili anche delle variabili che vengono impostate all'esterno dello script.

Per fare ciò, ci occorre un altro oggetto chiamato '''Bindings'''. Un modo per tirarlo fuori in modo semplice è questo:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
Bindings b = engine.getBindings(ScriptContext.GLOBAL_SCOPE);
>><<

Questa riga prende i bindings del contesto GLOBAL_SCOPE (ovvero globali), e li restituisce come un oggetto di tipo '''Bindings'''.

A questo punto, posso inserire nei bindings le cose che voglio io, in questo modo:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
b.put("Valore", 20);
>><<

Ho inserito la variabile '''Valore''', che sarà accessibile nel mio script, e le ho assegnato il valore 20. Questo va fatto '''prima''' di chiamare '''engine.eval();'''.

Dall'interno del codice JavaScript potrò recuperare il valore di '''Valore''' in modo semplice:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
println("Valore = " + Valore)
>><<

!!Portare valori fuori dallo script
Una volta che ho bindato la variabile '''Valore''', la posso anche tirare fuori dallo script usando i soliti bindings. Ho bindato, ed evaluato, e nello script ho queste righe:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
Valore = 132; // Ora la variabile Valore vale 132, sia dentro che fuori lo script
>><<

Al termine di '''eval()''' posso recuperare il valore in questo modo:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
System.out.println("Valore = " + (Double)b.get("Valore"));
>><<

!!Bindare oggetti Java in JavaScript
Tramite i '''Bindings''' è possibile anche portare dentro Java degli oggetti, ovvero delle classi compilate.

Supponiamo di avere una classe Esperimento, così scritta:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
public class Esperimento {\\

public Esperimento() {\\
System.out.println("Classe Esperimento, scritta in Java");\\
A = 0;\\
}\\

public void setA(int A) {\\
this.A = A;\\
}\\

public int getA() {\\
return A;\\
}\\

private int A;\\
}
>><<

Posso bindare un'istanza di questa classe nei Bindings, in questo modo:
>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
b.put("e", new Esperimento());
>><<

e da dentro lo script posso accedere ai metodi di Esperimento in modo naturale:

>>left bgcolor=#f5f9fc width=auto border='2px solid #cccccc' padding=5px<<
e.setA(400)
println("e.A = " + e.A)
>><<
Added lines 1-17:
(:title JavaScript in Java:)
%titolo%''':: JavaScript in Java ::'''

!!Introduzione
Quando si scrivono programmi, può venire utile avere un linguaggio di scripting che permetta di estenderne le funzionalità o fargli fare le cose che vogliamo, senza stare lì a ricompilare.\\
Ci sono diversi linguaggi di scripting, che si possono "embeddare" nei linguaggi "maggiori", come C, C++ etc. Per quanto riguarda il C++, ho trovato [[AngelScript -> http://www.angelcode.com/angelscript/]] che ha dalla sua una sintassi simile al C, ed una semplice integrazione con il C++ nativo (non semplicissima, ma rispetto ad altre cose è veramente facile).\\
In cerca di una roba del genere per Java, ho scoperto con somma meraviglia che JavaScript è già incluso, sottoforma di [[Rhino -> http://www.mozilla.org/rhino/]], nella JDK 6!\\
Qui metto quello che ho scoperto sull'integrazione di Rhino in un programma Java.

!!Nota su JavaScript
A dispetto del nome, non c'entra molto con Java. Ha una sintassi C-like, e quindi Java-like, ma è ben diverso. Se si lasciano stare i concetti balordi, una [[rapida occhiata alla fonte -> https://developer.mozilla.org/en/JavaScript]] permette di farsi un'idea di che aspetto abbia.

!!Primi passi
Tiriamo in piedi il nostro programma Java, ed aggiungiamo le seguenti, semplici righe:

----
[[!Programmazione]]