logo services about us contact
 

The intervalquery Module for Drupal

Download   Installation Notes   Testing Notes   Result Formats   Security Concerns

People who participate in discussions via Drupal generate events that can be monitored, but the monitoring of events engenders a liability. In order to guarantee delivery, the event-communication system typically must write to disk each event immediately, thus being able to resend in case of a communication failure.

In contrast to handling events, polling (querying the target every N minutes) offers different trade-offs. Polling is resilient to communication failures, assuming the interval of interest can be adjusted to cover any previous communication failure. Polling also solves the 'cold start' problem by providing a means to query for all info from time-zero up to the present time. However, polling does not provide, typically, information about deleted items and also suffers a time lag compared to events.

The "intervalquery" module provides a means for an external process to poll for Drupal information. The external process can query for information about nodes, comments and/or users that have been created or updated within a given time interval. This module makes use of the XML-RPC protocol and its implementation in Drupal. This module implements the hook "hook_xmlrpc " by querying the Drupal database for requested items with update timestamps within the interval of interest. It is licensed under GPLv2.

Installing Module

  • Download the intervalquery.zip file and expand it into /sites/all/modules/ as described by standard module install instructions for Drupal 5. (This module can probably run under Drupal 4, but has only been tested on 5.)
  • After installation, remember to enable the module using Drupal menus administer > site building > modules.

Testing

XML-RPC has implementations in most programming languages. Below are instructions for creating a simple Java client.

  • Download and install Java JDK if you don't have it already, version 5 or better.
  • Download the sample package that includes the following source and request files, expanding all into the same directory. The following Java source is a bare-bones HTTP Post client that reads a file and sends it, verbatim, to a given URL, and then reads the HTTP result to standard output. It assumes a Drupal server at http://localhost/drupal/ , but if your drupal installation is at a different location, send that URL in as a parameter to the java execution line in the files run.*.


import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;

/**
 * @author Larry Hamel, Codeguild.com
 */
public class XmlrpcClient {
    private synchronized void post(String urlStr, File request) throws Exception {
        try {
            // read in request file
            StringBuffer buff = new StringBuffer();
            if (request != null && request.exists()) {
                BufferedReader reader = new BufferedReader(new FileReader(request));
                String line = null;
                while ((line = reader.readLine()) != null) {
                    buff.append(line);
                }
            }

            // Send data
            URL url = new URL(urlStr);
            URLConnection conn = url.openConnection();
            conn.setDoOutput(true);
            OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
            wr.write(buff.toString());
            wr.flush();
            wr.close();

            // Get the response
            BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String line;
            while ((line = rd.readLine()) != null) {
                System.out.println(line);
            }
            rd.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
* call main with two optional parameters. first is url, second is request file.
* url can stand alone, but if you want a 2nd file param, you must include the url param too.
*/
public static void main(String[] args) throws Exception { File file = new File("request.xml");
if (args.length > 1) {
file = new File(args[1]);
}
if (!file.exists()) {
throw new Exception("Cannot find file: " + file.getCanonicalFile());
}
String url = "http://localhost/drupal/xmlrpc.php";
if ( args.length > 0 ) {
url = args[0];
}
new XmlrpcClient().post(url, file);
} }

 

  • Choose the method you wish to invoke: the following XML request (part of the sample package) demonstrates part of the XML-RPC protocol. The first tag is "methodCall", which has a child "methodName" as well as a child "params". The methodname can be:
    • intervalquery.nodes
    • intervalquery.comments
    • intervalquery.users
    • intervalquery.all

     

  • Add parameters to delineate the time interval: the "intervalquery" module expects two parameters, the 'from' start time (in extended iso8601 format) and the 'until' stop time. The defaults, if no parameters are supplied, are for the server to start at time-0 and end at the current time. (The parameters must be bundled in a struct, as shown.)

<?xml version="1.0" encoding="UTF-8"?>
<methodCall>
<methodName>intervalquery.all</methodName>
<params >
<param>
<value>
<struct>
<member>
<name>from</name>
<value>
<string>2007-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>until</name>
<value>
<string>2008-12-09T23:56:57-0800</string>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodCall>
  • After downloading the sample package, just run 'run.bat' or 'run.sh', depending on platform. This launches the client, assuming a Drupal server URL. If you need to change the URL or the request file location, edit run.* to specify the correct parameters on the 'java' launch line as parameters.

Result Formats

Result messages are formatted with the native Drupal style, which is to say verbose. Below is a sample with a single user, node, and comment found in the requested interval that is echoed in the result (from/to tags). The dates are in extended ISO 8601 format, using the server's local timezone.

<?xml version="1.0"?>
<methodResponse>
<params>
<param>
<value>
<struct>
<member>
<name>users</name>
<value>
<struct>
<member>
<name>from</name>
<value>
<string>2007-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>until</name>
<value>
<string>2008-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>count</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>comments</name>
<value>
<struct>
<member>
<name></name>
<value>
<struct>
<member>
<name>uid</name>
<value>
<string>4</string>
</value>
</member>
<member>
<name>name</name>
<value>
<string>testuser</string>
</value>
</member>
<member>
<name>pass</name>
<value>
<string></string>
</value>
</member>
<member>
<name>mail</name>
<value>
<string>x@y.com</string>
</value>
</member>
<member>
<name>mode</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>sort</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>threshold</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>theme</name>
<value>
<string></string>
</value>
</member>
<member>
<name>signature</name>
<value>
<string></string>
</value>
</member>
<member>
<name>created</name>
<value>
<string>2007-12-13T10:44:10-0800</string>
</value>
</member>
<member>
<name>access</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>login</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>status</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>timezone</name>
<value>
<string></string>
</value>
</member>
<member>
<name>language</name>
<value>
<string></string>
</value>
</member>
<member>
<name>picture</name>
<value>
<string></string>
</value>
</member>
<member>
<name>init</name>
<value>
<string>x@y.com</string>
</value>
</member>
<member>
<name>data</name>
<value>
<string>a:0:{}</string>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
<member>
<name>nodes</name>
<value>
<struct>
<member>
<name>from</name>
<value>
<string>2007-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>until</name>
<value>
<string>2008-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>count</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>nodes</name>
<value>
<struct>
<member>
<name>1</name>
<value>
<struct>
<member>
<name>nid</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>vid</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>type</name>
<value>
<string>article</string>
</value>
</member>
<member>
<name>title</name>
<value>
<string>asdffad</string>
</value>
</member>
<member>
<name>uid</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>status</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>created</name>
<value>
<string>2007-11-20T17:02:51-0800</string>
</value>
</member>
<member>
<name>changed</name>
<value>
<string>2007-12-10T10:51:22-0800</string>
</value>
</member>
<member>
<name>comment</name>
<value>
<string>2</string>
</value>
</member>
<member>
<name>promote</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>moderate</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>sticky</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>body</name>
<value>
<string>qweriooooooooo faf</string>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
<member>
<name>comments</name>
<value>
<struct>
<member>
<name>from</name>
<value>
<string>2007-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>until</name>
<value>
<string>2008-12-09T23:56:57-0800</string>
</value>
</member>
<member>
<name>count</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>comments</name>
<value>
<struct>
<member>
<name>1</name>
<value>
<struct>
<member>
<name>cid</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>pid</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>nid</name>
<value>
<string>4</string>
</value>
</member>
<member>
<name>uid</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>subject</name>
<value>
<string>etr</string>
</value>
</member>
<member>
<name>comment</name>
<value>
<string>tqet</string>
</value>
</member>
<member>
<name>hostname</name>
<value>
<string>127.0.0.1</string>
</value>
</member>
<member>
<name>timestamp</name>
<value>
<string>2007-12-10T12:41:20-0800</string>
</value>
</member>
<member>
<name>score</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>status</name>
<value>
<string>0</string>
</value>
</member>
<member>
<name>format</name>
<value>
<string>1</string>
</value>
</member>
<member>
<name>thread</name>
<value>
<string>01/</string>
</value>
</member>
<member>
<name>users</name>
<value>
<string>a:1:{i:0;i:0;}</string>
</value>
</member>
<member>
<name>name</name>
<value>
<string>root</string>
</value>
</member>
<member>
<name>mail</name>
<value>
<string></string>
</value>
</member>
<member>
<name>homepage</name>
<value>
<string></string>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</member>
</struct>
</value>
</param>
</params>
</methodResponse>

Security Concerns

To provide a modicum of security for the intervalquery service, the IP address of the request is limited, in v.1.0, to localhost (127.0.0.1). In other words, the calling process must be calling from the same computer as the Drupal process.

In a future release, the IP address that is allowed will be configurable.

 

Creative Commons License
This page is licensed under a Creative Commons License.

  services about us contact
©2000-2007 Codeguild, Inc.
Codeguild is a service mark of Codeguild, Inc.