I’ve been using VBCS for awhile now and it has really evolved over the past nine months. I guess that’s one of the wonderful things about these PaaS offerings from Oracle; we don’t have to wait so long for new features and capabilities.
One thing I wanted to do, but it isn’t directly supported in VBCS yet, is to have dynamic displays. I’ve done quite a bit of programming in native JavaScript and Oracle JET where I’ve used web sockets to make my graphs and gauges change automatically without the need for a refresh button.
Well, I figured out a way to do this in VBCS. Now I will admit right away, this is pretty ugly, so if you are a software development purist, please turn off your TV now!
Since many of my apps utilise the VB Business Objects, I wanted to have a table, chart or graph update when the business objects changed or when something was inserted or deleted. I figured websockets was the best option, but how can I tie the business object events to the javascript / JET objects on my dashboard.
Application Container cloud to the rescue. Again, there are 50 ways to leave your lover and more than 50 ways to setup a server to run a bit of java code. ACCS was just a very easy way to get things running and it was already part of my universal credits in my Oracle Cloud domain.
So here is a diagram showing what I did.
- The first thing was to add some JavaScript code to my application to connect to a socket on ACCS.
- Then, I needed to call ACCS when data changed in one of my business objects.
- This would trigger a call back to VBCS to update the display
- The UI updates when the filter is reset.
So, I first deployed a simple NodeJS app into ACCS that keeps track of websocket clients and notifies them whenever a REST call comes in. This was pretty easy, but I had to make sure I could use the same port for both the websockets and REST services. Fortunately NodeJS supports this.
//////
//
// This is sample code to bridge VB DB and WebApps via websockets.
//
//////// Read Environment Parameters from Oracle Application Container Cloud Service (ACCS)
// If no env variables are there, use default values.
var port = Number(process.env.PORT || 7789);//
// Setup express
//
var express = require(‘express’);
var bodyParser = require(‘body-parser’);
var app = express();
var util = require(‘util’)
var https = require(‘https’)
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());app.post(‘/notify’, function (req, res) {
console.log(“Message received”);
var payload = req.body;
var numClients = clientConnection.length;
var newClientConnection = clientConnection.slice(0);
for(var i=0;i<numClients;i++) {
console.log(“Sending to client “+i);
try {
clientConnection[i].send(JSON.stringify(payload));
} catch (ex) {
console.log(“error sending. Removing client: “+ex);
newClientConnection.splice(i,1);
}
}
clientConnection=newClientConnection.slice(0);
res.end(“Success”);
});var server = app.listen(port, function () {
console.log(“App listening at http://:”+port);
});
var WebSocketServer = require(‘ws’).Server
var clientConnection = new Array();// Create an instance of websocket server.
var wss = new WebSocketServer({server: server});
console.log(‘New server created, waiting for connections…’);// Add the connection listener that will be triggered once the connection is established.
wss.on(‘connection’, function(ws) {
console.log(‘Server was connected.’);
clientConnection.push(ws);
// Add the listener for that particular websocket connection instance.
ws.on(‘message’, function(message) {
console.log(‘Server received message: %s’, message);
// Send back the message that we receive from the browser
ws.send(message);
});
});
Next I added the call to VBCS app to make my websocket connection:
define([], function() {
‘use strict’;
var websocket = undefined;var AppModule = function AppModule() {
AppModule.prototype.OpenSocket = function(arg) {
console.log(“Websocket: In open socket.”);
if (this.websocket === undefined) {
console.log(“Websocket: Starting socket listener.”);
this.websocket = new WebSocket(
“wss://myaccs.oraclecloud.com/”);
this.websocket.onmessage = this.onMessage;
this.websocket.onerror = this.onError;
this.websocket.onclose = this.onClose;
}
}AppModule.prototype.onMessage = function(evt) {
console.log(“Websocket: On Message Called.”);
var data = JSON.parse(evt.data);
console.log(‘Websocket: message :’ + data.label);
$(“#oj-button–1075341696-1”).click();
}AppModule.prototype.onClose = function(evt) {
console.log(‘websocket closed :’ + evt.code + “:” + evt.reason);
websocket = undefined;
this.OpenSocket({}); // Reopen.
}AppModule.prototype.onError = function(evt) {
console.log(‘Websocket: Error :’ + evt);
}}
return AppModule;
});
Note: You’ll need to update the hostname from “myaccs.oraclecloud.com” to the one advertised by ACCS running the NodeJS code. Also, the button click object will need to change (See the video).
When I run this, I get some log messages in my debug window and can see the websocket connection succeed. A simple CURL call to my ACCS service validates this is all working.
The last thing needed is to update the values when on my screen when the call is made and tie this to my business objects.
All this is show in the demo video:
The code can be found here:
https://github.com/gravesjohnr/VBCSExamples/tree/master/DynamicUpdates
Have Fun!!!
-John