Ponder2 Communications

The Ponder2 SMC is capable of exporting Managed Objects from one SMC and importing them into another. Actually a reference is imported and any messages sent to the imported reference are sent as messages to the remote object. Similarly, replies from the remote object are returned to the local initiator of the messages. These message interactions are performed completely transparently with no setup being required by the user. Thus, you cannot tell whether a Managed Object is a local or remote one.

The Ponder2 SMC knows that Managed Objects may be remote but it has no knowledge of any protocols that may be used to pass the messages to and fro, external libraries need to be given on the classpath to so that protocol modules may be dynamically loaded as required. In the standard release, ponder2comms.jar contains some protocols that Ponder2 may use for inter-Ponder2 communications. Ponder2 knows nothing about protocols until it comes across a URL containing an unknown protocol either because it is started with the -address option or a remote object is specified using a URL. If the SMC does not recognise the protocol, and the first time it definitely will not, the SMC will search the classpath to see if an appropriate protocol module exists, if so it is loaded and used.

If you wish to use a protocol that has not been supplied in ponder2comms.jar then it is a simple matter to write your own protocol module for inter-Ponder2 communications. Once you have done so you just have to include your jar file in the Ponder2 classpath and it will be loaded when necessary, no configuration or changes to the Ponder2 core software are required.

Description

Communications protocols are divided into two sections, a transmitter for sending requests to another Ponder2 application and a receiver for receiving requests from remote Ponder2 applications. There are two operations that Ponder2 communications supports:

getObject

takes a pathname and returns a remote object. This is invoked by the following PonderTalk example:
root import: "root/dom/object" from: rmi://localhost/ponder2
which will load the Java RMI protocol module and use RMI as the communications channel.

execute

takes the unique id (OID) of a remote object, an operation and its arguments that are to be sent as a message to that remote object. The resulting object is returned. This operation is invoked by any use of a remote object that has already been imported using the getObject operation.

The transmitter has to pack up the arguments and transmit them to the remote end. The remote end has to receive the packed arguments, unpack them and call the equivalent recieve getObject and execute methods to perform the desired operations. The methods that perform all the work of locating the managed object and sending the messages are already included in Ponder2 and do not need to be written as part of the protocol.

Current Protocols Supplied

There are two protocols currently included in Ponder2Comms, they are, Java Remote Method Interaction (RMI) and HTTP Web Services.

RMI

Before using RMI communications in Ponder2, the Java RMI registry must be running on all the computers that Ponder2 is to run on.

When invoked, the RMI receive class registers itself with the Java RMI registry to enable it to receive RMI calls. These calls will occur asynchronously to the current operations of Ponder2.

To use RMI, the java.rmi.server.codebase property value must be set correctly. It represents one or more URL locations from which the RMI stub code used by the Java RMI system (and any classes needed by the stubs) can be downloaded. This property must be set to a URL which can be an http:// URL or a file:///full/pathname/... URL. If multiple JAR files are to be specified, as is the case here, then the URLs are separated by a space. As usual, if there is more than one argument then quotes are required to keep them together. The Ant build.xml command file already sets up the codebase correctly so you need not worry about it if you are using this file.

To make sure that Ponder2 registers itself with a particular name, the -address option can be given when it is started1

  java -Djava.rmi.server.codebase="file:///full/pathname/ponder2.jar file:///full/pathname/ponder2comms.jar"\
       -classpath ponder2.jar:ponder2comms.jar net.ponder2.SelfManagedCell -address rmi://localhost/MyPonder

The address argument may be repeated to register Ponder2 under several different names at the same time. See -address for more information.

Errors

Note: The following error indicates that ponder2comms.jar cannot be located by RMI via the codebase property.

RmiProtocol cannot create Ponder2: RemoteException occurred in server thread; nested exception is:
        java.rmi.UnmarshalException: error unmarshalling arguments; nested exception is:
        java.lang.ClassNotFoundException: net.ponder2.comms.rmi.RMIReceiveInterface

Note: It is possible that you will get a class not found error involving Element or TaggedElement in which case you will have to add qdparser.jar to the codebase argument.

SSComms

Single Socket Communications. This is a protocol using a simple server that allows a Ponder2 SMC to create a single TCP socket and then send and receive messages asynchronously over it. This allows a device, like a phone, that can only make outgoing TCP connections to participate fully in a distributed environment. Messages send to the SMC will be received over the same connection that outgoing messages are using.

SSComms requires a server that must be run on an accessible host computer. Every SMC taking part in the distributed system makes a connection to the server and all communications takes place to and from the server with the server routing the messages based on the addresses being used. the server is started as:

  java -jar sscomms.jar

This will start the server and will log all messages being sent through it. You can type a 't' command to it and that will turn tracing on or off so you can see the contents of the messages passing through.

SMC clients use the ssc protocol. e.g.

  java -classpath ponder2.jar:ponder2comms.jar:sscomms.jar net.ponder2.SelfManagedCell -address ssc://hostip/myphone

This will start an SMC which will open a socket to a server on the given host hostip and register itself as myphone. If another SMC want to communicate, e.g. import an object, then it can do:

  remoteobj := root import: "ssc://hostip/myphone".

The address argument may be repeated to register Ponder2 under several different names at the same time. See -address for more information.

HTTP/Web Services

HTTP Web Services only includes a transmitter class for making Web Service calls. Calls are received via Web Services by a web server which then forwards them to Ponder2 using RMI; thus no state is required at the web server for Ponder2 communications.

A special Java Web Service (.jws) file is included in the Ponder2 Comms distribution and also attached here at Ponder2.jws. This file can be used by Apache Axis under Apache Tomcat to provide the appropriate Web Service interface to Ponder2 communications.

To run Ponder2 using HTTP and Axis you must configure Axis

  1. Copy the Ponder2.jws file to AXIS_HOME
  2. Copy ponder2.jar and ponder2comms.jar to AXIS_HOME/WEB-INF/lib
  3. Restart Axis

There is a detailed step by step description in Ponder2 with Axis.

You must also include all the following files in your classpath:

  ponder2.jar
  ponder2comms.jar
  commslib/activation.jar
  commslib/axis.jar
  commslib/commons-discovery-0.2.jar
  commslib/commons-logging-1.0.4.jar
  commslib/jaxrpc.jar:commslib/mail.jar
  commslib/saaj.jar
  commslib/wsdl4j-1.5.1.jar

The Ponder2.jws file communicates with Ponder2 using Java RMI and expects the registered name to be Ponder2 therefore Ponder2 must be started with the option

If you want to use a different name then change the .jws file and restart Axis.

Managed objects can be imported from this Ponder2 instance using:

   1 root import: "root/an/object" from: "http://www.host.com:8080/axis/Ponder2.jws"

Rolling your own

To add your own protocol it is probably a good idea to look at the current code for RMI communications. The class named net.ponder2.comms.RmiProtocol has a special name, the others can be called anything and are grouped into the package net.ponder2.comms.rmi for convenience.

Class

Description

net.ponder2.comms.RmiProtocol

When the RMI protocol is first mentioned in a URL e.g. rmi://localhost/Ponder2 this is the class that is located dynamically by Ponder2. It must have this name. The name is calculated from the scheme, in this case "rmi" Note the capital letters, the first letter of the scheme is capitalised as is the first letter of the word "Protocol". This class knows of the classes mentioned below and makes use of them. None of the other classes have special names

net.ponder2.comms.rmi.RMIReceiveInterface

Needed by the RMI protocol for communications

net.ponder2.comms.rmi.RMIReceiver

The receiver, registered with the RMI registry by the class RmiProtocol, that waits for RMI communications

net.ponder2.comms.rmi.RMITransmitter

The transmitter registered with Ponder2 by the RmiProtocol class. This is used to send inter-Ponder2 requests

Let's say we want to write a protocol for Appletalk. We will use URLs of the form atalk://an/appletalk/specific/address. When a URL of this form is used, Ponder2 will look for a class called net.ponder2.comms.AtalkProtocol. This class simply contains an install method which may perform some protocol specific initialisation and it may set up a receiver in another thread. It must then register the transmit side of the protocol into Ponder2. e.g.

   1 public class AtalkProtocol implements net.ponder2.comms.Protocol {
   2   public void install(URI address) {
   3     // Perform protocol specific initialisation
   4     initialiseAtalk();
   5     // Start a receive thread for the protocol
   6     new ATALKReceiver(address);
   7     // Now register the protocol and let the external managed object use it
   8     ExternalManagedObject.registerProtocol("atalk", new ATALKTransmitter(), address);
   9   }
  10 }

The argument to install is the address that this Ponder2 application will be know by to the outside world using this protocol i.e. our address using the protocol to be installed. The arguments to registerProtocol (API http://InDocHereSomewhere) are:

String name

The name of the protocol

ExternalCommsProtocol transmitter

An instance of the protocol transmitter so that messages can be sent to another Ponder2 application.

URI address

The address so that it can be embedded in OIDs so that given an OID any Ponder2 application can communicate with our Ponder2 application using the protocol that is being loaded.

As mentioned above Ponder2 uses getObject and execute to communicate. In addition, the transmitter instance has a connect method which is called every time a new address using that protocol is to be used. Connect can act as a factory method returning a new instance of the transmitter if state is required for each remote address, or it can return itself if address resolution is to be performed every time getObject and execute are called.

   1 public interface Transmitter {
   2 
   3   /**
   4    * creates and connects a Transmitter to a remote location. This is called
   5    * once every time a new remote address is brought into play. If the location
   6    * is important to the Transmitter i.e. a permanent channel is opened then a
   7    * new instance of transmitter should be created. If the remote location does
   8    * not matter then only one instance of the Transmitter need be created and
   9    * this method can return itself.
  10    *
  11    * @param address
  12    *            the location that this protocol is to be connected to
  13    * @return a new communications protocol connected to the appropriate place or
  14    *         null if it fails
  15    */
  16   public Transmitter connect(URI address);
  17 
  18   /**
  19    * gets a managed object from a remote SMC
  20    *
  21    * @param location
  22    *            the address of the remote SMC
  23    * @param path
  24    *            the full path name of the remote managed object
  25    * @return the result of the operation.
  26    * @throws Ponder2Exception if an exception occurs in the remote system
  27    */
  28   public P2Object getObject(URI address, String path) throws Ponder2Exception;
  29 
  30   /**
  31    * executes commands at a remote managed object. The command will either be a
  32    * create or use clause.
  33    *
  34    * @param address
  35    *            the address of the remote SMC
  36    * @param target
  37    *            the remote object's OID
  38    * @param source
  39    *            the originator of the operation
  40    * @param op
  41    *            the operation to be performed
  42    * @param args
  43    *            the arguments for the operation
  44    * @return the result of the operation
  45    * @throws Ponder2Exception if an exception occurs in the remote system
  46    */
  47   public P2Object execute(URI address, OID target, P2Object source, String op, P2Object[] args)
  48       throws Ponder2Exception;
  49 }

The information in the arguments must be transferred, using the protocol, to the remote Ponder2 application (marshalling). At the receiving end, the arguments must be reconstructed and the supplied receive methods can be called to do all the work(unmarshalling).

A suitable transmitter for AppleTalk could be:

   1 package net.ponder2.comms.atalk;
   2 
   3 import java.net.URI;
   4 
   5 import net.ponder2.P2Object;
   6 import net.ponder2.comms.Transmitter;
   7 import net.ponder2.exception.Ponder2Exception;
   8 
   9 /**
  10  * This class embodies the sending mechanism for inter-SMC communications using
  11  * the AppleTalk protocol.
  12  *
  13  * @author Kevin Twidle
  14  */
  15 public class ATALKTransmitter extends TransmitterImpl implements Transmitter {
  16 
  17   public Transmitter connect(URI location) {
  18     // We will use the location whenever we send something
  19     // otherwise we would return new ATALKTransmitter(location)
  20     return this;
  21   }
  22 
  23   public P2Object getObject(URI location, String path) throws Ponder2Exception {
  24     // We assume that the AppleTalk protocol can only send and receive a single String
  25     // So pack all the arguments into a single XML structure and sent it as a String
  26     // We will receive an XML string containing a reply object
  27     // We will use the supplied helper routine which will call execute to perform the transfer
  28     return getObjectString(location, path);
  29   }
  30 
  31   public P2Object execute(URI address, OID target, P2Object source, String op, P2Object[] args)
  32     throws Ponder2Exception {
  33       return executeString(address, target, source, op, args);
  34   }
  35 
  36   protected String execute(URI address, String xmlString) throws Ponder2Exception {
  37     try {
  38       return sendThisAtalkMsg(location, xmlString);
  39     }
  40     catch (AtalkRemoteException e) {
  41       throw new Ponder2OperationException(e.getMessage());
  42     }
  43   }
  44 }

On the receiving end we need something like:

   1   // Called when AppleTalk receives a message
   2   // This assumes a request - reply mechanism
   3 
   4   public TaggedElement getObject(URI location, String path) throws Ponder2Exception {
   5     // Receiver.execute() may call this routine
   6     return Receiver.getObject(location, path).writeXml();
   7   }
   8 
   9   public String execute(String sxml) throws Ponder2Exception {
  10     // Make use of XML string helper code, it will decode and execute the call.  It will
  11     // encode the result as a String an return the result.
  12     return Receiver.execute(sxml);
  13   }


  1. use ; in the classpath for Windows (1)

Ponder2Comms (last edited 2010-03-23 16:55:53 by KevinTwidle)