Podpora skriptovacích jazyků v JDK6 a OpenJDK6

14. 4. 2011
Doba čtení: 21 minut

Sdílet

Ve čtrnáctém článku o jazyce Java se seznámíme s API určeným pro práci se skripty napsanými v různých skriptovacích programovacích jazycích. Toto API bylo navrženo tak, aby byl způsob volání skriptů, předávání parametrů skriptům, získávání návratových hodnot i další činnosti prováděny jednotným způsobem.

Obsah

1. Podpora skriptovacích jazyků v JDK6 a OpenJDK6

2. Skriptovací jazyky a JSR 223

3. Třídy a rozhraní používané při práci se skripty

4. První demonstrační příklad: výpis všech dostupných skriptovacích en­ginů

5. Druhý demonstrační příklad: získání skriptovacího engine několika způsoby

6. Třetí demonstrační příklad: několik způsobů spuštění skriptu

7. Čtvrtý demonstrační příklad: návratové hodnoty skriptů

8. Pátý demonstrační příklad: předávání parametrů a volání funkcí

9. Odkazy na Internetu

1. Podpora skriptovacích jazyků v JDK6 a OpenJDK6

V předchozích částech seriálu o programovacím jazyku Java i o vlastnostech JDK a OpenJDK jsme se zabývali především tím, jakým způsobem interně pracují správci paměti a jak lze v některých případech zvýšit výkonnost aplikací napsaných v Javě (změnou GC, nastavením parametrů haldy/heapu, povolením huge/large pages, použitím alternativních knihoven nabízených v Oracle JDK), popř. snížit jejich paměťové nároky, například použitím komprimovaných ukazatelů na objekty (compressed oops), konfigurací velikostí jednotlivých oblastí na haldě atd. Dnes poněkud od těchto témat odbočíme, protože se budeme zabývat podporou skriptovacích jazyků v JDK a JRE. V minulosti bylo vyvinuto poměrně velké množství skriptovacích jazyků určených pro běh na virtuálním stroji jazyka Java (JVM), ať již se jedná o reimplementace již existujících programovacích jazyků (Basic, Cobol, Lisp, Erlang, Forth, Logo, Python, Ruby či Scheme), tak i jazyků zcela nových, mezi něž patří například BeanShell, Groovy, Scala či právě vznikající jazyk Ceylon.

Důvodů, proč pro virtuální stroj jazyka Java vznikly a stále vznikají nové skriptovací jazyky, je více. Mezi ty hlavní důvody však patří především existence mnoha knihoven pro Javu (včetně knihoven, které jsou součástí každé JVM, což mj. znamená podporu pro práci se sítěmi, tvorbu GUI atd.), dnes již relativně dobrá přenositelnost aplikací běžících nad JVM na různé platformy, včetně platforem mobilních, automatická správa paměti alokované v rámci virtuálního stroje a v některých případech taktéž to, že skripty je možné překládat do plnohodnotného javovského bajtkódu, který je poté při běhu aplikace buď interpretován nebo opět překládán just-in-time překladačem do nativního kódu mikroprocesoru použitého na počítači, kde je virtuální stroj Javy spuštěn. To, že pro platformu Javy existuje velké množství skriptovacích jazyků různé složitosti a taktéž vyjadřovacích schopností, je samozřejmě dobře, protože je možné podporu pro skripty vložit do uživatelských aplikací, což může mít velký vliv na obchodní úspěch takové aplikace (známým příkladem je například AutoCAD, pro nějž vzniklo díky podpoře AutoLISPu velké množství amatérských i profesionálních nadstaveb, což na druhou stranu rozšířilo i okruh uživatelů, kteří si AutoCAD pořídili).

2. Skriptovací jazyky a JSR 223

Zpočátku skriptovací jazyky určené pro běh na virtuálním stroji Javy vznikaly takovým způsobem, že každý jazyk nabízel programátorům odlišné programátorské rozhraní pro komunikaci mezi programy napsanými v Javě a skripty. To samozřejmě nebyl ideální stav, protože to komplikovalo práci jak vývojářům daného skriptovacího jazyka (ti museli vymyslet vhodné API a to taktéž popsat), tak i vývojářům, kteří chtěli podporu pro nějaký skriptovací jazyk implementovat ve svých programech. Z tohoto důvodu vznikl v rámci jednoho „požadavku na změnu“ (JSR – Java Specification Request) i návrh jednotného API použitelného pro různé skriptovací jazyky. Tento JSR získal pořadové číslo 223 a výsledná specifikace je známá pod celým svým názvem JSR 223: Scripting for the JavaTM Platform. Ve specifikaci JSR 223 je popsáno jak API, které by měli tvůrci jednotlivých skriptovacích jazyků (nebo spíše skriptovacích enginů, které skripty zpracovávají) dodržet, tak i způsob, jak jsou jednotlivé skriptovací enginy inicializovány v době běhu aplikace, podpora pro skripty kompilované do bajtkódu atd.

Aby to však nebylo málo, byl do JDK integrován projekt Rhino, což je skriptovací engine určený pro programovací jazyk JavaScript (resp. jeho standard ECMA-262), který je kompletně napsán v Javě a navíc byl uvolněn jako open-source. Zatímco jsou přeložené třídy tvořící skriptovací engine Rhino v Oracle JDK uloženy přímo v archivu rt.jar, můžeme tento engine v IcedTea6 najít v samostatném archivu rhino.jar, umístěném ve stejném adresáři, jako rt.jar (jre/lib). Díky tomu, že je Rhino součástí JDK, lze v javovských programech volat JavaScriptové programy, dokonce lze spustit i JavaScriptový shell. Navíc, pokud by bylo nutné použít vlastní (novější) implementaci Rhina, než nabízí používaná JDK, může se rhino*.jar umístit na classpath a samotná JDK se již postará o to, aby měl tento archiv přednost před Rhinem dodávaným spolu s JDK. Vzhledem k tomu, že je dnes Rhino součástí JDK, budou všechny dnešní demonstrační příklady počítat s jeho podporou.

3. Třídy a rozhraní používané při práci se skripty

Pro jednotnou práci s různými skriptovacími enginy, spouštění celých skriptů (příkaz po příkazu), volání vybraných funkcí či metod ve skriptech i pro provádění dalších činností je v API Javy specifikováno pouze šest rozhraní a šest tříd; z toho jedna třída představuje obecnou výjimku vzniklou při práci se skripty. Všech šest rozhraní a šest tříd je uloženo v balíčku javax.script. V praxi, zejména tehdy, pokud se nebude pracovat s kompilovanými skripty, se však počet skutečně používaných tříd a rozhraní snižuje – zpravidla se používá pouze třída ScriptEngineMa­nager a rozhraní ScriptEngine, Invocable a ScriptException. V následující tabulce jsou vypsána všechna rozhraní definovaná v balíčku javax.script:

Jméno rozhraní Popis
Bindings Mapa obsahující klíče typu řetězec (jedná se o třídu zapouzdřující jednu z implementací rozhraní Map).
Compilable Rozhraní, které může být implementované skriptovacím enginem podporujícím překlad skriptů.
Invocable Rozhraní, které může být implementované skriptovacím enginem podporujícím volání jednotlivých funkcí nebo metod.
ScriptContext Třídy implementující toto rozhraní zajišťují komunikaci mezi skriptovacím enginem a ostatními objekty.
ScriptEngine Rozhraní implementované všemi skriptovacími enginy.
ScriptEngineFac­tory Rozhraní pro třídy používané pro získávání informací o jednotlivých skriptovacích enginech, popř. pro vytvoření (či získání) instance některého enginu.

V další tabulce je vypsáno všech šest výše zmíněných tříd, které jsou taktéž součástí balíčku javax.script:

Jméno třídy Popis
AbstractScrip­tEngine Standardní implementace přetížené metody eval().
CompiledScript Instance potomků této třídy reprezentují přeložený skript.
ScriptEngineMa­nager Třída používaná především pro vytvoření (získání) instance vybraného skriptovacího enginu.
SimpleBindings Implementace rozhraní Bindings (viz předchozí tabulka) pomocí HashMapy.
SimpleScriptCon­text Implementace rozhraní ScriptContext (viz předchozí tabulka).
ScriptException Třída reprezentující výjimky vyvolávané při inicializaci a spouštění skriptů. Důležité je, že tato výjimka může nést i informaci o jménu souboru se skriptem i přesné lokalizaci chyby (číslo řádku i číslo sloupce).

4. První demonstrační příklad: výpis všech dostupných skriptovacích en­ginů

V dnešním prvním demonstračním příkladu je ukázáno, jakým způsobem je možné získat informace o všech skriptovacích enginech, které jsou v javovském virtuálním stroji, v němž je testovací aplikace spuštěná, dostupné. Nejprve je vytvořena instance třídy StringEngineMa­nager, po jejíž inicializaci je již možné získat informace o všech podporovaných skriptovacích enginech pomocí metody StringEngineMa­nager.getEngi­neFactories(), která vrací seznam objektů implementující rozhraní StringEngineFac­tory. Toto rozhraní předepisuje některé metody, které je možné využít pro získání jména a verze podporovaného skriptovacího jazyka a taktéž seznam aliasů (přezdívek) daného skriptovacího enginu, což je poměrně důležitá informace použitá v následujícím demonstračním příkladu uvedeném v další kapitole. Zdrojový kód prvního demonstračního příkladu je poměrně jednoduchý:

import javax.script.ScriptEngineFactory;
import javax.script.ScriptEngineManager;



/**
 * Utilita, ktera po svem spusteni vypise vsechny dostupne skriptovaci enginy a
 * programovaci jazyky podporovane danym enginem.
 *
 * @author Pavel Tisnovsky
 */
public class ScriptingTest1
{
    private static void listAllScriptEngines()
    {
        // Zakladni pristupovy bod ke skriptovacim technologiim
        // zajistuje v JDK trida ScriptEngineManager.
        ScriptEngineManager engineManager = new ScriptEngineManager();

        // Ziskani vsech dostupnych skriptovacich enginu a vypis
        // jejich vlastnosti i podporovanych jazyku.
        for (ScriptEngineFactory factory : engineManager.getEngineFactories())
        {
            String engineName      = factory.getEngineName();
            String engineVersion   = factory.getEngineVersion();
            String languageName    = factory.getLanguageName();
            String languageVersion = factory.getLanguageVersion();
            System.out.printf("Language: %s (%s)\n", languageName, languageVersion);
            System.out.printf("Script engine: %s (%s)\n", engineName, engineVersion);

            // Vypis vsech aliasu.
            for (String name : factory.getNames())
            {
                System.out.printf("    Engine Alias: %s\n", name);
            }
        }
    }

    public static void main(String[] args)
    {
        listAllScriptEngines();
    }

}

Následuje příklad textového výstupu generovaného touto testovací aplikací při jejím překladu a spuštění pomocí IcedTea6–1.8.x (IcedTea je OpenJDK přeložené pomocí GNU nástrojů a s použitím poměrně velkého množství patchů, které nebyly z různých důvodů zařazeny přímo do OpenJDK):

Language: ECMAScript (1.6)
Script engine: Mozilla Rhino (1.6 release 2)
    Engine Alias: js
    Engine Alias: rhino
    Engine Alias: JavaScript
    Engine Alias: javascript
    Engine Alias: ECMAScript
    Engine Alias: ecmascript

5. Druhý demonstrační příklad: získání skriptovacího engine několika způsoby

Ve druhém demonstračním příkladu je ukázáno několik způsobů, jakými je možné získat skriptovací engine podporující požadovaný skriptovací jazyk. V tomto příkladu se počítá s tím, že JRE, v němž je příklad spuštěn, má nainstalovánu podporu pro JavaScript, popř. jsou potřebné knihovny dostupné na CLASSPATH. Jak jsme se již dozvěděli z předchozích kapitol, je JavaScript podporován jak v Oracle JDK, tak i v OpenJDK – v obou případech je použita implementace skriptovacího enginu Rhino. V demonstračním příkladu se pro získání instance tohoto enginu používá jak výběr pomocí jména či aliasu, tak i pomocí přípony souborů se skripty, popř. pomocí MIME typu. Pokud není skriptovací engine odpovídající zadané podmínce nalezen, vrátí se pouze hodnota NULL, tj. NEdojde přímo k vyvolání výjimky; až při pokusu o přístup k neexistujícímu objektu samozřejmě dojde k NPE :-). Následuje výpis zdrojového kódu druhého demonstračního příkladu:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;



/**
 * V teto utilite je ukazano nekolik zpusobu, jakymi je mozne ziskat
 * skriptovaci engine.
 *
 * @author Pavel Tisnovsky
 */
public class ScriptingTest2
{
    ScriptEngineManager engineManager;

    /**
      * Ziskani skriptovaciho engine podle jmena.
      */
    private void getEngineByNameTest(String name)
    {
        System.out.print("Hledani podle jmena '" + name + "'");
        printEngineInfo(this.engineManager.getEngineByName(name));
    }

    /**
      * Ziskani skriptovaciho engine podle pripony.
      */
    private void getEngineByExtensionTest(String extension)
    {
        System.out.print("Hledani podle pripony '" + extension + "'");
        printEngineInfo(this.engineManager.getEngineByExtension(extension));
    }

    /**
      * Ziskani skriptovaciho engine podle MIME typu.
      */
    private void getEngineByMimeTypeTest(String mimeType)
    {
        System.out.print("Hledani podle MIME typu '" + mimeType + "'");
        printEngineInfo(this.engineManager.getEngineByMimeType(mimeType));
    }

    private void runTests()
    {
        this.engineManager = new ScriptEngineManager();
        getEngineByNameTest("JavaScript");
        getEngineByNameTest("javaScript"); // spatne jmeno!
        getEngineByNameTest("javascript");
        getEngineByNameTest("EcmaScript"); // nektere verze Rhina podporuji "ECMAScript"
        getEngineByNameTest("ecmaScript"); // spatne jmeno!
        getEngineByNameTest("ecmascript");
        getEngineByExtensionTest("js");
        getEngineByExtensionTest("bas");   // pravdepodobne se nenalezne
        getEngineByMimeTypeTest("text/javascript");
        getEngineByMimeTypeTest("text/ecmascript");
        getEngineByMimeTypeTest("application/javascript");
        getEngineByMimeTypeTest("application/ecmascript");
    }

    /**
      * Vypis informace o tom, zda byl ci nebyl odpovidajici
      * skriptovaci engine nalezen.
      */
    private void printEngineInfo(ScriptEngine engine)
    {
        String answer = engine == null ? "ne" : "";
        System.out.println(":  skriptovaci engine " + answer + "byl nalezen");
    }

    public static void main(String[] args)
    {
        new ScriptingTest2().runTests();
    }

}

Pod tímto odstavcem je opět uvedena ukázka textového výstupu testovací aplikace v případě, že je pro její spuštění použito IcedTea6–1.8:

Hledani podle jmena 'JavaScript':  skriptovaci engine byl nalezen
Hledani podle jmena 'javaScript':  skriptovaci engine nebyl nalezen
Hledani podle jmena 'javascript':  skriptovaci engine byl nalezen
Hledani podle jmena 'EcmaScript':  skriptovaci engine nebyl nalezen
Hledani podle jmena 'ecmaScript':  skriptovaci engine nebyl nalezen
Hledani podle jmena 'ecmascript':  skriptovaci engine byl nalezen
Hledani podle pripony 'js':  skriptovaci engine byl nalezen
Hledani podle pripony 'bas':  skriptovaci engine nebyl nalezen
Hledani podle MIME typu 'text/javascript':  skriptovaci engine byl nalezen
Hledani podle MIME typu 'text/ecmascript':  skriptovaci engine byl nalezen
Hledani podle MIME typu 'application/javascript':  skriptovaci engine byl nalezen
Hledani podle MIME typu 'application/ecmascript':  skriptovaci engine byl nalezen

6. Třetí demonstrační příklad: několik způsobů spuštění skriptu

Třetí demonstrační aplikace je již zaměřena poněkud praktičtěji, než předchozí dva příklady. Po vytvoření instance třídy ScriptEngineMa­nager a získání skriptovacího enginu určeného pro programovací jazyk JavaScript se pomocí metody ScriptEngine.e­val() spustí jednoduchý skript, a to třemi různými způsoby. Při použití prvního způsobu je skript uložen v řetězci, při použití způsobu druhého je získán z některé třídy implementující rozhraní Reader (může se jednat například o stažení skriptu ze sítě, jeho načtení z archivu typu ZIP atd.) a konečně v případě třetím je skript načten z běžného souboru, popř. ze souboru uloženého v javovském archivu (JAR), v němž je zabalena celá aplikace. V případě, že při spuštění skriptu dojde k nějaké chybě, je vygenerována výjimka typu ScriptException, z níž je možné v některých případech získat i informace o čísle textového řádku, popř. i sloupce, ve kterém k chybě došlo:

import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.StringReader;
import java.io.IOException;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;



/**
 * Demonstracni priklad, v nemz je ukazano nekolik zpusobu spusteni skriptu.
 *
 * @author Pavel Tisnovsky
 */
public class ScriptingTest3
{
    static final String script = "println('Hello world');";
    ScriptEngineManager engineManager;
    ScriptEngine scriptEngine;

    /**
      * Spusteni skriptu, ktery je ulozen v retezci.
      */
    private void runScriptStoredInString()
    {
        try
        {
            this.scriptEngine.eval(script);
        }
        catch (ScriptException e)
        {
            e.printStackTrace();
        }
    }

    /**
      * Spusteni skriptu, ktery je ziskan z objektu typu Reader nebo
      * z nektereho potomka teto tridy.
      */
    private void runScriptFromReader()
    {
        StringReader stringReader = new StringReader(script);
        try
        {
            this.scriptEngine.eval(stringReader);
        }
        catch (ScriptException e)
        {
            e.printStackTrace();
        }
        finally
        {
            stringReader.close();
        }
    }

    /**
      * Spusteni skriptu, ktery je ulozen v externim souboru.
      */
    private void runScriptStoredInFile()
    {
        InputStream inputStream = this.getClass().getResourceAsStream("scripts/test1.js");
        try
        {
            this.scriptEngine.eval(new InputStreamReader(inputStream));
        }
        catch (ScriptException e)
        {
            e.printStackTrace();
        }
        finally
        {
            try
            {
                inputStream.close();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }
        }
    }

    /**
      * Spusteni skriptu tremi ruznymi moznostmi.
      */
    private void runTests()
    {
        this.engineManager = new ScriptEngineManager();
        this.scriptEngine = engineManager.getEngineByName("JavaScript");
        runScriptStoredInString();
        runScriptFromReader();
        runScriptStoredInFile();
    }

    public static void main(String[] args)
    {
        new ScriptingTest3().runTests();
    }

}

Pro správnou funkci aplikace je nutné, aby byl v podadresáři scripts vytvořen soubor nazvaný test1.js, který může obsahovat například následující příkaz:

println('Hello world');

7. Čtvrtý demonstrační příklad: návratové hodnoty skriptů

Skripty naprogramované v JavaScriptu, nebo v některém dalším programovacím jazyku implementovaném skriptovacím enginem, samozřejmě musí umět nějakým způsobem komunikovat s javovským programem, který skript spouští. Nejjednodušším způsobem, jakým je možné tuto komunikaci zajistit, je načtení návratové hodnoty skriptu. Metoda ScriptEngine.e­val() totiž vrací objekt, který vznikl vyhodnocením posledního příkazu skriptu (poněkud odlišná je situace při použití metody Invocable.invo­keFunction() či Invocable.invo­keMethod(), viz další kapitolu). Metoda ScriptEngine.e­val() má sice v deklaraci jako typ návratové hodnoty specifikován Object, ve skutečnosti se však skriptovací engine snaží vytvořit javovský objekt takového typu, který se co nejvíce přibližuje návratovému typu výrazu, což ovšem není vždy úplně jednoduché a ani jednoznačné, protože skriptovací jazyky jsou většinou dynamicky typované a někdy taktéž nerozlišují například mezi celými čísly a čísly reálnými. V následujícím příkladu je ukázáno, jak lze vyhodnotit poslední příkaz skriptu na javovský objekt typu Double, String či dokonce Date. Povšimněte si, jak lze přímo ve skriptu vytvořit nový javovský objekt:

import java.util.Date;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;



/**
 * Demonstracni priklad, v nemz je ukazano, jak muze skript vratit
 * Javovskemu programu navratovou hodnotu a jaky ma tato hodnota typ.
 *
 * @author Pavel Tisnovsky
 */
public class ScriptingTest4
{
    ScriptEngineManager engineManager;
    ScriptEngine scriptEngine;

    public void runSimpleScriptWhichReturnsDouble() throws ScriptException
    {
        final String script =
            "1.5/2;";

        Double result = (Double)this.scriptEngine.eval(script);
        System.out.println("Navratova hodnota skriptu '" + script + "': " + result);
    }

    public void runSimpleScriptWhichReturnsString() throws ScriptException
    {
        final String script =
            "'Hello' + ' ' + 'world'";

        String result = (String)this.scriptEngine.eval(script);
        System.out.println("Navratova hodnota skriptu '" + script + "': " + result);
    }

    public void createJavaObject1() throws ScriptException
    {
        final String script =
            "new java.util.Date()";

        Object result = this.scriptEngine.eval(script);
        System.out.println("Navratova hodnota skriptu '" + script + "': " + result);
    }

    public void createJavaObject2() throws ScriptException
    {
        final String script =
            "new java.util.Date()";

        Date result = (Date)this.scriptEngine.eval(script);
        System.out.println("Navratova hodnota skriptu '" + script + "': " + result);
    }

    /**
      * Spusteni skriptu tremi ruznymi moznostmi.
      */
    private void runTests()
    {
        this.engineManager = new ScriptEngineManager();
        this.scriptEngine = engineManager.getEngineByName("JavaScript");
        try
        {
            runSimpleScriptWhichReturnsDouble();
            runSimpleScriptWhichReturnsString();
            createJavaObject1();
            createJavaObject2();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        new ScriptingTest4().runTests();
    }

}

Příklad výstupu předchozího příkladu:

bitcoin_skoleni

Navratova hodnota skriptu '1/2;': 0.5
Navratova hodnota skriptu ''Hello' + ' ' + 'world'': Hello world
Navratova hodnota skriptu 'new java.util.Date()': Tue Apr 12 21:50:43 CEST 2011
Navratova hodnota skriptu 'new java.util.Date()': Tue Apr 12 21:50:43 CEST 2011

8. Pátý demonstrační příklad: předávání parametrů a volání funkcí

Demonstrační příklad uvedený v předchozí kapitole používal pro komunikaci mezi skriptem a Javovským programem v podstatě velmi primitivní způsob, který je možné použít pouze v těch nejjednodušších případech. V praxi se však většinou setkáme s tím, že je celý skript rozdělen do mnoha funkcí, které by bylo vhodné volat z programů napsaných v Javě, samozřejmě i s tím, že se těmto funkcím předají nějaké parametry a funkce vrátí výsledek. I toho je samozřejmě možné ve standardním „skriptovacím“ API dosáhnout a to poměrně jednoduše, ovšem pouze za předpokladu, že to daný skriptovací jazyk a skriptovací engine umožňuje. V případě použití projektu Rhino (JavaScript) implementuje jeho skriptovací engine rozhraní Invocable, které mj. obsahuje i metodu Invocable.invo­keFunction(). Tato metoda má jeden povinný parametr, kterým je název volané funkce, a potom libovolný počet dalších parametrů, které jsou přímo předány volané funkci (samozřejmě po konverzi mezi datovými typy Javy a daného skriptovacího jazyka). V následujícím demonstračním příkladu je ukázáno, jak lze metodu Invocable.invo­keFunction() použít. Povšimněte si, že skript musí být nejdříve „vyhodnocen“ pomocí eval():

import java.util.Date;

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;



/**
 * Demonstracni priklad, v nemz je ukazano spousteni vybranych funkci,
 * predavani parametru skriptum a ziskavani navratovych hodnot funkci.
 *
 * @author Pavel Tisnovsky
 */
public class ScriptingTest5
{
    ScriptEngineManager engineManager;
    ScriptEngine scriptEngine;
    Invocable invocableEngine;

    private void testInvokeFunction() throws ScriptException, NoSuchMethodException
    {
        final String script =
            "function foo() {\n" +
            "    println('Hello, world!');\n" +
            "}\n";

        this.scriptEngine.eval(script);
        this.invocableEngine.invokeFunction("foo");
    }

    private void testInvokeFunctionWithParameters() throws ScriptException, NoSuchMethodException {
        final String script =
            "function printHello(str1, str2) {\n" +
            "    println(str1 + ' ' + str2);\n" +
            "}\n";

        this.scriptEngine.eval(script);
        this.invocableEngine.invokeFunction("printHello", "hello", "world");
    }

    private void printFunctionResult(String script, Object result)
    {
        System.out.println("Navratova hodnota funkce:\n" + script + "je: " + result);
        System.out.println("Typ navratove hodnoty: " + result.getClass().getName() + "\n");
    }

    private void testInvokeFunctionWhichReturnsNumber() throws Exception
    {
        final String script =
            "function plus(x, y) {\n" +
            "    return x + y;\n" +
            "}\n";

        this.scriptEngine.eval(script);
        Object result = this.invocableEngine.invokeFunction("plus", 1, 2);
        printFunctionResult(script, result);
    }

    private void testInvokeFunctionWhichReturnsString() throws Exception
    {
        final String script =
            "function concatenateWords(str1, str2) {\n" +
            "    return str1 + ' ' + str2;\n" +
            "}\n";

        this.scriptEngine.eval(script);
        Object result = this.invocableEngine.invokeFunction("concatenateWords", "Hello", "world");
        printFunctionResult(script, result);
    }

    private void testInvokeFunctionWhichReturnsDate() throws Exception
    {
        final String script =
            "function calculateDate(epochTime) {\n" +
            "    var date = new java.util.Date(epochTime);\n" +
            "    return date;\n" +
            "}\n";

        this.scriptEngine.eval(script);
        Object result = this.invocableEngine.invokeFunction("calculateDate", 0);
        printFunctionResult(script, result);
        result = this.invocableEngine.invokeFunction("calculateDate", System.currentTimeMillis());
        printFunctionResult(script, result);
    }

    /**
      * Spusteni skriptu tremi ruznymi moznostmi.
      */
    private void runTests()
    {
        this.engineManager = new ScriptEngineManager();
        this.scriptEngine = engineManager.getEngineByName("JavaScript");
        this.invocableEngine = (Invocable)this.scriptEngine;
        try
        {
            testInvokeFunction();
            testInvokeFunctionWithParameters();
            testInvokeFunctionWhichReturnsNumber();
            testInvokeFunctionWhichReturnsString();
            testInvokeFunctionWhichReturnsDate();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        new ScriptingTest5().runTests();
    }

}

Po spuštění výše uvedeného příkladu se vypíše následující text:

Hello, world!
hello world
Navratova hodnota funkce:
function plus(x, y) {
    return x + y;
}
je: 3.0
Typ navratove hodnoty: java.lang.Double *** někdy též java.lang.Integer ***

Navratova hodnota funkce:
function concatenateWords(str1, str2) {
    return str1 + ' ' + str2;
}
je: Hello world
Typ navratove hodnoty: java.lang.String

Navratova hodnota funkce:
function calculateDate(epochTime) {
    var date = new java.util.Date(epochTime);
    return date;
}
je: Thu Jan 01 01:00:00 CET 1970
Typ navratove hodnoty: java.util.Date

Navratova hodnota funkce:
function calculateDate(epochTime) {
    var date = new java.util.Date(epochTime);
    return date;
}
je: Tue Apr 12 22:17:12 CEST 2011
Typ navratove hodnoty: java.util.Date

9. Odkazy na Internetu

  1. JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
    http://www.jcp­.org/en/jsr/de­tail?id=223
  2. Scripting for the Java Platform
    http://java.sun­.com/developer/techni­calArticles/J2SE/Des­ktop/scriptin­g/
  3. Scripting for the Java Platform (Wikipedia)
    http://en.wiki­pedia.org/wiki/Scrip­ting_for_the_Ja­va_Platform
  4. Java Community Process
    http://en.wiki­pedia.org/wiki/Ja­va_Specificati­on_Request
  5. Package javax.script (JavaDoc)
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/package-summary.html
  6. javax.script.Bin­dings
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/Bindings.html
  7. javax.script.Com­pilable
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/Compilable.html
  8. javax.script.In­vocable
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/Invocable.html
  9. javax.script.Scrip­tContext
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/ScriptContex­t.html
  10. javax.script.Scrip­tEngine
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/ScriptEngine­.html
  11. javax.script.Scrip­tEngineFactory
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/ScriptEngine­Factory.html
  12. javax.script.Ab­stractScriptEn­gine
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/AbstractScrip­tEngine.html
  13. javax.script.Com­piledScript
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/CompiledScrip­t.html
  14. javax.script.Scrip­tEngineManager
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/ScriptEngine­Manager.html
  15. javax.script.Sim­pleBindings
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/SimpleBindin­gs.html
  16. javax.script.Sim­pleScriptContext
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/SimpleScrip­tContext.html
  17. javax.script.Scrip­tException
    http://downlo­ad.oracle.com/ja­vase/6/docs/a­pi/javax/scrip­t/ScriptExcep­tion.html
  18. The Java Compatibility Test Tools: JavaTest Harness
    http://java.sun­.com/developer/techni­calArticles/JCPto­ols2/
  19. JavaScript engine (Wikipedia)
    http://en.wiki­pedia.org/wiki/Ja­vaScript_engi­ne
  20. Rhino (JavaScript engine)
    http://en.wiki­pedia.org/wiki/Rhi­no_(JavaScrip­t_engine)
  21. Rhino: JavaScript for Java
    http://www.mo­zilla.org/rhi­no/
  22. Java HotSpot VM Options
    http://www.ora­cle.com/technet­work/java/java­se/tech/vmopti­ons-jsp-140102.html
  23. HugePages
    http://linux-mm.org/HugePages
  24. Tuning big java heap and linux huge pages
    http://www.ti­kalk.com/alm/fo­rums/tuning-big-java-heap-and-linux-huge-pages
  25. How do I set up hugepages in Red Hat Enterprise Linux 4
    http://magazi­ne.redhat.com/2007/05­/29/how-do-i-set-up-hugepages-in-red-hat-enterprise-linux-4/
  26. Java SE Tuning Tip: Large Pages on Windows and Linux
    http://blogs.sun­.com/dagastine/en­try/java_se_tu­ning_tip_large
  27. Translation lookaside buffer
    http://en.wiki­pedia.org/wiki/Tran­slation_looka­side_buffer
  28. Physical Address Extension
    http://en.wiki­pedia.org/wiki/Phy­sical_Address_Ex­tension
  29. Java HotSpot VM Options
    http://www.ora­cle.com/technet­work/java/java­se/tech/vmopti­ons-jsp-140102.html
  30. Amdahl's law
    http://en.wiki­pedia.org/wiki/Am­dahl_law
  31. Garbage collection (computer science)
    http://en.wiki­pedia.org/wiki/Gar­bage_collecti­on_(computer_sci­ence)
  32. Dr. Dobb's | G1: Java's Garbage First Garbage Collector
    http://www.drdob­bs.com/article/prin­tableArticle.jhtml?ar­ticleId=219401061­&dept_url=/ja­va/
  33. Java's garbage-collected heap
    http://www.ja­vaworld.com/ja­vaworld/jw-08–1996/jw-08-gc.html
  34. Compressed oops in the Hotspot JVM
    http://wikis.sun­.com/display/Hot­SpotInternals/Com­pressedOops
  35. 32-bit or 64-bit JVM? How about a Hybrid?
    http://blog.ju­ma.me.uk/2008/10/­14/32-bit-or-64-bit-jvm-how-about-a-hybrid/
  36. Compressed object pointers in Hotspot VM
    http://blogs.sun­.com/nike/entry/com­pressed_objec­t_pointers_in_hot­spot
  37. Java HotSpot™ Virtual Machine Performance Enhancements
    http://downlo­ad.oracle.com/ja­vase/7/docs/techno­tes/guides/vm/per­formance-enhancements-7.html
  38. Using jconsole
    http://downlo­ad.oracle.com/ja­vase/1.5.0/doc­s/guide/manage­ment/jconsole­.html
  39. jconsole – Java Monitoring and Management Console
    http://downlo­ad.oracle.com/ja­vase/1.5.0/doc­s/tooldocs/sha­re/jconsole.html
  40. Great Computer Language Shootout
    http://c2.com/cgi/wi­ki?GreatCompu­terLanguageSho­otout
  41. x86–64
    http://en.wiki­pedia.org/wiki/X86–64
  42. Physical Address Extension
    http://en.wiki­pedia.org/wiki/Phy­sical_Address_Ex­tension
  43. Java performance
    http://en.wiki­pedia.org/wiki/Ja­va_performance
  44. 1.6.0_14 (6u14)
    http://www.ora­cle.com/technet­work/java/java­se/6u14–137039.html?ssSou­rceSiteId=otncn
  45. Update Release Notes
    http://www.ora­cle.com/technet­work/java/java­se/releasenotes-136954.html
  46. Java virtual machine: 4.10 Limitations of the Java Virtual Machine
    http://java.sun­.com/docs/book­s/jvms/second_e­dition/html/Clas­sFile.doc.html#88659
  47. Java™ Platform, Standard Edition 7 Binary Snapshot Releases
    http://dlc.sun­.com.edgesuite­.net/jdk7/bina­ries/index.html
  48. Trying the prototype
    http://mail.o­penjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  49. Better closures (for Java)
    http://blogs.sun­.com/jrose/en­try/better_clo­sures
  50. Lambdas in Java: An In-Depth Analysis
    http://www.in­foq.com/articles/lam­bdas-java-analysis
  51. Class ReflectiveOpe­rationExcepti­on
    http://downlo­ad.java.net/jdk7/doc­s/api/java/lan­g/ReflectiveO­perationExcep­tion.html
  52. Proposal: Indexing access syntax for Lists and Maps
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  53. Proposal: Elvis and Other Null-Safe Operators
    http://mail.o­penjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  54. Java 7 : Oracle pushes a first version of closures
    http://www.bap­tiste-wicht.com/2010/05­/oracle-pushes-a-first-version-of-closures/
  55. Groovy: An agile dynamic language for the Java Platform
    http://groovy­.codehaus.org/O­perators
  56. Better Strategies for Null Handling in Java
    http://www.sli­deshare.net/Step­han.Schmidt/bet­ter-strategies-for-null-handling-in-java
  57. Control Flow in the Java Virtual Machine
    http://www.ar­tima.com/under­thehood/flowP­.html
  58. Java Virtual Machine
    http://en.wiki­pedia.org/wiki/Ja­va_virtual_machi­ne
  59. ==, .equals(), compareTo(), and compare()
    http://leepoin­t.net/notes-java/data/expres­sions/22compa­reobjects.html
  60. New JDK7 features
    http://openjdk­.java.net/pro­jects/jdk7/fe­atures/
  61. Project Coin: Bringing it to a Close(able)
    http://blogs.sun­.com/darcy/en­try/project_co­in_bring_close
  62. ClosableFinder source code
    http://blogs.sun­.com/darcy/re­source/Projec­tCoin/Closeable­Finder.java
  63. Joe Darcy blog about JDK
    http://blogs.sun­.com/darcy
  64. Java 7 – more dynamics
    http://www.bap­tiste-wicht.com/2010/04­/java-7-more-dynamics/
  65. ArrayList (JDK 1.4)
    http://downlo­ad.oracle.com/ja­vase/1.4.2/doc­s/api/java/util/A­rrayList.html

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.