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.
This page
is licensed under a Creative
Commons License.
|