2. What is XML RPC?

Wikipedia defines XML-RPC as:

XML-RPC is a remote procedure call protocol which uses XML to encode its calls and HTTP as a transport mechanism. It is a very simple protocol, defining only a handful of data types and commands, and the entire description can be printed on two pages of paper. This is in stark contrast to most RPC systems, where the standards documents often run into the thousands of pages and require considerable software support in order to be used.

This means that, whatever your programming language of choice, you can surely find an XML-RPC library for it; and once you have the library, connection to QueueMetrics with it is straightforward.

2.1. Which functions does QueueMetrics export as XML-RPC?

QueueMetrics exports the full results of an analysis in XML-RPC, so you can access whatever information you feel you may need. Information is divided into blocks, i.e. sets of data that correspond roughly to the tables QM uses for its own output.

This means that you can build software that sits on top of QueueMetrics and uses its result as a starting point for further elaboration, e.g.:

  • Visualizing results with complex graphs currently not supported by QueueMetrics
  • Computing period comparison analyses (one period versus another period)
  • Accessing agent presence data for payroll computation

Of course there are a very big number of possible scenarios where you might want to use such information.

The XML-RPC interface is available in all version of QueueMetrics starting from version 1.3.1.

2.2. Example: accessing QueueMetrics from Python

In this example we’ll see how easy it is to access QueueMetrics from a scripted language like Python. You can enter the following statements interactively using a Python IDE like IDLE, or make them a part of a larger program.

The following code connects to a the XML-RPC port of a QueueMetrics instance running at http://qmserver:8080/qm130 and asks for a couple of tables, namely the distribution of answered calls per day and the Disconnection causes.

> import xmlrpclib
> server_url = ’http://qmserver:8080/qm130/xmlrpc.do’;
> server = xmlrpclib.Server(server_url);
> res = server.QM.stats( "queue-dps", "robot", "robot","", "", "2005-10-10.10:23:12", "2007-10-10.10:23:10","", [ ’KoDO.DiscCauses’, ’CallDistrDO.AnsDistrPerDay’ ] )

> res.keys()
[’CallDistrDO.AnsDistrPerDay’, ’result’, ’KoDO.DiscCauses’]

> res[’result’]
[[’Status’, ’OK’], [’Description’, ’’], [’Time elapsed (ms)’, 3008], [’QM Version’, ’1.3.1’]]

> res[’result’][2][1]
3008

As you can see, it only takes four lines of Python code to connect to QueueMetrics and get all the results back!

2.3. Example: Accessing QueueMetrics from Java

This is an example functionally equivalent to the one above in Python, but it’s written in Java using the Redstone XML-RPC client library.

import java.io.IOException;
import java.util.HashMap;
import java.net.URL;
import redstone.xmlrpc.XmlRpcClient;
import java.util.ArrayList;

public class xmlRpcTestClient {
    public void perform() {
        String stUrl = "http://server:8080/qm130/xmlrpc.do";
        System.setProperty(
                "org.xml.sax.driver",
                "org.apache.xerces.parsers.SAXParser"
        );

        try {
            XmlRpcClient client = new XmlRpcClient( stUrl, false );

            ArrayList arRes = new ArrayList();
            arRes.add( "OkDO.AgentsOnQueue" );
            arres.add( "KoDO.DiscCauses" );
            arRes.add( "KoDO.UnansByQueue" );
            arRes.add( "DetailsDO.CallsKO" );

            Object[] parms = { "queue-dps", "robot", "robot",
                               "", "", "2005-10-10.10:23:12",
                          "2007-10-10.10:23:10",
                               "", arRes };

            Object token = client.invoke( "QM.stats", parms );
            HashMap resp = (HashMap) token;
            System.out.println( "Resp: " + resp );
        } catch ( Exception e ) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        xmlRpcTestClient c = new xmlRpcTestClient();
        try {
            c.perform();
        } catch (Exception e ) {
            e.printStackTrace();
        }
    }
}

We’ll have to explicitly set which XML parser to use; for the rest, the code looks very much alike the Python one.

2.4. Example: Accessing QueueMetrics from PHP

This example is based on PHP’s XML_RPC class, that is a part of PEAR and so should be preinstalled with any modern PHP installation.

<h1>A QueueMetrics XML-RPC client in PHP</h1>
<?
require_once ’XML/RPC.php’;

$qm_server = "10.10.3.5";  // the QueueMetrics server address
$qm_port   = "8080";       // the port QueueMetrics is running on
$qm_webapp = "queuemetrics-1.3.3";  // the webapp name for QueueMetrics


// set which response blocks we are looking for
$req_blocks = new XML_RPC_Value(array(
                        new XML_RPC_Value("DetailsDO.CallsOK"),
                        new XML_RPC_Value("DetailsDO.CallsKO")
                ), "array");

// general invocation parameters - see the documentation
$params = array(
new XML_RPC_Value("queue-dps"),
                new XML_RPC_Value("robot"),
                new XML_RPC_Value("robot"),
                new XML_RPC_Value(""),
                new XML_RPC_Value(""),
                new XML_RPC_Value("2007-01-01.10:23:12"),
                new XML_RPC_Value("2007-10-10.10:23:10"),
                new XML_RPC_Value(""),
                $req_blocks
       );

$msg = new XML_RPC_Message(’QM.stats’, $params);
$cli = new XML_RPC_Client("/$qm_webapp/xmlrpc.do", $qm_server, $qm_port);
//$cli->setDebug(1);
$resp = $cli->send($msg);
if (!$resp) {
    echo ’Communication error: ’ . $cli->errstr;
    exit;
}
if ($resp->faultCode()) {
    echo ’Fault Code: ’ . $resp->faultCode() . "\n";
    echo ’Fault Reason: ’ . $resp->faultString() . "\n";
} else {
    $val = $resp->value();
    $blocks = XML_RPC_decode($val);

    // now we print out the details....
    printBlock( "result", $blocks );
    printBlock( "DetailsDO.CallsOK", $blocks );
    printBlock( "DetailsDO.CallsKO", $blocks );
}

// output a response block as HTML
function printBlock( $blockname, $blocks ) {
        echo "<h2>Response block: $blockname </h2>";
        echo "<table border=1>";
        $block = $blocks[$blockname];
        for ( $r = 0; $r < sizeof( $block ); $r++ ) {
                echo "<tr>";
                for ( $c = 0; $c < sizeof( $block[$r] ); $c++ ) {
                        echo( "<td>" . $block[$r][$c] . "</td>" );
                }
                echo "</tr>\n";
        }
        echo "</table>";
}
?>

As you can see, it is very similar to the other programming languages, and reading into the results is simply a matter of selecting the correct block and then accessing the data cell by row and column. The added complexity is due to the explicit error condition check and result printout.

2.5. Example: Accessing QueueMetrics from JavaScript

In order to access the XML-RPC interface from JavaScript, you need to use an adaptor library. We have been able to use successfully a library called JSON-XML-RPC that can be found at http://code.google.com/p/json-xml-rpc/ in a file caller rpc.js

Generally speaking, a JavaScript client can make requests only against the same server that is serving the HTML page, therefore you need to install it on the same server as QueueMetrics, creating a separate webapp.

<html>
<head>
<title>javascript_client.html</title>
<script src="rpc.js"></script>
</head>
<body>
<h1>QueueMetrics JavaScript XML-RPC example </h1>
<script>
var server = "/DAILY/xmlrpc.do";

function run() {
  try {
    var service = new rpc.ServiceProxy( server, {
           asynchronous:false,
           protocol: "XML-RPC",
           methods: ["QM.stats", "QM.realtime", "QM.auth"]
    } );
    res = service.QM.stats( "q1", "robot", "robot","", "",
            "2005-10-10.10:23:12", "2009-10-10.10:23:10","",
            [ "KoDO.DiscCauses", "CallDistrDO.AnsDistrPerDay" ]
    );
    document.getElementById("RESULT").innerHTML = plotBlocks(res);
  } catch(e) {
    alert("Error raised: " + e);
  }
}


function plotBlocks( hmBlocks ) {
  s = "";
  for (var i in hmBlocks) {
    s += "<h2>Block: " + i + "</h2>";
    s += plotBlock( hmBlocks[i] );
  }
  return s;
}

function plotBlock( arBlock ) {
  s = "";
  for ( r =0; r < arBlock.length; r++ ) {
    s += "<tr>";
    for ( c = 0; c < arBlock[r].length; c++ ) {
      s += "<td>" + arBlock[r][c] + "</td>";
    }
    s += "</tr>";
  }
  return "<table border=1>"  + s + "</table>";
}
</script>

<input type="button" value="Click me!" onclick="run();" >
<div id="RESULT"></div>

</body>
</html>

As you can see, the code is actually very similar to the Python one. The only important difference here is that the names of the methods have to be explicitly declared.