Incapture Technologies

Inside the Cloud

Incapture Technologies Blog

 

Web Development and Rapture

Published:
November 17, 2014
Author:

At Incapture we’ve been developing quite a number of web front ends to support both Rapture from a Developer Operations perspective and from a product perspective when creating applications for our sister company Incapture Investments. We’ve settled on a good design pattern and this blog post will describe how we create interactive web pages that use Rapture as a back end.

For these pages the standard model has been to use Javascript for the “active” side of the web page and in particular jQuery as a library that helps make a lot of the calls to Rapture more boilerplate. Furthermore in the applications / uses of Rapture that we are talking about here (internal dev ops and specific product work) we have chosen to use JSON as a format for storing information in Rapture repositories. JSON adapts well to being manipulated from within Javascript running within a browser.

There are usually two activities that are going on inside one of our pages – requests for Rapture data that needs to be formatted / displayed appropriately and requests to change things on the server, usually based on some user based action. In all cases we are using the ajax calls from within jQuery to perform these steps.

Before going into detail on the browser/javascript side it’s worth talking about the end point that the browser will be interacting with. Rapture’s API does have a Javascript implementation and that could certainly be used to interact with Rapture. However in this case it does make sense to let the server perform any prefiltering/precomputing/formatting work instead of passing raw data to the browser. This of course saves transport time (we are only sending data we need) and it can be good for security – it’s the server that contains the logic for the processing, not the client.

The technique we use is to use a special servlet that is installed in any Rapture API server. This servlet gives the caller the ability to invoke a Reflex script on the server and have that script return back some content for the client. Usually the return content is json formatted and the client has the ability to pass parameters to the Reflex script being executed. The script is executed in the entitlements context of the user that is logged in to the servlet.

As an example, consider the following screen image of browsing one of our internal test environments:

Reflex Web Servlet Screen shot

Here we were browsing to:

/rapture/web/oper/statusList.rrfx

and the response (printed prettily in this browser) was something like:

[ {
  "serverName" : "testaim001",
  "instance" : {
    "serverGroup" : "BloombergAIM",
    "appInstance" : "BloombergAIM",
    "appName" : "BloombergAIM",
    "status" : "STOPPED",
    "lastSeen" : "2014-11-17T12:58:07",
    "needsRestart" : false
  }
}, {
  "serverName" : "testdcp001",
  "instance" : {
    "serverGroup" : "DataCaptureServer",
    "appInstance" : "DataCaptureServer",
    "appName" : "DataCaptureServer",
    "status" : "RUNNING",
    "lastSeen" : "2014-11-17T15:03:19",
    "needsRestart" : false
  }
}, {
  "serverName" : "testdcp002",
  "instance" : {
    "serverGroup" : "DataCaptureServer",
    "appInstance" : "DataCaptureServer",
    "appName" : "DataCaptureServer",
    "status" : "RUNNING",
    "lastSeen" : "2014-11-17T15:03:16",
    "needsRestart" : false
  }
}, {
  "serverName" : "testidp001",
  "instance" : {
    "serverGroup" : "IDPWebServer",
    "appInstance" : "IDPWebServer",
    "appName" : "IDPWebServer",
    "status" : "RUNNING",
    "lastSeen" : "2014-11-17T15:03:16",
    "needsRestart" : false
  }
}
]

So given a simple URL call we get back some interesting JSON which we could use to update a web page. In fact the following screen shot (the main web front end to RaptureRunner, described in an earlier blog post) is showing this same information:

Rapture Runner processed output

The given URI above “means” to Rapture that it should execute the script

script://web/oper/statusList

and anything printed out from that script will be returned to the browser. In this case the content of that script is :

// Returns the list of servers and their status

servers = #runner.getRunnerServers();
ret = [];
for server in servers do
    statusInfo = #runner.getRunnerStatus(server);
    for instance in keys(statusInfo['statusByInstanceName']) do
       entry = {};
       value = statusInfo['statusByInstanceName'][instance];
       entry['serverName'] = statusInfo['serverName'];
       entry['instance'] = value;
       ret = ret + entry;
    end
end
println(json(ret));

And as you can see it makes some API calls to Rapture (the runner API gives information about the state of servers running in a Rapture environment) and then it creates a summary array of status information in the variable called “ret”. The final line converts the ret array into a json string and prints that out – which means that the code that is invoking that can simply work with the json content directly.

At the browser end the page that uses this call and displays the table shown earlier has JavaScript that looks something like this:

     $.ajax({
           url: "../web/oper/statusList.rrfx",
           dataType: 'json',
           success: function(data) {
          		 var oldTable = document.getElementById('cloudServers'),
          		 newTable = oldTable.cloneNode(false),tr,td;
          		 var thead = document.createElement('thead');
          		 addHeader(thead, 'Server');
          		 addHeader(thead, 'App');
          		 addHeader(thead, 'Status');
          		 addHeader(thead, 'Last Seen');
          		 newTable.appendChild(thead);
          		 var tbody = document.createElement('tbody');
          		 for(var i=0; i< data.length; i++) {
          		    tr = document.createElement('tr');
          		    addCell(tr, data[i].serverName);
          		    addCell(tr, data[i].instance.appInstance);
          		    addCell(tr, data[i].instance.status);
          		    var ls = new Date(data[i].instance.lastSeen);
          		    addCell(tr, ls);
          		    tbody.appendChild(tr);
          		 }
  		    newTable.appendChild(tbody);
  		    oldTable.parentNode.replaceChild(newTable, oldTable);
           }
           });

with functions such as addCell and addHeader doing appropriate things to create tr/td/th entries as part of the table. The ajax call in this case does not need to pass in any parameters but these can be done in the normal way – automatically creating a “web” variable in the Reflex script so that they can be accessed.

So for our web development we have a very simple pattern – in the browser we use JavaScript and jQuery to send a request to a Rapture server which then executes a Reflex script. That Reflex script returns back some json (or can throw errors of course) which can then be parsed in the success function attached to the ajax call. Code is nicely layered between formatting and user interaction (browser side code) and server side processing. Reflex is a reasonable (and simple) scripting language that helps with this as it also understands json content and provides many methods to manipulate such content.

Also because Reflex scripts in Rapture are simply documents that can be installed it is possible to use them for a business level product UI. The code below is a script we use to return “today’s trades” for a web front end. The web side of it is really a widget that can display trades given “an array of trade documents”. The fact that we use that widget with the return “value” from this script is what makes that instance of the widget show “today’s trades” in a consistent way:

require '//common/commonOrder' as order;
day = web['d'];
if day == 'now' do
// Get today's orders
  bd <-- '//idp.businessdate/official';
  day = bd['today'];
end
query = 'SELECT rowId WHERE executionDate="' + day + '"';
results = #index.queryIndex('//idp.execution',query);
response = [];
for x in results['rows'] do
   row = {};
   id = x[0];
   tradeId = "//idp.execution/${id}";
   tradeDoc <-- tradeId;
   orderDoc = order.locateOrder(tradeDoc['id']);
   row['id'] = tradeId;
   row['execution'] = tradeDoc;
   row['order'] = orderDoc;
   response += row;
end
println(json(response));

There’s a lot going on in that script but it is self contained and has server side logic that would be much more complex to embed within a JavaScript source on the client.

As before – if you’d like more information about Incapture or Rapture please drop me a line personally or to our general email address info@incapturetechnologies.com and we will get back to you for a more in depth discussion.


Subscribe for updates