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 }