1 | |
package org.paneris.bibliomania; |
2 | |
|
3 | |
import java.io.BufferedReader; |
4 | |
import java.io.CharArrayWriter; |
5 | |
import java.io.FilterWriter; |
6 | |
import java.io.IOException; |
7 | |
import java.io.InputStreamReader; |
8 | |
import java.io.OutputStreamWriter; |
9 | |
import java.io.StreamTokenizer; |
10 | |
import java.io.Writer; |
11 | |
import java.net.InetAddress; |
12 | |
import java.net.ServerSocket; |
13 | |
import java.net.Socket; |
14 | |
import java.util.Hashtable; |
15 | |
import java.util.Vector; |
16 | |
|
17 | |
import org.melati.poem.util.ArrayUtils; |
18 | |
|
19 | 0 | public class CommandServer extends Thread { |
20 | |
|
21 | |
private ServerSocket serverSocket; |
22 | |
private Hashtable interpreters; |
23 | |
private int maxInterpreterThreads; |
24 | |
|
25 | 0 | public CommandServer(int port, int maxInterpreterThreads) throws IOException { |
26 | 0 | this.maxInterpreterThreads = maxInterpreterThreads; |
27 | 0 | interpreters = new Hashtable(); |
28 | 0 | serverSocket = new ServerSocket(port); |
29 | 0 | } |
30 | |
|
31 | |
public void run() { |
32 | |
for (;;) { |
33 | |
try { |
34 | 0 | while (interpreters.size() >= maxInterpreterThreads) |
35 | 0 | synchronized (interpreters) { |
36 | 0 | interpreters.wait(); |
37 | 0 | } |
38 | |
|
39 | 0 | Socket socket = serverSocket.accept(); |
40 | 0 | if (socket.getInetAddress().equals(InetAddress.getLocalHost()) || |
41 | |
socket.getInetAddress().getHostAddress().equals("127.0.0.1")) |
42 | 0 | new Loop(DelegatingInterpreter.it, socket).start(); |
43 | |
else { |
44 | 0 | socket.getOutputStream().write( |
45 | |
("You are " + socket.getInetAddress() + " not " + |
46 | |
InetAddress.getLocalHost() + "\n").getBytes()); |
47 | 0 | socket.close(); |
48 | |
} |
49 | |
} |
50 | 0 | catch (Exception e) { |
51 | 0 | System.err.println("CommandServer: " + e); |
52 | 0 | } |
53 | |
} |
54 | |
} |
55 | |
|
56 | |
public static interface Interpreter { |
57 | |
void interpret(String[] args, Writer output, Writer errors) |
58 | |
throws Exception; |
59 | |
} |
60 | |
|
61 | 0 | public static class DelegatingInterpreter implements Interpreter { |
62 | 0 | public static final DelegatingInterpreter it = new DelegatingInterpreter(); |
63 | |
|
64 | |
public void interpret(String[] args, Writer output, Writer errors) |
65 | |
throws Exception { |
66 | 0 | ((Interpreter)Class.forName(args[0]).newInstance()). |
67 | |
interpret((String[])ArrayUtils.section(args, 1, args.length), |
68 | |
output, errors); |
69 | 0 | } |
70 | |
} |
71 | |
|
72 | |
public static class CarConWriter extends FilterWriter { |
73 | |
|
74 | |
private String prefix; |
75 | |
|
76 | 0 | private CharArrayWriter buffer = new CharArrayWriter(); |
77 | |
|
78 | |
public CarConWriter(Writer w, String prefix) { |
79 | 0 | super(w); |
80 | 0 | this.prefix = prefix; |
81 | 0 | } |
82 | |
|
83 | |
private void shift() throws IOException { |
84 | 0 | synchronized (out) { |
85 | 0 | out.write(prefix); |
86 | 0 | buffer.writeTo(out); |
87 | 0 | } |
88 | |
|
89 | 0 | out.flush(); |
90 | 0 | buffer.reset(); |
91 | 0 | } |
92 | |
|
93 | |
public void write(int c) throws IOException { |
94 | 0 | buffer.write(c); |
95 | 0 | if (c == '\n') |
96 | 0 | shift(); |
97 | 0 | } |
98 | |
|
99 | |
public void write(char cbuf[], int off, int len) |
100 | |
throws IOException { |
101 | 0 | int end = off + len; |
102 | |
|
103 | 0 | for (int i = off; i < end; ++i) { |
104 | 0 | if (cbuf[i] == '\n') { |
105 | 0 | buffer.write(cbuf, off, i + 1 - off); |
106 | 0 | shift(); |
107 | 0 | off = i + 1; |
108 | |
} |
109 | |
} |
110 | |
|
111 | 0 | if (off < end) |
112 | 0 | buffer.write(cbuf, off, end - off); |
113 | 0 | } |
114 | |
|
115 | |
public synchronized void write(String str, int off, int len) |
116 | |
throws IOException { |
117 | 0 | int end = off + len; |
118 | |
|
119 | |
for (;;) { |
120 | 0 | int i = str.indexOf('\n', off); |
121 | 0 | if (i == -1) { |
122 | 0 | buffer.write(str, off, end - off); |
123 | 0 | break; |
124 | |
} |
125 | |
else { |
126 | 0 | buffer.write(str, off, i + 1 - off); |
127 | 0 | shift(); |
128 | 0 | off = i + 1; |
129 | |
} |
130 | 0 | } |
131 | 0 | } |
132 | |
} |
133 | |
|
134 | 0 | public class Loop extends Thread { |
135 | |
|
136 | |
private Interpreter interpreter; |
137 | |
private Socket socket; |
138 | |
private StreamTokenizer in; |
139 | |
private Writer out; |
140 | |
private Writer outputs; |
141 | |
private Writer errors; |
142 | |
|
143 | 0 | private Loop(Interpreter interpreter, Socket socket) throws IOException { |
144 | 0 | this.interpreter = interpreter; |
145 | 0 | this.socket = socket; |
146 | 0 | in = new StreamTokenizer(new BufferedReader( |
147 | |
new InputStreamReader(socket.getInputStream()))); |
148 | 0 | in.ordinaryChars(33, 127); |
149 | 0 | in.wordChars(33, 127); |
150 | 0 | in.quoteChar('"'); |
151 | 0 | in.quoteChar('\''); |
152 | 0 | in.slashSlashComments(false); |
153 | 0 | in.slashStarComments(false); |
154 | 0 | in.eolIsSignificant(true); |
155 | |
|
156 | 0 | out = new OutputStreamWriter(socket.getOutputStream()); |
157 | 0 | outputs = new CarConWriter(out, "."); |
158 | 0 | errors = new CarConWriter(out, "!"); |
159 | 0 | } |
160 | |
|
161 | |
public void run() { |
162 | 0 | interpreters.put(this, Boolean.TRUE); |
163 | |
try { |
164 | 0 | Vector args = new Vector(); |
165 | |
|
166 | 0 | out.write(">\n"); |
167 | 0 | out.flush(); |
168 | |
|
169 | |
handle: for (;;) { |
170 | 0 | switch (in.nextToken()) { |
171 | |
case StreamTokenizer.TT_EOL: |
172 | 0 | String[] theArgs = new String[args.size()]; |
173 | 0 | args.copyInto(theArgs); |
174 | 0 | args.removeAllElements(); |
175 | |
try { |
176 | 0 | interpreter.interpret(theArgs, outputs, errors); |
177 | |
} |
178 | 0 | catch (Exception e) { |
179 | 0 | errors.write(e + "\n"); |
180 | 0 | } |
181 | |
|
182 | 0 | out.write(">\n"); |
183 | 0 | out.flush(); |
184 | |
|
185 | 0 | break; |
186 | |
|
187 | |
case StreamTokenizer.TT_EOF: |
188 | 0 | break handle; |
189 | |
|
190 | |
default: |
191 | 0 | args.addElement(in.sval); |
192 | |
} |
193 | |
} |
194 | |
} |
195 | 0 | catch (Exception e) { |
196 | 0 | System.err.println("CommandServer.Loop.run: " + e); |
197 | |
} |
198 | |
finally { |
199 | 0 | try { out.close(); } catch (Exception e) {} |
200 | 0 | try { socket.close(); } catch (Exception e) {} |
201 | |
|
202 | 0 | interpreters.remove(this); |
203 | 0 | synchronized (interpreters) { |
204 | 0 | interpreters.notifyAll(); |
205 | 0 | } |
206 | 0 | } |
207 | 0 | } |
208 | |
} |
209 | |
} |