Initial work on Java library.
[doldaconnect.git] / lib / java / dolda / dolcon / Connection.java
1 package dolda.dolcon;
2
3 import java.io.*;
4 import java.net.Socket;
5 import java.util.*;
6
7 public class Connection {
8     Socket s;
9     Reader reader;
10     LinkedList<Response> resps = new LinkedList<Response>();
11     
12     public Connection(String aspec) throws ConnectException {
13         try {
14             s = new Socket(aspec, 1500);
15         } catch(java.net.UnknownHostException e) {
16             throw(new ConnectException("Could not resolve host " + aspec, e));
17         } catch(IOException e) {
18             throw(new ConnectException("Could not connect to host " + aspec, e));
19         }
20         reader = new Reader(s, resps);
21         reader.start();
22     }
23     
24     static private class Reader extends Thread {
25         Exception error = null;
26         Socket s;
27         Collection<Response> resps;
28         
29         public Reader(Socket s, Collection<Response> resps) {
30             this.s = s;
31             this.resps = resps;
32             setDaemon(true);
33         }
34         
35         public void run() {
36             java.io.Reader r;
37             try {
38                 r = new BufferedReader(new InputStreamReader(s.getInputStream(), "UTF-8"));
39             } catch(IOException e) {
40                 synchronized(resps) {
41                     resps.notifyAll();
42                     error = e;
43                 }
44                 return;
45             }
46             String state = "start";
47             StringBuilder ct = new StringBuilder();
48             int code = -1;
49             boolean last = true;
50             List<List<String>>lines = new LinkedList<List<String>>();
51             List<String>tokens = new LinkedList<String>();
52             while(true) {
53                 char c;
54                 {
55                     int i;
56                     try {
57                         if((i = r.read()) < 0) {
58                             throw(new IOException("The server closed the connection"));
59                         }
60                     } catch(IOException e) {
61                         synchronized(resps) {
62                             resps.notifyAll();
63                             error = e;
64                         }
65                         return;
66                     }
67                     c = (char)i;
68                 }
69                 eat: do {
70                     if(state == "start") {
71                         if(c == '\r') {
72                             state = "nl";
73                         } else if(Character.isWhitespace(c)) {
74                         } else {
75                             if(code == -1)
76                                 state = "code";
77                             else
78                                 state = "token";
79                             continue eat;
80                         }
81                     } else if(state == "nl") {
82                         if(c == '\n') {
83                             if(code == -1) {
84                                 synchronized(resps) {
85                                     resps.notifyAll();
86                                     try {
87                                         throw(new IOException("Illegal response code " + code + " from the server"));
88                                     } catch(IOException e) {
89                                         error = e;
90                                     }
91                                 }
92                                 return;
93                             }
94                             lines.add(tokens);
95                             tokens = new LinkedList<String>();
96                             if(last) {
97                                 synchronized(resps) {
98                                     resps.add(new Response(code, lines));
99                                     resps.notifyAll();
100                                 }
101                                 lines = new LinkedList<List<String>>();
102                             }
103                             state = "start";
104                         } else {
105                             state = "start";
106                             continue eat;
107                         }
108                     } else if(state == "code") {
109                         if((c == '-') || Character.isWhitespace(c)) {
110                             last = c != '-';
111                             code = Integer.parseInt(ct.toString());
112                             ct.setLength(0);
113                             state = "start";
114                             continue eat;
115                         } else {
116                             ct.append(c);
117                         }
118                     } else if(state == "token") {
119                         if(Character.isWhitespace(c)) {
120                             tokens.add(ct.toString());
121                             ct.setLength(0);
122                             state = "start";
123                             code = -1;
124                             continue eat;
125                         } else if(c == '\\') {
126                             state = "bs";
127                         } else if(c == '"') {
128                             state = "cited";
129                         } else {
130                             ct.append(c);
131                         }
132                     } else if(state == "bs") {
133                         ct.append(c);
134                         state = "token";
135                     } else if(state == "cited") {
136                         if(c == '\\')
137                             state = "cbs";
138                         else if(c == '"')
139                             state = "token";
140                         else
141                             ct.append(c);
142                     } else if(state == "cbs") {
143                         ct.append(c);
144                         state = "cited";
145                     } else {
146                         throw(new Error("invalid state " + state));
147                     }
148                     break;
149                 } while(true);
150             }
151         }
152     }
153
154     protected void finalize() {
155         try {
156             s.close();
157         } catch(IOException e) {
158         }
159         reader.interrupt();
160     }
161
162     public static void main(String[] args) throws Exception {
163         Connection c = new Connection("pc18");
164         while(true) {
165             while(c.resps.size() > 0) {
166                 System.out.println(c.resps.remove(0));
167             }
168             synchronized(c.resps) {
169                 c.resps.wait();
170             }
171         }
172     }
173 }