More than just Node.js
on the Java Virtual Machine

Niko Köbler (@dasniko)
Heiko Spindler (@brainbrix)
Qualitects Group

written in

Speaking JavaScript

Like it or not, JavaScript is everywhere these days - from browser to server to mobile - and now you, too, need to learn the language or dive deeper than you have.
Dr. Axel Rauschmayer


Gartner predicts that through 2014, improved JavaScript performance will begin to push HTML5 and the browser as a mainstream enterprise application development environment.
(October 8, 2013)


I think JavaScript has been seen as a serious language for the last two or three years; I think now increasingly we’re seeing JavaScript as a platform.
(Sam Newman, ThoughtWorks’ Global Innovation Lead)

JavaScript has emerged both as a platform for server-side code but also a platform to host other languages.
(January, 2014)

Project Avatar

  • JavaScript service layer for Java EE
  • REST, WebSockets & Server-Sent Events
  • based on Nashorn, Avatar.js, Jersey, Grizzly, etc.
  • Rich HTML5 client side framework
  • Assumes very minor JavaScript knowledge
  • Thin Server Architecture (TSA)

Avatar Architecture

Excursion: Nashorn

Excursion: Nashorn

  • JavaScript Enginge on the JVM (native)
  • competes with Google V8
  • ECMAScript 5.1 compatible (ECMAScript 6 in future)
  • Seamless integration of Java and JavaScript
  • Language and API Extensions
    closures, collections & for each, multi-line string literals, string interpolation, __noSuchProperty__, __noSuchMethod__, typed arrays, binding properties, error extensions, conditional catch clause, String functions, and many, many more...

Java & JavaScript

...are similar than car and carpet are similar.

One is essentially a toy, designed for writing small pieces of code, and traditionally used and abused by inexperienced programmers.
The other is a scripting language for web browsers.


Command line client

$ $JAVA_HOME/bin/jjs
jjs> print('Hello Nashorn!');

Invoking JavaScript from Java

ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
engine.eval("print('Hello Nashorn!');");
engine.eval(new FileReader("scriptfile.js"));
Invocable invocable = (Invocable) engine;
Object result = invocable.invokeFunction("jsSayHello", "Nashorn");


Invoking Java from JavaScript

static String sayHello(String name) {
    return String.format("Hello %s from Java!", name);
var MyJavaClass = Java.type('my.package.MyJavaClass');
var result = MyJavaClass.sayHello('Nashorn');
print(result); // Hello Nashorn from Java!

Excursion: Avatar-js

Node.js on the JVM

~95% Node.js API compatibility
no Chrome V8 native APIs
many of the node-modules work
(e.g.: abbrev, ansi, async, block-stream, chmodr, chownr, coffee-script, colors, commander, connect, debug,, express, ftsream, glob, graceful-fs, inherits, ini, init-package-json, grunt, grunt-bower-task, jade, lodash, mime, mkdirp, mocha, moment, mongodb, mongoose, mustache, node-unit, node-uuid, once, opener, optimist, osenv, passport, q, read, redis, request, retry, rimraf, ronn, semver, slide,, tar, uglify-js, uid-number, underscore, which, winston)




<script data-model="local" data-instance="add">
  var AddMathModel = function() {
    this.left = 0;
    this.right = 0;
    this.reset = function() {
      this.left = this.right = 0;


<input id="lfa" type="text" data-value="#{add.left}"/>
<input id="rta" type="text" data-value="#{add.right}"/>
<span id="output1">
  The result is #{add.left} + #{add.right} = #{add.left + add.right}
<button onclick="#{add.reset()}" id="reset">Reset</button>


<script data-model="rest">
  var Message = function() {
    this.msg = '';
<script data-model="push">
  var Time = function() {
    this.msg = this.h = this.m = this.s = '';
<script data-type="Message" data-instance="message" data-url="data/message">
<script data-type="Time" data-instance="time" data-url="push/time"></script>
<output class="time">#{time.msg}# {time.h}:#{time.m}:#{time.s}</output><br>
<label for="im">New Message: </label>
<input id="im" size="35" data-value="#{message.msg}" />
<button onclick="#{message.put()}">Update</button>

Widgets & Themes

<div data-widget="stackContainer" data-selected="Tweets">
  <div data-widget="contentPane" data-title="Tweets">
    <div data-widget="table" data-model="#{tweets}" data-props="bindModel:'tweet'">
      <div data-widget="column" data-name="Message">
      <div data-widget="column" data-name="User">
        <div data-widget="link" data-label="@#{tweet.userName}"
default based on jQuery UI
other/custom themes & jQuery plugins possible
optional: Dojo dijit widgetLib extension

What about Angular.JS?

Yes! for Sure!
Why not?

Thanks to TSA! :-)


 var avatar = require('org/glassfish/avatar');

Data Provider

var itemsFileProvider = new avatar.FileDataProvider({
  filename: 'rest-sample.txt'
  key: 'key'

var itemsJpaProvider = new avatar.JPADataProvider({
  persistenceUnit: 'rest',
  createTables: true,
  entityType: 'Item'
myDataProvider.create(item, callback);
myDataProvider.del(item, callback);
myDataProvider.get(key, callback);
myDataProvider.getCollection(parameters, count, offset, callback);
myDataProvider.put(key, item, callback);


var Family = avatarModel.newModel('family', {
        "name" : {
            type : "string",
            primary : true
        "description" : "string"
var Product = avatarModel.newModel('product', {
        "name" : {
            type : "string",
            primary : true
        "madeBy" : "string",
        "price" : "number",
        "quantity" : "integer"
Family.hasMany(Product, {
    as : 'products',
    foreign : 'family'
store.bind(Family, Product);


var myJMS = new avatar.JMS({
    connectionFactoryName: 'jms/myConnFactory',
    destinationName: 'jms/myQueue'
myJMS.addListener(function(message) {
    avatar.log('Got message: ' + message);
}).then(function() {
    avatar.log('Sending message...');
    return myJMS.send('Test message');
}).then(function() {
    avatar.log('Message sent.');

REST Service

avatar.registerRestService({url: 'data/items/{item}', methods: ['GET']},
    function() {
        this.onGet = function(request, response) {
        url: 'data/items/{itemid}',
        dataProvider: myDataProvider,
        authorization: {...} },
    function() {}

Push Service

avatar.registerPushService({url: 'push/stocks'},
    function() {
        this.onOpen = function(context){

        this.onTimeout = function(context) {
avatar.registerPushService({url: '/push/chat',
  jms: {
    connectionFactoryName: 'jms/MyConnectionFactory',
    destinationName: 'jms/ChatQueue'}
  }, function(){});

Socket Service

avatar.registerSocketService({url: '/websocket/chat'},
    function() {
        this.onMessage = function(peer, message){
     url: '/websocket/jmschat/{chatroom}',
     jms: {
         connectionFactoryName: 'jms/MyConnectionFactory',
         destinationName: 'jms/ChatTopic',
         messageSelector: "chatroom='#{this.chatroom}'",
         messageProperties: {chatroom: '#{this.chatroom}'}}},
 function() {});

Message Bus

var bus = avatar.application.bus;
bus.publish('echo', { x : 'x', y : 'y' });
bus.on('echo', function(body, msg) {
    avatar.log('Got message: ' + JSON.stringify(body));

Demo Time


Period Milestone
JavaOne 2013 Project Avatar Launch
GlassFish Runtime
June 2014 WebLogic Runtime (WLS 12.1.3)
JavaOne 2014 ???
Mid 2015 WebLogic 12.1.4
Avatar Commercial Support

(WITHOUT warranty)

Competitors ?

AVATAR - Conclusion

  • Lightweight integration in Java EE and Enterprise context
    • JMS, JPA, REST, Java-APIs, …
    • WebLogic Runtime
  • Run JavaScript Apps on Java EE Infrastructure
    • 95% Node.js API compatibility
  • Multi-threaded, asynchronous, non-blocking API
  • Inter-Thread-communication with event bus
  • Perfect interaction between client and server
    • Use of the client-components is not a MUST
    • You can use Angular.js for the UI ;-)

Thank you!