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    package org.crsh.console;
020    
021    import org.crsh.text.Screenable;
022    import org.crsh.shell.ShellProcess;
023    import org.crsh.shell.ShellProcessContext;
024    import org.crsh.shell.ShellResponse;
025    import org.crsh.text.Style;
026    
027    import java.io.IOException;
028    import java.util.concurrent.ArrayBlockingQueue;
029    import java.util.concurrent.atomic.AtomicReference;
030    
031    /**
032     * A process execution state machine.
033     *
034     * @author Julien Viet
035     */
036    class ProcessHandler extends Plugin implements ShellProcessContext {
037    
038      /**
039       * A thread reading a line.
040       */
041      class Reader {
042        final Thread thread;
043        final Editor editor;
044        final ArrayBlockingQueue<String> line;
045        Reader(Thread thread, boolean echo) {
046          this.thread = thread;
047          this.editor = new Editor(console, echo);
048          this.line = new ArrayBlockingQueue<String>(1);
049        }
050      }
051    
052      /** . */
053      final Console console;
054    
055      /** . */
056      final ShellProcess process;
057    
058      /** Weather or not a thread is reading a line callback. */
059      final AtomicReference<Reader> editor;
060    
061      ProcessHandler(Console console, ShellProcess process) {
062        this.console = console;
063        this.process = process;
064        this.editor = new AtomicReference<Reader>();
065      }
066    
067      @Override
068      public boolean takeAlternateBuffer() throws IOException {
069        return console.driver.takeAlternateBuffer();
070      }
071    
072      @Override
073      public boolean releaseAlternateBuffer() throws IOException {
074        return console.driver.releaseAlternateBuffer();
075      }
076    
077      @Override
078      public String getProperty(String propertyName) {
079        return null;
080      }
081    
082      @Override
083      public String readLine(String msg, boolean echo) throws IOException, InterruptedException {
084        Reader waiter = new Reader(Thread.currentThread(), echo);
085        if (editor.compareAndSet(null, waiter)) {
086          if (msg != null && msg.length() > 0) {
087            console.driver.write(msg);
088            console.driver.flush();
089          }
090          console.iterate();
091          try {
092            return waiter.line.take();
093          } finally {
094            editor.set(null);
095          }
096        } else {
097          throw new IllegalStateException("A thread is already reading the line");
098        }
099      }
100    
101      @Override
102      public int getWidth() {
103        return console.driver.getWidth();
104      }
105    
106      @Override
107      public int getHeight() {
108        return console.driver.getHeight();
109      }
110    
111      @Override
112      public Screenable append(CharSequence s) throws IOException {
113        console.driver.write(s);
114        return this;
115      }
116    
117      @Override
118      public Screenable append(char c) throws IOException {
119        console.driver.write(c);
120        return this;
121      }
122    
123      @Override
124      public Screenable append(CharSequence csq, int start, int end) throws IOException {
125        console.driver.write(csq, start, end);
126        return this;
127      }
128    
129      @Override
130      public Screenable append(Style style) throws IOException {
131        console.driver.write(style);
132        return this;
133      }
134    
135      @Override
136      public Screenable cls() throws IOException {
137        console.driver.cls();
138        return this;
139      }
140    
141      @Override
142      public void flush() throws IOException {
143        console.driver.flush();
144      }
145    
146    
147      @Override
148      public void end(ShellResponse response) {
149    
150        // Interrupt reader
151        Reader reader = editor.get();
152        if (reader != null) {
153          reader.thread.interrupt();
154        }
155    
156        //
157        if (response instanceof ShellResponse.Close) {
158    
159        } else {
160    
161        }
162    
163        // Write message
164        try {
165          String msg = response.getMessage();
166          if (msg.length() > 0) {
167            console.driver.write(msg);
168          }
169          console.driver.writeCRLF();
170          console.driver.flush();
171        }
172        catch (IOException e) {
173          // Log it
174        }
175    
176        //
177        if (response instanceof ShellResponse.Close) {
178          console.close();
179        } else {
180          // Put back editor and redraw prompt
181          console.edit();
182          console.iterate();
183        }
184      }
185    }