Upload
others
View
19
Download
0
Embed Size (px)
Citation preview
Patterns for Integrating Java™ and JavaScript™ Technology: Tales from the Front Lines
David P. CaldwellPresident, David P. Caldwell, Inc. (Cleveland, OH)Committer, Mozilla Rhino
TS-6606
2008 JavaOneSM Conference | java.sun.com/javaone | 2
Today, you'll learn some approaches for:
Providing dynamic behavior for your application's end users without a Java development environment
Using the power of a loosely typed, dynamic language to reduce code size
Choosing the right pattern for integrating Java code and dynamic language code on your project
2008 JavaOneSM Conference | java.sun.com/javaone | 3
Agenda
Approaches: Using scripting languages on the JVM™ interfaceIntroduction to the JavaScript language and the Mozilla Rhino projectThe JavaScript language can do more than you may thinkUsing Rhino• The Rhino shell• Embedding Rhino in your application
Four Design Patterns for a Hybrid Application• Script as main()• JavaScript Objects with Java Peers• Script Implements Java Type• Explicit Script Invocation
2008 JavaOneSM Conference | java.sun.com/javaone | 5
Scripting Java: Approaches
JSR 223• Included as part of Java SE Development Kit (JDK), starting with Java SE
6 release (jrunscript)
• Sun-customized version of Mozilla Rhino bundled with SDK• Based on earlier release (1.6R2, current is 1.7R1)• Some features removed, minor modifications for compatibility• Adds JSR 223-compliant bindings to Rhino
• JSR 223-compliant applications can use your scripting language! (Did you attend TS-5693?)
• Pro: Allows Java application environment to be unaware of particular scripting languages being used (much like Apache BSF)
• Con: Either must develop to lowest-common-denominator scripting language or do lots of interrogation of installed script engine's capabilities
• Best use cases: very general-purpose engines (e.g., Project Phobos, Ant – uses Apache BSF)
2008 JavaOneSM Conference | java.sun.com/javaone | 6
Scripting on the Java Platform: Approaches
Custom Scripting Implementation• Several developers have implemented scripting languages on top of
the Java runtime environment• Biggest mindshare (my imperfect opinion), in no particular order
• JRuby• Jython• Scala• Groovy• JavaFX™ software• Mozilla Rhino (JavaScript language)
• Pro: Embedding APIs for each language are specific to that language• Con: Java application cannot support arbitrary choice of language• Best use case: Anything besides very general-purpose engine
2008 JavaOneSM Conference | java.sun.com/javaone | 7
Using JavaScript Technology on the JVM PlatformA Whirlwind Tour of the Glossary
About the JavaScript language• Not the Java language!• General-purpose scripting language
developed by Brendan Eich (Netscape, now Mozilla)
• Multiple definitions• “ECMAScript”: ECMA-262• “JavaScript”: Firefox/Gecko
• Scripting environment provides “host objects”
• Allow script objects to do useful things
• Most of you know about web browsers; host objects you may know:
• document• window• XMLHttpRequest
About Mozilla Rhino• Implements JavaScript language on
the Java platform• Original author: Norris Boyd
(Netscape, now Google)• Tends to track “JavaScript”
k(Firefox/Gecko)• Adds E4X (XML as primitive type,
ECMA-357)• Can compile JavaScript code to Java
class files or run as interpreter• Provides Java host objects
• Packages: provides access to entire Java API in classpath
• Embedder can provide arbitrary host objects to scripts
• Does not provide implementations of browser host objects (see HtmlUnit)
2008 JavaOneSM Conference | java.sun.com/javaone | 8
Things You May Not Know About the JavaScript Language
You can define your own class-like entities (using constructors).• Can do some things that traditional OO classes cannot• Can have private variables; in the JavaScript language (not ECMAScript),
properties can have getters/setters• Many JavaScript libraries/frameworks provide a way to emulate class
behavior (e.g., the open source Prototype library)• Native classes proposed for JavaScript version 2.0
First-Class Functions• Methods are just properties of type “function”• A function's this parameter can be specified at invocation time
• Therefore, JavaScript programmers can use aspect-oriented programming techniques
Full exploration of JavaScript technology is beyond our scope. See “For More Information” (later)
2008 JavaOneSM Conference | java.sun.com/javaone | 9
An Illustration: Creating a Constructor
var Person = function(data) { // constructor function var ssn = data.ssn; // creates private variable this.name = data.name; this.getAddress = function() { return data.address; } // add getter method this.__defineGetter__(“address”, function() { return data.address; }); // makes address available as read-only property if (typeof(data.salary) != “undefined”) { // can return different type return new Employee(data); }}
2008 JavaOneSM Conference | java.sun.com/javaone | 10
An Illustration – Hate Typing? (JavaScript code reduces repetition)
var getter = function(value) { return function() { return value; }}var Person = function(data) { // constructor function var ssn = data.ssn; // creates private variable this.name = data.name; this.getAddress = getter(data.address); this.__defineGetter__(“address”, getter(data.address)); if (typeof(data.salary) != “undefined”) { // can return different type return new Employee(data); }}
2008 JavaOneSM Conference | java.sun.com/javaone | 11
An Illustration – Using a constructor
var me = new Person({ name: { last: “Caldwell”, first: “David” }, address: { /* omitted */ }, phone: {/* ... */} }/* Caller can modify “class,” now all objects constructed by Person will have getFullName() method. */Person.prototype.getFullName = function() { return this.name.last + “, ” + this.name.first;}var full = me.getFullName(); // “Caldwell, David”
2008 JavaOneSM Conference | java.sun.com/javaone | 12
An Illustration (AOP) – A one-slide profiler
var profile = function(obj) { var rv = {}; for (var x in obj) { if (typeof(obj[x]) == “function”) { rv[x] = function() { var start = new Date().getTime(); var result = obj[x].apply(obj,arguments); var end = new Date().getTime(); print(“Executing ” + x + “ took ”
+ ((end – start) / 1000).toFixed(3)+ “ seconds”); // assume host defines print
return result; } } else rv[x] = obj[x]; } return rv;}someSlowObject = profile(someSlowObject);
2008 JavaOneSM Conference | java.sun.com/javaone | 13
Using Rhino on the JVM Implementation – the shell
Rhino comes with a rudimentary command shell which allows the interactive execution of JavaScript code within a JVM implementation.Many people start with using Rhino to do “exploratory programming” -- the ability to execute arbitrary Java code without having to “do a build.” (Python's shell is similar.)The Rhino command shell is packaged as an executable JAR file (though if you want to use your own code, you'll have to invoke the shell using a classpath).Here's what that looks like ...
2008 JavaOneSM Conference | java.sun.com/javaone | 14
The Rhino shell – example session
$ java -jar js.jarRhino 1.7 release 1 2008 03 06js> var now = new java.util.Date()js> var slidesDue = java.util.Calendar.getInstance()js> slidesDue.set(2008,3,14) // March 14? Why so early?js> slidesDue.getTime()Mon Apr 14 18:53:54 EDT 2008js> slidesDue.set(2008,2,14) // What were they thinking with the date stuff, anyway?js> slidesDue.set(2008,2,14,23,59) // let's be done by 11:59 PM; I do have a day jobjs> ((slidesDue.getTime().getTime() - now.getTime()) / 1000 / 60 / 60).toFixed(1) + " hours to go" // mix Java and JS APIs29.1 hours to gojs> print("Better get cracking!") // shell defines print()Better get cracking!
2008 JavaOneSM Conference | java.sun.com/javaone | 15
Beyond Exploratory ProgrammingRhino in Your Application
The shell is a relatively simple embedding which allows running JavaScript code interactivelyIt does have limited scripting capability for one-off tasksIf you want to include Rhino in your application, you'll need to develop your own embeddingWe'll show a code example of how this is done but the mechanics are beyond our scope here – we want to get to the big-picture choices about how to structure your hybrid Java/JavaScript application!
2008 JavaOneSM Conference | java.sun.com/javaone | 16
Beyond Exploratory ProgrammingEmbedding Rhino: What It Might Look Like
private static class MyContextFactory extends ContextFactory { /* code to customize */ }public void runScript(MyImportantResource foo, Reader script) { MyContextFactory rhino = new MyContextFactory(); Context context = rhino.enterContext(); // Create objects like String, Array, etc. ScriptableObject scope = context.initStandardObjects(); // Give scripts access to foo; they will be able to // refer to it as “bar” and will not be able to replace // or remove it scope.defineProperty(“bar”, foo, READONLY | PERMANENT); // last 3 arguments not important for now context.evaluateReader(scope, script, ...);}
2008 JavaOneSM Conference | java.sun.com/javaone | 17
Mixing Java and JavaScript TechnologiesDiscussing Patterns for Integration
We will look at four approaches for integrating JavaScript and Java technologiesThese approaches are not mutually exclusiveThese patterns are applicable to other dynamic languages with similar capabilitiesWe will explore them in order from most JavaScript code to least JavaScript code• JavaScript with Java as necessary• JavaScript with parts in Java• Java with parts in JavaScript • Java with JavaScript as desired
2008 JavaOneSM Conference | java.sun.com/javaone | 18
Integration Pattern: Script as main()
Write your program in the JavaScript languageUse the (sprawling, high-quality) Java API as neededRequires use of the Rhino shell or another shell-like embedding
2008 JavaOneSM Conference | java.sun.com/javaone | 19
Integration Example: Script as main()Find all HTML pages with title matching pattern
var readXmlFile = function(file) { var reader = new java.io.FileReader(file); var writer = new java.io.StringWriter(); var c; while((c = reader.read()) != -1) { writer.write(c); } return XML(writer.toString()) // E4X}Array.fromJava = /* omitted, maybe build into shell */var directory = new java.io.File(arguments[1]);var pattern = new RegExp(arguments[2]);var files = Array.fromJava(directory.listFiles());files.forEach(function(file) { if(pattern.test(readXmlFile(file).head.title)) {
print(file); }});
2008 JavaOneSM Conference | java.sun.com/javaone | 20
Evaluation: Script as main()Strengths and Weaknesses
Pros• Can whip up short JavaScript
application much faster than short Java application
• Can achieve big code size reduction, developer productivity gains
• Leverage Java libraries (Java runtime environment or user-supplied)
• Matches some APIs very well (e.g., Servlet API, with host objects representing request, etc.; see Project Phobos)
Cons• Need to supply a more feature-rich
shell; Rhino shell is rudimentary• Development team needs expertise
on JavaScript language plus understanding of shell environment
• No debugging without building Rhino debugger into your shell (which is possible but not painless)
• Concurrency management is difficult
• Some operations are much slower (but they can be rewritten in Java language as necessary)
2008 JavaOneSM Conference | java.sun.com/javaone | 21
Integration Pattern: JavaScript Objects with Java Peers
Main logic continues to be in JavaScript languageCreate JavaScript objects that provide a layer over the Java API• Automatic: JavaScript objects begin with same API as Java peers, but
modifiable• Custom: Create your own wrapper which creates a private Java
technology-based peer
Your code now accesses these objects rather than calling the Java API directly
2008 JavaOneSM Conference | java.sun.com/javaone | 22
Integration Example: JavaScript Objects with Java PeersSome Plumbing Code (Automatic Peers)
var peerConstructor = function(type) { // Omitted: handling of static members of class return function() { var peer = new type(); for (var x in peer) { if (typeof(x) == “function”) { this[x] = function() { return peer[x].apply(peer,arguments); } } } }}
2008 JavaOneSM Conference | java.sun.com/javaone | 23
Integration Example: JavaScript Objects with Java PeersCreate an Enhanced ArrayList
var ArrayList = peerConstructor(java.util.ArrayList);// Add method to ArrayList instancesArrayList.prototype.toHtmlRow = function() { var tr = <tr/>; // More E4X for (var i=0; i<this.size(); i++) { tr.appendChild(<td>{ this.get(i) }</td>); } return tr;}// Add something that looks a little like a static methodArrayList.create = function() { var rv = new ArrayList(); for (var i=0; i<arguments.length; i++) { rv.add(rv.size(), arguments[i]) } return rv;}
2008 JavaOneSM Conference | java.sun.com/javaone | 24
Integration Example: JavaScript Objects with Java PeersUsing Our Enhanced ArrayList
var header = ArrayList.create("Tool", "Quality");var netbeans = ArrayList.create("NetBeans", "Great");var eclipse = ArrayList.create("Eclipse", "Passable");var vi = ArrayList.create("Vi", "Good");var table = <table> { header.toHtmlRow() } { netbeans.toHtmlRow() } { eclipse.toHtmlRow() } { vi.toHtmlRow() }</table>;print(table.toXMLString()); // More E4X
2008 JavaOneSM Conference | java.sun.com/javaone | 25
Integration Example: JavaScript Objects with Java PeersUsing Our Enhanced ArrayList: Output
<table> <tr> <td>Tool</td> <td>Quality</td> </tr> <tr> <td>NetBeans</td> <td>Great</td> </tr> <tr> <td>Eclipse</td> <td>Passable</td> </tr> <tr> <td>Vi</td> <td>Good</td> </tr></table>
2008 JavaOneSM Conference | java.sun.com/javaone | 26
Integration Pattern: JavaScript Objects with Java PeersDiscussion: Offending Our Java Sensibilities
Should the ArrayList class have a toHtmlRow() method?• It is not very general• If we continue down this path, ArrayList is going to have thousands
of methods• toCommaDelimitedList()• getAverage()• getStandardDeviation()• getMedian()• getMode()• hasSameContentsAs(ArrayList other)• getNumberOfNullElements()• getFirstPrimeNumber()• getArrayContainingLastTokenOfEachElement()
2008 JavaOneSM Conference | java.sun.com/javaone | 27
Integration Pattern: JavaScript Objects with Java PeersJavaScript and Java languages demand different approaches
Java culture• One namespace to rule them all
(com.yourcompany)• Priority: class reuse; never develop
same class twice• Do not trust users of your class
(private variables, etc.); people cannot add methods
• Workaround: wrappers (MyArrayList extends ArrayList)
• Philosophy: Don't let people do dangerous things
• Imposes lots of overhead• getters and setters• other boilerplate code• one consequence: annotations
Culture of JavaScript and other dynamic languages• Namespaces very ad-hoc; can load
any script into any scope• Can assign new properties and
methods to objects (and remove them)
• If someone wants to add a property to Object, let them; only alters Object for this context
• Reuse and encapsulation at more granular level• Reuse: function• Encapsulation: scope
• Programmers are smart, give them power – this is why xkcd is flying!
• But it's a long way down• Team coordination issues
2008 JavaOneSM Conference | java.sun.com/javaone | 28
Evaluation: JavaScript Objects with Java PeersStrengths and Weaknesses
Pros• Many programmers are used to
Java API, and Java objects' scripting peers start with that same API
• You can do things you've always wanted to do, like remove methods from an object
• However, if your callers don't expect it, this can be a “con”
• Reduced impedance mismatch• Customized JavaScript wrappers can
make the resulting object look more like a native JavaScript object while using the power of Java platform underneath
Cons• Need plumbing code to construct
the automatic peers, or some boilerplate code for custom peers
• Works poorly if the Java API you are wrapping closely does not closely match the problem
• Custom peer API gives people using the objects a new API to learn (and an extra API for you to document)
2008 JavaOneSM Conference | java.sun.com/javaone | 29
Integration Pattern: Script Implements Java Type
Write your program mostly in Java programming languageIdentify classes that you might like to implement using scripting code, and make them abstract (or interfaces)Create an embedding that loads your JavaScript code and creates a Java object that delegates to the JavaScript object
2008 JavaOneSM Conference | java.sun.com/javaone | 30
Integration Example: Script Implements Java TypeThe Java Language Side
/** * These rules are updated very dynamically based on * fast-moving market criteria; we can't do a new build * of the application every time */public abstract class PricingModel { public abstract CreditCard getCreditCardToOffer(Customer c); public abstract Mortgage getMortgageToOffer(Customer c, House h); public abstract boolean onComplainWaiveLateFees(Customer c);}
2008 JavaOneSM Conference | java.sun.com/javaone | 31
Integration Example: Script Implements Java TypeThe JavaScript Language Side
var rate = function(customer) { // insert your complex scoring criteria}// change these thresholds when you wantrate.HIGH = 700;rate.MEDIUM = 600;var getCreditCardToOffer = function(customer) { if (rate(customer) > rate.HIGH) return Card.TITANIUM; if (rate(customer) > rate.MEDIUM) return Card.PLATINUM; return Card.GOLD;}var getMortgageToOffer = function(customer,house) { var rating = rate(customer); // ...}
2008 JavaOneSM Conference | java.sun.com/javaone | 32
Evaluation: Script Implements Java TypeStrengths and Weaknesses
Pros• Basic software is in the Java
language• Team familiarity• Enterprise considerations
• Individual scripts are isolated from one another and do not interact directly (also a “con”).
• Can modify Java application without rebuilding it
• Basically a version of the Dependency Injection pattern
• Can use scripting code in layers that would otherwise be boilerplate (cf. annotations)
• Great for prototyping (scripting now, Java code later)
• Can use different scripting languages for different objects
Cons• Overall code reduction is smaller,
so extra complexity of multilanguage application harder to justify
• Embedding is more involved• Must use Rhino object called JavaAdapter• Embedding also needs to supply
some boilerplate code to instantiate Java object
• Obviously even more involved if you use multiple languages
• Requires ability to modify compiled code in order to refactor
2008 JavaOneSM Conference | java.sun.com/javaone | 33
Integration Pattern: Explicit Script Invocation
Program is mostly Java codeExplicitly specify areas where the program's operation can be customizedProvide JavaScript API for dynamic behavior desired
2008 JavaOneSM Conference | java.sun.com/javaone | 34
Integration Example: Explicit Script InvocationThe Script Side
// Skinning API for my GUI application// “window” will be passed as argument to this function// Modify the “width” and “height” properties to specify// the window size// An object called “screen” is provided in the global// scope which has width and height propertiesfunction skin(window) { window.width = 1024; window.height = 768; }function getSettingsDirectory() { return java.lang.System.getProperty(“user.home”) + “/.myGuiApplication”;}
2008 JavaOneSM Conference | java.sun.com/javaone | 35
Evaluation: Explicit Script InvocationStrengths and Weaknesses
Pros• What scripts can and cannot do is
very clearly defined. Rhino can even make some classes inaccessible to scripts if you don't trust them.
• Makes it as easy as possible to write the JavaScript scripts themselves.
• Ideal for applications that wish to provide end-user customizability within a limited range
Cons• Developing one-off embeddings for
each customizable point is more work
• The only parts of the application that can be customized are those you envisioned in advance
• The only pieces of information available to the customizing scripts are those you thought the scripts might need
2008 JavaOneSM Conference | java.sun.com/javaone | 36
Summary
The JavaScript language is a serious programming language that is useful outside the browserIt is easier than you might think to build a hybrid Java/JavaScript applicationThere are several design patterns you might use in various situations• They are not mutually exclusive; they can be combined• Today we discussed them in order, starting from the most JavaScript
code to the least• Exploratory Programming• Integration Pattern: Script as main()• Integration Pattern: JavaScript Objects with Java Peers• Integration Pattern: Script Implements Java Type• Integration Pattern: Explicit Script Invocation
2008 JavaOneSM Conference | java.sun.com/javaone | 37
Other Resources
JSR 223• https://scripting.dev.java.net/
• download many JSR 223-compliant engines
• http://www.robert-tolksdorf.de/vmlanguages.html • venerable but well-maintained page listing many alternative JVM
programming languages (not just scripting)
JavaScript programming language• Standardized as ECMAScript: ECMA-262
• download: http://www.ecma-international.org/publications/standards/Ecma-262.htm
• David Flanagan, JavaScript: The Definitive Guide (O'Reilly).• Look for the rhino on the cover• Excellent book on the language; also has many chapters on browser scripting
environment
Rhino: http://www.mozilla.org/rhino/
2008 JavaOneSM Conference | java.sun.com/javaone | 38
Other Resources
Lively Kernel Project http://research.sun.com/projects/lively • Sun project exploring using web browser's JavaScript platform to
implement a “desktop” environment which can host “desktop” applications
• Has produced experience using JavaScript as a “real” programming language• http://research.sun.com/techrep/2008/smli_tr-2008-175.pdf • http://research.sun.com/techrep/2007/smli_tr-2007-168.pdf
2008 JavaOneSM Conference | java.sun.com/javaone | 39
Questions?
If it is after 3:40 PM right now, you are invited to join me in Room 105 at 4:00 for additional Q & A.Otherwise, a miracle has occurred and we have time for questions now!