View Javadoc

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 }