aboutsummaryrefslogtreecommitdiff
path: root/src/IvyClient.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/IvyClient.java')
-rwxr-xr-xsrc/IvyClient.java396
1 files changed, 195 insertions, 201 deletions
diff --git a/src/IvyClient.java b/src/IvyClient.java
index 7ec220f..dd0f156 100755
--- a/src/IvyClient.java
+++ b/src/IvyClient.java
@@ -1,7 +1,3 @@
-/*
-** IvyClient
-*/
-
package fr.dgac.ivy ;
import java.lang.Thread;
@@ -10,121 +6,93 @@ import java.io.*;
import java.util.*;
import gnu.regexp.*;
-public class IvyClient extends Thread {
+/**
+ * A private Class for the the peers on the bus
+ *
+ * @author François-Régis Colin
+ * @author Yannick Jestin
+ * @author <a href="http://www.tls.cena.fr/products/ivy/">http://www.tls.cena.fr/products/ivy/</a>
+ *
+ * each time a connexion is made with a remote peer, the regexp are exchanged
+ * once ready, a ready message is sent, and then we can send messages,
+ * die messages, direct messages, add or remove regexps, or quit. A thread is
+ * created for each remote client.
+ */
+
+class IvyClient extends Thread {
- /*
- * les types de messages
- * on ne *change* pas, sous peine d'incompatibilité avec les autres
- * implémentations ( C, C++, etc... ).
- * quoi que :)
- *
- */
- public final static int Bye = 0; /* l'application emettrice se termine */
- public final static int AddRegexp = 1;/* expression reguliere d'un client */
- public final static int Msg = 2 ; /* message reel */
- public final static int Error = 3; /* error message */
- public final static int DelRegexp = 4;/* Remove expression reguliere */
- public final static int EndRegexp = 5;/* fin de liste regexp */
- public final static int StartRegexp = 6;/* debut des expressions */
- public final static int DirectMsg = 7;/* message direct a l'appli */
- public final static int Die = 8; /* demande de terminaison de l'appli */
- public final static int Ping = 9; /* demande de réponse pong */
- public final static int Pong = 10; /* réponse au ping */
- public final static String StartArg = "\002";/* separateur debut args */
- public final static String EndArg = "\003"; /* separateur inter arguments */
-
- private String appName;
- private int appPort;
+ /* the protocol magic numbers */
+ final static int Bye = 0; /* end of the peer */
+ final static int AddRegexp = 1;/* the peer adds a regexp */
+ final static int Msg = 2 ; /* the peer sends a message */
+ final static int Error = 3; /* error message */
+ final static int DelRegexp = 4;/* the peer removes one of his regex */
+ final static int EndRegexp = 5;/* no more regexp in the handshake */
+ final static int SchizoToken = 6; /* avoid race condition in concurrent connexions */
+ final static int DirectMsg = 7;/* the peer sends a direct message */
+ final static int Die = 8; /* the peer wants us to quit */
+ final static String StartArg = "\002";/* begin of arguments */
+ final static String EndArg = "\003"; /* end of arguments */
- /*
- * gestion du protocole ping
- * ne marche pas encore
- */
- private long lastRead = 0;
- private long pingDate = 0 ;
- private long pingLag =0 ;
-
+ private static boolean debug = (System.getProperty("IVY_DEBUG")!=null) ;
private Ivy bus;
private Socket socket;
private BufferedReader in;
private OutputStream out;
private Hashtable regexp_in = new Hashtable();
+ private Hashtable regexp_text = new Hashtable();
+ private String appName;
+ private int appPort;
+ private boolean gardefou=true;
+ private boolean peerCalling;
- static private boolean debug = (System.getProperty("IVY_DEBUG")!=null) ;
-
- IvyClient( Ivy bus, Socket socket ) throws IOException {
+ IvyClient(Ivy bus, Socket socket,boolean peerCalling) throws IOException {
appName = "Unkown";
appPort = 0;
this.bus = bus;
this.socket = socket;
- lastRead = (new Date()).getTime();
+ this.peerCalling=peerCalling;
in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
out = socket.getOutputStream();
- sendService( bus.getRegexpOut());
- start();
- }
-
- /*
- * quelques accesseurs
- */
- public InetAddress getRemoteAddress() { return socket.getInetAddress(); }
- public String getApplicationName() { return appName ; }
- public int getAppPort() { return appPort ; }
-
- void sendBuffer( String buffer ) {
- buffer += "\n";
- try {
- out.write(buffer.getBytes() );
- out.flush();
- } catch ( IOException e ) {
- // TODO: write error
- System.err.println("IvyClient.sendBuffer.write failed. FIX ME");
+ Hashtable regexps=bus.regexp_out;
+ // sends our ID, whether we initiated the connexion or not
+ // the ID is the couple "host name,application Port", the host name
+ // information is in the socket itself, the port is not known if we
+ // initiate the connexion
+ send(SchizoToken,bus.applicationPort,bus.appName);
+ // sends our regexps to the peer
+ for (Enumeration e = regexps.keys(); e.hasMoreElements(); ) {
+ Integer key = (Integer)e.nextElement();
+ sendRegexp( key.intValue(),(String)regexps.get(key));
}
+ send( EndRegexp,0,"");
+ // spawns a thread to manage the incoming traffic on this
+ // socket. We should be ready to receive messages now.
+ start();
}
- void send( int type, int id, String arg) {
- String buffer = type+" "+id+StartArg+arg;
- sendBuffer(buffer );
- }
-
- void sendRegexp( int id, String regexp ) { send( AddRegexp,id,regexp); }
- public void sendDie( ) { send( Die,0,""); }
+ String getApplicationName() { return appName ; }
- public void sendDie(String message) { send( Die,0,message); }
-
- void sendPing() {
- pingDate = (new Date()).getTime();
- // on marque le message par la date actuelle
- send( Ping, 0, String.valueOf(pingDate) );
- }
-
- /*
- * notifie la liste des regexps aux autres clients du bus
+ /**
+ * allow an Ivy package class to access the list of regexps at a
+ * given time.
+ * perhaps we should implement a new IvyApplicationListener method to
+ * allow the notification of regexp addition and deletion
*/
- private void sendService( Hashtable regexps ) {
- send( StartRegexp, bus.getApplicationPort(), bus.appName);
- for (Enumeration e = regexps.keys(); e.hasMoreElements(); ) {
- Integer key = (Integer)e.nextElement();
- sendRegexp( key.intValue(),(String)regexps.get(key));
- }
- send( EndRegexp,0, "");
- }
+ Enumeration getRegexps() { return regexp_text.elements(); }
+ int getAppPort() { return appPort ; }
- void send( int type, Integer id, int nbsub, REMatch result) {
- String buffer = type+" "+id+StartArg;
- traceDebug ( "Send matching result \n" );
- // ????Start at 1 because group 0 represent entire matching
- for(int sub = 1; sub <= nbsub; sub++) {
- if (result.getSubStartIndex(sub) > -1) {
- buffer += result.toString(sub)+EndArg;
- traceDebug( "Send arg "+result.toString(sub));
- }
- }
- sendBuffer( buffer );
- }
+ /* perhaps we should perform some checking here */
+ void sendRegexp(int id,String regexp) {send(AddRegexp,id,regexp);}
+ public void delRegexp(int id) {send( DelRegexp,id,"");}
- public int sendMsg( String message ) {
+ /**
+ * sends the substrings of a message to the peer for each matching regexp.
+ * @param message the string that will be match-tested
+ * @return the number of messages sent to the peer
+ */
+ int sendMsg( String message ) {
int count = 0;
for (Enumeration e = regexp_in.keys();e.hasMoreElements();) {
Integer key = (Integer)e.nextElement();
@@ -138,152 +106,178 @@ public class IvyClient extends Thread {
return count;
}
+ /**
+ * closes the connexion to the peer.
+ * @param msg the debug information
+ * the thread managing the socket is stopped
+ */
void close(String msg) throws IOException {
traceDebug( msg );
- socket.close();
- //stop();
-}
+ socket.close(); // TODO it seems it doesnt stop the thread
+ out.close();
+ in.close();
+ gardefou=false;
+ }
- public boolean sameClient( IvyClient clnt ) {
+ /**
+ * compares two peers the id is the couple (host,service port).
+ * @param clnt the other peer
+ * @return true if the peers are similir. This should not happen, it is bad
+ * © ® (tm)
+ */
+ boolean sameClient( IvyClient clnt ) {
return ( appPort != 0 && appPort == clnt.appPort )
&& ( getRemoteAddress() == clnt.getRemoteAddress() ) ;
}
- public void delRegexp( int id ) { send( DelRegexp,id,"");}
-
+ /**
+ * the code of the thread handling the incoming messages.
+ * this thread stops (at least it should) when the socket is closed
+ * or when gardefou=false
+ */
public void run() {
String msg = null;
try {
- traceDebug("Connected from "+
- socket.getInetAddress().getHostName()+":"+socket.getPort());
- while((msg=in.readLine()) != null ) {
- int msgtype; /* type du dernier message recu */
- Integer msgid; /* id du dernier message recu */
- RE regexp = null; /* regexp compile */
+ traceDebug("Connected from "+ socket.getInetAddress().getHostName()+
+ ":"+socket.getPort());
+ while ( gardefou && ((msg=in.readLine()) != null )) {
+ int msgtype; // type of the last message received
+ Integer msgid; // ID of the last message received
+ RE regexp = null; // compiled regexp
String token = null;
- /*
- * ETAPE UN : extraire le message
+ /*
+ * First stage: extract the message
*/
- lastRead = (new Date()).getTime();
StringTokenizer st = new StringTokenizer(msg);
- if (!st.hasMoreTokens()){
- close("Bad format no type '"+msg+"'");
- break;
- }
+ if(!st.hasMoreTokens()){close("Bad format no type '"+msg+"'");break;}
token=st.nextToken();
- if (token.length()==0) {
- close("Bad format no type '"+msg+"'");
- break;
- }
+ if (token.length()==0){close("Bad format no type '"+msg+"'");break;}
try {
msgtype = Integer.parseInt(token);
} catch ( NumberFormatException e ) {
close("Bad format error parsing type'"+msg+"'");
break;
}
- if (!st.hasMoreTokens()) {
- close("Bad format no id '"+msg+"'");
- break;
- }
- msgid=Integer.valueOf(st.nextToken(StartArg));
+ if(!st.hasMoreTokens()){close("Bad format no id '"+msg+"'");break;}
+ token=st.nextToken(StartArg);
/*
- * DONE: il trainait un bug ici: on oubliait de réinitialiser msgarg
- * à la chaine vide, et du coup, pour les regexps sans groupe (),
- * ça envoyait des messages un peu fantaisistes
+ * TODO
+ * this doesn't work on jdk1.3 !!!
+ * the token equals " 3992", which provoques a NumberFormatException
*/
+ try {
+ msgid=Integer.valueOf(token);
+ } catch ( NumberFormatException e ) {
+ close("Bad format error parsing id '"+token+"'");
+ break;
+ }
String msgarg="";
- if (st.hasMoreTokens()) msgarg=st.nextToken("\n");
-
- /*
- *ETAPE DEUX : traitement adapté au type de message
+ if (st.hasMoreTokens()) msgarg=st.nextToken("\n");
+ /*
+ * second stage: process the message
*/
- switch (msgtype) {
- case Bye: break;
- case AddRegexp:
+ switch (msgtype) {
+ case Bye: break;
+ case AddRegexp:
if ( bus.CheckRegexp(msgarg) ) {
try {
regexp_in.put(msgid,new RE(msgarg));
- } catch (REException e) {
+ regexp_text.put(msgid,msgarg);
+ } catch (REException e) {
System.err.println("Bad pattern: "+e.getMessage());
}
- } else {
+ } else {
System.err.println(
- "Warning exp='"+msgarg+"' can't match removing from "+appName);
+ "Warning exp='"+msgarg+"' can't match removing from "+appName);
}
- break;
- case DelRegexp:
+ break;
+ case DelRegexp:
regexp_in.remove(msgid);
- break;
- case EndRegexp:
- /*
- * call application callback avec event Connected
- */
- bus.connect(this);
- if (bus.getReadyMessage()!=null) sendMsg(bus.getReadyMessage());
- break;
- case Msg:
- /*
- * call callback avec les arguments
- */
- bus.callCallback(this,msgid,msgarg);
- break;
- case Error:
- traceDebug("Error msg "+msgid+" "+msgarg);
- break;
- case StartRegexp:
- appName=msgarg;
- appPort=msgid.intValue();
- if ( bus.checkConnected(this) )
- close("Quitting Application already connected");
- break;
- case DirectMsg:
- traceDebug("Direct Message id="+msgid+" msg='"+msgarg+"'");
- /*
- * call directCallback avec les arguments
- */
- bus.directMessage( this, msgid.intValue(), msgarg );
- break;
- case Die:
- traceDebug("Die Message received . argh !");
- /*
- * call diecallBack aavant de quitter
+ regexp_text.remove(msgid);
+ break;
+ case EndRegexp:
+ bus.connect(this);
+ /* TODO
+ * BUG ? the peer is perhaps not ready to handle this message
+ * an assymetric processing should be written
*/
- bus.die( this,msgid.intValue());
- break;
- case Ping:
- traceDebug("Ping Message");
- // répond avec le même argument .. Pour le moment c'est inutile
- send(Pong,0,msgarg);
+ if (bus.ready_message!=null) sendMsg(bus.ready_message);
break;
- case Pong:
- // calcul du lag en millisecondes
- traceDebug("Pong Message");
- pingLag = (new Date()).getTime() - pingDate ;
+ case Msg:
+ try {
+ bus.callCallback(this,msgid,msgarg);
+ } catch (IvyException ie) {
+ // calling an inexistant callback
+ System.err.println("calling an inexistant callback, the caller must be wrong !");
+ }
break;
- default:
- System.err.println("*** IvyClient *** unhandled msg type "+
- msgtype+" "+msgid+msgarg);
- break;
- } // switch sur le type de message
- } // while readline
-
- // plus rien à lire .... ou alors break donc erreur
- traceDebug("zarbi Disconnected from "+
+ case Error:
+ traceDebug("Error msg "+msgid+" "+msgarg);
+ break;
+ case SchizoToken:
+ appName=msgarg;
+ appPort=msgid.intValue();
+ if ( bus.checkConnected(this) ) {
+ close("Quitting Application already connected");
+ System.err.println("Rare ! A concurrent connect occured");
+ }
+ break;
+ case DirectMsg:
+ bus.directMessage( this, msgid.intValue(), msgarg );
+ break;
+ case Die:
+ bus.die( this,msgid.intValue());
+ break;
+ default:
+ System.err.println("*** IvyClient *** unhandled msg type "+
+ msgtype+" "+msgid+msgarg);
+ break;
+ } // switch
+ } // while gardefou
+ traceDebug("normally Disconnected from "+
+ socket.getInetAddress().getHostName()+":"+socket.getPort());
+ } catch (IOException e) {
+ traceDebug("abnormally Disconnected from "+
socket.getInetAddress().getHostName()+":"+socket.getPort());
- } catch ( IOException e ) {
- traceDebug("ioexception Disconnected from "+
- socket.getInetAddress().getHostName()+":"+socket.getPort());
}
- /* je meurs en tant que client du bus */
- /* mais avant, j'exécute mon application callback perso */
bus.disconnect( this );
bus.removeClient( this );
- } // run
+ }
- public String From() { return socket.toString(); }
+ private void sendBuffer( String buffer ) {
+ buffer += "\n";
+ try {
+ out.write(buffer.getBytes() );
+ out.flush();
+ } catch ( IOException e ) {
+ /*
+ * TODO
+ * we should throw an exception here
+ */
+ System.err.println("IvyClient.sendBuffer.write failed. FIX ME");
+ }
+ }
+
+ private void send(int type, int id, String arg) {
+ sendBuffer(type+" "+id+StartArg+arg);
+ }
+
+ private void send(int type, Integer id, int nbsub, REMatch result) {
+ String buffer = type+" "+id+StartArg;
+ // Start at 1 because group 0 represent entire matching
+ for(int sub = 1; sub <= nbsub; sub++) {
+ if (result.getSubStartIndex(sub) > -1) {
+ buffer += result.toString(sub)+EndArg;
+ }
+ }
+ sendBuffer(buffer);
+ }
+ private void sendDie() {send(Die,0,"");}
+ private void sendDie(String message) {send(Die,0,message);}
+ private InetAddress getRemoteAddress() { return socket.getInetAddress(); }
private void traceDebug(String s){
- if (debug) System.out.println("-->ivyclient<-- "+s);
+ if (debug) System.out.println("-->IvyClient<-- "+s);
}
} // class IvyClient
/* EOF */