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.processor.term;
021    
022    import org.crsh.shell.ShellProcess;
023    import org.crsh.shell.ShellProcessContext;
024    import org.crsh.shell.ShellResponse;
025    import org.crsh.text.Chunk;
026    import org.crsh.term.TermEvent;
027    import org.crsh.text.Text;
028    
029    import java.io.IOException;
030    import java.util.logging.Level;
031    
032    class ProcessContext implements ShellProcessContext, Runnable {
033    
034      /** . */
035      final Processor processor;
036    
037      /** . */
038      final ShellProcess process;
039    
040      ProcessContext(Processor processor, ShellProcess process) {
041        this.process = process;
042        this.processor = processor;
043      }
044    
045      public boolean takeAlternateBuffer() {
046        throw new UnsupportedOperationException();
047      }
048    
049      public boolean releaseAlternateBuffer() {
050        throw new UnsupportedOperationException();
051      }
052    
053      public void run() {
054        process.execute(this);
055      }
056    
057      public int getWidth() {
058        return processor.term.getWidth();
059      }
060    
061      public int getHeight() {
062        return processor.term.getHeight();
063      }
064    
065      public String getProperty(String name) {
066        return processor.term.getProperty(name);
067      }
068    
069      public String readLine(String msg, boolean echo) {
070        try {
071          processor.term.provide(Text.create(msg));
072        }
073        catch (IOException e) {
074          return null;
075        }
076        boolean done = false;
077        while (true) {
078          synchronized (processor.lock) {
079            switch (processor.status) {
080              case CLOSED:
081              case CANCELLING:
082                return null;
083              case PROCESSING:
084                if (processor.queue.size() > 0) {
085                  TermEvent event = processor.queue.removeFirst();
086                  if (event instanceof TermEvent.ReadLine) {
087                    return ((TermEvent.ReadLine)event).getLine().toString();
088                  }
089                }
090                break;
091              default:
092                throw new AssertionError("Does not make sense " + processor.status);
093            }
094          }
095          if (done) {
096            return null;
097          } else {
098            done = true;
099            processor.waitingEvent = true;
100            try {
101              processor.term.setEcho(echo);
102              processor.readTerm();
103              processor.term.provide(Text.create("\r\n"));
104            }
105            catch (IOException e) {
106              processor.log.log(Level.SEVERE, "Error when readline line");
107            }
108            finally {
109              processor.waitingEvent = false;
110              processor.term.setEcho(true);
111            }
112          }
113        }
114      }
115    
116      public void provide(Chunk element) throws IOException {
117        processor.term.provide(element);
118      }
119    
120      public void flush() {
121        processor.term.flush();
122      }
123    
124      public void end(ShellResponse response) {
125        Runnable runnable;
126        ProcessContext context;
127        Status status;
128        synchronized (processor.lock) {
129    
130          //
131          processor.current = null;
132          switch (processor.status) {
133            case PROCESSING:
134              if (response instanceof ShellResponse.Close) {
135                runnable = processor.CLOSE;
136                processor.status = Status.CLOSED;
137              } else if (response instanceof ShellResponse.Cancelled) {
138                runnable = Processor.NOOP;
139                processor.status = Status.AVAILABLE;
140              } else {
141                final String message = response.getMessage();
142                runnable = new Runnable() {
143                  public void run() {
144                    try {
145                      processor.provide(Text.create(message));
146                    }
147                    catch (IOException e) {
148                      // todo ???
149                      e.printStackTrace();
150                    }
151                    finally {
152                      // Be sure to flush
153                      processor.term.flush();
154                    }
155                  }
156                };
157                processor.status = Status.AVAILABLE;
158              }
159              break;
160            case CANCELLING:
161              runnable = Processor.NOOP;
162              processor.status = Status.AVAILABLE;
163              break;
164            default:
165              throw new AssertionError("Does not make sense " + processor.status);
166          }
167    
168          // Do we have a next process to execute ?
169          context = processor.peekProcess();
170          status = processor.status;
171        }
172    
173        //
174        runnable.run();
175    
176        //
177        if (context != null) {
178          context.run();
179        } else if (status == Status.AVAILABLE) {
180          processor.writePromptFlush();
181        }
182      }
183    }