diff options
author | jestin | 2002-06-07 11:18:02 +0000 |
---|---|---|
committer | jestin | 2002-06-07 11:18:02 +0000 |
commit | be2d18b332eb74b6529e18a8f10abf71fcd7382a (patch) | |
tree | 66a3cd8752422dc63ee5ddfeb781c11ec4879212 /src/Ivy.java | |
parent | 56bad1fac964a8562ef46fa995766e9e28173dc5 (diff) | |
download | ivy-java-be2d18b332eb74b6529e18a8f10abf71fcd7382a.zip ivy-java-be2d18b332eb74b6529e18a8f10abf71fcd7382a.tar.gz ivy-java-be2d18b332eb74b6529e18a8f10abf71fcd7382a.tar.bz2 ivy-java-be2d18b332eb74b6529e18a8f10abf71fcd7382a.tar.xz |
doc change for the new release
Diffstat (limited to 'src/Ivy.java')
-rwxr-xr-x | src/Ivy.java | 227 |
1 files changed, 151 insertions, 76 deletions
diff --git a/src/Ivy.java b/src/Ivy.java index 08f3c6c..15926bc 100755 --- a/src/Ivy.java +++ b/src/Ivy.java @@ -10,8 +10,7 @@ package fr.dgac.ivy ; import java.net.*; import java.io.*; -import java.util.Vector; -import java.util.Hashtable; +import java.util.*; /** * A class connecting to the Ivy software bus. @@ -24,15 +23,22 @@ import java.util.Hashtable; * * CHANGELOG: * 1.0.12: + * - 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() */ -public class Ivy implements Runnable, IvyApplicationListener { +public class Ivy implements Runnable { /** * the name of the application on the bus */ - public String appName; + String appName; /** * the protocol version number */ @@ -49,22 +55,25 @@ public class Ivy implements Runnable, IvyApplicationListener { * the library version, useful for development purposes only, when java is * invoked with -DIVY_DEBUG */ - public static final String libVersion ="1.0.12"; + public static final String libVersion ="1.2.0"; private boolean debug; - private static int serial=0; /* an unique ID for each regexp */ + private static int serial=0; /* an unique ID for each regexp */ + private static int clientSerial=0; /* an unique ID for each IvyClient */ private ServerSocket app; - private IvyWatcher watch; - private Thread server; + private Vector watchers; + private volatile Thread serverThread; // to ensure quick communication of the end private Hashtable callbacks = new Hashtable(); - private Vector clients = new Vector(); + private Hashtable clients = new Hashtable(); private Vector ivyApplicationListenerList = new Vector(); private String messages_classes[] = null; - + private boolean sendToSelf = false ; + private boolean stopped = false; int applicationPort; /* Application port number */ - boolean ivyRunning = false; Hashtable regexp_out = new Hashtable(); String ready_message = null; + + public final static int TIMEOUTLENGTH = 3000; /** * Readies the structures for the software bus connexion. @@ -86,8 +95,8 @@ public class Ivy implements Runnable, IvyApplicationListener { /** * connects the Ivy bus to a domain or list of domains. * - * <li>One thread (IvyWatcher) to watch rendezvous traffic (UDP or TCPMulticast) - * <li>One thread (server/Ivy) to accept incoming connexions on server socket + * <li>One thread (IvyWatcher) for each traffic rendezvous (either UDP broadcast or TCPMulticast) + * <li>One thread (serverThread/Ivy) to accept incoming connexions on server socket * <li>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 @@ -100,41 +109,63 @@ public class Ivy implements Runnable, IvyApplicationListener { public void start(String domainbus) throws IvyException { try { app = new ServerSocket(0); + app.setSoTimeout(TIMEOUTLENGTH); 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)); + watchers = new Vector(); + + // readies the rendezvous : an IvyWatcher (thread) per domain bus + StringTokenizer st = new StringTokenizer(domainbus,","); + while ( st.hasMoreTokens()) { + String s = st.nextToken() ; + String domainaddr=IvyWatcher.getDomain(s); + int port=IvyWatcher.getPort(s); + IvyWatcher watcher =new IvyWatcher(this,domainaddr,port); + watchers.addElement(watcher); + } + serverThread = new Thread(this); + serverThread.start(); + // sends the broadcasts and listen to incoming connexions + for (int i=0;i<watchers.size();i++){ ((IvyWatcher)watchers.elementAt(i)).start(); } } /** - * disconnects from the Ivy bus. + * disconnects from the Ivy bus */ public void stop() { - if (!ivyRunning) { - traceDebug("was already stropped ..."); - return; - } + if (stopped ) return; + traceDebug("beginning stopping the bus"); try { - ivyRunning = false; + // stopping the serverThread + Thread t=serverThread; + serverThread=null; + t.interrupt(); app.close(); - watch.stop(); - for (int i=0;i<clients.size();i++) { - IvyClient client = (IvyClient)clients.elementAt(i); - client.close("normal Ivy Stopping..."); + // stopping the IvyWatchers + for (int i=0;i<watchers.size();i++){ ((IvyWatcher)watchers.elementAt(i)).stop(); } + // stopping the remaining IvyClients + for (Enumeration e=clients.elements();e.hasMoreElements();) { + IvyClient c = (IvyClient)e.nextElement(); + c.close(true); + removeClient(c); } } catch (IOException e) { traceDebug("IOexception Stop "); } - clients.removeAllElements(); + traceDebug("the bus should have stopped so far"); + stopped = true; } /** + * Toggles the sending of messages to oneself + * + */ + public void sendToSelf(boolean b) {sendToSelf=b;} + + /** * Performs a pattern matching according to everyone's regexps, and sends * the results to the relevant ivy agents. * <p><em>There is one thread for each client connected, we could also @@ -147,10 +178,13 @@ public class Ivy implements Runnable, IvyApplicationListener { int count = 0; // an alternate implementation would 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); + for ( Enumeration e=clients.elements();e.hasMoreElements();) { + IvyClient client = (IvyClient)e.nextElement(); count += client.sendMsg( message ); } + if (sendToSelf) { + // TODO + } return count; } @@ -176,8 +210,9 @@ public class Ivy implements Runnable, IvyApplicationListener { regexp_out.put(key,regexp); callbacks.put(key,callback ); // notifies the other clients this new regexp - for (int i=0;i<clients.size();i++){ - ((IvyClient)clients.elementAt(i)).sendRegexp(key.intValue(),regexp); + for (Enumeration e=clients.elements();e.hasMoreElements();) { + IvyClient c = (IvyClient)e.nextElement(); + c.sendRegexp(key.intValue(),regexp); } return key.intValue(); } @@ -193,8 +228,8 @@ public class Ivy implements Runnable, IvyApplicationListener { || (callbacks.remove(key) == null ) ) { throw new IvyException("client wants to remove an unexistant regexp "+id); } - for (int i=0;i<clients.size();i++ ) { - ((IvyClient)clients.elementAt(i)).delRegexp(id ); + for (Enumeration e=clients.elements();e.hasMoreElements();) { + ((IvyClient)e.nextElement()).delRegexp(id ); } } @@ -219,44 +254,67 @@ public class Ivy implements Runnable, IvyApplicationListener { ivyApplicationListenerList.removeElementAt(id); } - /* invokes the application listeners upon arrival of a new Ivy client - * it *might* be considered poor style to invoke them as the same level - * as the others applicationListeners. This is part of the interface - */ + /* invokes the application listeners upon arrival of a new Ivy client */ public void connect(IvyClient client){ for ( int i = 0 ; i < ivyApplicationListenerList.size(); i++ ) { ((IvyApplicationListener)ivyApplicationListenerList.elementAt(i)).connect(client); } } - /* invokes the application listeners upon departure of an Ivy client - * ibid. - */ - public void disconnect(IvyClient client){ + /* invokes the application listeners upon arrival of a new Ivy client */ + void disconnectReceived(IvyClient client){ for ( int i = 0 ; i < ivyApplicationListenerList.size(); i++ ) { ((IvyApplicationListener)ivyApplicationListenerList.elementAt(i)).disconnect(client); } } - /* invokes the application listeners upon death of an Ivy client - * ibid + /* + * removes a client from the list */ - public void die(IvyClient client, int id){ - for ( int i = 0 ; i < ivyApplicationListenerList.size(); i++ ) { - ((IvyApplicationListener)ivyApplicationListenerList.elementAt(i)).die(client, id); + void removeClient(IvyClient c) { clients.remove(c.getClientKey()); } + + /** + * invokes the application listeners when we are summoned to die + * then stops + */ + public void dieReceived(IvyClient client, int id){ + for ( int i=0 ;i<ivyApplicationListenerList.size();i++ ) { + ((IvyApplicationListener)ivyApplicationListenerList.elementAt(i)).die(client,id); } - stop(); } - /* invokes the direct message callbacks - * ibid - */ + /* invokes the direct message callbacks */ public void directMessage( IvyClient client, int id,String msgarg ){ for ( int i = 0 ; i < ivyApplicationListenerList.size(); i++ ) { ((IvyApplicationListener)ivyApplicationListenerList.elementAt(i)).directMessage(client,id, msgarg); } } + /** + * gives the names of IvyClient(s) + */ + public Vector getIvyClients() { + Vector v=new Vector(); + for (Enumeration e=clients.elements();e.hasMoreElements();) { + v.add(e.nextElement()); + } + return v; + } + + /** + * gives a list of IvyClient(s) with the name given in parameter + * + * @param name The name of the Ivy agent you're looking for + */ + public Vector getIvyClientsByName(String name) { + Vector v=new Vector(); + for (Enumeration e=clients.elements();e.hasMoreElements();) { + IvyClient ic = (IvyClient)e.nextElement(); + if ( ((ic.getApplicationName()).compareTo(name))==0 ) v.addElement(ic); + } + return v; + } + /////////////////////////////////////////////////////////////////: // // Protected methods @@ -264,12 +322,10 @@ public class Ivy implements Runnable, IvyApplicationListener { /////////////////////////////////////////////////////////////////: void addClient(Socket socket,boolean peerCalling) throws IOException { - IvyClient client = new IvyClient(this, socket,peerCalling); - clients.addElement(client); - } - - void removeClient( IvyClient client ) { - clients.removeElement( client ); + IvyClient client = new IvyClient( + this, socket,peerCalling,new Integer(clientSerial++)); + clients.put(client.getClientKey(),client); + traceDebug(getClientNames()); } void callCallback(IvyClient client, Integer key, String[] tab) throws IvyException { @@ -300,8 +356,7 @@ public class Ivy implements Runnable, IvyApplicationListener { return tab; } - - public static String getDomain(String domainbus) throws IvyException { + public static String getDomain(String domainbus) { if ( domainbus == null ) domainbus = System.getProperty("IVYBUS"); if ( domainbus == null ) domainbus = DEFAULT_DOMAIN; return domainbus; @@ -329,39 +384,59 @@ public class Ivy implements Runnable, IvyApplicationListener { */ boolean checkConnected( IvyClient clnt ) { if ( clnt.getAppPort() == 0 ) return false; - for ( int i = 0 ; i < clients.size(); i++ ) { - IvyClient client = (IvyClient)clients.elementAt(i); + for (Enumeration e=clients.elements();e.hasMoreElements();) { + IvyClient client = (IvyClient)e.nextElement(); if ( clnt != client && client.sameClient( clnt ) ) return true; } return false; } /* - * the service socket thread reader. + * the service socket thread reader main loop */ public void run() { - // traceDebug("IvyServer beginning transmission"); - while(ivyRunning){ + Thread thisThread=Thread.currentThread(); + while(thisThread==serverThread){ try { Socket socket = app.accept(); addClient(socket,true); // the peer called me + } catch (InterruptedIOException ie) { + if (thisThread!=serverThread) break; } catch( IOException e ) { - traceDebug("Error IvyServer exception: " + e.getMessage()); - System.out.println("DEBUG TCP socket reader caught an exception " + e.getMessage()); - e.printStackTrace(); + if (serverThread==thisThread) { + traceDebug("Error IvyServer exception: " + e.getMessage()); + System.out.println("Ivy server socket reader caught an exception " + e.getMessage()); + e.printStackTrace(); + } else { traceDebug("my server socket has been closed"); } } } - // traceDebug("IvyServer end of transmission"); + traceDebug("stopping the server Thread"); } - /////////////////////////////////////////////////////////////////: - // - // Private methods - // - /////////////////////////////////////////////////////////////////: - private void traceDebug(String s){ - if (debug) System.out.println("-->ivy<-- "+s); + private void traceDebug(String s){ if (debug) System.out.println("-->ivy<-- "+s); } + + /* a small private method for debbugging purposes */ + private String getClientNames() { + String s = appName+" clients are: "; + for (Enumeration e=clients.elements();e.hasMoreElements();){ + s+=((IvyClient)e.nextElement()).getApplicationName()+" "; + } + return s; + } + + /* + * unitary test. Normally, running java fr.dgac.ivy.Ivy should stop in 2.3 seconds :) + */ + public static void main(String[] args) { + Ivy bus = new Ivy("Test Unitaire","TU ready",null); + try { + bus.start(DEFAULT_DOMAIN); + try { Thread.sleep(2000); } catch (InterruptedException ie) { } + bus.stop(); + } catch (IvyException ie) { + ie.printStackTrace(); + } } } // class Ivy |