Java 8 Nashorn JavaScript Engine Tutorial | Sinhala Guide

Java 8 Nashorn JavaScript Engine Tutorial | Sinhala Guide

කට්ටියටම ආයුබෝවන්!

අද අපි කතා කරන්න යන්නේ ටිකක් විශේෂ මාතෘකාවක් ගැන. ඒ තමයි Java 8 එක්ක ආපු Nashorn JavaScript Engine එක. "Java Programming Language එකේ JavaScript මොකටද?" කියලා ඔයාලට හිතෙන්න පුළුවන්. ඒත් මේක හරිම ප්‍රයෝජනවත් විශේෂාංගයක්, විශේෂයෙන්ම dynamic scripting අවශ්‍ය වෙන තැන් වලට. අද අපි මේ Nashorn කියන්නේ මොකක්ද, ඒකෙන් මොනවද කරන්න පුළුවන්, සහ ඒක අපේ Java Applications වලට integrate කරගන්නේ කොහොමද කියලා විස්තරාත්මකව බලමු.

මේ ලිපිය කියෙව්වට පස්සේ, ඔයාලට පුළුවන් වෙයි:

  • Nashorn JavaScript Engine එක මොකක්ද කියලා තේරුම් ගන්න.
  • සරල JavaScript Code එකක් Java Application එකක් ඇතුලෙන් execute කරන්න.
  • Java Application එකකින් JavaScript Functions call කරන්න.
  • Java Objects JavaScript Context එකට pass කරලා, JavaScript වලින් ඒවා manipulate කරන්න.

ඉතින්, ලෑස්තිද? අපි පටන් ගමු!

Nashorn JavaScript Engine කියන්නේ මොකක්ද?

සරලව කිව්වොත්, Nashorn කියන්නේ Oracle විසින් Java SE 8 එක්ක හඳුන්වා දුන්නු JavaScript Engine එකක්. මේකේ ප්‍රධාන අරමුණ තමයි Java Virtual Machine (JVM) එක ඇතුළේම JavaScript Code execute කරන්න පුළුවන් වෙන එක. Nashorn, Mozilla SpiderMonkey වගේ කලින් තිබ්බ Engines වලට වඩා ගොඩක් වේගවත් සහ Java 7 වල තිබ්බ Rhino Engine එකේ අනුප්‍රාප්තිකයා (successor) විදිහට තමයි ආවේ.

මේකේ වැදගත්කම මොකක්ද?

  • Scripting Capabilities: Java Applications වලට dynamic scripting capabilities එකතු කරන්න පුළුවන්. ඒ කියන්නේ, අපිට compile නොකර, runtime එකේදී behavior එක වෙනස් කරන්න පුළුවන්.
  • Integration: Java Objects සහ JavaScript Objects අතර seamless integration එකක් තියෙනවා. Java code එකට JavaScript variables, functions access කරන්න පුළුවන් වගේම, JavaScript code එකට Java objects, methods use කරන්නත් පුළුවන්.
  • Performance: Nashorn, JVM එකේ invokedynamic instruction එක භාවිතා කරන නිසා හොඳ performance එකක් දෙනවා.

මීට කලින් Java 6 සහ 7 වල Rhino කියන JavaScript Engine එක තිබ්බා. ඒත් Nashorn එක ආවට පස්සේ Rhino engine එක deprecated (ක්‍රමයෙන් භාවිතයෙන් ඉවත් කිරීම) කරලා, Java 11 වලදී සම්පූර්ණයෙන්ම ඉවත් කළා. ඒ නිසා අපි අද කතා කරන්නේ Nashorn ගැන විතරයි.

Nashorn කොහොමද භාවිතා කරන්නේ? (Getting Started)

Nashorn භාවිතා කරන එක හරිම සරලයි. අපිට javax.script package එකේ තියෙන API ටිකක් පාවිච්චි කරන්න වෙනවා. මේක Java 8 වලට default install වෙලා තියෙන්නේ, ඒ නිසා වෙනම dependencies add කරන්න අවශ්‍ය වෙන්නේ නෑ.

ප්‍රධාන Class දෙකක් ගැන අපි දැනගෙන ඉන්න ඕන:

  1. ScriptEngineManager: මේකෙන් තමයි අපිට අවශ්‍ය ScriptEngine එක හොයාගන්නේ.
  2. ScriptEngine: මේකෙන් තමයි JavaScript code execute කරන්නේ.

අපි සරල "Hello, Nashorn!" JavaScript code එකක් Java Application එකක් ඇතුලෙන් execute කරලා බලමු.

උදාහරණය 1: සරල JavaScript Code එකක් ධාවනය කිරීම

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

public class SimpleNashornExample {
    public static void main(String[] args) {
        // ScriptEngineManager එකක් create කරගන්නවා
        ScriptEngineManager factory = new ScriptEngineManager();
        
        // "nashorn" engine එක හොයාගන්නවා
        ScriptEngine engine = factory.getEngineByName("nashorn");
        
        if (engine != null) {
            try {
                // සරල JavaScript code එකක් execute කරනවා
                engine.eval("print('Hello from Nashorn JavaScript Engine!');");
            } catch (ScriptException e) {
                System.err.println("Error executing script: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.err.println("Nashorn ScriptEngine not found. Make sure you are using Java 8.");
        }
    }
}

මේ Code එක run කරාම output එක විදිහට Hello from Nashorn JavaScript Engine! කියලා print වෙයි. print() කියන්නේ Nashorn එකේ තියෙන build-in function එකක්, ඒක Java එකේ System.out.println() එකට සමානයි.

පිටතින් JavaScript File එකක් Load කිරීම

බොහෝ වෙලාවට අපිට JavaScript code එක වෙනම .js file එකක තියාගෙන load කරගන්න සිද්ධ වෙනවා. අපි ඒකත් කරලා බලමු.

මුලින්ම අපි script.js කියලා file එකක් හදාගමු:

// script.js
var greeting = "ආයුබෝවන් Nashorn ලෝකයට!";
print(greeting);

function multiply(a, b) {
    return a * b;
}

දැන් මේ script.js file එක Java වලින් load කරලා execute කරමු:

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileReader;
import java.io.IOException;

public class LoadJavaScriptFileExample {
    public static void main(String[] args) {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("nashorn");

        if (engine != null) {
            try (FileReader reader = new FileReader("script.js")) {
                // script.js file එක load කරලා execute කරනවා
                engine.eval(reader);
            } catch (ScriptException e) {
                System.err.println("Error executing script: " + e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
                System.err.println("Error reading script file: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.err.println("Nashorn ScriptEngine not found. Make sure you are using Java 8.");
        }
    }
}

මේ Code එක run කරාම, script.js file එකේ තියෙන code එක execute වෙලා ආයුබෝවන් Nashorn ලෝකයට! කියලා print වෙයි.

Java වලින් JavaScript Functions Call කරන හැටි

දැන් අපි බලමු Java code එකකින් JavaScript file එකක තියෙන function එකක් call කරන්නේ කොහොමද කියලා. මේකට අපිට Invocable interface එක පාවිච්චි කරන්න පුළුවන්.

අපේ කලින් script.js file එකේ multiply(a, b) කියලා function එකක් තිබුණා මතකද? අපි ඒක Java වලින් call කරලා බලමු.

import javax.script.Invocable;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.FileReader;
import java.io.IOException;

public class CallJsFunctionFromJava {
    public static void main(String[] args) {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("nashorn");

        if (engine != null) {
            try (FileReader reader = new FileReader("script.js")) {
                // script.js file එක load කරලා execute කරනවා
                engine.eval(reader);

                // ScriptEngine එක Invocable එකකට cast කරනවා
                Invocable invocable = (Invocable) engine;

                // JavaScript function එක call කරනවා
                Object result = invocable.invokeFunction("multiply", 5, 10); // multiply(5, 10) call කරනවා
                
                System.out.println("Result of multiply(5, 10) from JavaScript: " + result); // Output: 50.0
                System.out.println("Result type: " + result.getClass().getName()); // Output: java.lang.Double
                
            } catch (ScriptException e) {
                System.err.println("Error executing script: " + e.getMessage());
                e.printStackTrace();
            } catch (IOException e) {
                System.err.println("Error reading script file: " + e.getMessage());
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                System.err.println("JavaScript function not found: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.err.println("Nashorn ScriptEngine not found. Make sure you are using Java 8.");
        }
    }
}

මේ code එක run කරාම, JavaScript එකේ multiply function එක 5 සහ 10 කියන values දෙකත් එක්ක call වෙලා, ප්‍රතිඵලය Java Double එකක් විදිහට අපිට ලැබෙනවා. System.out.println එකෙන් බලද්දී 50.0 කියලා print වෙයි.

Java Objects JavaScript එකට යවන හැටි (Binding Java Objects)

Nashorn වල තියෙන තවත් නියම විශේෂාංගයක් තමයි අපේ Java Objects, JavaScript context එකට bind කරන්න පුළුවන් වීම. ඒ කියන්නේ JavaScript code එක ඇතුලෙන් අපිට Java objects manipulate කරන්න පුළුවන්. මේකෙන් අපේ applications වලට අලුත් දොරටු ගොඩක් විවර වෙනවා.

මේකට අපි Bindings සහ ScriptContext භාවිතා කරනවා. අපි සරල Java class එකක් හදාගෙන ඒක JavaScript context එකට යවලා බලමු.

උදාහරණය 3: Java Object එකක් JavaScript Context එකට යැවීම

මුලින්ම, අපි User.java කියලා සරල Java class එකක් හදාගමු:

// User.java
public class User {
    private String name;
    private int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getInfo() {
        return "Name: " + name + ", Age: " + age;
    }
}

දැන් මේ User object එක JavaScript context එකට යවලා, JavaScript වලින් ඒක access කරලා බලමු.

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

public class PassJavaObjectToJs {
    public static void main(String[] args) {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("nashorn");

        if (engine != null) {
            try {
                // User object එකක් create කරනවා
                User javaUser = new User("Kamal", 30);

                // Java object එක JavaScript context එකට bind කරනවා
                Bindings bindings = engine.getBindings(ScriptContext.ENGINE_SCOPE);
                bindings.put("currentUser", javaUser); // "currentUser" කියන නමින් JavaScript එකට යවනවා

                // JavaScript code එක execute කරනවා
                engine.eval("print('Hello from JavaScript! User name: ' + currentUser.getName());");
                engine.eval("print('User age: ' + currentUser.getAge());");
                engine.eval("print('User info: ' + currentUser.getInfo());");
                
                // JavaScript එකෙන් object එක modify කරලා බලමු
                engine.eval("currentUser.setAge(31);");
                engine.eval("print('Updated user age: ' + currentUser.getAge());");

                // Java side එකෙන් updated value එක බලමු
                System.out.println("Age from Java after JS modification: " + javaUser.getAge()); // Output: 31

            } catch (ScriptException e) {
                System.err.println("Error executing script: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.err.println("Nashorn ScriptEngine not found. Make sure you are using Java 8.");
        }
    }
}

මේ Code එක run කරාම, JavaScript එකට javaUser object එක currentUser කියලා variable එකක් විදිහට ලැබෙනවා. ඒක ඇතුලෙන් අපිට Java object එකේ methods (getName(), getAge(), setAge(), getInfo()) call කරන්න පුළුවන්. තව, JavaScript එකෙන් setAge() call කරලා වයස update කරපු ගමන්, Java side එකේ තියෙන javaUser object එකෙත් ඒ වෙනස update වෙනවා. මේක තමයි Nashorn වල තියෙන සුපිරිම integration එක!

JavaScript වලින් Java Objects පාවිච්චි කරන හැටි

අපිට Java Objects JavaScript Context එකට pass කරනවා වගේම, JavaScript code එක ඇතුලෙන් කෙලින්ම Java Classes සහ Objects create කරන්නත් පුළුවන්. මේකෙන් ලැබෙන බලය සුළුපටු නෑ!

උදාහරණය 4: JavaScript එකෙන් Java Classes භාවිතා කිරීම

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

public class UseJavaObjectsInJs {
    public static void main(String[] args) {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("nashorn");

        if (engine != null) {
            try {
                // JavaScript එකෙන් Java String Class එක භාවිතා කිරීම
                engine.eval("var myString = new java.lang.String('Hello from JS to Java String!');");
                engine.eval("print(myString);");
                engine.eval("print('Length of string: ' + myString.length());");

                // Java List එකක් JavaScript එකෙන් create කරලා පාවිච්චි කිරීම
                engine.eval("var myList = new java.util.ArrayList();");
                engine.eval("myList.add('Apple');");
                engine.eval("myList.add('Banana');");
                engine.eval("myList.add('Cherry');");
                engine.eval("print('My List: ' + myList);");
                engine.eval("print('List size: ' + myList.size());");

                // System class එක පාවිච්චි කිරීම
                engine.eval("java.lang.System.out.println('This is printed directly from JavaScript using Java System.out.println!');");

            } catch (ScriptException e) {
                System.err.println("Error executing script: " + e.getMessage());
                e.printStackTrace();
            }
        } else {
            System.err.println("Nashorn ScriptEngine not found. Make sure you are using Java 8.");
        }
    }
}

මේ උදාහරණයේදී, new java.lang.String(), new java.util.ArrayList() වගේ දේවල් වලින් පෙන්නුම් කරන්නේ JavaScript එක ඇතුළතදී Java Classes instantiate කරලා ඒවායේ methods call කරන්න පුළුවන් බවයි. ඒ වගේම java.lang.System.out.println වගේ static methods call කරන්නත් පුළුවන්.

අවවාදයයි (A Word of Caution)

Nashorn හරහා JavaScript එකට Java Objects access කරන්න දෙන එක හරිම බලවත් විශේෂාංගයක් වුණත්, ඒක ප්‍රවේශමෙන් භාවිතා කරන්න ඕන. JavaScript code එකක් බාහිරින් (උදාහරණයක් විදිහට user input එකක් විදිහට) එනවා නම්, ඒකේ ආරක්ෂාව (security) ගැන හොඳට හිතන්න ඕන. මොකද, ද්වේෂසහගත JavaScript code එකකට (malicious JavaScript code) අපේ Java application එකේ security sandbox එකෙන් එළියට ගිහින් system operations කරන්න පුළුවන් වෙන්න පුළුවන් (උදා: file system access, network calls).

ඒ නිසා, විශ්වාසදායී නොවන JavaScript sources වලින් code execute කරනවා නම්, sandboxing techniques, class filters වගේ දේවල් භාවිතා කරන්න අමතක කරන්න එපා. Java 9 සහ 11 න් පස්සේ Nashorn අයින් වුණත්, මේ සංකල්පය වෙනත් scripting engines (GraalVM's JavaScript engine වගේ) වලටත් අදාළයි.

නිගමනය

ඉතින් යාලුවනේ, අද අපි Nashorn JavaScript Engine එක ගැන සම්පූර්ණ අවබෝධයක් ලබාගත්තා. Java 8 වලට මේක add කළේ ඇයි, ඒකෙන් අපිට ලැබෙන වාසි මොනවද, සහ practical විදිහට අපේ Java Applications වලට JavaScript code integrate කරන්නේ කොහොමද කියලා අපි ඉගෙන ගත්තා.

Nashorn, Java 8 වල තිබ්බ වැදගත් විශේෂාංගයක් වුණත්, Java 11 වලින් පස්සේ ඒක ඉවත් කළා. ඒ වෙනුවට GraalVM's JavaScript engine (GraalJS) වගේ වඩා දියුණු options දැන් තියෙනවා. ඒත් Nashorn වලින් ලබාදුන්නු Java-JavaScript integration concept එක සහ javax.script API එක අදටත් වැදගත්, මොකද ඒ API එක බොහෝ scripting engines වලට පොදුයි.

දැන් ඔයාලට මේ දැනුමෙන් ප්‍රයෝජන අරගෙන ඔයාලගේම Java Projects වලට dynamic scripting capabilities එකතු කරන්න පුළුවන්. මේකෙන් අපේ Applications වල flexibility එක වැඩි වෙනවා වගේම, ඇතැම් use cases වලට development time එකත් අඩු කරගන්න පුළුවන්.

මේ ලිපිය ගැන ඔයාලගේ අදහස්, ප්‍රශ්න පහලින් comment කරන්න. තව මොන වගේ topics ගැනද ඔයාලට දැනගන්න ඕන කියලා කියන්න. එහෙනම්, තවත් අලුත් දෙයක් එක්ක ඉක්මනින්ම හම්බවෙමු! ජය වේවා!