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.ShellProcess; 025 import org.crsh.shell.ShellProcessContext; 026 import org.crsh.shell.ShellResponse; 027 import org.crsh.util.CloseableList; 028 029 import java.io.Closeable; 030 import java.io.IOException; 031 import java.io.InputStream; 032 import java.io.ObjectInputStream; 033 import java.io.ObjectOutputStream; 034 import java.io.OutputStream; 035 import java.lang.reflect.UndeclaredThrowableException; 036 import java.util.logging.Level; 037 import java.util.logging.Logger; 038 039 public class ServerAutomaton implements Shell { 040 041 /** . */ 042 final Logger log = Logger.getLogger(ServerAutomaton.class.getName()); 043 044 /** . */ 045 final ObjectInputStream in; 046 047 /** . */ 048 final ObjectOutputStream out; 049 050 /** . */ 051 ServerProcess process; 052 053 /** . */ 054 final CloseableList listeners; 055 056 public ServerAutomaton(ObjectOutputStream out, ObjectInputStream in) { 057 CloseableList listeners = new CloseableList(); 058 listeners.add(in); 059 listeners.add(out); 060 061 // 062 this.in = in; 063 this.out = out; 064 this.listeners = listeners; 065 } 066 067 public ServerAutomaton(InputStream in, OutputStream out) throws IOException { 068 this(new ObjectOutputStream(out), new ObjectInputStream(in)); 069 } 070 071 public ServerAutomaton addCloseListener(Closeable closeable) { 072 listeners.add(closeable); 073 return this; 074 } 075 076 public String getWelcome() { 077 try { 078 out.writeObject(new ClientMessage.GetWelcome()); 079 out.flush(); 080 return ((ServerMessage.Welcome)in.readObject()).value; 081 } 082 catch (Exception e) { 083 throw new UndeclaredThrowableException(e); 084 } 085 } 086 087 public String getPrompt() { 088 try { 089 out.writeObject(new ClientMessage.GetPrompt()); 090 out.flush(); 091 return ((ServerMessage.Prompt)in.readObject()).value; 092 } 093 catch (Exception e) { 094 throw new UndeclaredThrowableException(e); 095 } 096 } 097 098 public ShellProcess createProcess(String request) throws IllegalStateException { 099 return new ServerProcess(this, request); 100 } 101 102 public CompletionMatch complete(String prefix) { 103 try { 104 out.writeObject(new ClientMessage.GetCompletion(prefix)); 105 out.flush(); 106 return ((ServerMessage.Completion)in.readObject()).value; 107 } 108 catch (Exception e) { 109 throw new UndeclaredThrowableException(e); 110 } 111 } 112 113 public void close() { 114 listeners.close(); 115 } 116 117 void execute(ServerProcess process, ShellProcessContext processContext) throws IllegalStateException { 118 119 if (this.process == null) { 120 this.process = process; 121 } else { 122 throw new IllegalStateException(); 123 } 124 125 // 126 ShellResponse response = null; 127 try { 128 out.writeObject(new ClientMessage.Execute(processContext.getWidth(), processContext.getHeight(), process.line)); 129 out.flush(); 130 131 // 132 while (response == null) { 133 ServerMessage msg = (ServerMessage)in.readObject(); 134 if (msg instanceof ServerMessage.GetSize) { 135 out.writeObject(new ClientMessage.SetSize(processContext.getWidth(), processContext.getHeight())); 136 out.flush(); 137 } else if (msg instanceof ServerMessage.ReadLine) { 138 // // This case should not really well supported ? 139 // String request = (String)in.readObject(); 140 // boolean echo = (Boolean)in.readObject(); 141 // String line = processContext.readLine(request, echo); 142 // out.writeObject(line); 143 // out.flush(); 144 // break; 145 throw new UnsupportedOperationException("Not handled"); 146 } else if (msg instanceof ServerMessage.UseAlternateBuffer) { 147 processContext.takeAlternateBuffer(); 148 } else if (msg instanceof ServerMessage.UseMainBuffer) { 149 processContext.releaseAlternateBuffer(); 150 } else if (msg instanceof ServerMessage.End) { 151 response = ((ServerMessage.End)msg).response; 152 } else if (msg instanceof ServerMessage.Chunk) { 153 processContext.provide(((ServerMessage.Chunk)msg).payload); 154 } else if (msg instanceof ServerMessage.Flush) { 155 processContext.flush(); 156 } else { 157 response = ShellResponse.internalError("Unexpected"); 158 } 159 } 160 } 161 catch (Exception e) { 162 log.log(Level.SEVERE, "Remoting issue", e); 163 response = ShellResponse.internalError("Remoting issue", e); 164 } 165 finally { 166 167 // 168 this.process = null; 169 170 // 171 if (response != null) { 172 processContext.end(response); 173 } else { 174 processContext.end(ShellResponse.internalError("")); 175 } 176 } 177 } 178 179 void cancel(ServerProcess process) throws IllegalStateException { 180 if (process == this.process) { 181 this.process = null; 182 try { 183 out.writeObject(new ClientMessage.Cancel()); 184 out.flush(); 185 } 186 catch (IOException ignore) { 187 } 188 } 189 } 190 }