Más contenido relacionado La actualidad más candente (20) Similar a EWD 3 Training Course Part 7: Applying the QEWD Messaging Pattern (20) EWD 3 Training Course Part 7: Applying the QEWD Messaging Pattern1. 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
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
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);
});
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'});
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
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
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
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
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