patterns for integrating java and javascript …...introduction to the javascript language and the...

40
Patterns for Integrating Javaand JavaScriptTechnology: Tales from the Front Lines David P. Caldwell President, David P. Caldwell, Inc. (Cleveland, OH) Committer, Mozilla Rhino TS-6606

Upload: others

Post on 22-May-2020

19 views

Category:

Documents


0 download

TRANSCRIPT

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 | 4

Why Scripting?

Source: xkcd.com

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!

2008 JavaOneSM Conference | java.sun.com/javaone | 40

David P. CaldwellPresident, David P. Caldwell, Inc. (Cleveland, OH)Committer, Mozilla Rhino

TS-6606