+ private void checkthread() {
+ if(Thread.currentThread() == reader)
+ throw(new RuntimeException("Cannot call synchronous method with dispatch thread!"));
+ }
+
+ public void syncConnect() throws ConnectException, ClosedException, InterruptedException {
+ checkthread();
+ final boolean[] donep = new boolean[] {false};
+ final Exception[] errp = new Exception[] {null};
+ ConnectListener l = new ConnectListener() {
+ public void connected() {
+ donep[0] = true;
+ synchronized(this) {
+ notifyAll();
+ }
+ }
+
+ public void error(Exception cause) {
+ donep[0] = true;
+ errp[0] = cause;
+ synchronized(this) {
+ notifyAll();
+ }
+ }
+ };
+ addConnectListener(l);
+ connect();
+ while(!donep[0]) {
+ synchronized(l) {
+ l.wait();
+ }
+ }
+ if(errp[0] != null)
+ throw(new ClosedException(errp[0]));
+ }
+
+ public void expectVersion(int reqver) {
+ this.reqver = reqver;
+ }
+
+ private void checkver(Response resp) throws VersionException {
+ revlo = Integer.parseInt(resp.token(0, 0));
+ revhi = Integer.parseInt(resp.token(0, 1));
+ if((reqver < revlo) || (reqver > revhi))
+ throw(new VersionException(reqver, revlo, revhi));
+ }
+
+ public Exception join() throws InterruptedException {
+ while(reader.isAlive()) {
+ reader.join();
+ }
+ close();
+ return(error);
+ }
+
+ public void addConnectListener(ConnectListener l) {
+ synchronized(connls) {
+ if((state != "idle") && (state != "connecting"))
+ throw(new IllegalStateException("Already connected"));
+ connls.add(l);
+ }
+ }
+
+ private void qcmd(Command cmd) {
+ synchronized(queue) {
+ queue.offer(cmd);
+ queue.notifyAll();
+ }
+ }
+
+ static private class StopCondition extends Error {
+ final boolean normal;
+
+ public StopCondition(Exception cause, boolean normal) {
+ super(cause);
+ this.normal = normal;
+ }
+ }
+
+ static private class Writer extends Thread {