Tuesday Feb 10, 2015

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 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 driver
var query ="SELECT first_name, last_name from employees";
// Establish a JDBC connection
var connection = oracleDriver.defaultConnection();
// Prepare statement
var preparedStatement = connection.prepareStatement(query);
// execute Query
var resultSet = preparedStatement.executeQuery();
// display results
     while(resultSet.next()) {
     print(resultSet.getString(1) + "== " + resultSet.getString(2) + " " );
     }
// cleanup
resultSet.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 on
SQL>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 settings
Statement.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. 

Friday Feb 08, 2013

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 number
EOS
}

// 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 found
if (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 63
changeset:   2:da1e581c933b
user:        jlaskey
date:        Fri Dec 21 16:36:24 2012 -0400
summary:     8005403: Open-source Nashorn

This is just the beginning.

Friday Dec 21, 2012

Open For Business

After a lot of blood, sweat and tears, we finally got Nashorn into OpenJDK.

hg fclone http://hg.openjdk.java.net/nashorn/jdk8 nashorn~jdk8

or for just Nashorn

hg clone http://hg.openjdk.java.net/nashorn/jdk8/nashorn nashorn

 More details about the tools you'll need and using OpenJDK are at 

http://openjdk.java.net/guide/index.html

This is just the first drop and needs some larger integration work, but you can browse the source, build and play.  Be sure to read the README and RELEASE_README,  If you have any questions or issues please send them along to nashorn-dev@openjdk.java.net .  Responses may be a little slow over the holidays, but we will respond.


Friday Dec 07, 2012

The Vote Is In

Just got the following e-mail.  Gonna be busy next week.

Voting on the Nashorn Project with initial Lead Jim Laskey [1] is

closed.

Yes:  20
Veto:  0
Abstain:  0

According to the Bylaws definition of Lazy Consensus, this is
sufficient to approve the new Project and its initial Lead.

-John Coomes

[1] http://mail.openjdk.java.net/pipermail/announce/2012-November/000139.html

Saturday Dec 01, 2012

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.
twitterverse











Thursday Nov 29, 2012

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

Monday Nov 26, 2012

Request for Project Nashorn (Open Source)

The request went out to the OpenJDK community last Thursday (November 22, 2012) for Project Nashorn.  http://mail.openjdk.java.net/pipermail/announce/2012-November/000139.html The deadline for voting is midnight December 6, 2012 UTC. If all goes well, we hope to have all the bits in the OpenJDK in time for all to play with during the holiday period. Fingers crossed.

Wednesday Oct 10, 2012

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 JVMUnfortunately, 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. 

Raging Red Rhino

About

Technical discussions and status of the Nashorn JavaScript Project.

Search

Categories
Archives
« May 2015
SunMonTueWedThuFriSat
     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
      
Today