/**
* a software bus package
*
* @author François-Régis Colin
* @author Yannick Jestin
* @author http://www.tls.cena.fr/products/ivy/
*
*/
package fr.dgac.ivy ;
import java.net.*;
import java.io.*;
import java.util.Vector;
import java.util.Hashtable;
/**
* A class connecting to the Ivy software bus.
* For example:
*
*Ivy bus = new Ivy("Dummy agent","ready",null);
*bus.bindMsg("(.*)",myMessageListener);
*bus.start(null);
*
*/
public class Ivy implements Runnable, IvyApplicationListener {
/**
* the name of the application on the bus
*/
public String appName;
/**
* the protocol version number
*/
public static final int PROCOCOLVERSION = 3 ;
/**
* the port for the UDP rendez vous, if none is supplied
*/
public static final int DEFAULT_PORT = 2010 ;
/**
* the domain for the UDP rendez vous
*/
public static final String DEFAULT_DOMAIN = "127.255.255.255:"+DEFAULT_PORT;
/**
* the library version
*/
public static String libVersion ="1.0.9";
private boolean debug;
private static int serial=0; /* an unique ID for each regexp */
private ServerSocket app;
private IvyWatcher watch;
private Thread server;
private Hashtable callbacks = new Hashtable();
private Vector clients = new Vector();
private Vector ivyApplicationListenerList = new Vector();
private String messages_classes[] = null;
int applicationPort; /* Application port number */
boolean ivyRunning = false;
Hashtable regexp_out = new Hashtable();
String ready_message = null;
/**
* Readies the structures for the software bus connexion.
*
* All the dirty work is done un the start() method
* @see #start
* @param name The name of your Ivy agent on the software bus
* @param message The hellow message you will send once ready
* @param appcb A callback handling the notification of connexions and
* disconnections, may be null
*/
public Ivy( String name, String message, IvyApplicationListener appcb) {
appName = name;
ready_message = message;
debug = (System.getProperty("IVY_DEBUG")!=null);
if ( appcb != null ) ivyApplicationListenerList.addElement( appcb );
}
/**
* connects the Ivy bus to a domain or list of domains.
*
* One thread (IvyWatcher) to watch rendezvous traffic (UDP or TCPMulticast)
* One thread (server/Ivy) to accept incoming connexions on server socket
* a thread for each IvyClient when the connexion has been done
*
* @param domainbus a domain of the form 10.0.0:1234, it is similar to the
* netmask without the trailing .255. This will determine the meeting point
* of the different applications. Right now, this is done with an UDP
* broadcast. Beware of routing problems ! You can also use a comma
* separated list of domains.
*
*/
public void start(String domainbus) throws IvyException {
try {
app = new ServerSocket(0);
applicationPort = app.getLocalPort();
} catch (IOException e) {
throw new IvyException("can't open TCP service socket " + e );
}
traceDebug("lib: "+libVersion+" protocol: "+PROCOCOLVERSION+" TCP service open on port "+applicationPort);
watch = new IvyWatcher(this);
ivyRunning = true;
server = new Thread(this);
server.start();
watch.start(getDomain(domainbus));
}
/**
* disconnects from the Ivy bus.
*/
public void stop() {
if (!ivyRunning) { return; }
try {
app.close();
ivyRunning = false;
watch.stop();
for (int i=0;iThere is one thread for each client connected, we could also
* create another thread each time we send a message.
* @param message A String which will be compared to the regular
* expressions of the different clients
* @return the number of messages actually sent
*/
public int sendMsg( String message ) {
int count = 0;
// TODO ? an alternate implementation is one sender thread per client
// instead of one for all the clients. It might be a performance issue
for ( int i = 0 ; i < clients.size(); i++ ) {
IvyClient client = (IvyClient)clients.elementAt(i);
count += client.sendMsg( message );
}
return count;
}
/**
* Subscribes to a regular expression.
*
* The callback will be executed with
* the saved parameters of the regexp as arguments when a message will sent
* by another agent. A program doesn't receive its own messages.
* Example:
*
the Ivy agent A performs
b.bindMsg("^Hello (*)",cb);
*
the Ivy agent B performs b2.sendMsg("Hello world");
*
a thread in A will uun the callback cb with its second argument set
* to a array of String, with one single element, "world"
* @param regexp a perl regular expression, groups are done with parenthesis
* @param callback any objects implementing the IvyMessageListener
* interface, on the AWT/Swing framework
* @return the id of the regular expression
*/
public int bindMsg(String regexp, IvyMessageListener callback ) {
// creates a new binding (regexp,callback)
Integer key = new Integer(serial++);
regexp_out.put(key,regexp);
callbacks.put(key,callback );
// notifies the other clients this new regexp
for (int i=0;iivy<-- "+s);
}
// TODO find out if this is useful or not ...
private void classes( String msg_classes[] ) {
messages_classes = msg_classes;
}
} // class Ivy
/* EOF */