001    package org.crsh.term.spi.net;
002    
003    import org.crsh.term.CodeType;
004    import org.crsh.term.spi.TermIO;
005    import org.crsh.util.Safe;
006    
007    import java.io.IOException;
008    import java.io.InputStream;
009    import java.io.OutputStream;
010    import java.net.InetSocketAddress;
011    import java.net.ServerSocket;
012    import java.net.Socket;
013    import java.nio.charset.Charset;
014    
015    /**
016     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
017     */
018    public class TermIOServer {
019    
020      /** . */
021      private static final Charset UTF_8 = Charset.forName("UTF-8");
022    
023      /** . */
024      private final TermIO delegate;
025    
026      /** . */
027      private final int bindingPort;
028    
029      /** . */
030      private ServerSocket socketServer;
031    
032      /** . */
033      private Socket socket;
034    
035      /** . */
036      private InputStream in;
037    
038      /** . */
039      private OutputStream out;
040    
041      /** . */
042      private int port;
043    
044      public TermIOServer(TermIO delegate, int bindingPort) {
045        this.delegate = delegate;
046        this.bindingPort = bindingPort;
047      }
048    
049      public int getBindingPort() {
050        return socketServer.getLocalPort();
051      }
052    
053      public int getPort() {
054        return port;
055      }
056    
057      public int bind() throws IOException {
058        ServerSocket socketServer = new ServerSocket();
059        socketServer.bind(new InetSocketAddress(bindingPort));
060        int port = socketServer.getLocalPort();
061    
062        //
063        this.socketServer = socketServer;
064        this.port = port;
065    
066        //
067        return port;
068      }
069    
070      public void accept() throws IOException {
071        if  (socketServer == null) {
072          throw new IllegalStateException();
073        }
074    
075        //
076        this.socket = socketServer.accept();
077        this.in = socket.getInputStream();
078        this.out = socket.getOutputStream();
079      }
080    
081      private byte read() throws IOException, Done {
082        int b = in.read();
083        if (b == -1) {
084          throw new Done();
085        }
086        return (byte)b;
087      }
088    
089      private int read(byte[] buffer, int off, int len) throws IOException, Done {
090        int b = in.read(buffer, off, len);
091        if (b == -1) {
092          throw new Done();
093        }
094        return b;
095      }
096    
097      private void write(byte b) throws IOException, Done {
098        out.write(b);
099      }
100    
101      private void write(byte[] bytes) throws IOException, Done {
102        out.write(bytes);
103      }
104    
105      private void flush() throws IOException, Done {
106        out.flush();
107      }
108    
109      public boolean execute() throws IOException, IllegalStateException {
110        if (socket == null) {
111          throw new IllegalStateException("No connection");
112        }
113        try {
114          iterate();
115          return true;
116        } catch (Done ignore) {
117          Safe.close(in);
118          Safe.close(out);
119          Safe.close(socket);
120          in = null;
121          out = null;
122          socket = null;
123          return false;
124        }
125      }
126    
127      private void iterate() throws IOException, Done {
128        byte b = read();
129        if (b == 0) {
130          int code = delegate.read();
131          CodeType codeType = delegate.decode(code);
132          byte ordinal = (byte) codeType.ordinal();
133          if (codeType == CodeType.CHAR) {
134            write(new byte[]{ordinal, (byte)((code & 0xFF00) >> 8), (byte)((code & 0xFF))});
135          } else {
136            write(ordinal);
137          }
138          flush();
139        } else if (b == 1) {
140          int b1 = in.read();
141          int b2 = in.read();
142          char c = (char)((b1 << 8) + b2);
143          delegate.write(c);
144        } else if (b == 2) {
145          b = read();
146          int remaining = (b + 2) * 2;
147          int offset = 0;
148          byte[] buffer = new byte[remaining];
149          while (remaining > 0) {
150            int r = read(buffer, offset, remaining);
151            offset += r;
152            remaining -= r;
153          }
154          char[] chars = new char[buffer.length / 2];
155          int index = 0;
156          for (int i = 0;i < chars.length;i++) {
157            int high = buffer[index++];
158            int low = buffer[index++];
159            chars[i] = (char)((high << 8) + low);
160          }
161          String s = new String(chars);
162          delegate.write(s);
163        } else if (b == 3) {
164          delegate.writeDel();
165        } else if (b == 4) {
166          delegate.writeCRLF();
167        } else if (b == 5) {
168          int b1 = in.read();
169          int b2 = in.read();
170          char c = (char)((b1 << 8) + b2);
171          delegate.moveRight(c);
172        } else if (b == 6) {
173          delegate.moveLeft();
174        } else if (b == 7) {
175          delegate.flush();
176        } else if (b == 8) {
177          int len = read() + 1;
178          byte[] bytes = new byte[len];
179          read(bytes, 0, len);
180          String propertyName = new String(bytes, UTF_8);
181          String propertyValue;
182          if ("width".equals(propertyName)) {
183            propertyValue = Integer.toString(delegate.getWidth());
184          } else {
185            propertyValue = delegate.getProperty(propertyName);
186          }
187          if (propertyValue == null) {
188            write((byte)0);
189          } else if (propertyValue.length() == 0) {
190            write((byte)1);
191          } else {
192            bytes = propertyValue.getBytes(UTF_8);
193            len = bytes.length;
194            if (len > 254) {
195              // We don't process that for now
196              // so we say it's null
197              write((byte)0);
198            } else {
199              write((byte)(len + 1));
200              write(bytes);
201            }
202            flush();
203          }
204        } else {
205          throw new UnsupportedOperationException("cannot handle " + b);
206        }
207      }
208    }