/** * 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.11"; 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) { traceDebug("was already stropped ..."); return; } try { ivyRunning = false; app.close(); 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 */