From 0cef96242b0e0aa10b4b33ee0f4b175048dbe3e0 Mon Sep 17 00:00:00 2001 From: jestin Date: Wed, 6 Jul 2005 20:03:49 +0000 Subject: Voir les fichiers eux-même pour les nouveautés. Préparation de 1.2.8 --- src/Ivy.java | 116 +++++++++++++++++++++++++++++++++++----- src/IvyApplicationListener.java | 10 ++-- src/IvyBindListener.java | 6 ++- src/IvyClient.java | 2 +- src/IvyMessageListener.java | 2 +- src/IvyWatcher.java | 22 ++++---- src/Makefile | 70 ++++++------------------ src/SelfIvyClient.java | 14 +++-- src/Waiter.java | 2 +- src/WaiterClient.java | 2 +- 10 files changed, 153 insertions(+), 93 deletions(-) diff --git a/src/Ivy.java b/src/Ivy.java index 3236ba4..2fc6307 100755 --- a/src/Ivy.java +++ b/src/Ivy.java @@ -13,6 +13,13 @@ * * * CHANGELOG: + * 1.2.8: + * - 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: @@ -71,13 +78,14 @@ 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 */ - protected String appName; + String appName; /** * the protocol version number */ @@ -95,7 +103,7 @@ public class Ivy implements Runnable { * the library version, useful for development purposes only, when java is * invoked with -DIVY_DEBUG */ - public static final String libVersion ="1.2.7"; + public static final String libVersion ="1.2.8"; private boolean debug; private ServerSocket app; @@ -106,7 +114,7 @@ public class Ivy implements Runnable { private Vector ivyApplicationListenerList = new Vector(); private Vector ivyBindListenerList = new Vector(); private Vector sendThreads = new Vector(); - private boolean stopped = false; + private boolean stopped=true; protected int applicationPort; /* Application port number */ protected String ready_message = null; protected boolean doProtectNewlines = false ; @@ -115,6 +123,8 @@ public class Ivy implements Runnable { public final static int TIMEOUTLENGTH = 3000; 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. @@ -191,6 +201,8 @@ public class Ivy implements Runnable { * */ public void start(String domainbus) throws IvyException { + if (!stopped) throw new IvyException("cannot start a bus that's already started"); + stopped=false; if (domainbus==null) domainbus=getDomain(null); Properties sysProp = System.getProperties(); sysProp.put("IVYBUS",domainbus); @@ -247,13 +259,15 @@ public class Ivy implements Runnable { Thread t=serverThread; serverThread=null; if (t!=null) t.interrupt(); // The serverThread might be stopped even before having been created + // TODO BUG avec gcj+kaffe, le close() reste pendu et ne rend pas la main app.close(); // stopping the IvyWatchers for (int i=0;idoesn't receive its own messages. + * by another agent. A program doesn't receive its own messages, + * except if sendToSelf() is set to true. *

Example: *
the Ivy agent A performs

b.bindMsg("^Hello (*)",cb);
*
the Ivy agent B performs
b2.sendMsg("Hello world");
@@ -385,6 +400,25 @@ public class Ivy implements Runnable { } /** + * Subscribes to a regular expression for one time only, useful for + * requests, in cunjunction with getWBUId() + * + * The callback will be executed once and only once, and the agent will + * unsubscribe + * @since 1.2.8 + * @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 bindMsgOnce(String sregexp, IvyMessageListener callback ) throws IvyException { + Once once = new Once(callback); + int id = bindMsg(sregexp,once); + once.setRegexpId(id); + return id; + } + + /** * unsubscribes a regular expression * * @param id the id of the regular expression, returned when it was bound @@ -452,6 +486,27 @@ public class Ivy implements Runnable { } } + // a private class used by bindMsgOnce, to ensure that a callback will be + // executed once, and only once + private class Once implements IvyMessageListener { + boolean received=false; + int id=-1; + IvyMessageListener callback=null; + Once(IvyMessageListener callback){this.callback=callback;} + void setRegexpId(int id){this.id=id;} + public void receive(IvyClient ic,String[] args){ + synchronized(this) { + // synchronized because it will most likely be called + // concurrently, and I *do* want to ensure that it won't + // execute twice + if (received||(callback==null)||(id==-1)) return; + received=true; + try {Ivy.this.unBindMsg(id);} catch (IvyException ie) { ie.printStackTrace(); } + callback.receive(ic,args); + } + } + } + /* invokes the application listeners upon arrival of a new Ivy client */ protected void clientConnects(IvyClient client){ for ( int i = 0 ; i < ivyApplicationListenerList.size(); i++ ) { @@ -480,7 +535,6 @@ public class Ivy implements Runnable { } } - /* * invokes the application listeners when we are summoned to die * then stops @@ -548,27 +602,61 @@ public class Ivy implements Runnable { return tab; } - public static String getDomain(String domainbus) { + /** + * returns the domain bus + * + * @param domainbus if non null, returns the argument + * @return It returns domainbus, if non null, + * otherwise it returns the IVYBUS property if non null, otherwise it + * returns Ivy.DEFAULT_DOMAIN + */ + public static String getDomain(String domainbus) { if ( domainbus == null ) domainbus = System.getProperty("IVYBUS"); if ( domainbus == null ) domainbus = DEFAULT_DOMAIN; return domainbus; } + /** + * returns the domain bus + * + * @since 1.2.8 + * @param progname The name of your program, for error message + * @param args the String[] of arguments passed to your main() + * @return returns the domain bus, ascending priority : ivy default bus, IVY_BUS + * property, -b domain on the command line + */ + public static String getDomainArgs(String progname, String[] args) { + Getopt opt = new Getopt(progname,args,"b:"); + int c; + if ( ((c=opt.getopt())!=-1) && c=='b' ) return opt.getOptarg(); + return getDomain(null); + } + + /** + * returns a "wana be unique" ID to make requests on the bus + * + * @since 1.2.8 + * @return returns a string wich is meant to be noisy enough to be unique + */ + public String getWBUId() { + return "ID<"+appName+myserial+":"+nextId()+":"+generator.nextInt()+">"; + } + private synchronized long nextId() { return current++; } void addClient(IvyClient c) { - clients.put(c.getClientKey(),c); + synchronized (clients) { clients.put(c.getClientKey(),c); } traceDebug("added "+c+" in clients: "+getClientNames(clients)); } void removeClient(IvyClient c) { - clients.remove(c.getClientKey()); + synchronized (clients) {clients.remove(c.getClientKey());} traceDebug("removed "+c+" from clients: "+getClientNames(clients)); } void addHalf(IvyClient c) { - half.put(c.getClientKey(),c); + synchronized(half){half.put(c.getClientKey(),c);} traceDebug("added "+c+" in half: "+getClientNames(half)); } void removeHalf(IvyClient c) { - half.remove(c.getClientKey()); + synchronized(half){half.remove(c.getClientKey());} traceDebug("removed "+c+" from half: "+getClientNames(half)); } @@ -633,7 +721,8 @@ public class Ivy implements Runnable { private String getClientNames(Hashtable t) { String s = "("; for (Enumeration e=t.elements();e.hasMoreElements();){ - s+=((IvyClient)e.nextElement()).getApplicationName()+","; + IvyClient ic = (IvyClient)e.nextElement(); + if (ic!=null) s+=ic.getApplicationName()+","; } return s+")"; } @@ -662,11 +751,12 @@ public class Ivy implements Runnable { public static void main(String[] args) { Ivy bus = new Ivy("Test Unitaire","TU ready",null); try { - bus.start(null); + bus.start(Ivy.getDomainArgs("IvyTest",args)); System.out.println("waiting 5 seconds for a coucou"); System.out.println(((bus.waitForMsg("^coucou",5000))!=null)?"coucou received":"coucou not received"); System.out.println("waiting 5 seconds for IvyProbe"); System.out.println(((bus.waitForClient("IVYPROBE",5000))!=null)?"Ivyprobe joined the bus":"nobody came"); + System.out.println("random values: "+bus.getWBUId()+", "+bus.getWBUId()+", "+bus.getWBUId()); bus.stop(); } catch (IvyException ie) { System.out.println("Ivy main test error"); diff --git a/src/IvyApplicationListener.java b/src/IvyApplicationListener.java index 2dac989..7f7ad3f 100755 --- a/src/IvyApplicationListener.java +++ b/src/IvyApplicationListener.java @@ -11,6 +11,8 @@ package fr.dgac.ivy; * bus: connexion, disconnexion, direct messages or requests to quit. * * Changelog: + * 1.2.8 + * - removed the public abstract modifiers, which are redundant * 1.2.4 * - sendDie now requires a String argument ! It is MANDATORY, and could * impact your implementations ! @@ -21,17 +23,17 @@ public interface IvyApplicationListener extends java.util.EventListener { * invoked when a Ivy Client has joined the bus * @param client the peer */ - public abstract void connect(IvyClient client); + void connect(IvyClient client); /** * invoked when a Ivy Client has left the bus * @param client the peer */ - public abstract void disconnect(IvyClient client); + void disconnect(IvyClient client); /** * invoked when a peer request us to leave the bus * @param client the peer */ - public abstract void die(IvyClient client, int id,String msgarg); + void die(IvyClient client, int id,String msgarg); /** * invoked when a peer sends us a direct message * @param client the peer @@ -43,5 +45,5 @@ public interface IvyApplicationListener extends java.util.EventListener { * poor style to enforce the end of a program with System.exit(), you should * consider terminating all threads ( AWT, etc ) */ - public abstract void directMessage( IvyClient client, int id,String msgarg ); + void directMessage( IvyClient client, int id,String msgarg ); } diff --git a/src/IvyBindListener.java b/src/IvyBindListener.java index 96096f2..6fc17e1 100644 --- a/src/IvyBindListener.java +++ b/src/IvyBindListener.java @@ -7,6 +7,8 @@ package fr.dgac.ivy; * @author http://www.tls.cena.fr/products/ivy/ * * Changelog: + * 1.2.8 + * - removed the public abstract modifiers, which are redundant */ public interface IvyBindListener extends java.util.EventListener { @@ -17,7 +19,7 @@ public interface IvyBindListener extends java.util.EventListener { * @param int the regexp ID * @param regexp the regexp */ - public abstract void bindPerformed(IvyClient client,int id, String regexp); + void bindPerformed(IvyClient client,int id, String regexp); /** * invoked when a Ivy Client performs a unbind @@ -25,6 +27,6 @@ public interface IvyBindListener extends java.util.EventListener { * @param int the regexp ID * @param regexp the regexp */ - public abstract void unbindPerformed(IvyClient client,int id,String regexp); + void unbindPerformed(IvyClient client,int id,String regexp); } diff --git a/src/IvyClient.java b/src/IvyClient.java index a53e398..0a06c55 100755 --- a/src/IvyClient.java +++ b/src/IvyClient.java @@ -107,7 +107,7 @@ public class IvyClient implements Runnable { Hashtable regexps = new Hashtable(); Hashtable regexpsText = new Hashtable(); static boolean debug = (System.getProperty("IVY_DEBUG")!=null) ; - int protocol; + // int protocol; private boolean incoming; IvyClient() { } diff --git a/src/IvyMessageListener.java b/src/IvyMessageListener.java index e960afb..1a8d8a5 100755 --- a/src/IvyMessageListener.java +++ b/src/IvyMessageListener.java @@ -16,5 +16,5 @@ public interface IvyMessageListener extends java.util.EventListener * @param client the peer who sent the message * @param args the array of string, on string for each subregexp */ - public abstract void receive(IvyClient client, String[] args); + void receive(IvyClient client, String[] args); } diff --git a/src/IvyWatcher.java b/src/IvyWatcher.java index 5009c03..93d5a8f 100755 --- a/src/IvyWatcher.java +++ b/src/IvyWatcher.java @@ -14,6 +14,9 @@ * thing. * * CHANGELOG: + * 1.2.8: + * - alreadyBroadcasted was static, thus Ivy Agents within the same JVM used + * to share the list of agents already connected. A nasty bug. * 1.2.7: * - better handling of multiple connexions from the same remote agent when * there are different broadcast addresses ( introduced the alreadyBroadcasted @@ -76,7 +79,7 @@ class IvyWatcher implements Runnable { private InetAddress localhost,loopback; private String domainaddr; private int port; - private volatile Thread listenThread; + private volatile Thread listenThread = null; private InetAddress group; private static int serial=0; private int myserial=serial++; @@ -146,17 +149,11 @@ class IvyWatcher implements Runnable { if (bus.applicationPort==remotePort) { traceDebug("ignoring a broadcast from "+ remotehostname+":"+packet.getPort() +" on my port number ("+remotePort+"), it's probably me"); - // TODO check better - // if bus.applicationPort=remotePort - // parse the list of Watchers and check for each - // iw.broadcast.getInetAddress().equals(packet().getAddress() - // if one is true, "continue" ( ignore the broadcast ) + // TODO check this in a better way continue; } traceDebug("broadcast accepted from " +remotehostname +":"+packet.getPort()+", port:"+remotePort+", protocol version:"+version); - // 1.2.7 ? TODO two connexions from the same host on different broadcast - // addresses (e.g. sam simu) if (!alreadyBroadcasted(remotehost.toString(),remotePort)) { traceDebug("no known agent originating from " + remotehost + ":" + remotePort); new IvyClient(bus,new Socket(remotehost,remotePort),remotePort); @@ -202,7 +199,8 @@ class IvyWatcher implements Runnable { } private class PacketSender implements Runnable { - // TODO do I need multiple packetsenders ? + // do I need multiple packetsenders ? Well, there is one PacketSender per + // domain. DatagramPacket packet; String data; public PacketSender(String data) { @@ -239,11 +237,12 @@ class IvyWatcher implements Runnable { /* * since 1.2.7 pre .... + * went local instead of static ! fixed a nasty bug in 1.2.8 * checks if there is already a broadcast received from the same address * on the same port */ - static private Hashtable alreadySocks=new Hashtable(); - static private synchronized boolean alreadyBroadcasted(String s,int port) { + private Hashtable alreadySocks=new Hashtable(); + private synchronized boolean alreadyBroadcasted(String s,int port) { // System.out.println("DEBUUUUUUUG " + s+ ":" + port); if (s==null) return false; Integer i = (Integer)alreadySocks.get(s); @@ -307,7 +306,6 @@ class IvyWatcher implements Runnable { return port; } - private void traceDebug(String s){ if (debug) System.out.println("-->IvyWatcher["+myserial+","+bus.getSerial()+"]<-- "+s); } diff --git a/src/Makefile b/src/Makefile index 4eea5ce..f6cdfe0 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,63 +1,24 @@ -#GNUPATH=/usr/share/java/gnu-getopt.jar:/usr/share/java/regexp.jar # debian SID -GNUPATH=/usr/lib/jdk1.1/lib/classes.zip:/usr/share/java/gnu.getopt.jar:/usr/share/java/regexp.jar # debian woody -#GNUPATH=${HOME}/java/jars/gnu-getopt.jar:${HOME}/java/jars/regexp.jar -#GNUPATH=../bundle +include ../java.mk -####################################### -# generic setup -####################################### - JAVAC = javac -JAVACOPTS = -d . -deprecation -CLASSPATH = -classpath .:$(GNUPATH) - -####################################### -# gcj setup -####################################### -# JAVAC = gcj -#JAVACOPTS = -d . -deprecation -#CLASSPATH = -classpath .:/usr/share/kaffe/Klasses.jar:$(GNUPATH) - -####################################### -# jikes setup on my box -####################################### -# RTPATH = /usr/local/jdk1.5.0/jre/lib/rt.jar -#JAVACOPTS = -d . -deprecation -# JAVAC = jikes -#CLASSPATH = -classpath .:$(RTPATH):$(GNUPATH) - -####################################### -# blackdown jdk118 setup -####################################### -# JAVAC = /usr/local/jdk118_v3/bin/javac -#CLASSPATH = -classpath .:/usr/local/jdk118_v3/lib/classes.zip:/home/jestin/java/Jars/swingall.jar:$(GNUPATH) -#JAVACOPTS = -d . - -###################################### -# local Blackdown linux 1.2.2 -###################################### -#CLASSPATH = -classpath .:$(GNUPATH) -#JAVACOPTS = -deprecation -d . -# JAVAC = /usr/local/jdk1.2.2/bin/javac - -###################################### -# local Blackdown linux 1.3.1 -###################################### -#CLASSPATH = -classpath .:$(GNUPATH) -#JAVACOPTS = -deprecation -d . -# JAVAC = /usr/local/j2sdk1.3.1/bin/javac - -.SUFFIXES: .java .class +#.SUFFIXES: .java .class SRCS = *.java OBJS = $(SRCS:.java=.class) DOCS = ../doc/html/api -.java.class: - $(JAVAC) $(JAVACOPTS) $(CLASSPATH) $< + GNUPATH = /usr/share/java/gnu-getopt.jar:/usr/share/java/regexp.jar # debian SID +#GNUPATH = /usr/lib/jdk1.1/lib/classes.zip:/usr/share/java/gnu.getopt.jar:/usr/share/java/regexp.jar # debian woody +#GNUPATH = ${HOME}/java/Jars/gnu.getopt.jar:${HOME}/java/Jars/regexp.jar # Others +#RTPATH = /usr/local/jdk1.5.0/jre/lib/rt.jar # for jikes on my box +#RTPATH = /usr/local/jdk118_v3/lib/classes.zip:/home/jestin/java/Jars/swingall.jar # for 1.1.8 on my box + +CLASSPATH = -classpath .:$(GNUPATH) -ivy-java: - $(JAVAC) $(JAVACOPTS) $(CLASSPATH) $(SRCS) +#ivy-java: +# $(JAVAC) $(JAVACOPTS) $(CLASSPATH) $(SRCS) -all: $(OBJS) +all: + $(JAVAC) -d . $(JAVACOPTS) $(CLASSPATH) $(SRCS) + clean: /bin/rm -f -- $(OBJS) *~ *.bak $(JAR) fr/dgac/ivy/*.class @@ -66,5 +27,6 @@ docs: rm -fR $(DOCS)/*html rm -fR $(DOCS)/*css rm -fR $(DOCS)/fr/dgac/ivy/*html - javadoc $(CLASSPATH) -d $(DOCS) $(SRCS) + #javadoc $(CLASSPATH) -d $(DOCS) $(SRCS) + javadoc -d $(DOCS) $(SRCS) rm -f $(DOCS)/package-list diff --git a/src/SelfIvyClient.java b/src/SelfIvyClient.java index acd2d66..43bfccb 100644 --- a/src/SelfIvyClient.java +++ b/src/SelfIvyClient.java @@ -36,7 +36,7 @@ class SelfIvyClient extends IvyClient { protected SelfIvyClient(Ivy bus,String appName) { this.bus=bus; - this.protocol=Ivy.PROTOCOLVERSION; + // this.protocol=Ivy.PROTOCOLVERSION; this.appName=appName; } @@ -99,11 +99,17 @@ class SelfIvyClient extends IvyClient { protected void callCallback(IvyClient client, Integer key, String[] tab) { IvyMessageListener callback=(IvyMessageListener)callbacks.get(key); - boolean threaded=((Boolean)threadedFlag.get(key)).booleanValue(); if (callback==null) { - System.out.println("(callCallback) Not regexp matching id "+key.intValue()); - System.exit(0); + traceDebug("Not regexp matching id "+key.intValue()+", it must have been unsubscribed concurrently"); + return; + // TODO check that nasty synchro issue, test suite: Request } + Boolean b = (Boolean)threadedFlag.get(key); + if (callback==null) { + System.out.println("threadedFlag.get returns null for"+key.intValue()+", it must have been unsubscribed concurrently"); + return; + } + boolean threaded=b.booleanValue(); if (!threaded) { // runs the callback in the same thread callback.receive(client, tab); diff --git a/src/Waiter.java b/src/Waiter.java index 8db6980..df1f427 100644 --- a/src/Waiter.java +++ b/src/Waiter.java @@ -33,7 +33,7 @@ class Waiter implements Runnable, IvyMessageListener { // System.out.println("DEV Waiter start"); while (encore) { try { - Thread.sleep(INCREMENT); + if (INCREMENT>0) Thread.sleep(INCREMENT); if (!forever) { timeout-=INCREMENT; if (timeout<=0) encore=false; diff --git a/src/WaiterClient.java b/src/WaiterClient.java index 0c75777..f9e1d06 100644 --- a/src/WaiterClient.java +++ b/src/WaiterClient.java @@ -35,7 +35,7 @@ class WaiterClient extends IvyApplicationAdapter implements Runnable { // System.out.println("DEV WaiterClient start"); while (encore) { try { - Thread.sleep(INCREMENT); + if (INCREMENT>0) Thread.sleep(INCREMENT); if (!forever) { timeout-=INCREMENT; if (timeout<=0) encore=false; -- cgit v1.1