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