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