X

Recent Posts

Personal

Flexible JSON with Nashorn Parser API (JDK9)

[Posted by Sundar]  I recently came across Hjson - "the Human JSON - A configurationfile format that caters to humans and helps reduce the errorsthey make". See also: http://hjson.org. I wanted to see if I can use Nashorn Parser API (jdk9)to support similar flexible JSON extension with Nashorn. In the following FlexiJSON.parseimplementation, Nashorn Parser API is used to validate that the extendable flexi JSON is "data only" (That is, no executable code) andthen 'eval'uated to make an object out of it. FlexiJSON allows the following: single and mutliple line comments anywhere non-quoted property names and values regexp literal values omitting trailing comma When nashorn -scripting mode is enabled, FlexiJSON supports theseas well: shell style # comments multiple line (Unix heredoc style) string values File: flexijson.js /* * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */"use strict";function FlexiJSON() {}// helper to locate Nashorn Parser API classesFlexiJSON.treeType = function(name) { return Java.type("jdk.nashorn.api.tree." + name);}// Nashorn Parser API classes usedFlexiJSON.ArrayLiteral = FlexiJSON.treeType("ArrayLiteralTree");FlexiJSON.ExpressionStatement = FlexiJSON.treeType("ExpressionStatementTree");FlexiJSON.ObjectLiteral = FlexiJSON.treeType("ObjectLiteralTree");FlexiJSON.RegExpLiteral = FlexiJSON.treeType("RegExpLiteralTree");FlexiJSON.Literal = FlexiJSON.treeType("LiteralTree");FlexiJSON.Parser = FlexiJSON.treeType("Parser");FlexiJSON.SimpleTreeVisitor = FlexiJSON.treeType("SimpleTreeVisitorES5_1");// FlexiJSON.parse APIFlexiJSON.parse = function(str) { var parser = (typeof $OPTIONS == "undefined")? FlexiJSON.Parser.create() : FlexiJSON.Parser.create("-scripting"); // force the string to be an expression by putting it inside (, ) str = "(" + str + ")"; var ast = parser.parse("", str, null); // Should not happen. parse would have thrown syntax error if (!ast) { return undefined; } // allowed 'literal' values in flexi JSON function isLiteral(node) { return node instanceof FlexiJSON.ArrayLiteral || node instanceof FlexiJSON.Literal || node instanceof FlexiJSON.ObjectLiteral || node instanceof FlexiJSON.RegExpLiteral; } var visitor; ast.accept(visitor = new (Java.extend(FlexiJSON.SimpleTreeVisitor)) { lineMap: null, throwError: function(msg, node) { if (this.lineMap) { var pos = node.startPosition; var line = this.lineMap.getLineNumber(pos); var column = this.lineMap.getColumnNumber(pos); // we introduced extra '(' at start. So, adjust column number msg = msg + " @ " + line + ":" + (column - 1); } throw new TypeError(msg); }, visitLiteral: function(node, extra) { print(node.value); }, visitExpressionStatement: function(node, extra) { var expr = node.expression; if (isLiteral(expr)) { expr.accept(visitor, extra); } else { this.throwError("only literals can occur", expr); } }, visitArrayLiteral: function(node, extra) { for each (var elem in node.elements) { if (isLiteral(elem)) { elem.accept(visitor, extra); } else { this.throwError("only literal array element value allowed", elem); } } }, visitObjectLiteral: function(node, extra) { for each (var prop in node.properties) { if (prop.getter != null || prop.setter != null) { this.throwError("getter/setter property not allowed", node); } var value = prop.value; if (isLiteral(value)) { value.accept(visitor, extra); } else { this.throwError("only literal property value allowed", value); } } }, visitCompilationUnit: function(node, extra) { this.lineMap = node.lineMap; var elements = node.sourceElements; if (elements.length > 1) { this.throwError("more than one top level expression", node.sourceElements[1]); } var stat = node.sourceElements[0]; if (! (stat instanceof FlexiJSON.ExpressionStatement)) { this.throwError("only one top level expresion allowed", stat); } stat.accept(visitor, extra); }, }, null); // safe to eval given string as flexi JSON! return eval(str);} Sample simple usage of FlexiJSON.parse would be as follows: File: fjson.js var obj = FlexiJSON.parse(<<EOF// this is a comment{ foo: 23, bar: [ 34, 454, 54,], // inline comment here /** multi line comments are fine too! */ # shell style line comment is fine! regex: /gdfg/i, // regexp literal str: <<ENDMultiple line strings via nashorn -scripting mode extension as wellEND}EOF)print(obj.foo);print(obj.bar);print(obj.regex);print(obj.str);

[Posted by Sundar]  I recently came across Hjson - "the Human JSON - A configuration file format that caters to humans and helps reduce the errors they make". See also: http://hjson.org. I wanted to see...

Personal

JavaScript Stored Procedures and Node.js Applications with Oracle Database 12c

This is a reposting of an article written by Kuassi Mensah JavaScript Stored Procedures and Node.js Applications with Oracle Database 12c Introduction Node.js and server-side JavaScript are hot and trendy; per the latest “RedMonk Programming Languages Rankings”[1], JavaScript and Java are the top two programming languages. For most developers building modern Web, mobile, and cloud based applications, the ability to use the same language across all tiers (client, middle, and database) feels like Nirvana but the IT landscape is not a green field; enterprises have invested a lot in Java (or other platforms for that matter) therefore, the integration of JavaScript with it becomes imperative. WebSockets and RESTful services enable loose integration however, the advent of JavaScript engines on the JVM (Rhino, Nashorn, DynJS), and Node.js APIs on the JVM (Avatar.js, Nodyn, Trireme), make possible and very tempting to co-locate Java and Node applications on the same JVM.  This paper describes the steps for running JavaScript stored procedures[2] directly on the embedded JVM in Oracle database 12c and the steps for running Node.js applications on the JVM against Orace database 12c, using Avatar.js, JDBC and UCP.           JavaScript and the Evolution of Web Applications Architecture                At the beginning, once upon a time, long time ago, JavaScript was a browser-only thing while business logic, back-end services and even presentations where handled/produced in middle-tiers using Java or other platforms and frameworks. Then JavaScript engines (Google’s V8, Rhino) leave the browsers and gave birth to server-side JavaScript frameworks and Node.js. Node Programming Model Node.js and similar frameworks bring ease of development rapid prototyping, event-driven, and non-blocking programming model[3] to JavaScript. This model is praised for its scalability and good enough performance however, unlike Java, Node lacks standardization in many areas such as database access i.e., JDBC equivalent, and may lead, without discipline, to the so called “callback hell[4]”. Nonetheless, Node is popular and has a vibrant community and a large set of frameworks[5]. Node Impact on Web Applications Architecture With the advent of Node, REST and Web Sockets, the architecture of Web applications has evolved into  (i) plain JavaScript on browsers (mobiles, tablets, and desktops);  (ii) server-side JavaScript modules (i.e., Node.js, ORM frameworks) interacting with Java business logic and databases. The new proposal for Web applications architecture is the integration of Node.js and Java on the JVM.  Let’s discuss the enabling technologies: JavaScript engine on the JVM and Node API on the JVM and describe typical use cases with Oracle database 12c.   JavaScript on the JVM Why implement a JavaScript engine and run JavaScript on the JVM? For starters, i highly recommend Mark Swartz ‘s http://moduscreate.com/javascript-and-the-jvm/ and Steve Yegge’s  http://steve-yegge.blogspot.com/2008/06/rhinos-and-tigers.html blog posts. In summary, the JVM brings (i) portability; (ii) manageability; (iii) Java tools; (iv) Java libraries/technologies such as JDBC, Hadoop; and (v) the preservation of investments in Java.  There are several implementations/projects of Java based JavaScript engines including Rhino, DynJS and Nashorn. Rhino First JavaScript engine entirery written in Java; started at NetScape in 1997 then, became an open-source Mozilla project [6]. Was for quite some time the default JavaScript engine in Java SE, now  replaced by Nashorn in Java SE 8. DynJS DynJS is another open-source JavaScript engine for the JVM. Here is the project homepage http://dynjs.org/. Nashorn Introduced in Java 7 but “production” in Java 8[7], the goal of project Nashorn (JEP 174), is to enhance the performance and security of the Rhino JavaScript engine on the JVM. It integrates with javax.script API (JSR 223) and allows seamless interaction between Java and JavaScript (i.e., invoking Nashorn from Java and invoking Java from Nashorn). To illustrate the reach of Nashorn on the JVM and the interaction between Java and JavaScript, let’s run some JavaScript directly on the database-embedded JVM in Oracle database 12c. JavaScript Stored Procedures with Oracle database 12c Using Nashorn Why would anyone run JavaScript in the database? For the same reasons you’d run Java in Oracle database. Then you might ask why run Java in the database, in the first place? As discussed in my book[8], the primary motivations are:  (i) reuse skills and code, i.e., which programming languages are your new hire knowledgeable of or willing to learn;  (ii) avoid data shipping[9] i.e., in-place processing of billions of data/documents;  (iii) combine SQL with foreign libraries to achieve new database capability thereby extending SQL and the reach of the RDBMS, e.g., Web Services callout, in-database container for Hadoop[10].  Some developers/architects prefer a tight separation between the RDBMS and applications therefore, no programming language in the database[11]but there are many pragmatic developers/architects who run code near data, whenever it is more efficient than shipping data to external infrastructure. Co-locating functions with data on the same compute engine is shared by many programming models such as Hadoop. With the surge and prevalence of Cloud computing, RESTful service based architecture is the new norm. Data-bound services can be secured and protected by the REST infrastructure, running outside the RDBMS. Typical use case: a JavaScript stored procedures service would process millions/billions of JSON documents in the Oracle database and would return the result sets to the service invoker. To conclude, running Java, JRuby, Python, JavaScript, Scala, or other programming language on the JVM in the database is a sound architectural choice. The best practices consist in: (i) partitioning applications into data-bound and compute-bound modules or services; (ii) data-bound services are good candidates for running in the database; (iii) understand DEFINER’s vs INVOKER’s right[12] and grant only the necessary privilege and/or permission.  The Steps The following steps allow implementing JavaScipt stored procedure  running in Oracle database; these steps represent an enhancement from the ones presented at JavaOne and OOW 2014 -- which consisted in reading the JavaScript from the database file system; such approach required granting extra privileges to the database schema for reading from RDBMS file system something not recommended from security perspective. Here is a safer approach: 1. Nashorn is part of Java 8 but early editions can be built for Java 7; the embedded JavaVM in Oracle database 12c supports Java 6 (the default) or Java 7. For this proof of concept, install Oracle database 12c with Java SE 7 [13] 2. Build a standard Nashorn.jar[14]; (ii) modify the Shell code to interpret the given script name as an OJVM resource; this consists mainly in invoking getResourceAsStream() on the current thread's context class loader ; (iii) rebuild Nashorn.jar with the modified Shell 3. Load the modified Nashorn jar into an Oracle database shema e.g., HR loadjava -v -r -u hr/ nashorn.jar 4. Create a new dbms_javascript package for invoking Nashorn’s Shell with a script name as parameter create or replace package dbms_javascript AUTHID CURRENT_USER as  procedure run(script varchar2);end;/create or replace package body dbms_javascript as  procedure run(script varchar2) as  language java name 'com.oracle.nashorn.tools.Shell.main(java.lang.String[])';end;/  Then call dbms_javascript,run(‘myscript.js’) from SQL which will invoke Nashorn  Shell to execute the previously loaded myscript.js . 5. Create a custom role, we will name it NASHORN, as follows, connected as SYSTEM SQL> create role nashorn;SQL> call dbms_java.grant_permission('NASHORN', 'SYS:java.lang.RuntimePermission', 'createClassLoader', '' );SQL> call dbms_java.grant_permission('NASHORN', 'SYS:java.lang.RuntimePermission', 'getClassLoader', '' );SQL> call dbms_java.grant_permission('NASHORN', 'SYS:java.util.logging.LoggingPermission', 'control', '' ); Best practice: insert those statements in a nash-role.sql file and run the script as SYSTEM 6. Grant the NASHORN role created above to the HR schema as follows (connected as SYSTEM): SQL> grant NASHORN to HR; 7. Insert the following JavaScript code in a file e.g., database.js stored on your client machine’s (i.e., a machine from which you will invoke loadjava as explained in the next step). This script illustrates using JavaScript and Java as it uses the server-side JDBC driver to execute a PreparedStatement to retrieve the first and last names from the EMPLOYEES table. var Driver = Packages.oracle.jdbc.OracleDriver;var oracleDriver = new Driver();var url = "jdbc:default:connection:";   // server-side JDBC drivervar query ="SELECT first_name, last_name from employees";// Establish a JDBC connectionvar connection = oracleDriver.defaultConnection();// Prepare statementvar preparedStatement = connection.prepareStatement(query);// execute Queryvar resultSet = preparedStatement.executeQuery();// display results     while(resultSet.next()) {     print(resultSet.getString(1) + "== " + resultSet.getString(2) + " " );     }// cleanupresultSet.close();preparedStatement.close();connection.close(); 8. Load database.js in the database as a Java resource (not a vanilla class) loadjava –v –r –u hr/ database.js 9. To run the loaded script sqlplus hr/SQL>set serveroutput onSQL>call dbms_java.set_output(80000)SQL>call dbms_javascript.run(‘database.js’); The Nashorn Shell reads ‘database.js’ script stored as Java Resource from internal table; the JavaScript in its turn invokes JDBC to execute a PreparedStatement and the result set is displayed on the console. The message “ORA=29515: exit called from Java code with status 0” is due to the invocation of java.lang.Runtime.exitInternal; and status 0 means normal exit (i.e., no error). The fix is to remove that call from Nashorn.  Node.js on the JVM As discussed earlier, Node.js is becoming the man-in-the-middle between Web applications front ends and back-end legacy components and since companies have invested a lot in Java, it is highly desirable to co-locate Node.js and Java components on the same JVM for better integration thereby eliminating the communication overhead. There are several projects re-implementing Node.js APIs on the JVM including: Avatar.js, Nodyn, and Trireme. This paper will only discuss Oracle’s Avatar.js. Project Avatar.js[15] The goal of project Avatar.js is to furnish “Node.js on the JVM”; in other words, an implementation of Node.js APIs, which runs on top of Nashorn and enables the co-location of Node.js programs and Java components. It has been outsourced by Oracle under GPL license[16]. Many Node frameworks and/or applications have been certified to run unchanged or slightly patched, on Avatar.js. There are binary distributions for Oracle Enterprise Linux, Windows and MacOS (64-bits). These builds can be downloaded from https://maven.java.net/index.html#welcome. Search for avatar-js.jar and platform specific libavatar-js libraries (.dll, .so, dylib). Get the latest and rename the jar and the specific native libary accordingly. For example: on  Linux, rename the libary to avatar-js.so; on Windows, rename the dll to avatar-js.dll and add its location to your PATH (or use -Djava.library.path=). RDBMSes in general and Oracle database in particular remain the most popular persistence engines and there are RDBMS specific Node drivers[17] as well as ORMs frameworks. However, as we will demonstrate in the following section, with Avatar.js, we can simply reuse existing Java APIs including JDBC and UCP for database access. Node Programming with Oracle Database using Avatar.js, JDBC and UCP The goal of this proof of concept is to illustrate the co-location of a Node.js application, the Avatar.js library, the Oracle JDBC driver and the Oracle Universal Connection Pool (UCP) on the same Java 8 VM. The sample application consists in a Node.js application which performs the following actions: (i) Request a JDBC-Thin connection from the Java pool (UCP) (ii)Create a PreparedStatement object for “SELECT FIRST_NAME, LAST_NAME FROM EMPLOYEES” (iii)Execute the statement and return the ResultSet in a callback (iv)Retrieve the rows and display in browser on port 4000 (v) Perform all steps above in a non-blocking fashion – this is Node.js’s raison d’être. The demo also uses Apache ab load generator to simulate concurrent users running the same application in the same/single JVM instance.For the Node application to scale in the absence of asynchronous JDBC APIs, we need to turn synchronous calls into non-blocking ones and retrieve the result set via callback. Turning Synchronous JDBC Calls into Non-Blocking Calls We will use the following wrapper functions to turn any JDBC call into a non-blocking call i.e., put the JDBC call into a thread pool and free up the Node event loop thread. var makeExecutecallback = function(userCallback) { return function(name, args){      ...      userCallback(undefined, args[1]);  }} function submit(task, callback, msg) {    var handle = evtloop.acquire();    try {    var ret = task();               evtloop.post(new EventType(msg, callback, null, ret)); {catch{}    evtloop.submit(r);} Let’s apply these wrapper functions to executeQuery JDBC call, to illustrate the concept exports.connect = function(userCallback) {..} // JDBC and UCP settingsStatement.prototype.executeQuery = function(query, userCallback) {           var statement = this._statement;           var task = function() {           return statement.executeQuery(query);        }      submit(task, makeExecutecallback(userCallback), "jdbc.executeQuery"); } Similarly the same technique will be applied to other JDBC statement APIs. Connection.prototype.getConnection = function() {…}Connection.prototype.createStatement = function() {..}Connection.prototype.prepareCall = function(storedprocedure) {..}Statement.prototype.executeUpdate = function(query, userCallback) {..} Returning Query ResultSet through a Callback The application code fragment hereafter shows how: for every HTTP request: (i) a connection is requested, (ii) the PreparedStatement is executed, and (iii) the result set printed on port 4000.    ...var ConnProvider = require('./connprovider').ConnProvider;var connProvider = new ConnProvider(function(err, connection){.. });var server = http.createServer(function(request, response) {   connProvider.getConn(function(name,data){..});        connProvider.prepStat(function(resultset) {                while (resultset.next()) {                   response.write(resultset.getString(1) + " --" + resultset.getString(2));                   response.write('');    }    response.write('');    response.end();    }server.listen(4000, '127.0.0.1'); Using Apache AB, we were able to scale to hundreds of simultaneous invocations of the Node application. Each instance grabs a Java connection from The Universal Connection Pool (UCP), executes the SQL statements through JDBC then return the result set via a Callbak on port 4000. Conclusions Through this paper, i discussed the rise of JavaScript for server-side programming and how Java is supporting such evolution; then – something we set out to demonstrate – furnished step by step details for implementing and running JavaScript stored procedures in Oracle database 12c using Nashorn as well as running Node.js applications using Avata.js, Oracle JDBC, UCP against Oracle database 12c. As server-side JavaScript (typified by Node.js) gains in popularity it’ll have to integrate with existing components (COBOL is still alive!!). Developers, architects will have to look into co-locating JavaScript with Java, across middle and database tiers. [1] http://redmonk.com/sogrady/2015/01/14/language-rankings-1-15/ [2] I’ll discuss the rationale for running programming languages in the database, later in this paper. [3] Request for I/O and resource intensive components run in separate process then invoke a Callback in the main/single Node  thread, when done. [4] http://callbackhell.com/ [5] Search the web for “Node.js frameworks” [6] https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino [7] Performance being one of the most important aspect [8] http://www.amazon.com/exec/obidos/ASIN/1555583296 [9] Rule of thumb: when processing more than ~20-25% of target data, do it in-place, where data resides (i.e., function shipping). [10] In-database Container for Hadoop is not available, as of this writing. [11] Other than database’s specific procedural language, e.g.,  Oracle’s PL/SQL [12] I discuss this in chapter 2 of my book; see also Oracle database docs. [13] See Multiple JDK Support in http://docs.oracle.com/database/121/JJDEV/E50793-03.pdf [14] Oracle does not furnish a public download of Nashorn.jar for Java 7; search “Nashorn.jar for Java 7”. [15]  https://avatar-js.java.net/ [16] https://avatar-js.java.net/license.html [17] The upcoming Oracle Node.js driver was presented at OOW 2014. 

This is a reposting of an article written by Kuassi Mensah JavaScript Stored Procedures and Node.js Applications with Oracle Database 12c Introduction Node.js and server-side JavaScript are hot and...

Personal

Nashorn Architecture and Performance Improvements in the Upcoming JDK 8u40 Release

Hello everyone! We've been bad at blogging here for a while. Apologies for that. I thought it would be prudent to talk a little bit about OpenJDK 8u40 which is now code frozen, and what enhancements we have made for Nashorn. 8u40 includes a total rewrite of the Nashorn code generator, which now contains the optimistic type system. JavaScript, or any dynamic language for that matter, doesn't provide enough compile time information to easily generate performant code. This is why, for 8u40, we have redesigned the Nashorn Type System, to produce better, faster code.  The output of the Nashorn compiler, Java byte code, is by design strongly typed and JavaScript isn't. There are significant problems translating a dynamic language AST to optimal bytecode. Attila Szegedi, Hannes Wallnöfer and myself have spent significant time researching and implementing a solution to this problem over the last year. Background: Conservatively, when implementing a JavaScript runtime in Java, anything known to be a number can be represented in Java as a double, and everything else can be represented as an Object. This includes numbers, ints, longs and other primitive types that aren't statically provable. Needless to say, this approach leads to a lot of internal boxing, which is quite a bottleneck for dynamic language execution speed on the JVM. The JVM is very good at optimizing Java-like bytecode, and this is not Java-like bytecode.  Type transitions in the optimistic type system Another novelty in 8u40 is that Nashorn actually performs extensive intra-function static type analysis, so the generated code ends up being much better than in the above conservative scenario. It still can't prove all the types, though, and that's where optimistic type system comes in. Our optimistic type system works by assuming that any statically unprovable type is an int, the narrowest possible of all types. If this turns out to be wrong at runtime, e.g. we load a field from memory/scope that turned out to be an Object or a double instead, or if we perform a 32-bit addition that overflows, we will replace the executing code with a more conservative version, that is regenerated on the fly. Nashorn supports simple continuations to facilitate code replacement at runtime. This is a feature that can have multiple other uses in the future, for example going back and forth between a hypothetical interpreter layer and compiled bytecode. We also specialize/guess how bytecode will look depending on what arguments are passed to a callsite at link time, with guards against these changing in the future. Octane benchmark scores, normalized on JDK 8.  This makes the bytecode that we produce (when stable) contain optimal Java types for speedy execution. The cost for this (everything has a cost) is that we spend more time generating code, which affects things like warmup slightly negatively. Warmup is the major R &D area for JDK 9, and we are confident that we can solve this, and also customize the workload we give HotSpot to compile better, so that it spends its cycles much more optimally.  In our efforts to turn Nashorn into a generic platform/runtime for dynamic languages for the JVM, the optimistic type system integrates nicely with whatever AST Nashorn is asked to generate code for. These plans will also solidify more for future Java releases, and we hope that Nashorn eventually will turn into a kind of "LLVM for dynamic languages on the JVM". The optimistic typing problem comes back to every dynamic language. To prove this, our excellent thesis student Andreas Gabrielsson has successfully implemented almost everything required to run TypeScript on Nashorn. At the time of this writing, modules in the only large feature missing. Nashorn goes directly to bytecode from TypeScript without generating JavaScript in a mid-level compiler tier. This is pretty awesome and shows how extensible Nashorn already is. We have thought about Ruby and Groovy running in a similar environment. Nashorn TypeScript is still not open sourced, but we hope we have the chance to do it soon. To run Nashorn with 8u40 and optimistic types, use the argument --optimistic-types=true. As we haven't had time to check in a solution to the warmup issues yet (it doesn't affect everything, but where issues remain it can be annoying), the optimistic type system is not yet the default behavior for Nashorn. This might be overly conservative, but we didn't want to break anyone's warmup unnecessarily. We can report several orders of magnitude of performance increase on things like the Octane benchmarks suite compared to previous releases. We can also report near native or native performance on the REST and HTTP benchmarks for the Avatar project. We feel pretty good about this. In several cases, JavaScript applications on Nashorn run as fast as the same application on a native runtime such as SpiderMonkey or v8. Needless to say, we are pretty proud of our work. Furthermore: Nashorn in JDK 8u40 also supports caching generated code and type information deduced at runtime to disk. This means that only the first iteration of a largish application with long warmup will be an issue. Consecutive runs of the same code will stabilize very quickly with the same good performance. Please try it out and tell us what you find! If you have questions, please read the documentation and feel free to join the nashorn-dev@openjdk.java.net list and talk to us. You can also follow the Nashorn team on Twitter: Jim Laskey: @wickund  Sundararajan Athijegannathan: @sundararajan_a Marcus Lagergren: @lagergren Attila Szegedi: @asz Hannes Wallnöfer: @hannesw  We'll try to blog more here in the near future. Stay tuned and sorry for the hiatus. Proudly yours, The Nashorn team through  Marcus Lagergren (dynamic language performance architect) P.S. If you are interested in the internal workings of the new type system or more information as the JVM as a polyglot multilanguage runtime and Nashorn as its facilitating framework, here are some links to presentations on the subject, that you may find interesting: Marcus Lagergren - GeekOut 2013 - The JVM as a multi language runtime Marcus Lagergren - JVMLS 2013 - Nashorn performance war stories and the optimistic type architecture Marcus Lagergren - Keynote, JAX 2013 - Why Dynamic Languages on the JVM matter Marcus Lagergren - JVMLS 2014 - Towards Native Performance with Dynamic Languags on the JVM Attila Szegedi - JVMLS 2014 - Dynamic Languages Toolchain on the JVM Attila Szegedi - StrangeLoop 2014 - Nashorn: implementing a Dynamic Language Runtime on the JVM in 2014

Hello everyone! We've been bad at blogging here for a while. Apologies for that. I thought it would be prudent to talk a little bit about OpenJDK 8u40 which is now code frozen, and what enhancements...

Personal

Porting from the Browser to Nashorn/JavaFX (Part I)

During the JavaOne Nashorn: JavaScript for the JVM session, I showed a couple examples of converting JavaScript browser examples to use Nashorn and JavaFX. The first example was using CKEditor, a rich text/HTML editor. This editor is written entirely in JavaScript using the browser DOM interface. In this case, it did not really make sense to convert all the DOM code over to FX. Instead, I used the JavaFX WebView which supports all the DOM needed. So let's start with a simple example to bring up a WebView (run with jjs -fx -scripting example1.js); // example1.jsvar Scene = Java.type("javafx.scene.Scene");var WebView = Java.type("javafx.scene.web.WebView");var site = "http://www.oracle.com";var webView = new WebView();webView.engine.load(site);$STAGE.title = site;$STAGE.scene = new Scene(webView, 800, 600);$STAGE.show(); The next example brings up a WebView with a CKEditor contained within. You can download the CKEditor toolkit from http://ckeditor.com/download. Place the ckeditor folder in your working directory. <!-- example2.html --><!DOCTYPE html><html><head> <script src="./ckeditor/ckeditor.js"></script></head><body> <form id="MainForm" method="post"> <textarea id="MainEditor"> &lt;h1&gt;Example&lt;/h1&gt; &lt;p&gt;Some content for the Demo&lt;/p&gt; </textarea> <script> CKEDITOR.replace("MainEditor"); </script> </form></body></html>// example2.jsvar Scene = Java.type("javafx.scene.Scene");var WebView = Java.type("javafx.scene.web.WebView");var link = "file:${$ENV.PWD}/example2.html";var webView = new WebView();webView.engine.load(link);$STAGE.title = "CKEditor";$STAGE.scene = new Scene(webView, 1024, 360);$STAGE.show();   For the next part, it gets a little confusing, but you should be able to catch on to the weirdness (after all, you're a JavaScript developer.) First, you have to be aware of the fact that there is a separate JavaScriptCore engine inside the WebView. The example shows interaction with this engine by asking it to load an URL. Second, we want to be able to have JSObject objects passed back from the WebView engine and have them behave like Nashorn objects. To accomplish this we need to "wrap" the JSObject objects in Nashorn JSAdaptor objects. function wrap(jsobject) { return new JSAdapter({ __get__ : function (key) { return jsobject.getMember(key); }, __has__ : function (key) { return jsobject.call("hasOwnProperty", key); }, __put__ : function (key, value) { return jsobject.setMember(key, value); }, __call__ : function (name) { var args = Array.prototype.slice.call(arguments); args.shift(); args = Java.to(args, ObjectArray); return jsobject.call(name, args); }, __new__ : function () { return wrap(jsobject.eval("new this()")); }, __delete__ : function (key) { jsobject.removeMember(key); return true; }, __getIds__ : function () { return jsobject.eval("Object.keys(this)"); } });} The wrap function creates a closure containing "jsobject" and the adaptor functions specified. This will allow you to do things like; var window = wrap(webview.engine.executeScript("window"));var document = wrap(window.document); The adaptor above is very basic. The complete code might look more like; var ObjectArray = Java.type("java.lang.Object[]");var NetscapeJSObject = Java.type("netscape.javascript.JSObject");var EventHandler = Java.type("javafx.event.EventHandler");// Lambda functions for 0, 1, or 2 arguments (no need for external java code.)var Supplier = Java.type("java.util.function.Supplier");var UniFunction = Java.type("java.util.function.Function");var BiFunction = Java.type("java.util.function.BiFunction");function wrap(jsobject) {// If not a JSObject type (primitives) then don't wrap. if (!(jsobject instanceof NetscapeJSObject)) { return jsobject; }// Construct a SAM to call back into Nashorn (event handling) function callback(func) { if (typeof func == 'function') { switch (func.length) { case 0: return new (Java.extend(Supplier, { get: function() { return func(); } }))(); case 1: return new (Java.extend(UniFunction, { apply: function(arg) { return func(wrap(arg)); } }))(); case 2: return new (Java.extend(BiFunction, { apply: function(arg1, arg2) { return func(wrap(arg1), wrap(arg2)); }}))(); } } throw "Callbacks can only have zero, one or two arguments"; } // Potentially wrap arguments for a call. function wrapArgs(args) { for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg) { if (arg.unwrap) { args[i] = arg.unwrap(); } else if (typeof arg == "function") { args[i] = callback(arg); } } } } return new JSAdapter({ __get__ : function (key) { // special case unwrap to return the jsobject if (key == "unwrap") { return function() { return jsobject }; } // Handle number indexing var value = typeof key == "number" ? jsobject.getSlot(key) : jsobject.getMember(key); // Wrap the result return wrap(value); }, __has__ : function (key) { return jsobject.call("hasOwnProperty", key); }, __put__ : function (key, value) { // Wrap functions as callback SAMs if (typeof value == "function") { value = callback(value); } // Handle number indexing return typeof key == "number" ? jsobject.setSlot(key, value) : jsobject.setMember(key, value); }, __call__ : function (name) { // Special case unwrap to return the jsobject if (name == "unwrap") { return jsobject; } var args = Array.prototype.slice.call(arguments); args.shift(); args = Java.to(args, ObjectArray); wrapArgs(args); return jsobject.call(name, args); }, __new__ : function () { return wrap(jsobject.eval("new this()")); }, __delete__ : function (key) { jsobject.removeMember(key); return true; }, __getIds__ : function () { // Convert the Node collection to a JS array var keys = jsobject.eval("Object.keys(this)"); var length = keys.getMember("length"); var ids = []; for (var i = 0; i < length; i++) { ids.push(keys.getSlot(i)); } return ids; } });} I know this code looks complex, but you only have to write once and include (load) in WebView related projects. Note that the code snippet above then becomes; var window = wrap(webview.engine.executeScript("window"));var document = window.document; In the example I also created a special helper wrapper for the WebView to simplify accessing the DOM. function WebViewWrapper(onload) { var This = this; var WebView = Java.type("javafx.scene.web.WebView"); var webview = new WebView(); This.webview = webview; This.engine = webview.engine; This.window = undefined; This.document = undefined; // Make sure the JavaScript is enabled. This.engine.javaScriptEnabled = true; // Complete initialization when page is loaded. This.engine.loadWorker.stateProperty().addListener(new ChangeListener() { changed: function(value, oldState, newState) { if (newState == Worker.State.SUCCEEDED) { This.document = wrap(This.engine.executeScript("document")); This.window = wrap(This.engine.executeScript("window")); // Call users onload function. if (onload) { onload(This); } } } }); // Divert alert message to print. This.engine.onAlert = new EventHandler() { handle: function(evt) { print(evt.data); } }; // Load page from URL. This.load = function(url) { This.engine.load(url); } // Load page from text. This.loadContent = function(text) { This.engine.loadContent(text); }} So now the main script looks as follows; var Scene = Java.type("javafx.scene.Scene");var link = "file:${$ENV.PWD}/example2.html";var wvw = WebViewWrapper();wvw.load(link);$STAGE.title = "CKEditor";$STAGE.scene = new Scene(wvw.webview, 1024, 360);$STAGE.show(); Getting the content from the CKEditor; var window = wvw.window;var CKEDITOR = window.CKEDITOR;var mainEditor = CKEDITOR.instances.MainEditor;var text = mainEditor.getData(); Setting the content in the CKEditor; var window = wvw.window;var CKEDITOR = window.CKEDITOR;var mainEditor = CKEDITOR.instances.MainEditor;mainEditor.setData(text);

During the JavaOne Nashorn: JavaScript for the JVM session, I showed a couple examples of converting JavaScript browser examples to use Nashorn and JavaFX. The first example was using CKEditor, a rich...

Personal

setInterval and setTimeout JavaScript Functions

With people porting HTML to Nashorn + JavaFX more frequently, I often get asked the question "how do you port functions like setInterval and setTimeout" (setInterval is used to have a function repeated at regular intervals, where setTimeout is used to have a function delayed.) The following code duplicates the functionality of the each of the setInterval family of functions, when used in a JavaFX application. var Platform = Java.type("javafx.application.Platform");var Timer = Java.type("java.util.Timer");function setInterval(func, milliseconds) {// New timer, run as daemon so the application can quitvar timer = new Timer("setInterval", true);timer.schedule(function() Platform.runLater(func), milliseconds, milliseconds);return timer;}function clearInterval(timer) {timer.cancel();}function setTimeout(func, milliseconds) {// New timer, run as daemon so the application can quitvar timer = new Timer("setTimeout", true);timer.schedule(function() Platform.runLater(func), milliseconds);return timer;}function clearTimeout(timer) {timer.cancel();} <Update March 21, 2014> I was requested by a reader to implement setInterval, setTimeout and setImmediate with the same arguments as defined in DOM. var Platform = Java.type("javafx.application.Platform");var Timer    = Java.type("java.util.Timer");function setTimerRequest(handler, delay, interval, args) {    handler = handler || function() {};    delay = delay || 0;    interval = interval || 0;    var applyHandler = function() handler.apply(this, args);    var runLater = function() Platform.runLater(applyHandler); var timer = new Timer("setTimerRequest", true);    if (interval > 0) {        timer.schedule(runLater, delay, interval);    } else {        timer.schedule(runLater, delay);    }    return timer;}function clearTimerRequest(timer) { timer.cancel();}function setInterval() {    var args = Array.prototype.slice.call(arguments);    var handler = args.shift();    var ms = args.shift(); return setTimerRequest(handler, ms, ms, args);}function clearInterval(timer) { clearTimerRequest(timer);}function setTimeout() {    var args = Array.prototype.slice.call(arguments);    var handler = args.shift();    var ms = args.shift(); return setTimerRequest(handler, ms, 0, args);}function clearTimeout(timer) { clearTimerRequest(timer);}function setImmediate() {    var args = Array.prototype.slice.call(arguments);    var handler = args.shift(); return setTimerRequest(handler, 0, 0, args);}function clearImmediate(timer) { clearTimerRequest(timer);}

With people porting HTML to Nashorn + JavaFX more frequently, I often get asked the question "how do you port functions like setInterval and setTimeout" (setInterval is used to have a function...

Personal

JavaOne: JavaScript Sessions

These are the sessions I found related to JavaScript.  There are likely others.  If you spot others, send a comment and I'll update this entry.  The session on the list is mine and the second is Attila's. Teaching the Java Platform with Nashorn is done with Ben Evans of the London JUG.  Come to the Script Bowl and vote for the only first time entry (Nashorn.) Nashorn: JavaScript on the JVM [CON7835] Monday, Sep 23, 11:30 AM - 12:30 PM - Hilton - Yosemite B/C Nashorn: Java and JavaScript—Shaken, Not Stirred [BOF5793] Monday, Sep 23, 6:30 PM - 7:15 PM - Hilton - Yosemite B/C Teaching the Java Platform with Nashorn [BOF5225] Tuesday, Sep 24, 4:30 PM - 5:15 PM - Hilton - Yosemite B/C The Curious Case of JavaScript on the JVM [CON2952] Tuesday, Sep 24, 1:00 PM - 2:00 PM - Hilton - Yosemite B/C Embedding JVM Scripting Languages [CON2585] Tuesday, Sep 24, 3:00 PM - 4:00 PM - Hilton - Yosemite B/C Modular JavaScript [CON2959] Wednesday, Sep 25, 3:00 PM - 4:00 PM - Hilton - Yosemite B/C MySQL User-Defined Functions....in JavaScript! [CON1738] Saturday, Sep 21, 1:00 PM - 2:00 PM - Hilton - Powell Effective Use of HTML5 JavaScript for Java EE 7 Web Applications [BOF7838] Monday, Sep 23, 4:30 PM - 5:15 PM - Parc 55 - Cyril Magnin II/III Script Bowl 2013: The Battle for Supremacy and Survival [CON2653] Wednesday, Sep 25, 4:30 PM - 5:30 PM - Hilton - Imperial Ballroom B Developing JavaScript Applications for Node.js with MySQL and NoSQL [CON6805] Sunday, Sep 22, 4:00 PM - 5:00 PM - Hilton - Powell

These are the sessions I found related to JavaScript.  There are likely others.  If you spot others, send a comment and I'll update this entry.  The session on the list is mine and the second is...

Personal

JavaOne: What a Difference a Year Makes

I haven't been blogging for a while.  JavaOne examples and slides are taking up all my time.  Marcus and Attila leaked out that I was doing a demo of the Nashorn Debugger prototype, but I still have some surprises up my sleeve.  I was reviewing examples from last year and felt that they needed some updating.  The FX Fireworks example had all kinds of Java code to support applications, timers and callbacks.  This year's Fireworks version is pure Nashorn.  I posted source and backdrop here.  Just run with jjs -fx -scripting fireworks.js  Enjoy. var ArrayList = Java.type("java.util.ArrayList");var File = Java.type("java.io.File");var AnimationTimer = Java.type("javafx.animation.AnimationTimer");var BlendMode = Java.type("javafx.scene.effect.BlendMode");var Canvas = Java.type("javafx.scene.canvas.Canvas");var Color = Java.type("javafx.scene.paint.Color");var CycleMethod = Java.type("javafx.scene.paint.CycleMethod");var Group = Java.type("javafx.scene.Group");var ImageView = Java.type("javafx.scene.image.ImageView");var Pane = Java.type("javafx.scene.layout.Pane");var RadialGradient = Java.type("javafx.scene.paint.RadialGradient");var Reflection = Java.type("javafx.scene.effect.Reflection");var Scene = Java.type("javafx.scene.Scene");var Stop = Java.type("javafx.scene.paint.Stop");var AnimationTimerExtend = Java.extend(AnimationTimer);var doubleArray = Java.type("double[]");var GRAVITY = 0.06;function Particle(posX, posY, velX, velY, targetX, targetY, color, size, usePhysics, shouldExplodeChildren, hasTail) { this.posX = posX; this.posY = posY; this.velX = velX; this.velY = velY; this.targetX = targetX; this.targetY = targetY; this.color = color; this.size = size; this.usePhysics = usePhysics; this.shouldExplodeChildren = shouldExplodeChildren; this.hasTail = hasTail; this.alpha = 1; this.easing = Math.random() * 0.02; this.fade = Math.random() * 0.1;}Particle.prototype.update = function() { this.lastPosX = this.posX; this.lastPosY = this.posY; if(this.usePhysics) { // on way down this.velY += GRAVITY; this.posY += this.velY; this.alpha -= this.fade; // fade out particle } else { // on way up var distance = (this.targetY - this.posY); // ease the position this.posY += distance * (0.03 + this.easing); // cap to 1 this.alpha = Math.min(distance * distance * 0.00005, 1); } this.posX += this.velX; return this.alpha < 0.005;}Particle.prototype.draw = function(context) { var x = Math.round(this.posX); var y = Math.round(this.posY); var xVel = (x - this.lastPosX) * -5; var yVel = (y - this.lastPosY) * -5; // set the opacity for all drawing of this particle context.globalAlpha = Math.random() * this.alpha; // draw particle context.fill = this.color; context.fillOval(x - this.size, y - this.size, this.size + this.size, this.size + this.size); // draw the arrow triangle from where we were to where we are now if (this.hasTail) { context.fill = Color.rgb(255, 255, 255, 0.3); var x = new doubleArray(3); var y = new doubleArray(3); x[0] = this.posX + 1.5; y[0] = this.posY; x[1] = this.posX + xVel; y[1] = this.posY + yVel; x[2] = this.posX - 1.5; y[2] = this.posY; context.fillPolygon(x, y, 3); }}function drawFireworks(gc) { var iter = particles.iterator(); var newParticles = new ArrayList(); while(iter.hasNext()) { var firework = iter.next(); // if the update returns true then particle has expired if(firework.update()) { // remove particle from those drawn iter.remove(); // check if it should be exploded if(firework.shouldExplodeChildren) { if(firework.size == 9) { explodeCircle(firework, newParticles); } else if(firework.size == 8) { explodeSmallCircle(firework, newParticles); } } } firework.draw(gc); } particles.addAll(newParticles);}function fireParticle() { particles.add(new Particle( surface.width * 0.5, surface.height + 10, Math.random() * 5 - 2.5, 0, 0, 150 + Math.random() * 100, colors[0], 9, false, true, true));}function explodeCircle(firework, newParticles) { var count = 20 + (60 * Math.random()); var shouldExplodeChildren = Math.random() > 0.5; var angle = (Math.PI * 2) / count; var color = (Math.random() * (colors.length - 1)); for(var i=count; i>0; i--) { var randomVelocity = 4 + Math.random() * 4; var particleAngle = i * angle; newParticles.add( new Particle( firework.posX, firework.posY, Math.cos(particleAngle) * randomVelocity, Math.sin(particleAngle) * randomVelocity, 0, 0, colors[Math.ceil(color)], 8, true, shouldExplodeChildren, true)); }}function explodeSmallCircle(firework, newParticles) { var angle = (Math.PI * 2) / 12; for(var count = 12; count > 0; count--) { var randomVelocity = 2 + Math.random() * 2; var particleAngle = count * angle; newParticles.add( new Particle( firework.posX, firework.posY, Math.cos(particleAngle) * randomVelocity, Math.sin(particleAngle) * randomVelocity, 0, 0, firework.color, 4, true, false, false)); }}function fileToURL(file) { return new File(file).toURI().toURL().toExternalForm();}var timer = new AnimationTimerExtend() { handle: function handle(now) { var gc = surface.graphicsContext2D; // clear area with transparent black gc.fill = Color.rgb(0, 0, 0, 0.2); gc.fillRect(0, 0, 1024, 708); // draw fireworks drawFireworks(gc); // countdown to launching the next firework if (countDownTillNextFirework <= 0) { countDownTillNextFirework = 10 + (Math.random() * 30); fireParticle(); } countDownTillNextFirework--; }};// Kill timer before exiting.function stop() { timer.stop();}var particles = new ArrayList();var countDownTillNextFirework = 40;// create a color palette of 180 colorsvar colors = new Array(181);var stops = new ArrayList();stops.add(new Stop(0, Color.WHITE));stops.add(new Stop(0.2, Color.hsb(59, 0.38, 1)));stops.add(new Stop(0.6, Color.hsb(59, 0.38, 1,0.1)));stops.add(new Stop(1, Color.hsb(59, 0.38, 1,0)));colors[0] = new RadialGradient(0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE, stops);for (var h = 0; h < 360; h += 2) { var stops2 = new ArrayList(); stops2.add(new Stop(0, Color.WHITE)); stops2.add(new Stop(0.2, Color.hsb(h, 1, 1))); stops2.add(new Stop(0.6, Color.hsb(h, 1, 1,0.1))); stops2.add(new Stop(1, Color.hsb(h, 1, 1,0))); colors[1 + (h / 2)] = new RadialGradient(0, 0, 0.5, 0.5, 0.5, true, CycleMethod.NO_CYCLE, stops2);}var surface = new Canvas(1024, 500);surface.blendMode = BlendMode.ADD;surface.effect = new Reflection(0, 0.4, 0.15, 0);var imageUrl = fileToURL("sf.jpg");var background = new ImageView(imageUrl);var pane = new Pane();pane.children.add(background);pane.children.add(surface);var root = new Group();root.children.add(pane);$STAGE.scene = new Scene(root);timer.start();

I haven't been blogging for a while.  JavaOne examples and slides are taking up all my time.  Marcus and Attila leaked out that I was doing a demo of the Nashorn Debugger prototype, but I still have...

Personal

Nashorn Multithreading and MT-safety

Tobias Schlotte asked the question (via twitter @tobsch), "Where is thread-safety on your agenda for Nashorn?"  The quick answer is that multithreading is very high on the list, but MT-safety is a very complicated issue. I'll attempt to explain our plan of action. As Attila responded http://mail.openjdk.java.net/pipermail/nashorn-dev/2013-July/001567.html "ECMAScript 5.1 language specification doesn't define multithreading semantics for programs written in the language; they are inherently single threaded. If we were to make them thread safe, we'd be sacrificing single threaded performance for a behaviour that falls outside of the specification." Why is performance affected?  Well, generally, the internal structure of a script object is complex.  Any modification to the object would have to be done with mutex locks (synchronize) or compare/swap.  As an example, take obj.x = 1.  In a static language, this code would likely generate a simple native store that can be executed, somewhat, atomically.  With multiple threads, obj.x = ? would simply be "last thread that stores, wins" (ignoring coherency et al) and the application would continue to run.  In dynamic languages like JavaScript, what happens when property "x" doesn't exist yet?  Internally, the script object has to be restructured to include the new property before the store takes place.  Now add the fact that another thread could be adding or removing properties on the same object; objects would have to be locked for (nearly) every operation. Then add in the thread coherency issue…  Slowness, reigns. On the other hand, having a language on the JVM and not supporting multithreading is just plain daft.  Especially, since our target platforms include multi-core servers. So, our agenda is two fold.  The first is to provide a "workers" library (timeline is not tied to JDK8) which uses an onevent model that JavaScripters are familiar with.  No synchronization/locking constructs to be added to the language.  Communication between threads (and potentially nodes/servers) is done using JSON (under the covers.) Going this route allows object isolation between threads, but also allows maximal use of CPU capacity. The second part is, we will not guarantee MT-safe structures, but we have to face reality.  Developers will naturally be drawn to using threads.  Many of the Java APIs require use of threads.  So, the best we can do is provide guidelines on how to not shoot yourself in the foot.  These guidelines will evolve and we'll post them 'somewhere' after we think them through.  In the meantime,  I follow some basic rules; Avoid sharing script objects or script arrays across threads (this includes global.)  Sharing script objects is asking for trouble.  Share only primitive data types, or Java objects. If you want to pass objects or arrays across threads, use JSON.stringify(obj) and JSON.parse(string) to transport using strings. If you really really feel you have to pass a script object, treat the object as a constant and only pass the object to new threads (coherency.)  Consider using Object.freeze(obj). If you really really really feel you have to share a script object, make sure the object's properties are stabilized.  No adding or removing properties after sharing starts.  Consider using Object.seal(obj). Given enough time, any other use of a shared script object will eventually cause your app to fail. The number of reallys in a rule reflects the uncertainty of the outcome. Note in the first rule, I stated that you shouldn't share global.  The reason is simple, almost everything adds properties to global.  How do you avoid share modifying global?  Simply give each thread a new global. Nashorn has two builtin functions for starting scripts; load and loadWithNewGlobal.  Each takes an arg specifying which script to load and evaluate; either an URL/file string or an object with a name and script properties (name is for source location, script is body of script.)  Additional arguments are passed as the arguments global when evaluating.  Unlike load, loadWithNewGlobal creates a fresh global before loading the script.  This isolates evaluation from the current global and thus suppresses sharing. Going back to Tobias' example (the original is at https://gist.github.com/tobsch/5955518); import javax.script.CompiledScript;import javax.script.Compilable;import javax.script.ScriptException; import jdk.nashorn.api.scripting.NashornScriptEngineFactory;import jdk.nashorn.api.scripting.NashornScriptEngine; import java.util.concurrent.Future;import java.util.concurrent.Executors;import java.util.concurrent.ExecutorService;import java.util.concurrent.ExecutionException;import java.util.concurrent.TimeUnit;import java.util.concurrent.Callable; import java.util.ArrayList; public class SSCCE {  private static final NashornScriptEngineFactory engineFactory = new NashornScriptEngineFactory();     public static void main(String[] args) throws ScriptException, InterruptedException, ExecutionException {    Compilable engine = (Compilable) engineFactory.getScriptEngine();         String script = new StringBuilder("i = 0;")      .append("i += 1;")      .append("shortly_later = new Date()/1000 + Math.random;") // 0..1 sec later      .append("while( (new Date()/1000) < shortly_later) { Math.random() };") //prevent optimizations      .append("i += 1;")      .toString();         final CompiledScript onePlusOne = engine.compile(script);         Callable<Double> addition = new Callable<Double>() {      @Override      public Double call() {        try {          return (Double) onePlusOne.eval();        }        catch(ScriptException e) {          throw new RuntimeException(e);        }      }    };         ExecutorService executor = Executors.newCachedThreadPool();    ArrayList<Future<Double>> results = new ArrayList<Future<Double>>();         for(int i = 0; i < 50; i++) {      results.add(executor.submit(addition));    }         int miscalculations = 0;    for(Future<Double> result : results) {      int jsResult = result.get().intValue();             if(jsResult != 2) {        System.out.println("Incorrect result from js, expected 1 + 1 = 2, but got " + jsResult);        miscalculations += 1;      }    }         executor.awaitTermination(1, TimeUnit.SECONDS);    executor.shutdownNow();         System.out.println("Overall: " + miscalculations + " wrong values for 1 + 1.");  }} Output; Incorrect result from js, expected 1 + 1 = 2, but got 11Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 9Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 5Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 13Incorrect result from js, expected 1 + 1 = 2, but got 10Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 13Incorrect result from js, expected 1 + 1 = 2, but got 5Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 11Incorrect result from js, expected 1 + 1 = 2, but got 9Incorrect result from js, expected 1 + 1 = 2, but got 7Incorrect result from js, expected 1 + 1 = 2, but got 11Incorrect result from js, expected 1 + 1 = 2, but got 11Incorrect result from js, expected 1 + 1 = 2, but got 7Incorrect result from js, expected 1 + 1 = 2, but got 9Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 13Incorrect result from js, expected 1 + 1 = 2, but got 11Incorrect result from js, expected 1 + 1 = 2, but got 12Incorrect result from js, expected 1 + 1 = 2, but got 8Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 4Incorrect result from js, expected 1 + 1 = 2, but got 8Incorrect result from js, expected 1 + 1 = 2, but got 9Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 5Incorrect result from js, expected 1 + 1 = 2, but got 3Incorrect result from js, expected 1 + 1 = 2, but got 9Incorrect result from js, expected 1 + 1 = 2, but got 6Incorrect result from js, expected 1 + 1 = 2, but got 7Overall: 41 wrong values for 1 + 1. I rewrote in JavaScript and introduced loadWithNewGlobal; #!/usr/bin/env jjs -scriptingvar Executors = java.util.concurrent.Executors;var TimeUnit  = java.util.concurrent.TimeUnit;var ArrayList = java.util.ArrayList;var script = <<EOD    i = 0;    i += 1;    shortly_later = new Date()/1000 + Math.random;    while( (new Date()/1000) < shortly_later) { Math.random() };    i += 1;EODfunction addition() {    return loadWithNewGlobal({ name: "addition", script: script });}var executor = Executors.newCachedThreadPool();var results = new ArrayList();for(var i = 0; i < 50; i++) {    // Clarify Runnable versus Callable    results.add(executor["submit(java.util.concurrent.Callable)"](addition));}var miscalculations = 0;for each (var result in results) {    var jsResult = result.get().intValue();    if (jsResult != 2) {        print("Incorrect result from js, expected 1 + 1 = 2, but got " + jsResult);        miscalculations += 1;    }}executor.awaitTermination(1, TimeUnit.SECONDS);executor.shutdownNow();print("Overall: " + miscalculations + " wrong values for 1 + 1."); Works as expected; Overall: 0 wrong values for 1 + 1.

Tobias Schlotte asked the question (via twitter @tobsch), "Where is thread-safety on your agenda for Nashorn?"  The quick answer is that multithreading is very high on the list, but MT-safety is a...

Personal

Nashorn and Lambda, What the Hey!

Yesterday, Brian Goetz (Lambda architect) suggested that I produce an example of Lambda being used from Nashorn.  Since, I've been heads down in Nashorn, I really haven't played with Lambda that much.  After looking at some examples from Stuart Marks,  I figured, what the hey, it doesn't look that hard.  Details of the Lambda APIs are available at JDK 8 b92 API . Many constructs are familiar to JavaScript developers.  The main things to note; where you can use a Lambda you can use a JavaScript function JavaScript arrays need to be converted to Java collections JavaScript syntax requires the '.' end a phrase, not start one (forces continuation) Other than that, the JavaScript source and Java source looks very much the same. #!/usr/bin/env jjs -scriptingvar copyright = <<<EOS;/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * *   - Redistributions of source code must retain the above copyright *     notice, this list of conditions and the following disclaimer. * *   - Redistributions in binary form must reproduce the above copyright *     notice, this list of conditions and the following disclaimer in the *     documentation and/or other materials provided with the distribution. * *   - Neither the name of Oracle nor the names of its *     contributors may be used to endorse or promote products derived *     from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */EOSvar Collectors = java.util.stream.Collectors;// Break the copyright into tokens.var tokens = copyright.split(/\s+/);// Convert to ArrayList.var list = new java.util.ArrayList();tokens.map(function(e) list.add(e));// The JavaScript collection for the result.var result = [];// Parallelize some of the activity.list.parallelStream().    // Select only words.    filter(function(t) t.match(/^[A-Za-z]+$/)).    // Make case comparable.    map(function(t) t.toLowerCase()).    // Fold duplicates.    collect(Collectors.groupingBy(function(t) t)).    // Move results to JavaScript collection.    forEach(function(t) result.push(t));// Sort the result.result.sort();print(result); The result; a,above,advised,all,and,any,are,arising,be,binary,business,but,by,caused,code,conditions,consequential,contributors,copyright,damages,derived,disclaimer,documentation,endorse,even,event,express,fitness,following,for,form,from,goods,holders,however,if,implied,in,is,its,liable,limited,list,loss,materials,may,merchantability,must,name,names,negligence,neither,no,nor,not,of,on,or,oracle,other,out,owner,particular,permitted,possibility,prior,procurement,products,promote,provided,purpose,redistribution,redistributions,reproduce,retain,rights,shall,software,source,specific,strict,substitute,such,that,the,theory,this,to,tort,use,used,warranties,way,whether,with,without,written

Yesterday, Brian Goetz (Lambda architect) suggested that I produce an example of Lambda being used from Nashorn.  Since, I've been heads down in Nashorn, I really haven't played with Lambda that much....

Personal

Repost: Taming the Nashorn (first impressions)...

[This is a repost of an article written by our friend @hansolo_ with his permission.  The original article is at  Taming the Nashorn (first impressions)...] Hi there, JavaScript is everywhere these days and so it is also part of JDK8 dev. prev. with Project Nashorn which is a lightweight high-performance JavaScript runtime engine. Because I never used Rhino (which is in principle the same just older and slower) I had no  idea how to use it and for what reason. After I met Marcus Lagergren (@lagergren) at JAX in Mainz (Germany), Geecon in Krakow (Poland) and at Java Forum in Malmö (Sweden) I decided that I have to take a look at the Nashorn to get an idea on how to use it. Of course I'm especially interested on how to use Nashorn in combination with JavaFX. Lucky me that Nashorn is part of the weekly developer previews of JDK8 since a few weeks ago and because Jim Laskey (@wickund) blogged about this use case I was able to start with it yesterday. After some starting problems I slowly begin to understand and would like to share it with you... First of all I would like to see how I could use Nashorn with JavaScript in combination with my controls, so the idea is to visualize a Lcd control of my Enzo library with Nashorn. For the following example you'll need the jdk8 developer preview (grab it here) and a current version of my Enzo library (grab it here). And with a shell and a text editor you are good to go...really nice :) So first of all we need to create a JavaScript file that should create a JavaFX application which should show the Lcd control and set's the value of the Lcd control every 3 seconds to a random value between 0 and 100. This is the JavaFX code to realize that... import eu.hansolo.enzo.lcd.Lcd;import eu.hansolo.enzo.lcd.LcdBuilder;import javafx.animation.AnimationTimer;import javafx.application.Application;import javafx.geometry.Insets;import javafx.scene.Scene;import javafx.scene.layout.StackPane;import javafx.stage.Stage;import java.util.Random;public class EnzoFX extends Application {  private Lcd            lcd;  private Random         random;  private long           lastTimerCall;  private double         charge;  private AnimationTimer timer;  @Override public void init() {    // Initialize the AnimationTimer    random        = new Random();    lastTimerCall = System.nanoTime();    charge        = 0;    timer         = new AnimationTimer() {      @Override public void handle(long now) {        if (now > lastTimerCall + 3_000_000_000l) {          lcd.setValue(random.nextDouble() * 100);          lcd.setTrend(Lcd.Trend.values()[random.nextInt(5)]);          charge += 0.02;          if (charge > 1.0) charge = 0.0;          lcd.setBatteryCharge(charge);          lastTimerCall = now;          System.out.println(lcd.getValue());        }      }    };    // Initialize the Enzo Lcd control    lcd = LcdBuilder.create()                    .styleClass(Lcd.STYLE_CLASS_STANDARD_GREEN)                    .title("Room Temp")                    .unit("°C")                    .decimals(2)                    .minMeasuredValueDecimals(2)                    .maxMeasuredValueDecimals(2)                    .unitVisible(true)                    .batteryVisible(true)                    .alarmVisible(true)                    .minMeasuredValueVisible(true)                    .maxMeasuredValueVisible(true)                    .lowerRightTextVisible(true)                    .formerValueVisible(true)                    .trendVisible(true)                    .lowerRightText("Info")                    .valueAnimationEnabled(true)                    .foregroundShadowVisible(true)                    .crystalOverlayVisible(true)                    .build();  }  @Override public void start(Stage stage) {    // Prepare stage and add controls    StackPane root = new StackPane();    root.setPadding(new Insets(10, 10, 10, 10));    root.getChildren().add(lcd);    stage.setTitle("Enzo in JavaFX");    stage.setScene(new Scene(root, 528, 192));    stage.show();    // Start the timer    timer.start();  }  public static void main(String[] args) {    launch(args);  }} Ok, so now we know how to achieve this in JavaFX but now let's take a look at the JavaScript code that leads to the same result. Here you go... var System         = java.lang.System;var Random         = java.util.Random;var StackPane      = javafx.scene.layout.StackPane;var Scene          = javafx.scene.Scene;var Insets         = javafx.geometry.Insets;var AnimationTimer = javafx.animation.AnimationTimer;var Lcd            = Packages.eu.hansolo.enzo.lcd.Lcd;// Initialize the AnimationTimervar random        = new Random();var lastTimerCall = System.nanoTime();var charge        = 0;var timer         = new AnimationTimer() {    handle: function(now) {        if (now > lastTimerCall + 3000000000) {            lcd.value = random.nextDouble() * 100;            lcd.trend = Lcd.Trend.values()[random.nextInt(5)];            charge += 0.02;            if (charge > 1.0) charge = 0.0;            lcd.batteryCharge = charge;            lastTimerCall = now;            print(lcd.value);        }    }}// Initialize the Enzo Lcd controlvar lcd   = new Lcd();lcd.styleClass.add(Lcd.STYLE_CLASS_STANDARD_GREEN);lcd.title                    = "Room Temp";lcd.unit                     = "°C";lcd.decimals                 = 2;lcd.minMeasuredValueDecimals = 2;lcd.maxMeasuredValueDecimals = 2;lcd.unitVisible              = true;lcd.batteryVisible           = true;lcd.alarmVisible             = true;lcd.minMeasuredValueVisible  = true;lcd.maxMeasuredValueVisible  = true;lcd.lowerRightTextVisible    = true;lcd.formerValueVisible       = true;lcd.trendVisible             = true;lcd.lowerRightText           = "Info";lcd.valueAnimationEnabled    = true;lcd.foregroundShadowVisible  = true;lcd.crystalOverlayVisible    = true;// Prepare the stage and add controlsvar root     = new StackPane();root.padding = new Insets(10, 10, 10, 10);root.children.add(lcd);$STAGE.title = "Enzo with Nashorn";$STAGE.scene = new Scene(root, 528, 192);$STAGE.show();// Start the timertimer.start(); The JavaScript code that I saved to a file "javafx.js" looks not that different from the JavaFX code except...it's JavaScript...and the resulting application will look like this... You might ask yourself how you could run this code and here is the answer, all it takes is one call on the command line that looks like this: /PATH/TO/JDK/jdk1.8.0.jdk/Contents/Home/jre/bin/jjs-cp /PATH/TO/LIBRARY/Enzo.jar -fx /PATH/TO/JS-FILE/javafx.js Means you have to now the path to your jdk8 installation folder where you could find the jjs executable that is needed to start nashorn from the command line. In addition you have to add the Enzo.jar to the classpath so that you could use it within your JavaScript file and at last you have to call the JavaScript file with the -fx parameter which will start the application....BAM...that's all...sweet :) I've put the commandline in a bash script so that I could call it by simple calling the bash script instead of typing the whole line over and over again. If you start the javafx.js file you should see something like on this youtube video. Ok you might say where is the advantage of using JavaScript to run a JavaFX application...just think about not starting an IDE, not compiling and building a JavaFX application just to make a short test. Isn't it be much nicer to simply have a small JavaScript, edit it with your default text editor and run it with from the command line with one single call...I really like that for testing things. If you would like to know more about Nashorn you should definitely take a look at the Nashorn blog ,subscribe to the Nashorn mailing list and take a look at the Nashorn Wiki. At this point I would say THANK YOU to Jim Laskey and Marcus Lagergren which helped me to getting this stuff done!!! This is really a first test of using Nashorn with JavaFX but now that I know how to use it I will use more often...so stay tuned and keep coding...

[This is a repost of an article written by our friend @hansolo_ with his permission.  The original article is at  Taming the Nashorn (first impressions)...] Hi there, JavaScript is everywhere these days...

Personal

jjs -fx

So after some playing around and working with the JavaFX folks, I think we have a proposal for jjs that works with JavaFX.  The -fx flag on jjs will bootstrap scripts using a javafx.application.Application.  Thus, writing JavaFX scripts in Nashorn is very easy. The basic command line is; jjs -fx fxscript.js You can mix and match other jjs options like -scripting and -- ; jjs -fx -scripting fxscript.js -- my script args The content of the script follows some of the examples I've posted before.  The script may optionally contain JavaFX init, start and/or stop functions.  What is new, is that you can leave them behind and just straight script.  The original hello world example; var Button = Java.type("javafx.scene.control.Button");var StackPane = Java.type("javafx.scene.layout.StackPane");var Scene = Java.type("javafx.scene.Scene");function start(stage) { stage.title = "Hello World!"; var button = new Button(); button.text = "Say 'Hello World'"; button.onAction = function() print("Hello World!"); var root = new StackPane(); root.children.add(button); stage.scene = new Scene(root, 300, 250); stage.show();} becomes; var Button = Java.type("javafx.scene.control.Button");var StackPane = Java.type("javafx.scene.layout.StackPane");var Scene = Java.type("javafx.scene.Scene");$STAGE.title = "Hello World!";var button = new Button();button.text = "Say 'Hello World'";button.onAction = function() print("Hello World!");var root = new StackPane();root.children.add(button);$STAGE.scene = new Scene(root, 300, 250);$STAGE.show(); where the stage is now a global var $STAGE (instead of the start function argument.) Also for convenience, we've predefined includes for all of the JavaFX classes.  I would recommend using only the classes you need (only needed for new and for static field access), but for prototyping having includes really helps things move along. The hello world example can then be rewritten as; load("fx:base.js");load("fx:controls.js");load("fx:graphics.js");$STAGE.title = "Hello World!";var button = new Button();button.text = "Say 'Hello World'";button.onAction = function() print("Hello World!");var root = new StackPane();root.children.add(button);$STAGE.scene = new Scene(root, 300, 250);$STAGE.show(); The complete set of includes are as follows; fx:base.jsjavafx.stage.Stagejavafx.scene.Scenejavafx.scene.Groupjavafx/beansjavafx/collectionsjavafx/eventsjavafx/utilfx:graphics.jsjavafx/animationjavafx/applicationjavafx/concurrentjavafx/cssjavafx/geometryjavafx/printjavafx/scenejavafx/stagefx:controls.jsjavafx/scene/chartjavafx/scene/controlfx:fxml.jsjavafx/fxmlfx:web.jsjavafx/scene/webfx:media.jsjavafx/scene/mediafx:swing.jsjavafx/embed/swingfx:swt.jsjavafx/embed/swt Here are a couple more examples; // fx3d.jsload("fx:base.js");load("fx:controls.js");load("fx:graphics.js");var material = new PhongMaterial();material.diffuseColor = Color.LIGHTGREEN;material.specularColor = Color.rgb(30, 30, 30);var meshView = Java.to([ new Box(200, 200, 200), new Sphere(100), new Cylinder(100, 200)], "javafx.scene.shape.Shape3D[]");for (var i = 0; i != 3; i++) { meshView[i].material = material; meshView[i].translateX = (i + 1) * 220; meshView[i].translateY = 500; meshView[i].translateZ = 20; meshView[i].drawMode = DrawMode.FILL; meshView[i].cullFace = CullFace.BACK;};var pointLight = new PointLight(Color.WHITE);pointLight.translateX = 800;pointLight.translateY = -200;pointLight.translateZ = -1000;var root = new Group(meshView);root.children.add(pointLight);var scene = new Scene(root, 800, 800, true);scene.fill = Color.rgb(127, 127, 127);scene.camera = new PerspectiveCamera(false);$STAGE.scene = scene;$STAGE.show(); // ColorfulCircles.jsload("fx:base.js");load("fx:controls.js");load("fx:graphics.js");var WIDTH = 500;var HEIGHT = 600;var animation;function setup(primaryStage) { var root = new Group(); primaryStage.resizable = false; var scene = new Scene(root, WIDTH, HEIGHT); scene.title = "Colourful Circles"; primaryStage.scene = scene; // create first list of circles var layer1 = new Group(); for(var i = 0; i < 15; i++) { var circle = new Circle(200, Color.web("white", 0.05)); circle.strokeType = StrokeType.OUTSIDE; circle.stroke = Color.web("white", 0.2); circle.strokeWidth = 4; layer1.children.add(circle); } // create second list of circles var layer2 = new Group(); for(var i = 0; i < 20; i++) { var circle = new Circle(70, Color.web("white", 0.05)); circle.strokeType = StrokeType.OUTSIDE; circle.stroke = Color.web("white", 0.1); circle.strokeWidth = 2; layer2.children.add(circle); } // create third list of circles var layer3 = new Group(); for(var i = 0; i < 10; i++) { var circle = new Circle(150, Color.web("white", 0.05)); circle.strokeType = StrokeType.OUTSIDE; circle.stroke = Color.web("white", 0.16); circle.strokeWidth = 4; layer3.children.add(circle); } // Set a blur effect on each layer layer1.effect = new BoxBlur(30, 30, 3); layer2.effect = new BoxBlur(2, 2, 2); layer3.effect = new BoxBlur(10, 10, 3); // create a rectangle size of window with colored gradient var colors = new Rectangle(WIDTH, HEIGHT, new LinearGradient(0, 1, 1, 0, true, CycleMethod.NO_CYCLE, new Stop(0, Color.web("#f8bd55")), new Stop(0.14, Color.web("#c0fe56")), new Stop(0.28, Color.web("#5dfbc1")), new Stop(0.43, Color.web("#64c2f8")), new Stop(0.57, Color.web("#be4af7")), new Stop(0.71, Color.web("#ed5fc2")), new Stop(0.85, Color.web("#ef504c")), new Stop(1, Color.web("#f2660f")))); colors.blendMode = BlendMode.OVERLAY; // create main content var group = new Group(new Rectangle(WIDTH, HEIGHT, Color.BLACK), layer1, layer2, layer3, colors); var clip = new Rectangle(WIDTH, HEIGHT); clip.smooth = false; group.clip = clip; root.children.add(group); // create list of all circles var allCircles = new java.util.ArrayList(); allCircles.addAll(layer1.children); allCircles.addAll(layer2.children); allCircles.addAll(layer3.children); // Create a animation to randomly move every circle in allCircles animation = new Timeline(); for each (var circle in allCircles) { animation.getKeyFrames().addAll( new KeyFrame(Duration.ZERO, // set start position at 0s new KeyValue(circle.translateXProperty(), Math.random() * WIDTH), new KeyValue(circle.translateYProperty(), Math.random() * HEIGHT)), new KeyFrame(new Duration(20000), // set end position at 20s new KeyValue(circle.translateXProperty(), Math.random() * WIDTH), new KeyValue(circle.translateYProperty(), Math.random() * HEIGHT)) ); } animation.autoReverse = true; animation.cycleCount = Animation.INDEFINITE;}function stop() { animation.stop();}function play() { animation.play();}function start(primaryStage) { setup(primaryStage); primaryStage.show(); play();}

So after some playing around and working with the JavaFX folks, I think we have a proposal for jjs that works with JavaFX.  The -fx flag on jjs will bootstrap scripts using...

Personal

HTTP Server Written In Nashorn

This is just a little "thinking outside the box" example. Node.js is hot and anyone who has used it knows there is a ton of applications possible. Some of Node.js features remind me of a tool kit I had, when I worked for another server company prior to Oracle. All my development was remote and had to run on remote servers. I hate typing and ssh/console was my only way in. So, I decided that I would create a little HTTP server on the remote end, to proxy all my routine repository, build and file editing tasks via a browser. This didn't take a lot of effort and was very flexible. There are many many HTTP server apps out there (many written in Java.) I could modify one of them, but I just wanted to prove to myself it could all be done in pure Nashorn. This is what I whipped up; #!/usr/bin/jjs -scripting#var Thread = java.lang.Thread;var ServerSocket = java.net.ServerSocket;var PrintWriter = java.io.PrintWriter;var InputStreamReader = java.io.InputStreamReader;var BufferedReader = java.io.BufferedReader;var FileInputStream = java.io.FileInputStream;var ByteArray = Java.type("byte[]");var PORT = 8080;var CRLF = "\r\n";var FOUROHFOUR = <<<EOD;<HTML> <HEAD> <TITLE>404 Not Found</TITLE> </HEAD> <BODY> <P>404 Not Found</P> </BODY></HTML>EODvar serverSocket = new ServerSocket(PORT);while (true) { var socket = serverSocket.accept(); try { var thread = new Thread(function() { httpRequestHandler(socket); }); thread.start(); Thread.sleep(100); } catch (e) { print(e); }}function httpRequestHandler(socket) { var out = socket.getOutputStream(); var output = new PrintWriter(out); var inReader = new InputStreamReader(socket.getInputStream(), 'utf-8'); var bufReader = new BufferedReader(inReader); var lines = readLines(bufReader); if (lines.length > 0) { var header = lines[0].split(/\b\s+/); if (header[0] == "GET") { var URI = header[1].split(/\?/); var path = String("./serverpages" + URI[0]); try { if (path.endsWith(".jjsp")) { var body = load(path); if (!body) throw "JJSP failed"; respond(output, "HTTP/1.0 200 OK", "text/html", body); } else { sendFile(output, out, path); } } catch (e) { respond(output, "HTTP/1.0 404 Not Found", "text/html", FOUROHFOUR); } } } output.flush(); bufReader.close(); socket.close();}function respond(output, status, type, body) { sendBytes(output, status + CRLF); sendBytes(output, "Server: Simple Nashorn HTTP Server" + CRLF); sendBytes(output, "Content-type: ${type}" + CRLF); sendBytes(output, "Content-Length: ${body.length}" + CRLF); sendBytes(output, CRLF); sendBytes(output, body);}function contentType(path) { if (path.endsWith(".htm") || path.endsWith(".html")) { return "text/html"; } else if (path.endsWith(".txt")) { return "text/text"; } else if (path.endsWith(".jpg") || path.endsWith(".jpeg")) { return "image/jpeg"; } else if (path.endsWith(".gif")) { return "image/gif"; } else { return "application/octet-stream"; }}function readLines(bufReader) { var lines = []; try { var line; while (line = bufReader.readLine()) { lines.push(line); } } catch (e) { } return lines;}function sendBytes(output, line) { output.write(String(line));}function sendFile(output, out, path) { var file = new FileInputStream(path); var type = contentType(path); sendBytes(output, "HTTP/1.0 200 OK" + CRLF); sendBytes(output, "Server: Simple Nashorn HTTP Server" + CRLF); sendBytes(output, "Content-type: ${contentType(path)}" + CRLF); sendBytes(output, "Content-Length: ${file.available()}" + CRLF); sendBytes(output, CRLF); output.flush(); var buffer = new ByteArray(1024); var bytes = 0; while ((bytes = file.read(buffer)) != -1) { out.write(buffer, 0, bytes); }} Short and sweet, all done in 84 lines of JavaScript. I could have handled more of the http spec, but this will do as POC. You can use this server to download html, jpeg et al, but in the midst of this server code you will see the following lines; if (path.endsWith(".jjsp")) { var body = load(path); if (!body) throw "JJSP failed"; respond(output, "HTTP/1.0 200 OK", "text/html", body); This reads as, if the requested file ends with .jjsp, then evaluate the content as JavaScript and use the final result as an HTML response. The following is a sample ".jjsp" file the I used for testing. #!/usr/bin/jjs -scripting#var colours = { java: "BLUE", js: "RED", css: "GREEN", html: "ORANGE"};function colorize(file) { var suffix = file.substr(file.lastIndexOf(".") + 1); var colour = colours[suffix]; if (colour) { return "<FONT COLOR='${colour}'>${file}</FONT>"; } return file;}var files = `ls`.trim().split("\n");files = files.map(colorize);files = files.map(function(file) "${file}<BR />");files = files.join("\n");var HTML = <<<EOD;<HTML> <HEAD> <TITLE>Simple HTML</TITLE> </HEAD> <BODY> <img width="256" height="138" src="rrr256x138.jpg" alt="rrr256x138" /> <BR /> <FONT FACE="Courier New" SIZE="2"> ${files} </FONT> </BODY></HTML>EODHTML; Note that both the JavaScript and HTML content of the .jjsp file is very easy to read.  This particular script catalogs a directory (ls) and colourizes the result depending on the file extension. In my case the result was; FX3D.jsHTML.jsHelloWorld.javaServerServer.zipSimpleHTTPServer.jsTest.classTest.javaText.jscanvas.jscolourfulcircles.jshellofxml.jshelloworld1.jshelloworld2.jshttp.jsintrospect.jsjogllanguages.csslanguages1.jslanguages2.jsscript.jsscripting.fxmlserverpagesslow1.jssuspect.jstest.jsthreading.jstrends.csstrends.jstwitter4j-core-3.0.1.jartwitter4j.properties Lots of possibilities.

This is just a little "thinking outside the box" example. Node.js is hot and anyone who has used it knows there is a ton of applications possible. Some of Node.js features remind me of a tool kit I...

Personal

Keynoting at JAX2013

I have the honor to be keynoting JAX 2013 on April 25. The Keynote is called "Project Nashorn - and why dynamic languages on the JVM really matter". Exciting enough, surely, but it's not just "dynamic languages on the JVM", as it says in the title, that are becoming more and more important - I will show that it's really "languages on the JVM" that matters too, the JVM has its future as a polyglot runtime regardless of paradigm. Also, we are going to look at Project Nashorn as one good example of the future of the JVM. There will also be a deep dive session about Nashorn during the conference, currently scheduled later the same day.  The abstract is "More languages than Java have been implemented on top of the JVM since the very beginning in 1995. The platform independent bytecode format has always made it possible to compile anything and have it run on the JVM with the same write once/run anywhere benefits. Lately we are seeing an explosion in JVM languages. This is partly because of Java 7, which is the first giant leap in turning the JVM from a Java runtime to a true dynamic polyglot runtime. This keynote explains why language implementations, especially dynamic languages, are more feasible to implement on top of the JVM than ever and how the JVM can execute them with high performance. As an example, we will go into detail of the Nashorn project, Oracle's new JavaScript runtime, part of the JDK as of Java 8." I'll see you there, and hopefully the spring weather in in Rhineland-Palatinate beats the spring weather in Stockholm. Probably not much of a competition, really. Regards, Marcus 

I have the honor to be keynoting JAX 2013 on April 25. The Keynote is called "Project Nashorn - and why dynamic languages on the JVM really matter". Exciting enough, surely, but it's not just...

Personal

To Shell Or Not To Shell

I find myself facing a dilemma today. How should I use Java FX from Nashorn? So far, I have two approaches I could use, but each comes with some issues. Some background first. Java FX, even though ships with the JDK, is on a different build cycle and has dependencies on elements of the JDK. This arraignment limits Nashorn, which is part of the JDK, from actually having dependencies into Java FX. But, there is a dependency requirement to implement a Java FX application. Java FX applications begin with a subclass instance of javafx.application.Application. Therefore, whatever choice is made, it has to be independent of the JDK (at some point should be part of Java FX.) The first approach, in general terms, is the easiest to use. It involves using a predefined shell that is similar to jjs but handles the overrides of Application methods init, start and finish. The source of this shell is currently checked into the Nashorn repo under nashorn/tools/fxshell.  /* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation.  Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */package jdk.nashorn.tools;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.InputStreamReader;import java.io.UnsupportedEncodingException;import java.util.ArrayList;import java.util.List;import java.util.Map;import java.util.Set;import java.util.logging.Level;import java.util.logging.Logger;import javafx.application.Application;import javafx.stage.Stage;import javax.script.Invocable;import javax.script.ScriptContext;import javax.script.ScriptEngine;import javax.script.ScriptEngineFactory;import javax.script.ScriptEngineManager;import javax.script.ScriptException;import jdk.nashorn.api.scripting.NashornScriptEngineFactory;/** * This shell is designed to launch a JavaFX application written in Nashorn JavaScript. */public class FXShell extends Application {    /**     * Script engine manager to search.     */    private ScriptEngineManager manager;    /**     * Nashorn script engine factory.     */    private NashornScriptEngineFactory factory;    /**     * Main instance of Nashorn script engine.     */    private ScriptEngine engine;    /**     * Needed so that the FX launcher can create an instance of this class.     */    public FXShell() {    }    /**     * Main entry point. Never actually used.     * @param args Command line arguments.     */    public static void main(String[] args) {        launch(args);    }    /*     * Application overrides.     */    @Override    public void init() throws Exception {        // Script engine manager to search.        this.manager = new ScriptEngineManager();        // Locate the Nashorn script engine factory.  Needed for passing arguments.        for (ScriptEngineFactory engineFactory : this.manager.getEngineFactories()) {             if (engineFactory.getEngineName().equals("Oracle Nashorn") && engineFactory instanceof NashornScriptEngineFactory) {                this.factory = (NashornScriptEngineFactory)engineFactory;            }        }        // If none located.        if (this.factory == null) {            System.err.println("Nashorn script engine not available");            System.exit(1);        }        // Get the command line and JNLP parameters.        final Parameters parameters = getParameters();        // To collect the script paths and command line arguments.        final List<String> paths = new ArrayList<>();        final List<String> args = new ArrayList<>();        // Pull out relevant JNLP named parameters.        final Map<String, String> named = parameters.getNamed();        for (Map.Entry<String, String> entry : named.entrySet()) {            final String key = entry.getKey();            final String value = entry.getValue();            if ((key.equals("cp") || key.equals("classpath")) && value != null) {                args.add("-classpath");                args.add(value);            } else if (key.equals("source") && value != null && value.toLowerCase().endsWith(".js")) {                paths.add(value);            }        }        // Pull out relevant command line arguments.        boolean addNextArg = false;        boolean addAllArgs = false;        for (String parameter : parameters.getUnnamed()) {            if (addAllArgs || addNextArg) {                args.add(parameter);                addNextArg = false;            } else if (parameter.equals("--")) {                args.add(parameter);                addAllArgs = true;            } else if (parameter.startsWith("-")) {                args.add(parameter);                addNextArg = parameter.equals("-cp") || parameter.equals("-classpath");            } else if (parameter.toLowerCase().endsWith(".js")) {                paths.add(parameter);            }        }        // Create a Nashorn script engine with specified arguments.        engine = factory.getScriptEngine(args.toArray(new String[args.size()]));        // Load initial scripts.        for (String path : paths) {            load(path);        }        // Invoke users JavaScript init function if present.        try {            ((Invocable) engine).invokeFunction("init");        } catch (NoSuchMethodException ex) {            // Presence of init is optional.        }    }    @Override    public void start(Stage stage) throws Exception {        // Invoke users JavaScript start function if present.        try {            ((Invocable) engine).invokeFunction("start", stage);        } catch (NoSuchMethodException ex) {            // Presence of start is optional.        }    }    @Override    public void stop() throws Exception {        // Invoke users JavaScript stop function if present.        try {            ((Invocable) engine).invokeFunction("stop");        } catch (NoSuchMethodException ex) {            // Presence of stop is optional.        }    }    /**     * Load and evaluate the specified JavaScript file.     *     * @param path Path to UTF-8 encoded JavaScript file.     *     * @return Last evaluation result (discarded.)     */    private Object load(String path) {        try {            FileInputStream file = new FileInputStream(path);            InputStreamReader input = new InputStreamReader(file, "UTF-8");            return engine.eval(input);        } catch (FileNotFoundException | UnsupportedEncodingException | ScriptException ex) {            ex.printStackTrace();        }        return null;    }} To built it you can (cd make ; ant build-fxshell) from within the nashorn repo. The result is in nashorn/dist/nashornfx.jar. To use just java -cp dist/nashornfx.jar jdk.nashorn.tools.FXShell <myscript.js> … . For the JDK savvy you can create a launcher by modelling an entry in jdk/makefiles/CompileLaunchers.gmk after the jjs entry. The big plus for this approach is that it handles almost everything for you. You just have to define a start method with a few class declarations and that is it. The down side is that ideally you would want this implemented as a jjsfx launcher embedded in the JDK. But then we run into the chicken and egg dependency on Java FX. The second approach only relies on jjs. With a recent modification to Java.extend (currently only in the nashorn forest), it is now possible to subclass javafx.application.Application. and thus launch from within a script. This sounds like all pluses except for the fact you have to wrap your brain around the fact that FX applications take control of execution and has static init dependencies that require careful use in your program. I prototyped a simple fxinit.js include that shows how we could implement such a scheme. Ignore the implementation quirks. It's simpler than it seems. GLOBAL = this;javafx = Packages.javafx;com.sun.javafx.application.LauncherImpl.launchApplication((Java.extend(javafx.application.Application, {    init: function() {        // FX packages and classes must be defined here because they may not be        // viable until launch time.        Stage          = javafx.stage.Stage;        scene          = javafx.scene;        Scene          = scene.Scene;        Group          = scene.Group;        chart          = scene.chart;        control        = scene.control;        Button         = control.Button;        StackPane      = scene.layout.StackPane;        FXCollections  = javafx.collections.FXCollections;        ObservableList = javafx.collections.ObservableList;        Chart          = chart.Chart;        CategoryAxis   = chart.CategoryAxis;        NumberAxis     = chart.NumberAxis;        BarChart       = chart.BarChart;        XYChart        = chart.XYChart;        Series         = chart.XYChart$Series;        Data           = chart.XYChart$Data;        TreeView       = control.TreeView;        TreeItem       = control.TreeItem;        if (GLOBAL.init) {            init();        }    },    start: function(stage) {        if (GLOBAL.start) {            start(stage);        }    },    stop: function() {        if (GLOBAL.stop) {            stop();        }    }})).class, new (Java.type("java.lang.String[]"))(0)); How you would use it is straight forward. Here is the FX HelloWorld.java example written for Nashorn; function start(stage) {    stage.title = "Hello World!";    var button = new Button();    button.text = "Say 'Hello World'";    button.onAction = function() print("Hello World!");    var root = new StackPane();    root.children.add(button);    stage.scene = new Scene(root, 300, 250);    stage.show();}load("fxinit.js"); Note the placement of the load("fxinit.js");. Since this is where the FX Application takes control, anything after the load will not complete until the application exits. One other quirk. Since you can not static init some of Java FX classes until after the application launches. You can not globally (script level) declare any uses of these classes. Uses can be embedded in methods used after the launch, but no where else. This is a style cramp for me. There is a third approach I have been considering. It involves some argument trickery, but may play out as a better way of doing things. Imagine jjs fxinit.js -- myscript.js -- my scripts args . The -- indicates the beginning of arguments passed to the script. The notion here is that fxinit.js launches the application and then evals myscript.js. This cleanses my script of any quirks, while putting the onus on getting the command line right. Thoughts?

I find myself facing a dilemma today. How should I use Java FX from Nashorn? So far, I have two approaches I could use, but each comes with some issues. Some background first. Java FX, even though...

Personal

CSI: Nashorn - Shell Scripting in JavaScript, WAT?

I was reading the article in The Register with the heading GNOME project picks JavaScript as sole app dev language, when I remembered that we haven't said much about shell scripting using Nashorn. This may seem sacrilegious to both JavaScripters and shell scripters, but think about it. The features that make JavaScript good for browser support are similar to what is needed for shell scripting. Plus you have access to all those Java libraries, and JavaFX, wink, wink, nudge, nudge (think visualization.) There is an option (-scripting) in the Nashorn engine that extends the JavaScript language with features that make JavaScript very useful for writing shell scripts (even shebang scripts.) These features include; function $EXEC("command args", "input"); that executes a command string as a separate process with handling of stdin, stdout $OUT, stderr $ERR and exit code $EXIT, an exec string `command args` syntax for simple execution, edit strings for embedding expressions in a double quote or exec strings, single quote strings are always unedited, here strings, with editing for multi-line strings, <<TAG…TAG for include end of line and <<<TAG…TAG for exclude end of line, environment variable $ENV for access to shell variables, access to command line arguments with $ARG, exit(code) and quit() for terminating the script, and, # style comments I will submit more scripting examples in the future, but let's start off with the following teaser. Fingerprinting Source Code  Often enough, when we are working on Nashorn, we run across some source that is unfamiliar and we would like to discuss the code with the original author. This is sometimes called blaming, but really, it's just about getting up to speed on the code without a lot of pain and suffering.  Nashorn is stored in a Mercurial repository on openjdk.java.net. Mercurial already supports basic change set annotation of source, but sometimes you just want to cut to the chase and get the full details of a specific source line. The following shell script, suspect, takes a root source file name and a line number, and then displays the change set information associated with the source line. #!/usr/bin/jjs# This script hunts down the change set associated with a# source file and a line number.#// Report proper command usage.function usage() {    error(<<EOS);usage: suspect javaFileName lineNumber    javaFileName - name of file in local mercurial repository    lineNumber   - file line numberEOS}// Report on stderr.function error(message) {    java.lang.System.err.print(message);    exit(1);}// Provide meaningful names for arguments.var fileName   = $ARG[0];var lineNumber = $ARG[1];// If arguments are missing, report proper usage.if (!fileName || !lineNumber) {    usage();}// Add .java if not present.if (!fileName.endsWith(".java")) {    fileName += ".java";}// Search for matching files and convert the result to an array of paths.var where = `find . -name ${fileName}`.trim().split("\n");// If not foundif (where == "") {    error("File ${fileName} is not in the current repository.\n");} else if (where.length != 1) {    error("File ${fileName} found in multiple locations\n${where.join('\n')}\n");}// Get the source annotated with change set number.var annotated = `hg annotate -c ${where}`.split("\n");// Get the target source line.var line = annotated[lineNumber];// Make sure the line exists.if (!line) {    error("File ${fileName} does not contain line number ${lineNumber}\n");}// Extract the revision number.var revision = line.substring(0, 12);// Report the change set information from the revision number.print(`hg log -r ${revision}`); If I wanted to find out about the changed set for line 63 of SpillProperty.java, >> suspect SpillProperty 63changeset:   2:da1e581c933buser:        jlaskeydate:        Fri Dec 21 16:36:24 2012 -0400summary:     8005403: Open-source Nashorn This is just the beginning.

I was reading the article in The Register with the heading GNOME project picks JavaScript as sole app dev language, when I remembered that we haven't said much about shell scripting using Nashorn. This...

Personal

Nashorn in the Twitterverse, Continued

After doing the Twitter example, it seemed reasonable to try graphing the result with JavaFX.  At this time the Nashorn project doesn't have a JavaFX shell, so we have to go through some hoops to create an JavaFX application.  I thought showing you some of those hoops might give you some idea about what you can do mixing Nashorn and Java (we'll add a JavaFX shell to the todo list.) First, let's look at the meat of the application.  Here is the repackaged version of the original twitter example. var twitter4j      = Packages.twitter4j; var TwitterFactory = twitter4j.TwitterFactory; var Query          = twitter4j.Query; function getTrendingData() {     var twitter = new TwitterFactory().instance;     var query   = new Query("nashorn OR nashornjs");     query.since("2012-11-21");     query.count = 100;     var data = {};     do {         var result = twitter.search(query);         var tweets = result.tweets;         for each (var tweet in tweets) {             var date = tweet.createdAt;             var key = (1900 + date.year) + "/" +                       (1 + date.month) + "/" +                       date.date;             data[key] = (data[key] || 0) + 1;         }     } while (query = result.nextQuery());     return data; } Instead of just printing out tweets, getTrendingData tallies "tweets per date" during the sample period (since "2012-11-21", the date "New Project: Nashorn" was posted.)   getTrendingData then returns the resulting tally object. Next, use JavaFX BarChart to display that data. var javafx         = Packages.javafx; var Stage          = javafx.stage.Stage var Scene          = javafx.scene.Scene; var Group          = javafx.scene.Group; var Chart          = javafx.scene.chart.Chart; var FXCollections  = javafx.collections.FXCollections; var ObservableList = javafx.collections.ObservableList; var CategoryAxis   = javafx.scene.chart.CategoryAxis; var NumberAxis     = javafx.scene.chart.NumberAxis; var BarChart       = javafx.scene.chart.BarChart; var XYChart        = javafx.scene.chart.XYChart; var Series         = javafx.scene.chart.XYChart.Series; var Data           = javafx.scene.chart.XYChart.Data; function graph(stage, data) {     var root = new Group();     stage.scene = new Scene(root);     var dates = Object.keys(data);     var xAxis = new CategoryAxis();     xAxis.categories = FXCollections.observableArrayList(dates);     var yAxis = new NumberAxis("Tweets", 0.0, 200.0, 50.0);     var series = FXCollections.observableArrayList();     for (var date in data) {         series.add(new Data(date, data[date]));     }     var tweets = new Series("Tweets", series);     var barChartData = FXCollections.observableArrayList(tweets);     var chart = new BarChart(xAxis, yAxis, barChartData, 25.0);     root.children.add(chart); } I should point out that there is a lot of subtlety in this sample.  For example; stage.scene = new Scene(root) is equivalent to stage.setScene(new Scene(root)). If Nashorn can't find a property (scene), then it searches (via Dynalink) for the Java Beans equivalent (setScene.)  Also note, that Nashorn is magically handling the generic class FXCollections.  Finally,  with the call to observableArrayList(dates), Nashorn is automatically converting the JavaScript array dates to a Java collection.  It really is hard to identify which objects are JavaScript and which are Java.  Does it really matter? Okay, with the meat out of the way, let's talk about the hoops. When working with JavaFX, you start with a main subclass of javafx.application.Application.  This class handles the initialization of the JavaFX libraries and the event processing.  This is what I used for this example; import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import javafx.application.Application;import javafx.stage.Stage;import javax.script.ScriptEngine;import javax.script.ScriptEngineManager;import javax.script.ScriptException;public class TrendingMain extends Application { private static final ScriptEngineManager MANAGER = new ScriptEngineManager(); private final ScriptEngine engine = MANAGER.getEngineByName("nashorn"); private Trending trending; public static void main(String[] args) { launch(args); } @Override public void start(Stage stage) throws Exception { trending = (Trending) load("Trending.js"); trending.start(stage); } @Override public void stop() throws Exception { trending.stop(); } private Object load(String script) throws IOException, ScriptException { try (final InputStream is = TrendingMain.class.getResourceAsStream(script)) { return engine.eval(new InputStreamReader(is, "utf-8")); } }} To initialize Nashorn, we use JSR-223's javax.script.  private static final ScriptEngineManager MANAGER = new ScriptEngineManager(); private final ScriptEngine engine = MANAGER.getEngineByName("nashorn"); This code sets up an instance of the Nashorn engine for evaluating scripts. The  load method reads a script into memory and then gets engine to eval that script.  Note, that load also returns the result of the eval. Now for the fun part.  There are several different approaches we could use to communicate between the Java main and the script.  In this example we'll use a Java interface.  The JavaFX main needs to do at least start and stop, so the following will suffice as an interface; public interface Trending {     public void start(Stage stage) throws Exception;     public void stop() throws Exception; } At the end of the example's script we add; function newTrending() {     return new Packages.Trending() {         start: function(stage) {             var data = getTrendingData();             graph(stage, data);             stage.show();         },         stop: function() {         }     } } newTrending(); which instantiates a new subclass instance of Trending and overrides the start and stop methods.  The result of this function call is what is returned to main via the eval. trending = (Trending) load("Trending.js"); To recap, the script Trending.js contains functions getTrendingData, graph and newTrending, plus the call at the end to newTrending.  Back in the Java code, we cast the result of the eval (call to newTrending) to Trending, thus, we end up with an object that we can then use to call back into the script.  trending.start(stage); Voila. 

After doing the Twitter example, it seemed reasonable to try graphing the result with JavaFX.  At this time the Nashorn project doesn't have a JavaFX shell, so we have to go through some hoops to...

Personal

Nashorn in the Twitterverse

I have been following how often Nashorn has been showing up on the net.  Nashorn got a burst of tweets when we announced Project Nashorn and I was curious how Nashorn was trending per day, maybe graph the result.  Counting tweets manually seemed mindless, so why not write a program to do the same. This is where Nashorn + Java came shining through.  There is a very nice Java library out there called Twitter4J https://github.com/yusuke/twitter4j that handles all things Twitter.  After running bin/getAccessToken.sh to get a twitter4j.properties file with personal authorization, all I had to do to run my simple exploratory app was; nashorn -cp $TWITTER4J/twitter4j-core-3.0.1.jar GetHomeTimeline.js The content of GetHomeTimeline.js is as follows; var twitter4j      = Packages.twitter4j;var TwitterFactory = twitter4j.TwitterFactory;var Query          = twitter4j.Query;var twitter = new TwitterFactory().instance;var query   = new Query("nashorn OR nashornjs");query.count = 100;do {    var result = twitter.search(query);    var tweets = result.tweets;    for each (tweet in tweets) {        print("@" + tweet.user.screenName + "\t" + tweet.text);    }} while (query = result.nextQuery()); How easy was that?  Now to hook it up to the JavaFX graphing library... 

I have been following how often Nashorn has been showing up on the net.  Nashorn got a burst of tweets when we announced Project Nashorn and I was curious how Nashorn was trending per day, maybe graph...

Personal

Welcome To The Nashorn Blog

Welcome to all.  Time to break the ice and instantiate The Nashorn Blog.  I hope to contribute routinely, but we are very busy, at this point, preparing for the next development milestone and, of course, getting ready for open source. So, if there are long gaps between postings please forgive. We're just coming back from JavaOne and are stoked by the positive response to all the Nashorn sessions. It was great for the team to have the front and centre slide from Georges Saab early in the keynote. It seems we have support coming from all directions. Most of the session videos are posted. Check out the links. Nashorn: Optimizing JavaScript and Dynamic Language Execution on the JVM. Unfortunately, Marcus - the code generation juggernaut,  got saddled with the first session of the first day. Still, he had a decent turnout. The talk focused on issues relating to optimizations we did to get good performance from the JVM. Much yet to be done but looking good. Nashorn: JavaScript on the JVM. This was the main talk about Nashorn. I delivered the little bit of this and a little bit of that session with an overview, a follow up on the open source announcement, a run through a few of the Nashorn features and some demos. The room was SRO, about 250±. High points: Sam Pullara, from Twitter, came forward to describe how painless it was to get Mustache.js up and running (20x over Rhino), and,  John Ceccarelli, from NetBeans came forward to describe how Nashorn has become an integral part of Netbeans. A healthy Q & A at the end was very encouraging. Meet the Nashorn JavaScript Team. Michel, Attila, Marcus and myself hosted a Q & A. There was only a handful of people in the room (we assume it was because of a conflicting session ;-) .) Most of the questions centred around Node.jar, which leads me to believe, Nashorn + Node.jar is what has the most interest. Akhil, Mr. Node.jar, sitting in the audience, fielded the Node.jar questions. Nashorn, Node, and Java Persistence. Doug Clarke, Akhil and myself, discussed the title topics, followed by a lengthy Q & A (security had to hustle us out.) 80 or so in the room. Lots of questions about Node.jar. It was great to see Doug's use of Nashorn + JPA. Nashorn in action, with such elegance and grace. Putting the Metaobject Protocol to Work: Nashorn’s Java Bindings. Attila discussed how he applied Dynalink to Nashorn. Good turn out for this session as well. I have a feeling that once people discover and embrace this hidden gem, great things will happen for all languages running on the JVM. Finally, there were quite a few JavaOne sessions that focused on non-Java languages and their impact on the JVM. I've always believed that one's tool belt should carry a variety of programming languages, not just for domain/task applicability, but also to enhance your thinking and approaches to problem solving. For the most part, future blog entries will focus on 'how to' in Nashorn, but if you have any suggestions for topics you want discussed, please drop a line.  Cheers. 

Welcome to all.  Time to break the ice and instantiate The Nashorn Blog.  I hope to contribute routinely, but we are very busy, at this point, preparing for the next development milestone and, of...

Oracle

Integrated Cloud Applications & Platform Services