aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rwxr-xr-xsrc/Ivy.java116
-rwxr-xr-xsrc/IvyApplicationListener.java10
-rw-r--r--src/IvyBindListener.java6
-rwxr-xr-xsrc/IvyClient.java2
-rwxr-xr-xsrc/IvyMessageListener.java2
-rwxr-xr-xsrc/IvyWatcher.java22
-rw-r--r--src/Makefile70
-rw-r--r--src/SelfIvyClient.java14
-rw-r--r--src/Waiter.java2
-rw-r--r--src/WaiterClient.java2
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 @@
*</pre>
*
* 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;i<watchers.size();i++){ ((IvyWatcher)watchers.elementAt(i)).stop(); }
+ watchers.clear();
// stopping the remaining IvyClients
for (Enumeration e=clients.elements();e.hasMoreElements();) {
IvyClient c = (IvyClient)e.nextElement();
- c.close(true);
+ if (c!=null) c.close(true);
removeClient(c);
}
} catch (IOException e) {
@@ -359,7 +373,8 @@ public class Ivy implements Runnable {
*
* The callback will be executed with
* the saved parameters of the regexp as arguments when a message will sent
- * by another agent. A program <em>doesn't</em> receive its own messages.
+ * by another agent. A program <em>doesn't</em> receive its own messages,
+ * except if sendToSelf() is set to true.
* <p>Example:
* <br>the Ivy agent A performs <pre>b.bindMsg("^Hello (*)",cb);</pre>
* <br>the Ivy agent B performs <pre>b2.sendMsg("Hello world");</pre>
@@ -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 <a href="http://www.tls.cena.fr/products/ivy/">http://www.tls.cena.fr/products/ivy/</a>
*
* 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;