/**
* A private Class for ourself on the bus
*
* @author Yannick Jestin
* @author http://www.tls.cena.fr/products/ivy/
* @since 1.2.4
*
* CHANGELOG:
* 1.2.14
* - uses autoboxing for Boolean
* - switch from gnu regexp (deprecated) to the built in java regexp
* - add generic types to declarations
* 1.2.7:
* - fixes a bug on unbindMsg(String) ( closes Matthieu's burreport )
* 1.2.6:
* - jakarta regexp are not threadsafe, adding extra synch blocks
* 1.2.5:
* - uses apache regexp instead of gnu regexp
* 1.2.4:
* - adds a the threaded option for callbacks
* - Matthieu's bugreport on unBindMsg()
*/
package fr.dgac.ivy ;
import java.util.*;
import java.util.regex.*;
public class SelfIvyClient extends IvyClient {
private Ivy bus;
private static int serial=0; /* an unique ID for each regexp */
private Hashtable callbacks=new Hashtable();
private Hashtable threadedFlag=new Hashtable();
public void sendDirectMsg(int id,String message) {
bus.directMessage(this,id,message);
}
public void sendDie(String message) { bus.dieReceived(this,0,message); }
protected SelfIvyClient(Ivy bus,String appName) {
this.bus=bus;
// this.protocol=Ivy.PROTOCOLVERSION;
this.appName=appName;
}
synchronized protected int bindMsg(String sregexp, IvyMessageListener callback, BindType type ) throws IvyException {
// creates a new binding (regexp,callback)
try {
Pattern re=Pattern.compile(sregexp,Pattern.DOTALL);
Integer key = serial++;
regexps.put(key,re);
regexpsText.put(key,sregexp);
callbacks.put(key,callback);
threadedFlag.put(key,type); // use autoboxing of boolean
return key.intValue();
} catch (PatternSyntaxException ree) {
throw new IvyException("Invalid regexp " + sregexp);
}
}
synchronized protected void unBindMsg(int id) throws IvyException {
Integer key = id;
if ( ( regexps.remove(key) == null )
|| (regexpsText.remove(key) == null )
|| (callbacks.remove(key) == null )
|| (threadedFlag.remove(key) == null )
)
throw new IvyException("client wants to remove an unexistant regexp "+id);
}
// unbinds to the first regexp
synchronized protected boolean unBindMsg(String re) {
if (!regexpsText.contains(re)) return false;
for (Integer k : regexpsText.keySet()) {
if ( (regexpsText.get(k)).compareTo(re) == 0) {
try {
bus.unBindMsg(k.intValue());
} catch (IvyException ie) {
return false;
}
return true;
}
}
return false;
}
protected int sendSelfMsg(String message) {
int count = 0;
traceDebug("trying to send to self the message <"+message+">");
for (Integer key : regexps.keySet() ) {
Pattern regexp = regexps.get(key);
String sre = regexpsText.get(key);
synchronized(regexp) {
traceDebug("checking against: "+sre);
Matcher m = regexp.matcher(message);
if (!m.matches()) {
traceDebug("checking against: "+sre+" failed");
continue;
}
traceDebug("checking against: "+sre+" succeeded");
count++;
callCallback(this,key,toArgs(m));
}
}
return count;
}
protected void callCallback(IvyClient client, Integer key, String[] tab) {
IvyMessageListener callback=callbacks.get(key);
if (callback==null) {
traceDebug("Not regexp matching id "+key.intValue()+", it must have been unsubscribed concurrently");
return;
// DONE check that nasty synchro issue, test suite: Request
}
BindType type = threadedFlag.get(key);
switch (type) {
case NORMAL:
// runs the callback in the same thread
callback.receive(client, tab); // can tab can be faulty ?! TODO
break;
case ASYNC:
// starts a new Thread for each callback ... ( Async API )
new Runner(callback,client,tab);
break;
case SWING:
// deferes the callback to the Event Dispatch Thread
new SwingRunner(callback,client,tab);
break;
}
}
private String[] toArgs(Matcher m) {
String[] args=
(m.groupCount()>0) ? new String[m.groupCount()] : new String[0];
//System.out.println("DEBUG "+args.length+" arguments");
for(int sub=0;subSelfIvyClient "+bus.getAppName()+":"+appName+"<-- "+s);
}
}
/* EOF */