XML-RPC
As implied by the acronym, XML-RPC is an xml-based mechanism for supporting remote procedure calls. In this model, an client program bundles up a procedure call and a set of arguments in an XML document, and sends the document off to an XML server. The XML server executes the procedure call and bundles the return values in a second blob of XML, which is returned to the client for processing.
HTTP is used for XML-RPC communication, but at a level that will generally be invisible to OME developers.
XML-RPC Server
XML-RPC requests are handled by a daemon executing on the OME
server. The StandaloneServer.pl script (as found in
./src/perl2/OME/Remote) provides a basic instance of
such a server. This program can be invoked by
typing perl StandaloneServer.pl -t XMLRPC
. The
default port is 8002, alternatives can be specified with
the -p <port number>
flag. Finally, the
-d
option keeps the server from forking and
prints debug output on the console.
A note on ports: some operating systems (Mac OS X in particular) hold ports for several minutes after programs terminate. If you need to kill an instance of the server, it's often best to start the next instance with a fresh port.
StandaloneServer.pl is a simple wrapper which uses the
XMLRPC::Transport::HTTP::Daemon
class to dispatch
calls to a OME::Remote::Dispatcher
. This class
handles the calls from the XML-RPC clients. Specifically, the
dispatcher finds the appropriate classes for a given procedure
call, verifies the inputs, executes the method, and packages
the results appropriately.
OME::Remote::Dispatcher
relies
upon OME::Remote::Prototypes
to define the
methods that can be accessed via XML-RPC.
The Prototypes.pm file contains a number of calls to
addPrototype
. Each of these calls specifies a
class, a method, and formats for input and output. Only those
methods that are mentioned in the prototype file can be
executed via XML-RPC calls.
XML-RPC Client
OME currently contains an example XML-RPC client. This client, and the supporting libraries that it uses, are all written in Java. The client is not very interesting in itself — it simply provides a GUI browser for semantic types, semantic elements, and modules — but it provides a model of how to write an XML-RPC-based OME client.
The XML-RPC client is built on
the org.apache.xmlrpc.XmlRpc
,
org.apache.xmlrpc.XmlRpcClient
, and
org.apache.xmlrpc.XmlRpcClientLite
packages,
available from Apache.
These packages provide the low-level handling of XML-RPC.
As currently distributed, the JAR files containing the required libraries can be found in the src/java/lib directory under CVS. However, the appropriate class paths must be manually established — speak to the OME developers for help.
The Alligator application
— org.openmicroscopy.alligator.Alligator
— is the
client GUI application. The code in Alligator provides an
overview of what is needed to communicate with OME via
XML-RPC. The support libraries found
in org.openmicroscopy
and org.openmicroscopy.remote
manage the OME
objects and related functionality. These packages have
somewhat parallel structure: org.openmicroscopy
defines interfaces that are implemented by classes in
org.openmicroscopy.remote
. This cleanly allows
for the possibility of non-remote implemenations of these
interfaces. All of the database objects in the remote package
are subclasses of the RemoteOMEObject
class,
which is a subclass of RemoteObject
. Together,
these base classes provide support for OME objects that are
derived from a remote database.
The first interaction with OME can be seen in the Alligator
login code (in Controller.java), which creates a
RemoteBindings
object and uses it to login to the
OME Server, thus creating a session and a factory. This is
done using the URL specified in the login dialog, which should
correspond to an invocation of the StandaloneServer. To
execute a login, the RemoteBindings
object does
creates an XmlRpcCaller
, which wraps
an XmlRpcClientLite
(from the Apache XML
libraries) object and handles the execution of XML-RPC calls.
Note that the login procedure in Alligator does not take
advantage of the stored sessions as implemented in the Perl
code. There are two reasons for this:
the Dispatcher
does not expose a method for
creating sessions based on a stored session cookie, and the
client code does not have the libraries for handling this form
of login (the Java analogs of the
Perl Apache::Session
packages).
After login, the controller object calls the database to populate GUI widgets with the semantic types and modules found in the database. The remainder of this section will focus on the semantic types — the modules are similar.
The list of semantic types is udpated by setting the table
model for a JTable
to contain a list of objects
as returned by the XML-RPC server. This list is retrieved by
caling SemanticTypeTableModel.update(factory)
with the factory for the current session. Note that this code
is wrapped in external threads so as to avoid interference
with the GUI-building thread.
The update method is used to find all of
the SemanticType
s in the factory
(factory.findObjects("OME::SemanticType",null)
).
To find these objects, the factory sends
a findObjects
message to
the XmlRpcCaller
, with a set of criteria
indicating that objects of type
OME::SemanticType
are desired. The result of
this call is a list of objects, which are instantiated as
SemanticType
s, using the mapping in the
RemoteObject
static Hash classes
.
Thus, as we see in RemoteSemanticTypes.java, all
objects of type OME::SemanticType
are instantiated as
RemoteSemanticType
objects. The names of these
semantic type objects are then used to populate the list of
remote types (see getValueAt()
in ThreadedTypeTableModel.java
and getValueAtFromList()
in
SemanticTypeTableModel.java).
When one of the items in the table is selected (double
clicked), the controller displays the details of this semantic
type and its elements in a new frame
(SematicTypeFrame
). The elements are retrieved
by calling getElements()
on the remote semantic
type. This procedure leads to another XML-RPC call, which
calls for
semantic_elements
to be executed as the method
against the selected semantic type. As before, the result is
a list of objects, which are then intantiated
as Elements
(defined
in RemoteSemanticType
).