/*
* Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved.
*/
package systemobject.terminal;
import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
/**
* Generic systemobject.Cli
*
* @author Guy Arieli
*/
public class Cli {
//private static Logger log = Logger.getLogger(Cli.class.getName());
private static final String ENTER = "\r";
private String enterStr = ENTER;
protected Terminal terminal = null;
private StringBuffer result = new StringBuffer();
private Prompt resultPrompt;
/**
* if set to true will send enterString when prompt wait timeout is received
*/
private boolean graceful = false;
private long startTime = 0;
/**
* in case that graceful is true, how many times press enter
*/
private int waitWithGraceCounter = 0;
/**
* Maximum time for retires of graceful operation
*/
private int maxGracefulRetries = 2;
private boolean dontWaitForPrompts = false;
/**
* Create a systemobject.terminal.Cli object
*
* @param terminal The terminal to use, can be Telnet, Rs232, Cmd or SSH
*
* @exception IOException
*/
public Cli(Terminal terminal) throws IOException {
this.terminal = terminal;
terminal.connect();
}
/**
* add a Prompt to the terminal Prompts list
*
* @param prompt the Prompt to add
*/
public void addPrompt(Prompt prompt) {
terminal.addPrompt(prompt);
}
/**
* locate the matching Terminal Prompt object by the given Prompt String
*
* @param prompt the Prompt String
* @return the Prompt object from the Terminal Prompts list or null if none was found
*/
public Prompt getPrompt(String prompt) {
return terminal.getPrompt(prompt);
}
/**
* Sets the print stream to which the stream of the connection
* will be dumped to.
* Set the print stream to System.out to dump terminal stream to the console,
* Set print stream to null to turn off stream dump.
*/
public void setPrintStream(PrintStream printStream) {
terminal.setPrintStream(printStream);
}
/**
* send an enter string and wait for a matching Prompt in 60 seconds
*
* @exception IOException
*/
public void login() throws Exception {
login(60000);
}
/**
* send an enter string and wait for a matching Prompt in given time
*
* @param timeout the time after which a timeout exception will be thrown
* @throws Exception
*/
public void login(long timeout) throws Exception {
login(timeout, false);
}
/**
* send an enter string and wait for a matching Prompt in given time
*
* @param timeout the time after which a timeout exception will be thrown
* @param delayedTyping if True then terminal buffer reading will be delayed (20 ms sleep between each byte)
* @throws Exception
*/
public void login(long timeout, boolean delayedTyping) throws Exception {
Thread.sleep(1000);
command(null, timeout, true, delayedTyping);
}
/**
* Sends the command without waiting to any prompt.
* If delayedTyping is true, sends each byte desperately + small wait after each byte.
*/
public void sendString(String command, boolean delayedTyping) throws Exception {
terminal.sendString(command, delayedTyping);
}
/**
* Send a command and wait for prompt, with a timeout of 20 seconds
*
* @param command Command text.
*
* @exception IOException
*/
public void command(String command) throws Exception {
command(command, 20000, true, false);
}
/**
* Get the systemobject.terminal.Cli output text.
*
* @return systemobject.terminal.Cli capture text.
*/
public String getResult() {
String toReturn = result.toString();
result = new StringBuffer();
return toReturn;
}
/**
* Returns the prompt which identification triggered the termination
* of the cli operation.
*/
public Prompt getResultPrompt() {
return resultPrompt;
}
/**
* Send a command and wait for prompt.
*
* @param command Command text.
* @param timeout Command timeout in miliseconds
* @param addEnter If true enterString will be add to the command.
*
* @exception IOException
*/
public void command(String command, long timeout, boolean addEnter) throws Exception {
command(command, timeout, addEnter, false);
}
/**
* Send a command and wait for prompt.
*
* @param command Command text.
* @param timeout Command timeout in miliseconds
* @param addEnter If True, defined enter string will be added to the command.
*
* @exception IOException
*/
public void command(String command, long timeout, boolean addEnter, boolean delayedTyping) throws Exception {
command(command, timeout, addEnter, delayedTyping, (String) null);
}
/**
* Send a command and wait for prompt.
*
* @param command Command text.
* @param timeout Command timeout in miliseconds
* @param addEnter If True, defined enter string will be added to the command.
* @param delayedTyping if True then terminal buffer reading will be delayed (20 ms sleep between each byte)
* @param promptString a Prompt String to wait for (if null then default terminal prompts will be used)
* @throws Exception
*/
public void command(String command, long timeout, boolean addEnter, boolean delayedTyping, String promptString) throws Exception {
if (promptString != null) {
command(command, timeout, addEnter, delayedTyping, new String[] { promptString });
} else {
command(command, timeout, addEnter, delayedTyping, (String[]) null);
}
}
/**
* Send a command and wait for all given Prompts Strings.
*
* @param command Command text.
* @param timeout Command timeout in miliseconds
* @param addEnter If True, defined enter string will be added to the command.
* @param delayTyping if True then terminal buffer writing will be delayed (20 ms sleep between each byte)
* @param promptStrings an array of all Prompt Strings that should be found (if null then default terminal prompts will be used)
* @throws Exception
*/
public void command(String command, long timeout, boolean addEnter, boolean delayTyping, String[] promptStrings) throws Exception {
command(command, timeout, addEnter, delayTyping, promptStrings, null);
}
/**
* send a given command with given parameters and wait for given prompts
*
* @param command the command to send
* @param timeout the time to wait for a Prompt before throwing a timeout exception
* @param addEnter if True will add the predefined enter string to the command before sending
* @param delayedTyping if True will sleep 20 ms between each typed byte sent to the terminal
* @param promptStrings if not null then wait for <b>ALL</b> Strings in the given Array to be found in the terminal
* @param prompts if promptStrings is null, wait for ONE of the prompts, if any exists
* @throws Exception
*/
public void command(String command, long timeout, boolean addEnter, boolean delayedTyping, String[] promptStrings, Prompt[] prompts)
throws Exception {
resultPrompt = null;
ArrayList<Prompt> defaultPromts = null;
if (prompts != null) {
defaultPromts = terminal.getPrompts();
terminal.removePrompts();
for (int i = 0; i < prompts.length; i++) {
terminal.addPrompt(prompts[i]);
}
}
try {
if (command != null) {
if (addEnter) {
command = command + getEnterStr();
}
result.append(terminal.getResult());
terminal.sendString(command, delayedTyping);
}
if (dontWaitForPrompts){
finishCommandExecution();
return;
}
startTime = System.currentTimeMillis();
if (promptStrings != null) {
terminal.waitForPrompt(promptStrings, timeout);
finishCommandExecution();
return;
}
Prompt prompt = waitWithGrace(timeout);
waitWithGraceCounter = 0;
while (true) {
if (prompt == null){
finishCommandExecution();
return;
}
if (timeout > 0) {
if (System.currentTimeMillis() - startTime > (timeout)) {
throw new IOException("timeout: " + timeout);
}
}
/*
* If the scrollEnd property of the found prompt is set to true
* the check for terminal scroll end is skipped.
*/
if (prompt.dontWaitForScrollEnd()) {
if (prompt.isCommandEnd()) {
break;
}
} else {
if (terminal.isScrallEnd()) {
if (prompt.isCommandEnd()) {
break;
}
} else {
waitWithGraceCounter++;
prompt = waitWithGrace(timeout);
continue;
}
}
String stringToSend = prompt.getStringToSend();
if (stringToSend != null) {
if (prompt.isAddEnter()) {
stringToSend = stringToSend + getEnterStr(); //ENTER;
}
terminal.sendString(stringToSend, delayedTyping);
}
prompt = waitWithGrace(timeout);
}
resultPrompt = prompt;
} finally {
finishCommandExecution();
if (defaultPromts != null) {
terminal.setPrompts(defaultPromts);
}
}
}
private void finishCommandExecution(){
dontWaitForPrompts = false;
result.append(terminal.getResult());
}
/**
* Close the systemobject.terminal.Cli connection.
*
* @exception IOException
*/
public void close() throws IOException {
if (terminal != null && terminal.isConnected()) {
terminal.disconnect();
}
}
/**
* Reads the stream in the input buffer
* and returns it as a String.
*/
public String read() throws Exception {
return terminal.readInputBuffer();
}
/**
* connect the related terminal if it is not connected already
* @throws IOException
*/
public void connect() throws IOException {
if (terminal != null && !terminal.isConnected()) {
terminal.connect();
}
}
/**
* disconnects the related terminal and then reconnects
* @throws IOException
*/
public void reconnect() throws IOException {
close();
connect();
}
/**
* checks if the current status of the terminal is "connected" or not
* @return true if the terminal is not null and connected
*/
public boolean isConnected() {
if (terminal == null) {
return false;
}
return terminal.isConnected();
}
/**
* Check if working in graceful mode.
* If true will send ENTER if prompt wait fail
* @param timeout the timeout to wait
* @return the prompt
* @throws Exception
*/
private Prompt waitWithGrace(long timeout) throws Exception {
try {
Prompt p = terminal.waitForPrompt(timeout);
result.append(terminal.getResult());
return p;
} catch (Exception e) {
if ((!graceful) || (waitWithGraceCounter > maxGracefulRetries)) {
throw e;
}
return sendEnter(Math.min(15 * 1000, timeout));
}
}
/**
* sendEnter to terminal
*
* @param timeout
* the prompt timeout
* @return the prompt found
* @throws Exception
*/
private Prompt sendEnter(long timeout) throws Exception {
startTime = System.currentTimeMillis();
terminal.sendString(getEnterStr(), false);
result.append(terminal.getResult());
Prompt p = terminal.waitForPrompt(timeout);
result.append(terminal.getResult());
return p;
}
/**
* get the Terminal defined enter string
*
* @return
*/
public String getEnterStr() {
return enterStr;
}
/**
* set the terminal enter string (used when sending command or for graceful wait)
*
* @param enterStr the enter String (default is "\r")
*/
public void setEnterStr(String enterStr) {
this.enterStr = enterStr;
}
/**
* checks if graceful wait is enabled
*
* @return the Graceful flag
*/
public boolean isGraceful() {
return graceful;
}
/**
* if set to True then enter String will be sent after Timeout was reached.<br>
* the number of times the enter string will be sent can be configured using the <I>setWaitWithGraceCounter(int)</I>
*
* @param graceful
*/
public void setGraceful(boolean graceful) {
this.graceful = graceful;
}
/**
* in case that graceful is true, how many times press enter
* @return how many times press enter
*/
public int getWaitWithGraceCounter() {
return waitWithGraceCounter;
}
/**
*
* @param waitWithGraceCounter in case that graceful is true, how many times press enter
*/
public void setWaitWithGraceCounter(int waitWithGraceCounter) {
this.waitWithGraceCounter = waitWithGraceCounter;
}
/**
* @return true if the CLI was signaled to skip prompt checking
*/
public boolean isDontWaitForPrompts() {
return dontWaitForPrompts;
}
/**
* Default is false, returned to false after each command execution.
* @param dontWaitForPrompts if set to true will skip prompt waiting
*/
public void setDontWaitForPrompts(boolean dontWaitForPrompts) {
this.dontWaitForPrompts = dontWaitForPrompts;
}
public int getMaxGracefulRetries() {
return maxGracefulRetries;
}
/**
* Set the maximum retries the cli connection will perform when working in
* graceful mode.
*
* @param maxGracefulRetries
*/
public void setMaxGracefulRetries(int maxGracefulRetries) {
this.maxGracefulRetries = maxGracefulRetries;
}
}