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

R
Rob TweedIT Consultant, Developer & Director/Founder at M/Gateway Developments Ltd
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
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
Copyright © 2016 M/Gateway Developments Ltd
Let’s Apply these One by One
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
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
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>
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
Copyright © 2016 M/Gateway Developments Ltd
Try it out
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
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
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…
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"}
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'
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"}}}
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;
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);
});
Copyright © 2016 M/Gateway Developments Ltd
Now the messages show up
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?
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
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
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
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);
}
};
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!'
});
}
}
};
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'});
Copyright © 2016 M/Gateway Developments Ltd
Save Module and Try it out
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
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
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
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
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!'
});
}
}
};
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
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
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
Copyright © 2016 M/Gateway Developments Ltd
Try it out
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
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
Copyright © 2016 M/Gateway Developments Ltd
Try it out
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
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
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
Copyright © 2016 M/Gateway Developments Ltd
Try it out
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
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
Copyright © 2016 M/Gateway Developments Ltd
Try it out
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
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
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);
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')
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')
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
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
1 of 51

More Related Content

What's hot(20)

Similar to EWD 3 Training Course Part 7: Applying the QEWD Messaging Pattern(20)

Service Worker 201 (en)Service Worker 201 (en)
Service Worker 201 (en)
Chang W. Doh426 views
Reactive application using meteorReactive application using meteor
Reactive application using meteor
Sapna Upreti278 views
JavaCro'14 - Building interactive web applications with Vaadin – Peter LehtoJavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
JavaCro'14 - Building interactive web applications with Vaadin – Peter Lehto
HUJAK - Hrvatska udruga Java korisnika / Croatian Java User Association2.3K views
06 Javascript06 Javascript
06 Javascript
Herman Tolle1.8K views
Google Web ToolkitsGoogle Web Toolkits
Google Web Toolkits
Yiguang Hu1.4K views
From Ruby to Node.jsFrom Ruby to Node.js
From Ruby to Node.js
jubilem1K views
Google Web ToolkitGoogle Web Toolkit
Google Web Toolkit
Software Park Thailand1.8K views
Introduction to Node.jsIntroduction to Node.js
Introduction to Node.js
Vikash Singh71K views
Dancing with websocketDancing with websocket
Dancing with websocket
Damien Krotkine3.8K views

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

  • 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. 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. Copyright © 2016 M/Gateway Developments Ltd Let’s Apply these One by One
  • 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. 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. 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. 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. Copyright © 2016 M/Gateway Developments Ltd Try it out
  • 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. 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. 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. 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. 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. 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. 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. 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. Copyright © 2016 M/Gateway Developments Ltd Now the messages show up
  • 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. 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. 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. 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. 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. 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. 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. Copyright © 2016 M/Gateway Developments Ltd Save Module and Try it out
  • 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. 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. 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. 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. 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. 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. 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. 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. Copyright © 2016 M/Gateway Developments Ltd Try it out
  • 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. 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. Copyright © 2016 M/Gateway Developments Ltd Try it out
  • 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. 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. 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. Copyright © 2016 M/Gateway Developments Ltd Try it out
  • 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. 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. Copyright © 2016 M/Gateway Developments Ltd Try it out
  • 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. 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. 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. 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. 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. 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. 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