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 }