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 }