001    /*
002     * Copyright (C) 2012 eXo Platform SAS.
003     *
004     * This is free software; you can redistribute it and/or modify it
005     * under the terms of the GNU Lesser General Public License as
006     * published by the Free Software Foundation; either version 2.1 of
007     * the License, or (at your option) any later version.
008     *
009     * This software is distributed in the hope that it will be useful,
010     * but WITHOUT ANY WARRANTY; without even the implied warranty of
011     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012     * Lesser General Public License for more details.
013     *
014     * You should have received a copy of the GNU Lesser General Public
015     * License along with this software; if not, write to the Free
016     * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
017     * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
018     */
019    
020    package org.crsh.shell.impl.remoting;
021    
022    import org.crsh.cmdline.CommandCompletion;
023    import org.crsh.shell.Shell;
024    import org.crsh.shell.ShellResponse;
025    import org.crsh.util.CloseableList;
026    import org.crsh.util.Statement;
027    
028    import java.io.Closeable;
029    import java.io.IOException;
030    import java.io.InputStream;
031    import java.io.ObjectInputStream;
032    import java.io.ObjectOutputStream;
033    import java.io.OutputStream;
034    
035    public class ClientAutomaton implements Runnable {
036    
037      /** . */
038      final Shell shell;
039    
040      /** . */
041      final ObjectOutputStream out;
042    
043      /** . */
044      final ObjectInputStream in;
045    
046      /** . */
047      ClientProcessContext current;
048    
049      /** . */
050      final CloseableList listeners;
051    
052      /** . */
053      Integer width;
054    
055      /** . */
056      Integer height;
057    
058      /** . */
059      long last;
060    
061      public ClientAutomaton(ObjectOutputStream out, ObjectInputStream in, Shell shell) {
062        CloseableList listeners = new CloseableList();
063        listeners.add(in);
064        listeners.add(out);
065    
066        //
067        this.in = in;
068        this.out = out;
069        this.shell = shell;
070        this.listeners = listeners;
071        this.width = null;
072        this.height = null;
073      }
074    
075      public ClientAutomaton(InputStream in,OutputStream out, Shell shell) throws IOException {
076        this(new ObjectOutputStream(out), new ObjectInputStream(in), shell);
077      }
078    
079      public ClientAutomaton addCloseListener(Closeable closeable) {
080        listeners.add(closeable);
081        return this;
082      }
083    
084      public void run() {
085        try {
086          while (!listeners.isClosed()) {
087            ClientMessage msg = (ClientMessage)in.readObject();
088    
089            //
090            if (msg instanceof ClientMessage.GetWelcome) {
091              String welcome = shell.getWelcome();
092              out.writeObject(new ServerMessage.Welcome(welcome));
093              out.flush();
094            } else if (msg instanceof ClientMessage.GetPrompt) {
095              String prompt = shell.getPrompt();
096              out.writeObject(new ServerMessage.Prompt(prompt));
097              out.flush();
098            } else if (msg instanceof ClientMessage.GetCompletion) {
099              String prefix = ((ClientMessage.GetCompletion)msg).prefix;
100              CommandCompletion completion = shell.complete(prefix);
101              out.writeObject(new ServerMessage.Completion(completion));
102              out.flush();
103            } else if (msg instanceof ClientMessage.SetSize) {
104              ClientMessage.SetSize setSize = (ClientMessage.SetSize)msg;
105              width = setSize.width;
106              height = setSize.height;
107              last = System.currentTimeMillis();
108            } else if (msg instanceof ClientMessage.Execute) {
109              ClientMessage.Execute execute = (ClientMessage.Execute)msg;
110              width = execute.width;
111              height = execute.height;
112              last = System.currentTimeMillis();
113              current = new ClientProcessContext(this, shell.createProcess(execute.line));
114              current.execute();
115            } else if (msg instanceof ClientMessage.Cancel) {
116              if (current != null) {
117                final ClientProcessContext context = current;
118                Statement statements = new Statement() {
119                  @Override
120                  protected void run() throws Throwable {
121                    context.end(ShellResponse.cancelled());
122                  }
123                }.with(new Statement() {
124                  @Override
125                  protected void run() throws Throwable {
126                    context.process.cancel();
127                  }
128                });
129                statements.all();
130              }
131            } else if (msg instanceof ClientMessage.Close) {
132              close();
133            }
134          }
135        }
136        catch (Exception e) {
137          // e.printStackTrace();
138          //
139        }
140        finally {
141          close();
142        }
143      }
144    
145      void close() {
146        listeners.close();
147      }
148    
149      public int getWidth() {
150        return width;
151      }
152    
153      public int getHeight() {
154        return height;
155      }
156    }