001    package org.crsh.term.spi.net;
002    
003    import org.crsh.term.CodeType;
004    import org.crsh.term.spi.TermIO;
005    
006    import java.io.IOException;
007    import java.io.InputStream;
008    import java.io.OutputStream;
009    import java.net.InetSocketAddress;
010    import java.net.Socket;
011    import java.nio.ByteBuffer;
012    import java.nio.charset.Charset;
013    
014    /**
015     *
016     * @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a>
017     */
018    public class TermIOClient implements TermIO {
019    
020      /** . */
021      private static final Charset UTF_8 = Charset.forName("UTF-8");
022    
023      /** . */
024      private int port;
025    
026      /** . */
027      private Socket socket;
028    
029      /** . */
030      private InputStream in;
031    
032      /** . */
033      private OutputStream out;
034    
035      /** . */
036      private byte[] bytes = new byte[2000];
037    
038      /** . */
039      private ByteBuffer buffer = ByteBuffer.wrap(bytes);
040    
041      public TermIOClient(int port) {
042        this.port = port;
043      }
044    
045      public void connect() throws IOException {
046        Socket socket = new Socket();
047        socket.connect(new InetSocketAddress(port));
048        InputStream in = socket.getInputStream();
049        OutputStream out = socket.getOutputStream();
050    
051        //
052        this.socket = socket;
053        this.in = in;
054        this.out = out;
055      }
056    
057      private void put(byte b) {
058        if (buffer.remaining() == 0) {
059          byte[] bytesCopy = new byte[bytes.length * 2 + 1];
060          System.arraycopy(bytes, 0, bytesCopy, 0, bytes.length);
061          ByteBuffer bufferCopy = ByteBuffer.wrap(bytesCopy);
062          bufferCopy.position(buffer.position());
063    
064          //
065          bytes = bytesCopy;
066          buffer = bufferCopy;
067        }
068        buffer.put(b);
069      }
070    
071    
072      private int _read(byte[] buffer, int off, int len) throws IOException, Done {
073        int b = in.read(buffer, off, len);
074        if (b == -1) {
075          throw new Done();
076        }
077        return b;
078      }
079    
080      private byte _read() throws IOException, Done {
081        int b = in.read();
082        if (b == -1) {
083          throw new Done();
084        }
085        return (byte)b;
086      }
087    
088      public int read() throws IOException {
089        try {
090          out.write(0);
091          out.flush();
092          byte b = _read();
093          CodeType codeType = CodeType.valueOf(b);
094          if (codeType == null) {
095            throw new UnsupportedOperationException("todo " + b);
096          } else if (codeType == CodeType.CHAR) {
097            byte b1 = _read();
098            byte b2 = _read();
099            return (b1 << 8) + b2;
100          } else {
101            return codeType.ordinal() << 16;
102          }
103        } catch (Done done) {
104          throw new UnsupportedOperationException("implement me", done);
105        }
106      }
107    
108      public int getWidth() {
109        String width = getProperty("width");
110        return Integer.parseInt(width);
111      }
112    
113      public String getProperty(String name) {
114        // We don't process empty name
115        if (name.length() == 0) {
116          return null;
117        }
118        byte[] bytes = name.getBytes(UTF_8);
119        int len = bytes.length;
120        if (len > 256) {
121          throw new IllegalArgumentException("Property name too long : " + name);
122        }
123        try {
124          out.write(8);
125          out.write(len - 1);
126          out.write(bytes);
127          out.flush();
128          len = _read();
129          if (len == 0) {
130            return null;
131          } else if (len == 1) {
132            return "";
133          } else {
134            bytes = new byte[len - 1];
135            _read(bytes, 0, bytes.length);
136            return new String(bytes, 0, bytes.length);
137          }
138    
139          //
140        } catch (Done done) {
141          throw new UnsupportedOperationException("implement me", done);
142        } catch (IOException e) {
143          throw new UnsupportedOperationException("implement me", e);
144        }
145      }
146    
147      public CodeType decode(int code) {
148        code &= 0xFFFF0000;
149        if (code == 0) {
150          return CodeType.CHAR;
151        } else {
152          code >>= 16;
153          return CodeType.valueOf(code);
154        }
155      }
156    
157      public void close() {
158        try {
159          this.socket.close();
160        } catch (IOException e) {
161          e.printStackTrace();
162        }
163      }
164    
165      public void flush() throws IOException {
166        put((byte)7);
167        out.write(bytes, 0, buffer.position());
168        buffer.clear();
169      }
170    
171      public void write(char c) throws IOException {
172        put((byte)1);
173        put((byte)((c & 0xFF00) >> 8));
174        put((byte)(c & 0xFF));
175      }
176    
177      public void write(String s) throws IOException {
178        int prev = 0;
179        int len = s.length();
180        while (prev < len) {
181          int pos = Math.min(len, prev + 257);
182          int chunkLen = pos - prev;
183          if (chunkLen == 1) {
184            write(s.charAt(prev++));
185          } else {
186            put((byte)2);
187            put((byte)(chunkLen - 2));
188            while (prev < pos) {
189              char c = s.charAt(prev++);
190              put((byte)((c & 0xFF00) >> 8));
191              put((byte)(c & 0xFF));
192            }
193          }
194        }
195      }
196    
197      public void writeDel() throws IOException {
198        put((byte)3);
199      }
200    
201      public void writeCRLF() throws IOException {
202        put((byte)4);
203      }
204    
205      public boolean moveRight(char c) throws IOException {
206        put((byte)5);
207        put((byte)((c & 0xFF00) >> 8));
208        put((byte)(c & 0xFF));
209        return true;
210      }
211    
212      public boolean moveLeft() throws IOException {
213        put((byte)6);
214        return true;
215      }
216    }