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