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 }