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