aboutsummaryrefslogtreecommitdiff
path: root/src/IvyClient.java
blob: 8ec226db7d7e16600ee5c260261072d922411b64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
/*
**
** IvyClient
** Wed Aug 27 15:02:00 MET DST 1997 -> rajout des fonction ping & pong
**
** correction: un Die va faire finir le Thread, pas l'*ensemble*
*/

package fr.dgac.ivy ;

import java.lang.Thread;
import java.net.*;
import java.io.*;
import java.util.Date;
import java.util.Vector;
import java.util.StringTokenizer;
import gnu.regexp.*;

public class IvyClient extends Thread {
    
  // les types de messages
  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 */
  
  protected String appName;
  public int appPort;

  // gestion du protocole ping
  long lastRead  = 0;
  long pingDate = 0 ;
  long pingLag =0 ;
  
  Ivy bus;
  Socket socket;
  BufferedReader in;
  OutputStream out;
  
  Vector regexp_in;
  Vector regexp_id;

  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();
    regexp_in = new Vector();
    regexp_id = new Vector();
    sendService( bus.getRegexpOut() );
    start();
  }

  public InetAddress getRemoteAddress() { return socket.getInetAddress(); }
  public String getApplicationName() { return appName ; }

  void sendBuffer( String buffer ) {
	buffer += "\n";
	try {
    out.write(buffer.getBytes() );
	out.flush();
	} catch ( IOException e )
	{
		// TODO: write error
	}
  }
  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) );
  }
  
  void sendService( Vector regexps ) 
  {
    send( StartRegexp, bus.getApplicationPort(), bus.appName);
    for ( int id = 0 ; id < regexps.size(); id++ ) 
	{
      String regexp;
      regexp = (String)regexps.elementAt(id);
      sendRegexp( id,regexp);
    }
    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 ) 
  {
    REMatch result;
    RE regexp;
	Integer id;
	int count = 0;
    for ( int i = 0 ; i < regexp_in.size(); i++ ) 
	{
      regexp = (RE)regexp_in.elementAt(i);
      id = (Integer) regexp_id.elementAt(i);
      result   = regexp.getMatch(message);
	  if ( result != null )
		{
	    send( Msg,id,regexp.getNumSubs(),result);
		count ++;
		}
    }
	return count;
  }
  
  void close(String msg) throws IOException 
  {
	traceDebug( msg );
    socket.close();
    //stop();
  }

  public boolean sameClient( IvyClient clnt )
  {
    if ( appPort != 0 && appPort == clnt.appPort ) {
      if ( getRemoteAddress() == clnt.getRemoteAddress() ) return true;
    }
    return false;
  }
  public void delRegexp( int id )
  {
	send( DelRegexp,id,"");     
  }
  public void run()
  {

    String msg = null;
    String token = null;
    int i;
    int msgtype;  /* type du dernier message recu */
    Integer msgid;  /* id du dernier message recu */
    String msgarg = null;  /* argument du dernier message recu */
    RE regexp = null; /* regexp compile */

    try {

      traceDebug("Connected from "+
        socket.getInetAddress().getHostName()+":"+socket.getPort());

      parseInput:
      while( (msg = in.readLine()) != null ) {

        /* étape un : extrait le message */
        lastRead = (new Date()).getTime();
        StringTokenizer st = new StringTokenizer(msg);
        traceDebug("Receive msg '"+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) );
        if  ( st.hasMoreTokens()) {
          msgarg = st.nextToken("\n");
        }

        /* étape deux : traitement adapté */
        switch( msgtype ){
        case Bye: break;
        case AddRegexp:
          if ( bus.CheckRegexp( msgarg ) ) {
            // Attempt to compile the pattern.  If the pattern is not valid,
            // report the error and exit.
            try {
              regexp = new RE(msgarg);
			  if ( regexp.getNumSubs()!= 0 )
			  {
				  /* check to see if any subexp */
				  /* these are needed to send msg */
              regexp_in.addElement( regexp );
              regexp_id.addElement( msgid );
			  }
			  else System.err.println("Bad pattern: No () groups");
            } 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:
          i = regexp_id.indexOf( msgid );
		  if  ( i >=0 )
		  {
          regexp_in.removeElementAt(i);
          regexp_id.removeElementAt(i);
		  }
          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.intValue(), 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 parseInput;
	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