/** * a software bus package * * @author Yannick Jestin * @author http://www.tls.cena.fr/products/ivy/ * * (c) CENA 1998-2004 * *
*Ivy bus = new Ivy("Dummy agent","ready",null); *bus.bindMsg("(.*)",myMessageListener); *bus.start(getDomain(null)); ** * CHANGELOG: * 1.2.8: * - addclient and removeclient going synchronized * - domainaddr goes protected in Domain ( gij compatibility ) * - checks if (Client)e.nextElement() each time we want to ... * Multithreaded Enumerations ..., should fix [YJnul05] * - added getDomainArgs(String,String[]) as a facility to parse the * command line in search of a -b domain * - added getWBUId(), un function returning a string ID to perform * queries, computed strings look like IDTest0:1105029280616:1005891134 * - empties the watchers vector after a stop(), and handles the "stopped" * better, FIXES FJ's bugreport stop/start * 1.2.7: * - minor fixes for accessing static final values * 1.2.6: * - added serial numbers for traceDebug * - changed the semantic of -b a,b:port,c:otherport if no port is * specified for a, it take the port from the next one. If none is * specified, it takes DEFAULT_PORT * - no more asynchronous sending of message ( async bind is ok though ) * because the tests are sooooo unsuccessful * - use addElement/removeElement instead of add/remove is registering * threads ( jdk1.1 backward compatibility ) * 1.2.5: * - protection of newlines * 1.2.4: * - added an accessor for doSendToSelf * - waitForMsg() and waitForClient() to make the synchronization with * other Ivy agents easier * - with the bindAsyncMsg() to subscribe and perform each callback in a * new Thread * - bindMsg(regexp,messagelistener,boolean) allow to subscribe with a * synchrone/asynch exectution * - API change, IvyException raised when \n or \0x3 are present in bus.sendMsg() * - bindListener are now handled * - removeApplicationListener can throw IvyException * - bus.start(null) now starts on getDomain(null), first the IVYBUS * property, then the DEFAULT_DOMAIN, 127:2010 * - bindMsg() now throws an IvyException if the regexp is invalid !!! * BEWARE, this can impact lots of programs ! (fixes J007) * - no more includes the "broadcasting on " in the domain(String) method * - new function sendToSelf(boolean) allow us to send messages to * ourselves * 1.2.3: * - adds a IVYBUS property to propagate the domain once set. This way, * children forked through Ivy java can inherit from the current value. * - adds synchronized flags to allow early disconnexion * 1.2.2: * added the String domains(String d) function, in order to display the * domain list * 1.2.1: * bus.start(null) now starts on DEFAULT_DOMAIN. ( correction 1.2.4 This was not true.) * added the getDomains in order to correctly display the domain list * checks if the serverThread exists before interrupting it * no has unBindMsg(String) * 1.2.0: * setSoTimeout is back on the server socket * added a regression test main() * clients is now a Hashtable. the deletion now works better * getIvyClientsByName allows the research of IvyClient by name * getDomain doesnt throw IvyException anymore * removed the close() disconnect(IvyClient c). Fixes a big badaboum bug * getDomain becomes public * adding the sendToSelf feature * fixed the printStackTrace upon closing of the ServerSocket after a close() */ package fr.dgac.ivy ; import java.net.*; import java.io.*; import java.util.*; import gnu.getopt.Getopt; public class Ivy implements Runnable { /** * the name of the application on the bus */ String appName; /** * the protocol version number */ public static final int PROTOCOLVERSION = 3 ; public static final int PROTOCOLMINIMUM = 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, useful for development purposes only, when java is * invoked with -DIVY_DEBUG */ public static final String libVersion ="1.2.8"; private boolean debug; private ServerSocket app; private Vector watchers = new Vector(); private volatile Thread serverThread; // to ensure quick communication of the end private Hashtable clients = new Hashtable(); private Hashtable half = new Hashtable(); private Vector ivyApplicationListenerList = new Vector(); private Vector ivyBindListenerList = new Vector(); private Vector sendThreads = new Vector(); private boolean stopped=true; protected int applicationPort; /* Application port number */ protected String ready_message = null; protected boolean doProtectNewlines = false ; private boolean doSendToSelf = false ; protected SelfIvyClient selfIvyClient ; public final static int TIMEOUTLENGTH = 1000; private static int serial=0; private int myserial=serial++; static long current = System.currentTimeMillis(); private static java.util.Random generator = new java.util.Random(current*(serial+1)); /** * 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 ); selfIvyClient=new SelfIvyClient(this,name); } /** * Waits for a message to be received * * @since 1.2.4 * @param regexp the message we're waiting for to continue the main thread. * @param timeout in millisecond, 0 if infinite * @return the IvyClient who sent the message, or null if the timeout is * reached */ public IvyClient waitForMsg(String regexp,int timeout) throws IvyException { Waiter w = new Waiter(timeout); int re = bindMsg(regexp,w); IvyClient ic=w.waitFor(); unBindMsg(re); return ic; } /** * Waits for an other IvyClient to join the bus * * @since 1.2.4 * @param name the name of the client we're waiting for to continue the main thread. * @param timeout in millisecond, 0 if infinite * @return the first IvyClient with the name or null if the timeout is * reached */ public IvyClient waitForClient(String name,int timeout) throws IvyException { IvyClient ic; if (name==null) throw new IvyException("null name given to waitForClient"); // first check if client with the same name is on the bus if ((ic=alreadyThere(clients,name))!=null) return ic; // if not enter the waiting loop WaiterClient w = new WaiterClient(name,timeout,clients); int i = addApplicationListener(w); ic=w.waitForClient(); removeApplicationListener(i); return ic; } /* * since 1.2.8 */ static protected IvyClient alreadyThere(Hashtable c,String name) { IvyClient ic; for (Enumeration e=c.elements();e.hasMoreElements();) { try { ic = (IvyClient)e.nextElement(); } catch (ArrayIndexOutOfBoundsException _ ) { return null; // with gij, it ... can happen } if ((ic!=null)&&(name.compareTo(ic.getApplicationName())==0)) return ic; } return null; } /** * connects the Ivy bus to a domain or list of domains. * *
Example:
*
the Ivy agent A performs
b.bindMsg("^Hello (*)",cb);*
b2.sendMsg("Hello world");*
Example:
*
the Ivy agent A performs
b.bindMsg("^Hello (*)",cb);*
b2.sendMsg("Hello world");*