/*
* Copyright 2011 Jesper Terkelsen.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy of
* the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations under
* the License.
*
*/
package dk.deck.remoteconsole;
import com.jcraft.jsch.ChannelShell;
import com.jcraft.jsch.JSchException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
/**
* Class that reads from a shell, and allows the user to wait for certain strings, and then send data
* @todo add a global timeout config and throw an exception when timeout occours
*
* @author Jesper Terkelsen
*/
public class QuestionAnswerer {
private long globalTimeout = 10000;
private InputStream in;
private OutputStream out;
private OutputStreamWriter writer;
private StringBuffer allInput = new StringBuffer();
private StringBuffer input = new StringBuffer();
private boolean running = false;
private boolean done = false;
private ChannelShell channel;
private Runnable reader = new Runnable() {
public void run() {
Reader reader = new InputStreamReader(in);
try {
while (!done) {
if (reader.ready()) {
int data = reader.read();
if (data == -1) {
break;
}
char c = (char) data;
input.append(c);
allInput.append(c);
System.out.print(c);
System.out.flush();
} else {
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
};
public QuestionAnswerer() {
}
public void init(ChannelShell channel) throws IOException{
this.channel = channel;
this.in = channel.getInputStream();
this.out = channel.getOutputStream();
writer = new OutputStreamWriter(out);
}
public void start() throws IOException {
try {
if (running){
throw new IllegalStateException("Already running");
}
if (done){
throw new IllegalStateException("This question answerer is used, please create a new one");
}
channel.connect();
Thread readerThread = new Thread(reader);
readerThread.start();
running = true;
} catch (JSchException ex) {
IOException ioe = new IOException();
ioe.initCause(ex);
throw ioe;
}
}
public void stop() throws IOException {
if (!done){
done = true;
running = false;
in.close();
out.close();
channel.disconnect();
}
// Ignore, it is ok to call stop multible times
}
public void waitFor(String waitfor) {
long start = System.currentTimeMillis();
while (!input.toString().contains(waitfor)) {
try {
System.out.println("Input " + input.toString());
timeout(start);
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
// Found, lets reset the waitForBuffer
input = new StringBuffer();
}
/**
* Wait until the prefered string is found or the alternate string is found in the output.
*
* Blocks until one of them is found
*
* @param prefered The prefered string
* @param alternate The alternate string
* @return true of the prefered string is found, false if the alternate string is found
*/
public boolean waitFor(String prefered, String alternate){
long start = System.currentTimeMillis();
boolean result = true;
while (true) {
boolean preferedFound = input.toString().contains(prefered);
boolean alternateFound = input.toString().contains(alternate);
if (preferedFound){
result = true;
break;
}
if (alternateFound){
result = false;
break;
}
try {
timeout(start);
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
// Found, lets reset the waitForBuffer
input = new StringBuffer();
return result;
}
public void write(String data) throws IOException {
try {
Thread.sleep(1000); // Make sure that the server is waiting for input
writer.write(data);
writer.flush();
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
public void setGlobalTimeout(long globalTimeout) {
this.globalTimeout = globalTimeout;
}
public long getGlobalTimeout() {
return globalTimeout;
}
private void timeout(long startTime){
long now = System.currentTimeMillis();
if (now - startTime > globalTimeout){
throw new IllegalStateException("Timeout occoured");
}
}
}