CLISER allows to call XEP from any language with access to TCP sockets. A client application connects to XEP server by means of a simple protocol, sends an XSL Formatting Objects document and receives its formatted representation. Clients in several languages, including Perl, C, and Java, are provided.
Table of Contents
Originally, we introduced XEP CLISER to support SEEXEP, an on-line preview of a new (at that time) version of RenderX XEP. The web form was backed by a CGI script written in Perl, and we needed a way to call XEP from Perl. Launching Java for each request would mean high load and slow response (1 second at least to start JVM).
The obvious solution had been to start XEP once and to call it via an IPC channel; a solution based on TCP sockets had proved to be the simplest and the most straightforward one. It lets develop lightweight clients in various languages easily, and the server-side code is still simple enough to be stable. After the public launch, the service had run for several months almost unattended, and the load during first several weeks had been high enough to confirm the need for and feasibility of the solution.
A significant problem worth mentioning is the handling of images local to the client side. The protocol must have a means to pass them from the client to the server so that the server can render the images in the document. Among many ways to implement it, we chose to let the server query the client for client-local images it needs, and the client to send the images to the server over the same connection. Implemented in this manner, the protocol needs only a single communication channel, the server and the client are free to use their own file systems and run on different platforms, and relative images local to the client are handled transparently, with the source XSL FO document remaining intact.
The distribution contains:
documentation describing the protocol and the implementations;
Java source code;
client modules and command-line utilities in Perl, Python and C;
C client module and command-line utility;
generated Java API documentation for Java classes;
compiled java classes in a single Java archive file;
Makefile to compile Java and C sources, suits both BSD and Gnu make utilities.
The XEP CLISER protocol is connection-oriented; it uses plain-text commands; to send binary data, it first announces the length of the data to be sent. A single session allows to format multiple files and to change server options, such as the output format, as well as options for the formatter and an output generator. Failures caused by the environment (lost connection, file system error, protocol violation) will stop the session; but the server continues to process queries when a new session is established.
Both sides send to introduce themselves to each other. The major number (digit before the dot) must be the same at both ends.
Both sides send, requests shutdown of the peer.
Both sides send, confirms successful operation.
Both sides send, a protocol-related warning.
Both sides send, a protocol error.
Server sends, XEP log entry.
Client sends, sets a server-side option.
Server sends, requests a file from the client.
Both sides send, announces data transfer, the string is either a system identifier or a format, depending on the context.
There are three automata, the main server, the file requester on the server, and the client. The tables below outline states and transitions for each of them. For convenience, the client automaton is split into parts.
Table 1. Server
|Connected, send HELO.||If versions match, send OK and go to Ready, otherwise, send BYE and go to Shutdown.||Go to Shutdown.|
|Ready||Go to Shutdown.||Set server property, remain Ready.||Receive source, send RECV on success, ERR on errors and remain Ready. Send BYE on fatal errors and go to Shutdown.|
The following automaton comes into play when the server needs an external-graphic relative to a client-local document.
In the tables below, protocol commands are in upper case, API calls are in lower case letters.
Table 3. Handshake
|Connected||If versions match, send HELO, go to Introduced, otherwise, send BYE, go to Shutdown.|
|Introduced||Go to Shutdown.||Go to Ready.|
Table 4. Ready to Render
|Ready||Send SET, remain Ready.||Go to Render.||Go to Shutdown.|
The server-side part of the protocol is implemented in com.renderx.xepx.cliser.Server. com.renderx.xepx.cliser.MTServer wraps a multi-threaded server around the core functionality, making it possible to concurrently serve multiple requests.
com.renderx.xepx.cliser.SampleEngine is a simple server launcher with command-line interface, once started it listens for incoming connections (the port is 6570 by default and can be changed by com.renderx.xepx.cliser.port java property or '-port' command-line switch) and launches server threads for each of them.
Clients in Java, C, Python, Perl and C# are provided with the distribution. The APIs are documented, javadoc in Java, Pod in Perl, Python documentation strings for Python. Client APIs are similar, but not identical; each implementation has been written in a way natural for the host language. We encourage the user to pursue the API descriptions and source codes of the clients.
The implementation, along with a sample command-line interface. is in class com.renderx.xepx.cliser.Client. An application passes a connected socket to the constructor to create a client instance.
The client is in xec.h, xec.c; the sample command line utility is in xcc.c. The client can only handle one connection at a time, an application specifies server's host name and port number to initiate a session. to
The client is in package XEPX::CLISER::Client, the command-line driver is in xcc.pl. Plain Old Documentation, embedded into the source code of the client and explains the interface in detail. The constructor optionally expects server's host name and port number; the implementation uses IO::Socket to maintain the connection.
The client is implemented as class xepx.cliser.Client, the command-line driver is in xcc.py. EnMasse, the XEP multiplexer, uses Python implementation of CLISER.
The client is implemented as class Cliser.CliserClient, the command-line driver is CliserDriver.CliserDriver.
All clients can format multiple files and generate different output formats during a single session; they have been tested on a single computer and in a distributed environment.