© 2012 IBM Corporation
How to embed your scripting languageJavaOne 2012 - CON3978
Paul Thwaite – Java 8 Quality Assurance EngineerMonday 1 October 2012
2 © 2012 IBM Corporation
Important Disclaimers
THE INFORMATION CONTAINED IN THIS PRESENTATION IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.
WHILST EFFORTS WERE MADE TO VERIFY THE COMPLETENESS AND ACCURACY OF THE INFORMATION CONTAINED IN THIS PRESENTATION, IT IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
ALL PERFORMANCE DATA INCLUDED IN THIS PRESENTATION HAVE BEEN GATHERED IN A CONTROLLED ENVIRONMENT. YOUR OWN TEST RESULTS MAY VARY BASED ON HARDWARE, SOFTWARE OR INFRASTRUCTURE DIFFERENCES.
ALL DATA INCLUDED IN THIS PRESENTATION ARE MEANT TO BE USED ONLY AS A GUIDE.
IN ADDITION, THE INFORMATION CONTAINED IN THIS PRESENTATION IS BASED ON IBM’S CURRENT PRODUCT PLANS AND STRATEGY, WHICH ARE SUBJECT TO CHANGE BY IBM, WITHOUT NOTICE.
IBM AND ITS AFFILIATED COMPANIES SHALL NOT BE RESPONSIBLE FOR ANY DAMAGES ARISING OUT OF THE USE OF, OR OTHERWISE RELATED TO, THIS PRESENTATION OR ANY OTHER DOCUMENTATION.
NOTHING CONTAINED IN THIS PRESENTATION IS INTENDED TO, OR SHALL HAVE THE EFFECT OF:
- CREATING ANY WARRANT OR REPRESENTATION FROM IBM, ITS AFFILIATED COMPANIES OR ITS OR THEIR SUPPLIERS AND/OR LICENSORS
3 © 2012 IBM Corporation
Introduction to the speaker – Paul Thwaite
■ 11 years experience developing and deploying Java SDKs
■ Recent work focus:– Quality Assurance specialist
• Leading cross-continent teams• System Test on IBM SDKs
– Quality assurance lead for Java 8• Focus on testing in OpenJDK• OpenJDK contributor
■ My contact information:– [email protected]– linkedin.com/profile/view?id=26327969
4 © 2012 IBM Corporation
What you will learn from this talk
■ Why me and what I do■ Why we run scripting languages on the JVM■ Methods of embedding■ Models of embedding ■ Comparison of two embedding frameworks■ Which approach is best
5 © 2012 IBM Corporation
Why me and what I do
■ Test IBM's Java SDK– I break Java
■ Focus on system testing in QA– Multi-threaded load testing– Third-party applications
■ Increasing use of scripting languages running on the JVM– We need to ensure they run on the IBM SDK
6 © 2012 IBM Corporation
How many languagesrun on the JVM?
7 © 2012 IBM Corporation
How many languagesrun on the JVM?
>800total
http://en.wikipedia.org/wiki/List_of_JVM_languages
>60active
8 © 2012 IBM Corporation
How many languagesrun on the JVM?
Most popular include
9 © 2012 IBM Corporation
How many languagesrun on the JVM?
Most popular include
JavaScript
10 © 2012 IBM Corporation
How many languagesrun on the JVM?
Why is the JVM so popular?
11 © 2012 IBM Corporation
Why is the JVM so popular?
■ Runtime performance benefits■ Threading and scaling support■ JVM profiling tools■ Access to the impressive array of Java APIs■ Support for multiple languages
The JVM is fast
12 © 2012 IBM Corporation
How many languagesrun on the JVM?
Let's examine a few implementation methods
13 © 2012 IBM Corporation
Implementation Methods
■ Compiled to bytecodes– Jython– Groovy– Scala
14 © 2012 IBM Corporation
Implementation Methods
■ Compiled to bytecodes– Jython– Groovy– Scala
■ Interpreted on the JVM– JavaScript– JRuby
15 © 2012 IBM Corporation
Implementation Methods
■ Compiled to bytecodes– Jython– Groovy– Scala
■ Interpreted on the JVM– JavaScript– JRuby
■ Embedded in a Java application on the JVM– Jython– Groovy– Scala– JavaScript– JRuby
16 © 2012 IBM Corporation
Compiled to bytecodes
MyJythonApp
JythoncCompiler
JVM
MyJythonApp.classMyJythonApp.py
Compiling a Jython script to bytecodes and running it on the JVM
17 © 2012 IBM Corporation
Interpreted on the JVM
JRuby.rbJRuby JavaInterpreter
JVM
Interpreting a JRuby script on the JVM
The JRuby language provides the interpreter in Java
18 © 2012 IBM Corporation
Embedding in a Java application
Ruby.rb
Embedding and running a JRuby script inside a Java application on the JVM
MyJavaApp.class JRubyEmbed Engine
JVM
The language provides the embed engine
19 © 2012 IBM Corporation
Embedding in a Java application – multiple scripts
Embedding and running multiple scripts inside a Java application on the JVM
The language provides the embed engine
Ruby.rb
Ruby.rb
JRuby.rb
JavaScript.js
MyJavaApp.class
JRubyEmbed Engine
JVM
JavascriptEmbed Engine
JRubyEmbed Engine
JavaScriptEmbed Engine
20 © 2012 IBM Corporation
Scripting on the JVM
Models
21 © 2012 IBM Corporation
Scripting on the JVM - Models
Script Java
JVM
Java Script
JVM
Java Script
JVM
22 © 2012 IBM Corporation
Scripting on the JVM – Script domain knowledge
■ Java objects are created and used from inside the script
■ Requires– Scripting language
knowledge to implement Java objects
– Java knowledge
■ Limited re-use capabilities– Not portable code– Locked in to using the
chosen scripting language
Language-specifc
Script Java
JVM
require 'java'frame = javax.swing.JFrame.new("Window") label = javax.swing.JLabel.new("Hello")frame.getContentPane.add(label)frame.setDefaultCloseOperation (javax.swing.JFrame::EXIT_ON_CLOSE)frame.packframe.setVisible(true)
23 © 2012 IBM Corporation
Scripting on the JVM – Java domain knowledge
■ Java runs a script which is embedded within the Java application
■ The APIs used to invoke the script belong to the scripting language
■ Requires– Java knowledge– Language embed API
knowledge– Bridging knowledge
■ Re-use existing scripts– Optional bridge for
legacy scripts– Investment in using
chosen scripting language
Java Script
JVM
Bridge
import org.jruby.embed.*;ScriptingContainer container = new ScriptingContainer();container.runScriptlet(PathType.RELATIVE, "myscripts/ruby.rb");
24 © 2012 IBM Corporation
Scripting on the JVM – Java and script domain knowledge
■ Options– Invoke a script from a
Java application– Create and use Java
objects inside a script
■ Requires– Java knowledge– Knowledge of the JSR
223 API– Some knowledge of the
scripting language may be required
■ Re-use existing scripts– Support for multiple
scripts
Java Script
JVM
import javax.script.*;ScriptEngineManager engineMgr = new ScriptEngineManager();ScriptEngine engine = engineMgr.getEngineByName("jruby");InputStream is = this.getClass().getResourceAsStream("/myscripts/ruby.rb");Reader reader = new InputStreamReader(is);engine.eval(reader);
25 © 2012 IBM Corporation
What is embedding?
26 © 2012 IBM Corporation
Embedding in a Java application – multiple scripts
Embedding and running multiple scripts inside a Java application on the JVM
The language provides the embed engine
Ruby.rb
Ruby.rb
Ruby.rb
JavaScript.js
MyJavaApp.class
JRubyEmbed Engine
JVM
JavascriptEmbed Engine
JRubyEmbed Engine
JavaScriptEmbed Engine
27 © 2012 IBM Corporation
What can you do with an embedded language?
Embedding
Run a script
Call a script's function andretrieve its return valueConfigure script
environment
Pass variables to the script
Run multiple scripts on the
same JVM
Retrieve variables from
the script
28 © 2012 IBM Corporation
Ways to embed a scripting language on the JVM
JSR 223
javax.script
Implementations
Language-specific
Embed
Implementations
● A common API for embedding multiple languages
● Implementation provided by the language
● Some popular languages provide a javax.script API
● Implementation provided by the language
● Similar to JSR223● Extensions available● Ability to fine-tune the scripting
environment● Most popular languages provide
an embed API
29 © 2012 IBM Corporation
Comparison of embedding frameworks
JSR 223
javax.script
Implementations
Language-specific
Embed
Implementationsvs
■ Introduction to javax.script■ Code examples using these languages
– Jruby– Jython– Groovy
■ Exception handling may be missed off some examples to save space
30 © 2012 IBM Corporation
What is javax.script?
■ Allows a developer to embed a scripting language in a Java application ■ Available from Java 6 SE■ Implementation provided by the scripting language■ JSR 223 specification defines 6 interfaces
– ScriptEngine– ScriptEngineFactory– ScriptContext– Bindings– Invocable– Compilable
■ Setup– Download the JSR 223 implementation from your language provider's website– Add the jar(s) to the CLASSPATH– Add your script directory to the CLASSPATH
■ ScriptEngine is discovered at runtime via the JAR services mechanism
JSR 223 Scripting for the Java Platform
31 © 2012 IBM Corporation
Example: Query JAR services for installed JSR223 Java Scripting Engines
import javax.script.*;public class ListScriptEngines {
public static void main(String[] args) {ScriptEngineManager mgr = new ScriptEngineManager();List<ScriptEngineFactory> factories = mgr.getEngineFactories();for (ScriptEngineFactory factory: factories) {
String engName = factory.getEngineName(); String engVersion = factory.getEngineVersion(); System.out.println("Script Engine: " + engName + " V" + engVersion);
} }
}
Output to stdout:Script Engine: Groovy Scripting Engine V2.0Script Engine: jython V2.5.3Script Engine: JSR 223 JRuby Engine V1.6.7.2Script Engine: Mozilla Rhino V1.7 release 3 PRERELEASE
JSR 223
32 © 2012 IBM Corporation
Example: Embedding a Ruby script into a Java application
import javax.script.*;ScriptEngineManager engineMgr = new ScriptEngineManager();ScriptEngine engine = engineMgr.getEngineByName("jruby");InputStream is = this.getClass().getResourceAsStream("/myscripts/ruby.rb");Reader reader = new InputStreamReader(is);engine.eval(reader); //throws ScriptException
Script: /myscripts/ruby.rbstringHello = "Hello, I am a jruby script!"puts "#{stringHello.to_s}"
Output to stdout:Hello, I am a ruby script!"
JSR 223 - JRuby
import org.jruby.embed.*;ScriptingContainer container = new ScriptingContainer();container.runScriptlet(PathType.RELATIVE, "myscripts/ruby.rb");
JRuby Embed API
33 © 2012 IBM Corporation
Example: Passing a variable to a Jython script and retrieving it back again
import javax.script.*;ScriptEngineManager engineMgr = new ScriptEngineManager();ScriptEngine engine = engineMgr.getEngineByName("jython");InputStream is = this.getClass().getResourceAsStream("/myscripts/jython_var.py");Reader reader = new InputStreamReader(is);try {
engine.put("javaString", "red green blue");engine.eval(reader);System.out.println("java> received " + engine.get("javaString"));
} catch (ScriptException e) {}
Script: /myscripts/jython_var.pyprint "jython> received " + javaString javaString += " yellow indigo white"
Output to stdout:jython> received red green bluejava> received red green blue yellow indigo white
JSR 223 - Jython
import org.python.util.PythonInterpreter;PythonInterpreter python = new PythonInterpreter();python.set ( "javaString", new org.python.core.PyString("red green blue"));python.execfile ( "myscripts/jython_var.py" );System.out.println("java> received " + python.get ("javaString"));
Jython Embed API
34 © 2012 IBM Corporation
Example: Invoke a Groovy function with a return value
ScriptEngineManager engineMgr = new ScriptEngineManager();ScriptEngine engine = engineMgr.getEngineByName("groovy");InputStream is = this.getClass().getResourceAsStream("/myscripts/groovy_func.groovy");Reader reader = new InputStreamReader(is);if (engine instanceof Invocable) { //Invocable is an optional interface
Invocable invocableEngine = (Invocable) engine;engine.eval(reader);System.out.println("java> What's the Square root of 360?");double squareRoot = (double) invocableEngine.invokeFunction("squareRoot", 360);System.out.println("java> " + squareRoot);
}
Script: /myscripts/groovy_func.groovydef squareRoot(number) { println "groovy> Sqrt of ${number} is" Math.sqrt(number)}
Output to stdout:java> What's the square root of 360?groovy> Sqrt of 360 isjava> 18.973665961010276
JSR 223 - Groovy
String[] roots = new String[] { "C:\\scripts" };GroovyScriptEngine gse = new GroovyScriptEngine(roots);Class<?> groovyClass = gse.loadScriptByName("groovy_func.groovy");GroovyObject groovyObject = (GroovyObject) groovyClass.newInstance();System.out.println("java> What's the square root of 360?");System.out.println("java> " + groovyObject.invokeMethod("squareRoot", 360).toString());
Groovy Embed API
35 © 2012 IBM Corporation
Example: How to set options in JRuby
// Make JRuby's engine thread safeSystem.setProperty("org.jruby.embed.localcontext.scope", “threadsafe”);
// Turn on JIT verbose loggingSystem.setProperty("jruby.jit.logging.verbose", “true”);
// Set JRuby homeSystem.setProperty("jruby.home", “/path/to/jruby”);
■ JRuby provides many options to the developer to allow for the JRuby ScriptEngine to be customised and finely-tuned
■ In JRuby, these options are set using SystemProperty– Outside the spec of JSR 223– Requires language-specific knowledge
36 © 2012 IBM Corporation
Example: Comparison of setting options in JRuby
■ Jruby's EmbedCore API– Set on a per engine basis– Well documented and easy to find
■ Javax.script API– Set system wide– Multiple engines will all have the same behaviour– Harder to find documentation (not part of an API)
// JRuby EmbedCore API// Make JRuby's engine thread safe// Set via a constructor argument of ScriptingcontainerScriptingContainer instance = new ScriptingContainer(LocalContextScope.THREADSAFE);
// JSR 223 API// Make JRuby's engine thread safeSystem.setProperty("org.jruby.embed.localcontext.scope", “threadsafe”);
37 © 2012 IBM Corporation
Example: Comparison of setting options in Groovy
// Groovy Embed API// Set the compiler warning message levelCompilerConfiguration.setWarningLevel(int warningLevel);
// JSR 223 API// Set the compiler warning message levelNo easy way to do it
38 © 2012 IBM Corporation
How far does javax.script go?
■ Provides useful interaction between Java and many scripting languages– Plug 'n Play support for multiple languages– Great for simple embedding– Easy-to-use API
■ Limitations– The Invocable and Compilable interfaces are optional– Setting language-specific options removes the abstraction JSR 223 provides– Not all engines will provide the same configuration options– Requires knowledge of the underlying ScriptEngine implementation beyond JSR 223
39 © 2012 IBM Corporation
Scripting on the JVM is great
■ Some of the most popular languages support Java embedding■ Embedding a language in a new application is easy to get started■ Deciding how to embed has consequences
–JSR 223 is a great framework for basic embedding
–If you need to harness the power of the language, you will need to use the language API
• For example, JRuby Embed Core
■ How are you embedding your scripting language on the JVM?
40 © 2012 IBM Corporation
References
■ JSR 223– JSR 223 specification
• http://www.jcp.org/en/jsr/detail?id=223
– JRuby implementation• http://kenai.com/projects/jruby/pages/JavaIntegration
– Groovy implementation• http://groovy.codehaus.org/JSR+223+Scripting+with+Groovy
■ Jython Java Integration– http://www.jython.org/jythonbook/en/1.0/JythonAndJavaIntegration.html
■ Scripting in Java: Languages, Frameworks, and Patterns– Dejan Bosanac, Addison-Wesley
41 © 2012 IBM Corporation
References
■ Get Products and Technologies:– IBM Java Runtimes and SDKs:
• https://www.ibm.com/developerworks/java/jdk/– IBM Monitoring and Diagnostic Tools for Java:
• https://www.ibm.com/developerworks/java/jdk/tools/
■ Learn:– IBM Java InfoCenter:
• http://publib.boulder.ibm.com/infocenter/java7sdk/v7r0/index.jsp
■ Discuss:– IBM Java Runtimes and SDKs Forum:
• http://www.ibm.com/developerworks/forums/forum.jspa?forumID=367&start=0
42 © 2012 IBM Corporation
Copyright and Trademarks
© IBM Corporation 2011. All Rights Reserved.
IBM, the IBM logo, and ibm.com are trademarks or registered trademarks of International Business Machines Corp., and registered in many jurisdictions worldwide.
Other product and service names might be trademarks of IBM or other companies.
A current list of IBM trademarks is available on the Web – see the IBM “Copyright and trademark information” page at URL: www.ibm.com/legal/copytrade.shtml