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