APEXblog.nl - Tips and Tricks

About This Blog:
I (Richard Weug) started this blog primary for myself to save all kinds of Apex tips and tricks in one place. To use it as a place to write down how I used some coding in my own projects, but also to copy and paste all kinds of articles I find on the Internet. (So I never have to wonder on what website did I read about??? When I see something interesting I collect the content so I have my own archive/knowlegde base.

View my profile on LinkedIn

 

Tips & Tricks

Print
14
Feb

Using websockets in APEX for automatic refresh

Written by Richard Weug. Posted in Tips and Tricks

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

You will get something like Newly started 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.

Original article: http://emoracle.wordpress.com/2012/04/11/using-websockets-in-apex-for-automatic-refresh-with-nodejs/