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 }