In my former post Using websockets in APEX for automatic refresh I explained how to implement a mechanism with an external websocketserver to push a refresh to an APEX page. It used Beaconpush.
But I didn’t like the dependency on an external websocketserver (I’m just that way), so I investigated what it should take to implement my own websocketserver.
Introducing node.js
Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight and efficient, perfect for data-intensive real-time applications that run across distributed devices.
JavaScript is a growing skill amongst Oracle/APEX developers, so it was a logical choice to look into using server-side JavaScript to implement a http/websocketserver combination. The idea was to create a very simple server which the clients could connect to using the websocket-mechanism. The database should be able post requests to the HTTP-part of the server that would be used to the connected clients.
- Install node.js
On the website of node.js you can download an installer for node.js. I downloaded the msi (I’m on a Windows 7 machine).
Install websocket.
Node.js works with modules that can be installed. For this example we need the websocket module. To install, use the NPM executable
npm install websocket
As a sidenote, this installation failed on my machine. I think the node.js version was not compatible with the websocket version (1.0.4). I had to install one version lower:
npm install websocket@1.0.3
- Create the server.js
As I mentioned before, we are talking here about server-side JavaScript. So you have to create a JavaScript file, e.g. server.js
"use strict";
process.title = 'database-chat';
var config = {
port:1337
};
/*
We need a HTTP-server and a websocketserver
*/
var webSocketServer = require('websocket').server;
var http = require('http');
/*
We need to keep record of connected clients
*/
var clients = [ ];
/*
The HTTP server
*/
var server = http.createServer( function(req, resp){
var body = '';
var json;
req.setEncoding('utf8');
resp.writeHead(200,{'Content-Type':'application/json' });
req.on('data', function(data) {
body += data.toString();
/*
When we get a stringified JSON-object, that's oke.
If not, we just create one with one attribute
*/
try {
json = body;
var test = JSON.parse(json);
}
catch (e) {
json = JSON.stringify({ 'message':body} );
}
/*
Push the JSON-string to all the connected clients
*/
for (var i=0; i < clients.length; i++) {
clients[i].sendUTF(json);
}
resp.end(JSON.stringify({ message: 'Send to '+ clients.length + ' clients' }));
});
});
/* Start listening on the configured port an write to standard output*/
server.listen(config.port, function() {
console.log((new Date()) + " Server is listening on port " + config.port);1
});
/*
WebSocket server
*/
var wsServer = new webSocketServer({
// De WebSocket server is tied to a HTTP server.
httpServer: server
});
/* If a client connects to the websocketserver,
this callback accepts the request and adds it to the list
*/
wsServer.on('request', function(request) {
console.log((new Date()) + ' Websocketconnection from origin ' + request.origin + '.');
var connection = request.accept(null, request.origin);
// we need to know client index to remove them on 'close' event
var index = clients.push(connection) - 1;
console.log((new Date()) + ' Connection accepted.');
connection.on('close', function(connection) {
console.log((new Date()) + " Peer " + connection.remoteAddress + " disconnected.");
clients.splice(index, 1);
});
});
- Start the server
Starting this server.js script is easy. In a command window type
node server.js
But what is a server without the client?
First of all you will have to have some sort of procedure on the database that will sent a message to your server.js
procedure push
( p_text in varchar2
)
is
l_clob clob;
begin
l_clob := APEX_WEB_SERVICE.MAKE_REST_REQUEST
( p_url => 'http://127.0.0.1:1337'
, p_method => 'POST'
, p_body => '{"message":"'||p_text||'"}'
);
end;
With such a procedure you can e.g. push the message REFRESH to you page and refresh the region.
Create a page with an interactive report that you want to be refreshed.
In the page footer add the following script:
$(function(){
window.WebSocket = window.WebSocket || window.MozWebSocket;
if (!window.WebSocket) {
console.log('Sorry, no websockets');
}
else {
var connection = new WebSocket('ws://127.0.0.1:1337');
connection.onerror = function (error) {
console.log( 'Sorry, but there is some problem with your connection or the server is down.');
};
connection.onmessage = function (message) {
console.log(message.data);
try {
var json = JSON.parse(message.data);
if (json.message=='REFRESH') {
gReport.pull();
}
else {
console.log(json.message);
}
}
catch (e) {
console.log('This is not valid JSON: ' + message.data);
}
};
}
});
and that’s it.
Mind you, this is just one implementation, but you can push every database event to the clients page.

One small item that I noted…not sure of your APEX version but, under 4.2.1.00.08, the name of the method argumnet to APEX_WEB_SERVICE.MAKE_REST_REQUEST is p_http_method rather than p_method.
Great article! This was exactly what we needed and, given the nature of our business, we wouldn’t have been able to employ connections to a third party. Thanks for sharing.