The CUI framework provides:
1. A simple console user interface.
2. An extensible error handling strategy.
3. A simplified Model-View architecture.
4. The ability to save application data to secondary memory.
5. The ability to load application data from secondary memory.
6. Extensible help and about mechanisms.
CUI is simple to customize. The user only needs to provide a model that implements the Serializable interface, and a subclass of Console that provides an implementation of the abstract execute method.
See the Javadoc pages for more information.
package jutil;
import java.io.*;
abstract public class Console {
protected BufferedReader stdin;
protected PrintWriter stdout;
protected PrintWriter stderr;
protected String prompt = "->
";
protected Serializable model;
private String fname = null;
protected boolean unsavedChanges =
false;
public
Console(Serializable model) {
this.model = model;
stdout = new PrintWriter(
new BufferedWriter(
new
OutputStreamWriter(System.out)), true);
stderr = new PrintWriter(
new BufferedWriter(
new
OutputStreamWriter(System.out)), true);
stdin = new BufferedReader(
new
InputStreamReader(System.in));
}
public Console() { this(null); }
public void controlLoop()
{
String cmmd = " ";
String result = " ";
stdout.println("type
\"help\" for commands");
while(true) {
try {
stdout.print(prompt);
stdout.flush(); // force the
write
cmmd = stdin.readLine();
cmmd = cmmd.trim(); // trim
white space
if
(cmmd.equalsIgnoreCase("quit")) {
saveChanges();
break;
}
if
(cmmd.equalsIgnoreCase("help")) {
help();
continue;
}
if
(cmmd.equalsIgnoreCase("about")) {
about();
continue;
}
if
(cmmd.equalsIgnoreCase("save")) {
save(false);
stdout.println("done");
continue;
}
if
(cmmd.equalsIgnoreCase("save as")) {
save(true);
stdout.println("done");
continue;
}
if
(cmmd.equalsIgnoreCase("load")) {
load();
stdout.println("done");
continue;
}
// application-specific
command:
result = execute(cmmd);
stdout.println(result);
} catch(AppError exp) {
handle(exp);
continue;
} catch (Exception exp) {
exp.printStackTrace();
stderr.println("Serious
error, " + exp);
break;
}
} // while
stdout.println("bye");
} // controlLoop
abstract protected String execute(String cmmd) throws AppError;
protected void help() {
stdout.println("Console Help
Menu:");
stdout.println(" about:
displays application information");
stdout.println(" help:
displays this message");
stdout.println(" save:
saves model to a file");
stdout.println(" save as: saves model to a new file");
stdout.println(" load:
load model from a file");
stdout.println(" quit:
terminate application");
}
protected void about() {
stdout.println("Console
Framework");
stdout.println("copyright (c)
2001, all rights reserved\n");
}
protected void handle(AppError exp) {
stderr.println("Application
error, " + exp.getMessage());
}
protected void save(boolean saveAs)
throws IOException {
if (model != null &&
unsavedChanges) {
if (saveAs) {
saveChanges();
return;
}
if (fname == null) fname =
getFname();
ObjectOutputStream obstream =
new ObjectOutputStream(
new
FileOutputStream(fname));
obstream.writeObject(model);
obstream.flush();
obstream.close();
unsavedChanges = false;
}
}
protected void load()
throws IOException, ClassNotFoundException {
if (model != null) {
saveChanges();
String fname = getFname();
ObjectInputStream ois =
new ObjectInputStream(new
FileInputStream(fname));
model = (Serializable)
ois.readObject();
ois.close();
unsavedChanges = false;
}
}
private void
saveChanges() throws IOException {
if (model != null &&
unsavedChanges) {
stdout.print("Save
changes?(y/n): ");
stdout.flush(); // force the
write
String response =
stdin.readLine();
if
(response.equals("y"))
save(false);
else
stdout.println("changes
discarded");
}
}
private String getFname()
throws IOException {
stdout.print("enter file name:
");
stdout.flush(); // force the write
String result = stdin.readLine();
return result;
}
} // Console
package jutil;
public class AppError extends Exception {
public
AppError(String g) { super(g); }
public AppError() {
this("unknown"); }
}
ATM is a simplified account manager. It allows users to load a single account, make deposits and withdrawals from this account, save the account.
import jutil.*;
import java.io.*;
public class BankAccount implements Serializable {
private double balance = 0;
public double getBalance() { return balance;
}
public void withdraw(double amt) throws
AppError {
if (balance < amt) throw new
AppError("Insufficient funds");
balance -= amt;
}
public void deposit(double amt) {
balance += amt;
}
}
import jutil.*;
import java.util.*;
public class ATM extends Console {
public ATM(BankAccount acct) {
super(acct); }
public ATM() { this(new BankAccount());
}
public BankAccount getModel() {
return (BankAccount)model; }
protected String execute(String cmmd)
throws AppError {
StringTokenizer tokens = new
StringTokenizer(cmmd);
if (!tokens.hasMoreTokens())
throw new AppError("Type
help for commands");
String operator =
tokens.nextToken();
if
(operator.equals("balance")) {
return "$" +
getModel().getBalance();
}
if (operator.equals("deposit"))
{
double amount =
getOperand(tokens);
getModel().deposit(amount);
unsavedChanges = true;
return "done";
}
if
(operator.equals("withdraw")) {
double amount =
getOperand(tokens);
getModel().withdraw(amount);
unsavedChanges = true;
return "done";
}
throw new
AppError("Unrecognized command: " + operator);
}
private double
getOperand(StringTokenizer tokens)
throws AppError {
if (!tokens.hasMoreTokens())
throw new AppError("Amount
required");
try {
Double amt = new
Double(tokens.nextToken());
return amt.doubleValue();
} catch(NumberFormatException e) {
throw new AppError("Amount
must be a number");
}
}
protected void help() {
super.help();
stdout.println("ATM Help
Menu:");
stdout.println(" balance:
displays current
balance");
stdout.println(" withdraw AMT: withdraws $AMT");
stdout.println(" deposit AMT: deposits $AMT");
}
protected void about() {
super.about();
stdout.println("ATM
Demo");
stdout.println("copyright (c)
2004, all rights reserved\n");
}
public static void
main(String[] args) {
ATM console = new ATM();
console.controlLoop();
}
} // ATM
type "help" for commands
-> help
Console Help Menu:
about: displays application information
help: displays this message
save: saves model to a file
save as: saves model to a new file
load: load model from a file
quit: terminate application
ATM Help Menu:
balance: displays current balance
withdraw AMT: withdraws $AMT
deposit AMT: deposits $AMT
-> about
Console Framework
copyright (c) 2001, all rights reserved
ATM Demo
copyright (c) 2004, all rights reserved
-> deposit 50
done
-> balance
$50.0
-> withdraw 15
done
-> balance
$35.0
-> transfer 100
Application error, Unrecognized command: transfer
-> withdraw
Application error, Amount required
-> withdraw ten
Application error, Amount must be a number
-> withdraw 100
Application error, Insufficient funds
-> withdraw 10
done
-> balance
$25.0
-> quit
Save changes?(y/n): y
enter file name: savings
bye
type "help" for commands
-> deposit 1500
done
-> balance
$1500.0
-> load
Save changes?(y/n): y
enter file name: checking
enter file name: savings
done
-> balance
$25.0
-> deposit 30
done
-> quit
Save changes?(y/n): n
changes discarded
bye