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.shell.ErrorType;
023 import org.crsh.shell.ShellProcess;
024 import org.crsh.shell.ShellProcessContext;
025 import org.crsh.shell.ShellResponse;
026 import org.crsh.text.Chunk;
027 import org.crsh.util.Statement;
028
029 import java.io.IOException;
030 import java.util.ArrayList;
031
032 class ClientProcessContext implements ShellProcessContext {
033
034 /** . */
035 final ClientAutomaton client;
036
037 /** . */
038 final ShellProcess process;
039
040 /** . */
041 final ArrayList<Chunk> buffer;
042
043 /** . */
044 private boolean closed;
045
046 ClientProcessContext(ClientAutomaton client, ShellProcess process) {
047 this.client = client;
048 this.process = process;
049 this.buffer = new ArrayList<Chunk>(1000);
050 this.closed = false;
051 }
052
053 /**
054 * Ensure we have a recent size, the size is considered as recent if it's younger than 2 second, otherwise
055 * send a get size message.
056 */
057 private void ensureSize() {
058 if (System.currentTimeMillis() - client.last > 2000) {
059 synchronized (this) {
060 try {
061 client.out.writeObject(new ServerMessage.GetSize());
062 client.out.flush();
063 }
064 catch (Exception e) {
065 //
066 }
067 }
068 }
069 }
070
071 void execute() {
072 try {
073 process.execute(this);
074 }
075 catch(final Throwable t) {
076 new Statement() {
077 @Override
078 protected void run() throws Throwable {
079 // If it's not executing then we attempt to end it
080 end(ShellResponse.error(ErrorType.INTERNAL, "Unexpected process execution error", t));
081 }
082 }.all();
083 }
084 }
085
086 public int getWidth() {
087 if (!closed) {
088 ensureSize();
089 return client.getWidth();
090 } else {
091 return -1;
092 }
093 }
094
095 public int getHeight() {
096 if (!closed) {
097 ensureSize();
098 return client.getHeight();
099 } else {
100 return -1;
101 }
102 }
103
104 public boolean takeAlternateBuffer() {
105 if (!closed) {
106 try {
107 client.out.writeObject(new ServerMessage.UseAlternateBuffer());
108 client.out.flush();
109 }
110 catch (Exception e) {
111 //
112 }
113 }
114
115 // For now we suppose any impl return true;
116 return true;
117 }
118
119 public boolean releaseAlternateBuffer() {
120 if (!closed) {
121 try {
122 client.out.writeObject(new ServerMessage.UseMainBuffer());
123 client.out.flush();
124 }
125 catch (Exception e) {
126 //
127 }
128 }
129
130 // For now we suppose any impl return true;
131 return true;
132 }
133
134 public String getProperty(String name) {
135 return null;
136 }
137
138 public String readLine(String msg, boolean echo) {
139 // try {
140 // client.out.writeObject(ServerMessage.READLINE);
141 // client.out.writeObject(msg);
142 // client.out.writeObject(echo);
143 // client.out.flush();
144 // return (String)client.in.readObject();
145 // }
146 // catch (Exception e) {
147 // return null;
148 // }
149 return null;
150 }
151
152 public void provide(Chunk element) throws IOException {
153 if (!closed) {
154 buffer.add(element);
155 }
156 }
157
158 public Class<Chunk> getConsumedType() {
159 return Chunk.class;
160 }
161
162 public synchronized void flush() {
163 if (!closed) {
164 if (buffer.size() > 0) {
165 try {
166 for (Chunk chunk : buffer) {
167 client.out.writeObject(new ServerMessage.Chunk(chunk));
168 }
169 client.out.writeObject(new ServerMessage.Flush());
170 client.out.flush();
171 }
172 catch (IOException ignore) {
173 //
174 }
175 finally {
176 buffer.clear();
177 }
178 }
179 }
180 }
181
182 public synchronized void end(ShellResponse response) {
183
184 // It may have been cancelled concurrently
185 if (client.current == this) {
186
187 // Flush what we have in buffer first
188 flush();
189
190 // Send end message
191 try {
192 client.current = null;
193 client.out.writeObject(new ServerMessage.End(response));
194 client.out.flush();
195 }
196 catch (IOException ignore) {
197 //
198 }
199 finally {
200 closed = true;
201 if (response instanceof ShellResponse.Close) {
202 client.close();
203 }
204 }
205 }
206 }
207 }