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.cli.impl.completion.CompletionMatch;
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 CompletionMatch 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
118 // For now we
119 // 1/ end the context
120 // 2/ cancel the process
121 // it is not the best strategy instead we should
122 // 1/ cancel the process
123 // 2/ wait a few milli seconds
124 // 3/ if it's not ended then we end it
125
126 final ClientProcessContext context = current;
127 Statement statements = new Statement() {
128 @Override
129 protected void run() throws Throwable {
130 context.end(ShellResponse.cancelled());
131 }
132 }.with(new Statement() {
133 @Override
134 protected void run() throws Throwable {
135 context.process.cancel();
136 }
137 });
138 statements.all();
139 }
140 } else if (msg instanceof ClientMessage.Close) {
141 close();
142 }
143 }
144 }
145 catch (Exception e) {
146 e.printStackTrace();
147 //
148 }
149 finally {
150 close();
151 }
152 }
153
154 void close() {
155 listeners.close();
156 }
157
158 public int getWidth() {
159 return width;
160 }
161
162 public int getHeight() {
163 return height;
164 }
165 }