/** * 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; import java.util.StringTokenizer; /** * 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; private static boolean debug = (System.getProperty("IVY_DEBUG")!=null) ; private static int serial=0; /* an unique ID for each regexps */ 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; if ( appcb != null ) ivyApplicationListenerList.addElement( appcb ); } /** * connects the Ivy bus to a domain or list of domains * @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("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. * TODO is there a bug here ? There is still a thread running and a * standalone application won't quit here. */ public void stop() { try { ivyRunning = false; watch.stop(); app.close(); for ( int i = 0 ; i < clients.size(); i++ ) { IvyClient client = (IvyClient)clients.elementAt(i); client.close("normal Ivy Stopping..."); // advertise that this is a normal //close for debugging purposes } } catch (IOException e) { traceDebug("IOexception Stop "); } clients.removeAllElements(); } /** * Performs a pattern matching according to everyone's regexps, and sends * the results to the relevant ivy agents. *

There 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: il faudrait mettre une Thread emission par client */ 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; } }