2010. február 19., péntek

JavaScript EE, első felvonás

Bár a téma nem új-keletű, én most jutottam el oda, hogy legalább kipróbálás szinten foglalkozzam vele. Java SE 6-os verziója óta megtalálható benne a Mozilla Rhinó-ja, amely egy JavaScript értelmező, és segítségével a JVM-en lehetséges JavaScript kódok futtatása Java kódból. Nincs más dolgunk, mint importálni a javax.script csomagot, és a ScriptEngineManager segítségével példányosítani egy ScriptEngine értelmezőt.
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
Java kód:
import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.StringBuilder;
import javax.script.*;

public class SimpleJavaScriptTest {
public static void main(String[] args) throws Exception {
//Get reference to the engine
ScriptEngine engine = new ScriptEngineManager().getEngineByName("JavaScript");
//Bind some Java object to the script
Bindings vars = new SimpleBindings();
vars.put("testString", "This is a test string.");
StringBuilder stringBuilder = new StringBuilder();
vars.put("testStringBuilder", stringBuilder);
//Read the JavaScript code
Reader scriptReader = new InputStreamReader(SimpleJavaScriptTest.class.getResourceAsStream("test.js"));
try {
//Run the JavaScript
engine.eval(scriptReader, vars);

System.out.println(stringBuilder.toString());
System.out.println(vars.get("testFile").getClass());
System.out.println(vars.get("jsObject").getClass());
} finally {
scriptReader.close();
}
}
}
JavaScript kód:
function printType(obj) {
if (obj.getClass) println("Java object: " + obj.getClass().name);
else println("JS object: " + obj.toSource());
}
printType(testString);

printType(testStringBuilder);
testStringBuilder.append("This content added by JavaScript.");

var testFile = new java.io.File("/");
printType(testFile);

var jsObject = {x: 1, y: { u: 2, v: 3 }};
printType(jsObject);
A példát futtatva az alábbi eredményt kapjuk:
JS object: (new String("This is a test string."))
Java object: java.lang.StringBuilderJava object: java.io.File JS object: ({x:1, y:{u:2, v:3}})
This content added by JavaScript.
class java.io.File
class sun.org.mozilla.javascript.internal.NativeObject
Mint az jól lát-szódik szinte teljes az átjárás a két kód között, bemenő paramétert megfelelő JavaScript típusra cast-olja az értelmező, ennek sikertelensége esetén Java objektumként viselkedik, annak minden funkciójával. Továbbmenve JavaScript kódunkban is van lehetőség Java objektumok létrehozására, melyeket a script futása után elkérhetünk az értelmezőtől. Amennyiben olyan változót kapunk a scriptből, amit Java oldalon nem lehet megfeleltetni egyik osztálynak sem, akkor azzal egy dolgot tehetünk, paraméterként egy másik JavaScriptnek átadhatjuk.
Ezen a ponton merülhet fel a kérdés, hogy valójában ez mire is való? A válasz erre a kérdésre eléggé összetett, és nem is célom maradéktalanul körbejárni. Egyrészt ezzel a módszerrel tudjuk ötvözni a két nyelv tulajdonságait, tehát a Java robusztusságát a JavaScript egyszerűségével összepárosítva kiszélesedik a programozói paletta. Megjegyzem erre a célra nem csak JavaScriptet használhatunk, akár Groovie, vagy Scala kódot is integrálhatunk Java programunkba, ráadásul utóbbiak Java bytecode-ra fordulnak, ami mélyebb integrációra ad lehetőséget. Másrészt kliens oldali scriptjeinket is futtathatjuk server oldalon, ami azt jelenti, hogy nem kell két helyen, két környezetben implementálnunk az azonos működést, hanem szerver oldalon használhatjuk a kliens oldali program-kódokat. Hagyományosan egy űrlap elküldése esetén a böngészőben történik egy előellenőrzés, hogy az adatok formailag megfelelnek-e a követelménynek, ezzel csökkentve a hálózati forgalmat. Formailag helyes adatok elküldésre kerülnek, ahol szerver oldalon újra ellenőrizni kell őket, mind formailag, mind már adat-logikailag is. Mivel szerver környezetben nem a JavaScript az elterjedt programozási nyelv, a formai ellenőrzést sajnos ott is implementálni kell. Ehelyett a kliens oldali JavaScript-ünket nyugodtan felhasználhatjuk, időt, energiát, költséget, és nem utolsó sorban hiba-lehetőséget megspórolva.
Java kód:
engine.eval(scriptReader);
if (engine instanceof Invocable) {
Invocable invEngine = (Invocable) engine;
Object result = invEngine.invokeFunction("testStringLength", "valid string", 2);
System.out.println("Result: " + result + "(" + result.getClass().getName() + ")");
result = invEngine.invokeFunction("testStringLength", "invalid string", 20);
System.out.println("Result: " + result + "(" + result.getClass().getName() + ")");
} else System.out.println("NOT Invocable");
JavaScript kód:
function testStringLength(input, lenght) {
return input.length >= lenght ? true : false;
}
Eredmény:
Result: true(java.lang.Boolean)
Result: false(java.lang.Boolean)
Bár a példa nem tükrözi a technológia hasznosságát (így még talán bonyolultabb is), viszont bemutatja, hogyan tudunk JavaScript függvényeket meghívni, és azok visszatérési értékét felhasználni Java kódunkban. Folyt köv...
Aki szeretne a témáról bővebben is olvasni, az itt talál információt.

Nincsenek megjegyzések:

Megjegyzés küldése