Five tips for Java Scripting API

Source: Internet
Author: User

Currently, many Java developers prefer to use the scripting language on the Java platform, but the dynamic language compiled into the Java bytecode is sometimes not feasible. In some cases, it is faster and more efficient to directly compile a Java application script or call a specific Java object in a script.

This is why javax. script is generated. The Java Scripting API was introduced from Java 6 and fills in the gap between a convenient small Scripting language and a robust Java ecosystem. By using the Java Scripting API, you can quickly integrate almost all script languages in your Java code, which allows you to have more options to solve some small problems.

1. Use jrunscript to execute JavaScript
Every release of the new Java platform will bring a new command line tool set, which is located in the bin directory of JDK. The same is true for Java 6, where jrunscript is a small supplement to the Java platform tool set.

Imagine a simple problem of writing a command line script for performance monitoring. This tool uses jmap (see the previous article in this series) to run a Java Process every five seconds to understand the running status of the process. In general, we will use the command line shell script to do this, but here the server application is deployed on some very different platforms, including Windows? And Linux ?. The system administrator will find it very painful to write shell scripts that can run on both platforms at the same time. The common practice is to write a Windows batch processing file and a UNIX? Shell script, and ensure that these two files are updated synchronously.

However, anyone who has read The Pragmatic Programmer knows that this seriously violates The DRY (Dont Repeat Yourself) principle and produces many defects and problems. What we really want is to write a script that is not related to the operating system, which can run on all platforms.

Of course, the Java language is platform-independent, but it is not necessary to use the "System" language here. What we need is a scripting language, for example, JavaScript.
Listing 1 shows the simple shell script we need:
Listing 1. periodic. js
While (true)
{
Echo ("Hello, world! ");
}
Many Java developers know JavaScript (or ECMAScript; JavaScript is an ECMAScript language developed by Netscape) because they often deal with Web browsers ). The problem is, how does the system administrator execute this script?
Of course, the solution is the JDK's jrunscript utility, as shown in Listing 2:
Listing 2. jrunscript
C: developerWorks5things-scriptingcodejssrc> jrunscript periodic. js
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
Hello, world!
...
Note: You can also use the for loop to execute this script cyclically according to the specified number of times before exiting. Basically, jrunscript allows you to perform all JavaScript operations. The only difference is that its runtime environment is not a browser, so there is no DOM in the runtime. Therefore, the top-level functions and objects are slightly different.

Because Java 6 uses the Rhino ECMAScript engine as part of JDK, jrunscript can execute any ECMAScript code that is passed to it, whether it is a file (as shown in this figure) or in a more interactive REPL ("Read-Evaluate-Print-Loop") shell environment. Run jrunscript to access the REPL shell.

2. Access Java objects from scripts
It is good to be able to write JavaScript/ECMAScript code, but we do not want to be forced to re-compile all the code we use in the Java language-this is against our original intention. Fortunately, all the code using the Java Scripting API engine can fully access the entire Java ecosystem, because essentially all the code is still Java bytecode. Therefore, back to our previous issue, we can use the traditional Runtime.exe c () call on the Java platform to start the process, as shown in listing 3:

Listing 3. Runtime.exe c () starts jmap
Var p = java.lang.runtime.getruntime(cmd.exe c ("jmap", ["-histo", arguments [0])
P. waitFor ()
The array arguments points to the ECMAScript standard built-in reference passed to this function parameter. In the top-level script environment, it is an array of parameters passed to the script itself (command line parameters ). Therefore, in listing 3, this script is expected to receive a parameter that contains the VMID of the Java Process to be mapped.
In addition, we can use jmap itself as a Java class and then directly call its main () method, as shown in Listing 4. With this method, we do not need to "transmit" The in/out/err stream of the Process object.

Listing 4. JMap. main ()
Var args = ["-histo", arguments [0]
Packages. sun. tools. jmap. JMap. main (args)
The Packages syntax is a Rhino ECMAScript identifier that points to a java package created in Rhino that is not included in the core Java. * package.

3. Call scripts from Java code
Only half of the work is completed by calling Java objects through scripts: the Java Script environment also provides the ability to call scripts from Java code. You only need to instantiate a ScriptEngine object and load and evaluate the script, as shown in listing 5:

Listing 5. script calls on the Java platform
Import java. io .*;
Import javax. script .*;
Public class App
{
Public static void main (String [] args)
{
Try
{
ScriptEngine engine =
New ScriptEngineManager (). getEngineByName ("javascript ");
For (String arg: args)
{
FileReader fr = new FileReader (arg );
Engine. eval (fr );
}
}
Catch (IOException ioEx)
{
IoEx. printStackTrace ();
}
Catch (ScriptException scrEx)
{
ScrEx. printStackTrace ();
}
}
}
The eval () method can also directly operate on a String, so this script is not necessarily a file in the file system-it can be from the database, user input, or you can even generate an application based on the environment and user operations.
4. Bind the Java object to the script Space
It is not enough to call only one script: the script usually interacts with the objects created in the Java environment. In this case, some objects must be created and bound to the Java host environment, so that the script can easily find and use these objects. This process is a task of the ScriptContext object, as shown in Listing 6:

Listing 6. bind an object to the script
Import java. io .*;
Import javax. script .*;
Public class App
{
Public static void main (String [] args)
{
Try
{
ScriptEngine engine =
New ScriptEngineManager (). getEngineByName ("javascript ");
For (String arg: args)
{
Bindings bindings = new SimpleBindings ();
Bindings. put ("author", new Person ("Ted", "Neward", 39 ));
Bindings. put ("title", "5 Things You Didnt Know ");
FileReader fr = new FileReader (arg );
Engine. eval (fr, bindings );
}
}
Catch (IOException ioEx)
{
IoEx. printStackTrace ();
}
Catch (ScriptException scrEx)
{
ScrEx. printStackTrace ();
}
}
}
It is easy to access the bound object-the name of the bound object is introduced to the script as a global namespace, so it is easy to use Person in Rhino, as shown in listing 7:

Listing 7. Who wrote this article?
Println ("Hello from inside scripting! ")
Println ("author. firstName =" author. firstName)
As you can see, the attributes of the JavaBeans style are simplified to using names for direct access, as if they are fields.

5. Compile frequently used scripts
The disadvantage of the script language has always existed in performance. The reason is that in most cases, the script language is "instantly" interpreted, so it will lose some parsing and verification text time and CPU cycle during execution. Many scripting languages running on JVM will eventually convert the received code into Java bytecode, at least during the first parsing and verification of the script; when the Java program is disabled, these instantly compiled codes will disappear. Keeping frequently-used scripts in the form of bytecode can help improve performance.

We can use the Java Scripting API in a natural and meaningful way. If the returned ScriptEngine implements the Compilable interface, the method compiled by this interface can be used to compile the script (passed by a String or Reader) into a CompiledScript instance, it can then be used to repeatedly process compiled code using different bindings in the eval () method, as shown in listing 8:

Listing 8. Compiled and interpreted code
Import java. io .*;
Import javax. script .*;
Public class App
{
Public static void main (String [] args)
{
Try
{
ScriptEngine engine =
New ScriptEngineManager (). getEngineByName ("javascript ");
For (String arg: args)
{
Bindings bindings = new SimpleBindings ();
Bindings. put ("author", new Person ("Ted", "Neward", 39 ));
Bindings. put ("title", "5 Things You Didnt Know ");
FileReader fr = new FileReader (arg );
If (engine instanceof Compilable)
{
System. out. println ("Compiling ....");
Compilable compEngine = (Compilable) engine;
CompiledScript cs = compEngine. compile (fr );
Cs. eval (bindings );
}
Else
Engine. eval (fr, bindings );
}
}
Catch (IOException ioEx)
{
IoEx. printStackTrace ();
}

Catch (ScriptException scrEx)
{
ScrEx. printStackTrace ();
}
}
}
In most cases, CompiledScript instances need to be stored in a long storage (for example,

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.