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 }