Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

EWD 3 Training Course Part 7: Applying the QEWD Messaging Pattern

790 views

Published on

This presentation is Part 7 of the EWD 3 Training Course. It takes you through the QEWD messaging pattern which is applied to the demonstration application that you'd started in Part 6

Published in: Software
  • Be the first to comment

EWD 3 Training Course Part 7: Applying the QEWD Messaging Pattern

  1. 1. Copyright © 2016 M/Gateway Developments Ltd EWD 3 Training Course Part 7 Applying the QEWD Messaging Pattern Rob Tweed Director, M/Gateway Developments Ltd Twitter: @rtweed
  2. 2. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD Application • Generate an event in the browser • Send a message to the QEWD back-end • At the back-end, a handler function for that message type processes the message and usually creates a response message • Response message returned to browser where a handler function processes it and usually modifies the User Interface
  3. 3. Copyright © 2016 M/Gateway Developments Ltd Let’s Apply these One by One
  4. 4. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • Generate an event in the browser, eg: – Click a button – Change a form field value – Move the mouse over a particular area – etc… • Need to be able to trigger a handler function when the required event occurs
  5. 5. Copyright © 2016 M/Gateway Developments Ltd Let's Create an Event • We'll: – Add a button to index.html – Add a click event handler for the button in app.js
  6. 6. Copyright © 2016 M/Gateway Developments Ltd Add button to index.html <html> <head> <title>Demo ewd-xpress application</title> </head> <body> <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script src="/ewd-client.js"></script> <script src="app.js"></script> <button id="testBtn">Click Me</button> <div id="content"> Content goes here </div> </body> </html>
  7. 7. Copyright © 2016 M/Gateway Developments Ltd Add click handler to app.js $(document).ready(function() { EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { console.log('button was clicked!'); }); }); EWD.start('demo1', $, io); }); jQuery event handler Initially just to make sure the click event is handled Note how we define the handler within the document.ready() function and before we start EWD
  8. 8. Copyright © 2016 M/Gateway Developments Ltd Try it out
  9. 9. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • Sending a message from the browser to the QEWD back-end: – Use the EWD.send() function – Messages must have a type property – The type property's value is up to you to define • Any string value – EWD.send() function not available for use until registration completes – EWD.send() automatically adds the session token to the message • Its behaviour is protected within a closure and cannot be modified • Note that manual socket.io messaging is unavailable to user
  10. 10. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message); }); }); EWD.start('demo1', $, io); }); Simplest message possible for now Just a type property
  11. 11. Copyright © 2016 M/Gateway Developments Ltd Try it out • Nothing appears to happen in the browser when you click the button! • But check the Command Prompt or terminal window in which you're running the QEWD Node.js process…
  12. 12. Copyright © 2016 M/Gateway Developments Ltd Back-end log • The message was received by the master process and passed to a worker: • Notice that the session token has been added to the message by the EWD.send() function worker 2052 received message: {"type":"testButton", "token":"4fb0efcd-458c-4afd-a053-8a19600867c4"}
  13. 13. Copyright © 2016 M/Gateway Developments Ltd Back-end log • Worker process reported an error • QEWD was unable to find and load a module containing message handlers for this application ('demo1') – That's because we haven't written one yet! Unable to load handler module for: demo1: Error: Cannot find module 'demo1'
  14. 14. Copyright © 2016 M/Gateway Developments Ltd Back-end log • This error message was returned to master process by the worker • The master process will have forwarded this message to the browser – Nothing displayed in the browser though! master process received response from worker 2052: {"type":"testButton","finished":true,"message":{"error":"Unable to load handler module for: demo1","reason":{"code":"MODULE_NOT_FOUND"}}}
  15. 15. Copyright © 2016 M/Gateway Developments Ltd Displaying messages in browser • Normally it's up to you to handle message responses and display them in the UI • During development it's useful to see a trace of all messages sent and received in the JavaScript console • To do this, set EWD.log = true;
  16. 16. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message); }); }); EWD.start('demo1', $, io); });
  17. 17. Copyright © 2016 M/Gateway Developments Ltd Now the messages show up
  18. 18. Copyright © 2016 M/Gateway Developments Ltd Fixing this error • EWD.send() is working fine – It's sending the message to the back-end as expected • How do we fix the error at the back-end and how do we handle the incoming message there?
  19. 19. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • At the back-end, you must define a handler function for each of your message types • Each handler function processes the message for the specified type, and usually creates a response message • All the handler functions for any one application are defined within a single Node.js module – That module can, of course, be split into multiple sub-modules if required
  20. 20. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • So, for each application you define a back-end module • By default, the module name is the same as the application name – Eg, in our case: demo.js • You can over-ride this and map an application name to a module name/path, if you prefer • Your application module defines a hander function for each of your application's message types – Typically a handler function will do any or all of the following: • Read from / write to a database • Read from/ write to the user's QEWD Session • Invoke legacy application functions • Invoke 3rd-party Node.js modules • Make web/REST service calls to other local or remote services – Each of your handler functions has full read/write access to your embedded Global Storage database: • Cache, GT.M or Redis
  21. 21. Copyright © 2016 M/Gateway Developments Ltd Back-end Application module pattern • Default name / path: – Windows: • C:qewdnode_modules{applicationName}.js – Linux / Raspberry Pi • ~/qewd/node_modules/{applicationName}.js
  22. 22. Copyright © 2016 M/Gateway Developments Ltd Back-end Application module pattern module.exports = { handlers: { messageType1: function(messageObj, session, send, finished) { // do something with the incoming message // create a response object // use the finished() function to end the processing and // release the worker finished(responseObj); }, messageType2: function(messageObj, session, send, finished) { // etc…. finished(responseObj); } };
  23. 23. Copyright © 2016 M/Gateway Developments Ltd Create our back-end module • C:qewdnode_modulesdemo1.js or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); finished({ ok: 'testButton message was processed successfully!' }); } } };
  24. 24. Copyright © 2016 M/Gateway Developments Ltd Create our back-end module module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); finished({ ok: 'testButton message was processed successfully!' }); } }; This was the value of the type property in our EWD.send() function EWD.send({type: 'testButton'});
  25. 25. Copyright © 2016 M/Gateway Developments Ltd Save Module and Try it out
  26. 26. Copyright © 2016 M/Gateway Developments Ltd And check out the back-end log worker 2000 received message: {"type":"testButton","token":"527bd51f-7d6a-4dd7-8 27d-c1ea8dfa1f43"} *** handling the button click message! master process received response from worker 2000: {"type":"testButton","finished":true,"message":{"ok":"testButton message was processed successfully!","ewd_application":"demo1"}} *** handleMessage response {"type":"testButton","finished":true,"message":{"ok": "testButton message was processed successfully!","ewd_application":"demo1"}} sending to socket /#5NdGRfkMn17-vboPAAAC Master process has finished processing response from worker process 2000 which is back in available pool Came from this line: console.log('*** handling the button click message!'); In our handler function
  27. 27. Copyright © 2016 M/Gateway Developments Ltd Got an error? • Check back-end log: – "Unable to load module" message? • Means you have a syntax error in the module • How to locate it? – Use the Node.js REPL
  28. 28. Copyright © 2016 M/Gateway Developments Ltd Using the Node.js REPL C:UsersRob Tweed> cd qewd C:qewd> node > var x = require('demo1') C:qewdnode_modulesdemo1.js:6 ok: 'testButton message was processed successfully!'' ^ SyntaxError: Unexpected token ILLEGAL at exports.runInThisContext (vm.js:53:16) at Module._compile (module.js:373:25) at Object.Module._extensions..js (module.js:416:10) at Module.load (module.js:343:32) at Function.Module._load (module.js:300:12) at Module.require (module.js:353:17) at require (internal/module.js:12:17) at repl:1:9 at REPLServer.defaultEval (repl.js:262:27) at bound (domain.js:287:14) > 2 X Ctrl & C to exit from REPL
  29. 29. Copyright © 2016 M/Gateway Developments Ltd Back-end message handler resources • Within a back-end message handler function you have access to everything you need: – testButton: function(messageObj, session, send, finished) {..} – Incoming message: messageObj – QEWD session: session.data (read/write access) – Global Storage database (read/write/execute access): • this.db gives access to the cache.node APIs, – eg this.db.function() to execute a function / procedure • this.documentStore gives access to ewd-document-store JavaScript / Document database abstraction of your Global Storage database
  30. 30. Copyright © 2016 M/Gateway Developments Ltd Using the QEWD Session • C:qewdnode_modulesdemo1.js or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { console.log('*** handling the button click message!'); session.data.$('foo').value = 'bar'; finished({ ok: 'testButton message was processed successfully!' }); } } };
  31. 31. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • At the back-end, a handler function for the specific message type processes the message and usually creates a response message – Response messages are JSON objects – If using web-sockets, you can send more than 1 message • send() function for intermediate messages. Worker remains unavailable • finished() function for final message. Worker released to available pool – Response messages have a type property • By default, the type is the same as that of the original incoming message from the browser • Optionally, when using the send() function for intermediate messages, you can over- ride the type • The type of the finished() message cannot be over-ridden – it is always the same as the incoming message – A Handler function MUST end by invoking the finished() function • Releases the ewd-qoper8 worker process back to the available pool – Response messages are automatically sent to the originating client or browser
  32. 32. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – UI modification using JavaScript • Up to you which framework, if any, you use
  33. 33. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { console.log('Response received: ' + JSON.stringify(messageObj.message.ok)); }); }); }); EWD.start('demo1', $, io); }); Using the EWD.send() callback function to handle the response
  34. 34. Copyright © 2016 M/Gateway Developments Ltd Try it out
  35. 35. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – UI modification using JavaScript • Up to you which framework, if any, you use • We'll just use jQuery since it's already loaded
  36. 36. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.log = true; EWD.on('ewd-registered', function() { $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').text(messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Change the text inside the <div id="content"> tag
  37. 37. Copyright © 2016 M/Gateway Developments Ltd Try it out
  38. 38. Copyright © 2016 M/Gateway Developments Ltd Pattern of a QEWD application • Response message is returned to the browser where a handler function processes it and usually modifies the User Interface – Two methods for handling responses within the browser: • Callback function as 2nd argument of EWD.send() function – EWD.send(messageObj, function(responseObj) {…}); • Pub/Sub mechanism, specific to a message type: – EWD.on(messageType, function(responseObj) {…}); – Mainly used for messages you'll send frequently from back-end – Particularly intermediate messages using send() function – UI modification using JavaScript • Up to you which framework, if any, you use
  39. 39. Copyright © 2016 M/Gateway Developments Ltd Intermediate messages • C:qewdnode_modulesdemo1.js or • ~/qewd/node_modules/demo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { session.data.$('foo').value = 'bar'; send({ type: 'intermediate', foo: 'bar', date: new Date().toString() }); finished({ ok: 'testButton message was processed successfully!' }); } }; Overrides the incoming message type
  40. 40. Copyright © 2016 M/Gateway Developments Ltd Intermediate messages • C:ewd3node_modulesdemo1.js or • C:ewd3node_modulesdemo1.js module.exports = { handlers: { testButton: function(messageObj, session, send, finished) { session.data.$('foo').value = 'bar'; send({ type: 'intermediate', foo: 'bar', date: new Date().toString() }); finished({ ok: 'testButton message was processed successfully!' }); } }; Must still invoke the finished() function to tell ewd-qoper8 to release the worker back to the available pool
  41. 41. Copyright © 2016 M/Gateway Developments Ltd Try it out
  42. 42. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.log = true; EWD.on('ewd-registered', function() { EWD.on('intermediate', function(responseObj) { $('#content').text(responseObj.message.date); }); $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').append('<br /> ' + messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Handle instances of the 'intermediate' message Using Pub/Sub handler
  43. 43. Copyright © 2016 M/Gateway Developments Ltd Edit app.js $(document).ready(function() { EWD.log = true; EWD.on('ewd-registered', function() { EWD.on('intermediate', function(responseObj) { $('#content').text(responseObj.message.date); }); $('#testBtn').on('click', function(e) { var message = {type: 'testButton'}; EWD.send(message, function(messageObj) { $('#content').append('<br /> ' + messageObj.message.ok); }); }); }); EWD.start('demo1', $, io); }); Combine the responses within the <div id="content"> tag
  44. 44. Copyright © 2016 M/Gateway Developments Ltd Try it out
  45. 45. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • By default, the back-end handler module for a QEWD application is named the same as the application, eg: – Our application is named demo1 – By default, QEWD will assume that the handler functions for this application are in a module named demo1.js ie: • C:qewdnode_modulesdemo1.js or • ~/qewd/node_modules/demo1.js
  46. 46. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • You can over-ride this default behaviour by defining a module map in your QEWD startup file • Application module mapping is done in your QEWD start-up file – Define a config property named moduleMap • This is an object / hash mapping one or more Application names to corresponding module names/paths
  47. 47. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: 'myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config);
  48. 48. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: 'myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config); This tells QEWD that in order to handle messages for the demo1 application, it must load a module using require('myDemoApp')
  49. 49. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: '/path/to/myDemoApp' } }; var qewd = require('qewd').master; qewd.start(config); This tells QEWD that in order to handle messages for the demo1 application, it must load a module using require('/path/to/myDemoApp')
  50. 50. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • Example: var config = { managementPassword: 'keepThisSecret!', serverName: 'My QEWD Server', port: 8080, poolSize: 2, database: { type: 'gtm' }, moduleMap: { demo1: '/path/to/myDemoApp', finance: 'myFinanceApp' } }; var qewd = require('qewd').master; qewd.start(config); You can map as many Applications as needed
  51. 51. Copyright © 2016 M/Gateway Developments Ltd Application Module Mapping • QEWD Application back-end modules can therefore be defined as standard Node.js modules – Can be published to NPM – Can be installed from NPM

×