Writing EWD Applications entirely in Javascript

One of the main features of  the recently-released EWD Build 960 is the ability to write web applications (including real-time ones as described in my previous postings) entirely in Javascript.

Of course, Javascript has always been a key component of the front-end of EWD applications: ie defining the functionality that occurs in the user’s browser. Now, with the rapid uptake of Node.js, Javascript is becoming the language used to also describe the back-end behaviour too, and the language with which the back-end database is manipulated.

Until now, the back-end functionality of EWD applications had to be written using Mumps code. This, inevitably, has limited the broader appeal of EWD as a web application framework, and has limited the interest in Mumps databases (GT.M or Caché) as a back-end technology for web applications, even though I’ve yet to find a tried and tested database technology that is such a natural fit with the web technology landscape.

With Build 960, that all changes. Anyone who knows Javascript can now use EWD. Even more interesting is the fact that although EWD relies on a Mumps database for its run-time Session management and the execution of your compiled EWD pages and fragments, your application database doesn’t have to be GT.M or Caché. With your back-end logic running in Node.js, you’ll be able to use the many 3rd-party interface Node.js modules that exist for every other database you can think of. Indeed, you could use your EWD/Javascript logic layer as a web-based integration platform, pulling together data from many databases (including GT.M or Caché) for the user to view and manipulate.

There are, as I’ve explained in earlier articles, very good reasons why developers should seriously consider using GT.M or Caché as their application database: it behaves beautifully as a “Native JSON Database”, and is therefore perfect for use with Javascript.

So, in this posting, I’d like to introduce you to how you write 100% Javascript EWD applications.

If you tried out the realtime demo application (ewdGateway2) that I described in the previous article, you’ll have been running a 100% Javascript EWD application, and you’ll be able to look at its source code for working examples. The file you should look at is named ewdGW2Mgr.js – it’s probably easiest to look at the copy on Github.

This file is known as a Module, and has to follow a particular pattern so that it can be dynamically loaded, whenever needed, into the Node.js child processes used by the ewdGateway2 web framework.  The key part is a bit of syntax that creates an outer wrapper:

module.exports = {

  // your functions go here

};

This ensures that your EWD functions are exported into the running Node.js environment and become available for use by any of the child processes. ewdGateway2 looks after the loading (and reloading – which happens automatically – if you make any changes) of your Module.

An EWD application is described as a set of XML/HTML pages or fragments, each of which has a single “touch point” with the back-end database, known as the onBeforeRender() method.  This is a function that is your responsibility to write and define.  Typically you’ll use it to move data between the back-end database and the EWD Session, though EWD leaves it entirely up to you what you do in an onBeforeRender() method.  EWD Build 960 now allows those onBeforeRender() methods to be written in Javascript contained in one or more Modules that you design and maintain.  Typically you’ll put all your onBeforeRender() methods for an EWD application into a single Module, and therefore you’ll have one Module for each EWD application (though EWD applications can share Modules if you wish/prefer).

So, in the example Module (ewdGW2Mgr.js), you’ll see all the onBeforeRender() methods used by the ewdGateway2 EWD application.  They sit inside the Module’s outer wrapper.  The general syntax is:

module.exports = {

  onBeforeMethod1: function(ewd) {
     // your code goes here
     return '';
  },

  onBeforeMethod2: function(ewd) {
     // your code goes here
     return '';
  },

  // etc

};

It’s up to you what you name your functions. Don’t worry about using the same function name in two different Modules: The way they are loaded into Node.js will prevent them clashing.

You have to tell EWD that you want to load and use a particular Module in your EWD Application.  You do this in your main first Container page using the <ext4:requires> tag (this will also become available in future releases for Sencha Touch and “traditional” EWD applications in future builds).  The <ext4:requires> tag defines the physical path for the Module (so that Node.js can load it) and a logical name with which you refer to the module in your EWD pages. Typically, the syntax you’ll use is similar to this:

  <ext4:requires>
      <ext4:require moduleName="myEWDModule" path="c:\\node\\myEWDModule.js" />
  </ext4:requires>

If you look at the top of the index.ewd page for the ewdGateway2 application, you’ll see the following:

  <ext4:requires>
      <ext4:require moduleName="ewdGW2Mgr" cachePath="c:\\node\\ewdGW2Mgr.js" gtmPath="./ewdGW2Mgr.js" />
  </ext4:requires>

This is because this application has been designed to run on either GT.M or Caché, so it allows two different paths to be defined, one for each environment. You can use either format as you wish or need.

So EWD now knows how to load your module, and you also have a logical name for it.  Now you can define your onBeforeRender() methods for each EWD page.  You do this in the <ext4:container> and <ext4:fragment> tags at the top of each page, using the onBeforeRender attribute, eg in the <ext4:container> tag of the index page for the ewdGateway2 application you’ll see:

 <ext4:container isFirstPage="true" title="ewdGateway2" webSockets="true" onBeforeRender="js:ewdGW2Mgr.initialise">

The js: prefix tells EWD that this is a Javascript method rather than a Mumps one. After that, ewdGW2Mgr.initialise tells EWD to execute the initialise() function in the module we’ve named (in the tag) ewdGW2Mgr.

So, if you look in the actual Module you’ll find this initialise() function:

    initialise: function(ewd) {
      var path = '/ext-4.1';
      if (ewd.database === 'gtm') path = '/vista/ext-4.1';
      ewd.session.$('framework_rootPath')._value = path;
      var chart = ewd.session.$('memoryPlot');
      var data = {rss: [0], 'timeslot': [0], heapTotal:[0], heapUsed: [0]};
      chart._setDocument(data);
      var memory = ewd.session.$('memory');
      data = {'1': {type: 'rss', mb: 0},'2': {type: 'Heap Total', mb: 0},'3': {type: 'Heap Used', mb: 0}};
      memory._setDocument(data);
      return '';
    },

So, that’s how to hook it all together. Now, how do you go about writing onBeforeRender() methods in Javascript?

It’s actually very simple because EWD has done most of the hard work for you.  The first thing to notice is that every onBeforeRender() method must have a single argument: ewd.   ewd is a pre-defined Javascript object that is automatically passed to your onBeforeRender() method at run time.  It contains everything you need.  It’s structure is as follows:

  • ewd.session: pointer to the user’s EWD Session Global. 
  • ewd.request: pointer to the incoming HTTP request, containing its name/value pairs
  • ewd.mumps: pointer to the environment that abstracts all other Mumps Globals into Javascript syntax
  • ewd.technology: either ‘gtm’ or ‘cache’, depending on which technology you’re running

The trick with the first three pointers is that they are all pointing to Javascript-abstracted Mumps Globals.  This abstraction and the  syntax for manipulating Global storage via this abstraction was described in an earlier posting which you should consult in detail when looking at the example Module.  It explains everything you need to know.

You should be able to pretty quickly see that most of the logic you’ll write involves getting a value from the EWD Session, the HTTP Request or a Mumps Global by using the _value property, and/or setting a value of an EWD Session variable or Mumps Global (again by using the _value property).  If you require multi-dimensional data, you use the _getDocument() or _setDocument() methods to map JSON data in and out of the EWD Session or Mumps Globals.  If you’re a Mumps developer and familiar with EWD’s Session Arrays, then _getDocument() is equivalent to EWD’s mergeArrayFromSession() procedure, and _setDocument is equivalent to EWD’s mergeArrayToSession() procedure.

Handling WebSocket Messages

So how do you handle incoming WebSocket messages in Javascript and return a message back to the browser?  The trick is to add a specially named function to the module: webSocketHandler().  This has the same signature and syntax as your onBeforeRender() functions, with the same single argument, ewd.  ewd has one extra property when this function is triggered by an incoming WebSocket message:

  • ewd.webSocketMessage: the JSON object representing the incoming message.

This JSON object has two key properties:

  • type: the message type you’ve defined in your browser’s Javascript logic that sent the message
  • params: a JSON object containing the additional name/value pairs that you defined and sent in the message.

Just as in the onBeforeRender() methods, the ewd argument also includes the ewd.session and ewd.mumps pointers, so your message handler has full access to the EWD Session for the user who sent the message and the GT.M or Caché Global database.

To send back a message, simply return a JSON object (that you have free reign to design) as a returnValue from your handler.

So take a look at the message handlers in  the example Module, for example this one:

  var wsMsg = ewd.webSocketMessage;
  var params = wsMsg.params;

  if (wsMsg.type === 'getSessionData') {
    var session = new ewd.mumps.GlobalNode('%zewdSession', ['session', params.sessid]);
    return session._getDocument();
  }

What this is doing is detecting an incoming WebSocket message of type ‘getSessionData’. The handler simply returns the entire EWD Session contents for this user as a JSON object. This will then be handled in the user’s browser by a corresponding WebSocket handler for an incoming message, also of type ‘getSessionData’: the JSON object you returned will be in the incoming message’s message property. You’ll see the corresponding handler for dealing with the getSessionData message in the browser in the ewdGW2.js file:

      if (messageObj.type === 'getSessionData') {
        Ext.getCmp('sessionTree').destroy();
        var store = Ext.create('Ext.data.TreeStore', convertToTreeStore(messageObj.message));
        var treePanel = Ext.create('Ext.tree.Panel', {
          title: 'Session: ' + messageObj.message['ewd_sessid'],
          store: store,
          id: 'sessionTree'
        });
        Ext.getCmp('sessionTreePanel').add(treePanel);
        var height = Ext.getCmp('sessionPanel').getHeight();
        treePanel.setHeight(height - 5);
        messageObj = null;
        return;
      }

What this is doing is setting up an ExtJS TreePanel widget and populating it from the incoming JSON object that contains the user’s EWD Session contents.

And so the last piece of this magic: how does the browser instruct EWD that the message it’s going to send is to be handled by a particular Module?  You’ll see several examples in the ewdGW2.js Javascript file.  Let’s take a look at the outgoing getSessionData message:

    var getSessionData = function(sessid) {
      EWD.sockets.sendMessage({type: 'getSessionData', handlerModule: 'ewdGW2Mgr', handlerFunction: 'webSocketHandler', params: {sessid: sessid}});
    };

Hopefully it’s self-explanatory: the handlerModule property specifies the name of the Module and the handlerFunction property specifies the function that handles incoming messages. In fact handlerFunction defaults to webSocketHandler anyway, so this property can usually be left out provided you use this default function name in your Module. Otherwise, you define a params property that can contain any JSON object content you like.

That’s pretty much all there is to it.  You now have everything you need to write all your EWD applications entirely in Javascript, and yet you’ll have full access to the  GT.M or Caché.  But remember: because your onBeforeRender() methods and WebSocket message handlers are now running in Node.js, what else you access from within Node.js in those methods and handlers is entirely up to you – given the huge range of 3rd-party modules and database interfaces that the Node.js community has developed in the last 2-3 years, what is now possible with EWD is really mind-boggling!

Welcome to the bright new future of that old, reliable tried and tested, but nearly-forgotten Mumps database technology: it’s suddenly at the leading edge!

Advertisements

One comment

  1. Many thanks Rob
    Another important article.

    Could I ask for another little example that gives an even smaller intro to this approach.. one that particularly shows the first iteration of development cycle that involves both front and back ends.

    I’m thinking of something like a very simple table/list/tree etc on a frontpage and tying it back to the data that sits behind it. (e.g. Patient Name/Address/Age)
    Most all of the Javascript UI frameworks cant go that far with their tutorials and this EWD/Javascript approach from front to back promises to change all that.
    I assume that would mean 2 files (1 .ewd file and 1.js as minimum) with a few lines each.. the leaner the better please..

    thanks in advance,

    Tony

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: