001    package org.crsh.shell.impl.remoting;
002    
003    import org.crsh.cmdline.CommandCompletion;
004    import org.crsh.shell.Shell;
005    import org.crsh.shell.ShellProcess;
006    import org.crsh.shell.ShellProcessContext;
007    import org.crsh.shell.ShellResponse;
008    import org.crsh.util.CloseableList;
009    import org.slf4j.Logger;
010    import org.slf4j.LoggerFactory;
011    
012    import java.io.Closeable;
013    import java.io.IOException;
014    import java.io.InputStream;
015    import java.io.ObjectInputStream;
016    import java.io.ObjectOutputStream;
017    import java.io.OutputStream;
018    import java.lang.reflect.UndeclaredThrowableException;
019    
020    /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */
021    public class ServerAutomaton implements Shell {
022    
023      /** . */
024      final Logger log = LoggerFactory.getLogger(ServerAutomaton.class);
025    
026      /** . */
027      final ObjectInputStream in;
028    
029      /** . */
030      final ObjectOutputStream out;
031    
032      /** . */
033      ServerProcess process;
034    
035      /** . */
036      final CloseableList listeners;
037    
038      public ServerAutomaton(ObjectOutputStream out, ObjectInputStream in) {
039        CloseableList listeners = new CloseableList();
040        listeners.add(in);
041        listeners.add(out);
042    
043        //
044        this.in = in;
045        this.out = out;
046        this.listeners = listeners;
047      }
048    
049      public ServerAutomaton(InputStream in, OutputStream out) throws IOException {
050        this(new ObjectOutputStream(out), new ObjectInputStream(in));
051      }
052    
053      public ServerAutomaton addCloseListener(Closeable closeable) {
054        listeners.add(closeable);
055        return this;
056      }
057    
058      public String getWelcome() {
059        try {
060          out.writeObject(ClientMessage.GET_WELCOME);
061          out.flush();
062          return (String)in.readObject();
063        }
064        catch (Exception e) {
065          throw new UndeclaredThrowableException(e);
066        }
067      }
068    
069      public String getPrompt() {
070        try {
071          out.writeObject(ClientMessage.GET_PROMPT);
072          out.flush();
073          return (String)in.readObject();
074        }
075        catch (Exception e) {
076          throw new UndeclaredThrowableException(e);
077        }
078      }
079    
080      public ShellProcess createProcess(String request) throws IllegalStateException {
081        return new ServerProcess(this, request);
082      }
083    
084      public CommandCompletion complete(String prefix) {
085        try {
086          out.writeObject(ClientMessage.GET_COMPLETION);
087          out.writeObject(prefix);
088          out.flush();
089          return (CommandCompletion)in.readObject();
090        }
091        catch (Exception e) {
092          throw new UndeclaredThrowableException(e);
093        }
094      }
095    
096      void close() {
097        listeners.close();
098      }
099    
100      void execute(ServerProcess process, ShellProcessContext processContext) throws IllegalStateException {
101    
102        if (this.process == null) {
103          this.process = process;
104        } else {
105          throw new IllegalStateException();
106        }
107    
108        //
109        ShellResponse response = null;
110        try {
111          out.writeObject(ClientMessage.EXECUTE);
112          out.writeObject(processContext.getWidth());
113          out.writeObject(process.line);
114          out.flush();
115    
116          //
117          while (response == null) {
118            ServerMessage msg = (ServerMessage)in.readObject();
119            switch (msg) {
120              case GET_WIDTH:
121                int width = processContext.getWidth();
122                out.writeObject(width);
123                out.flush();
124                break;
125              case READLINE:
126                String request = (String)in.readObject();
127                boolean echo = (Boolean)in.readObject();
128                String line = processContext.readLine(request, echo);
129                out.writeObject(line);
130                out.flush();
131                break;
132              case END:
133                response = (ShellResponse)in.readObject();
134                break;
135              default:
136                response = ShellResponse.internalError("Unexpected");
137                break;
138            }
139          }
140        }
141        catch (Exception e) {
142          log.error("Remoting issue", e);
143          response = ShellResponse.internalError("Remoting issue", e);
144        }
145        finally {
146    
147          //
148          this.process = null;
149    
150          //
151          if (response != null) {
152            processContext.end(response);
153          } else {
154            processContext.end(ShellResponse.internalError(""));
155          }
156        }
157      }
158    
159      void cancel(ServerProcess process) throws IllegalStateException {
160        if (process == this.process) {
161          this.process = null;
162          try {
163            out.writeObject(ClientMessage.CANCEL);
164            out.flush();
165          }
166          catch (IOException ignore) {
167          }
168        }
169      }
170    }