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 */
019package org.crsh.console;
020
021import org.crsh.shell.ShellProcess;
022import org.crsh.shell.ShellProcessContext;
023import org.crsh.shell.ShellResponse;
024import org.crsh.text.CLS;
025import org.crsh.text.Chunk;
026import org.crsh.text.Style;
027import org.crsh.text.Text;
028
029import java.io.IOException;
030import java.util.concurrent.ArrayBlockingQueue;
031import java.util.concurrent.atomic.AtomicReference;
032
033/**
034 * A process execution state machine.
035 *
036 * @author Julien Viet
037 */
038class 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}