/* ** IvyClient */ package fr.dgac.ivy ; import java.lang.Thread; import java.net.*; import java.io.*; import java.util.*; import gnu.regexp.*; public 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; /* * gestion du protocole ping * ne marche pas encore */ private long lastRead = 0; private long pingDate = 0 ; private long pingLag =0 ; private Ivy bus; private Socket socket; private BufferedReader in; private OutputStream out; private Hashtable regexp_in = new Hashtable(); static private boolean debug = (System.getProperty("IVY_DEBUG")!=null) ; IvyClient( Ivy bus, Socket socket ) throws IOException { appName = "Unkown"; appPort = 0; this.bus = bus; this.socket = socket; lastRead = (new Date()).getTime(); 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"); } } 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,""); } 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 */ 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, ""); } 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 ); } public int sendMsg( String message ) { int count = 0; for (Enumeration e = regexp_in.keys();e.hasMoreElements();) { Integer key = (Integer)e.nextElement(); RE regexp = (RE)regexp_in.get(key); REMatch result = regexp.getMatch(message); if ( result != null ) { send(Msg,key,regexp.getNumSubs(),result); count++; } } return count; } void close(String msg) throws IOException { traceDebug( msg ); socket.close(); //stop(); } public boolean sameClient( IvyClient clnt ) { return ( appPort != 0 && appPort == clnt.appPort ) && ( getRemoteAddress() == clnt.getRemoteAddress() ) ; } public void delRegexp( int id ) { send( DelRegexp,id,"");} 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 */ String token = null; /* * ETAPE UN : extraire le message */ lastRead = (new Date()).getTime(); StringTokenizer st = new StringTokenizer(msg); if (!st.hasMoreTokens()){ close("Bad format no type '"+msg+"'"); break; } token=st.nextToken(); 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)); /* * 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 */ String msgarg=""; if (st.hasMoreTokens()) msgarg=st.nextToken("\n"); /* *ETAPE DEUX : traitement adapté au type de message */ switch (msgtype) { case Bye: break; case AddRegexp: if ( bus.CheckRegexp(msgarg) ) { try { regexp_in.put(msgid,new RE(msgarg)); } catch (REException e) { System.err.println("Bad pattern: "+e.getMessage()); } } else { System.err.println( "Warning exp='"+msgarg+"' can't match removing from "+appName); } 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 */ 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); break; case Pong: // calcul du lag en millisecondes traceDebug("Pong Message"); pingLag = (new Date()).getTime() - pingDate ; 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 "+ 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 traceDebug(String s){ if (debug) System.out.println("-->ivyclient<-- "+s); } } // class IvyClient /* EOF */