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}