import java.util.*;
/**
* Description : ControlCommand, interface for processing commands
* @author dbauman
* @since Jun 11, 2004
* Jun 11, 2004 (DBauman) Original Release
*/
public interface ControlCommand {
public boolean processCommand(ControlProcessing controlProcessing);
}
import java.util.*;
/**
* Description : ControlCommandAbstract, holds the parameters, implements ControlCommand
* @author dbauman
* @since Jun 11, 2004
* Jun 11, 2004 (DBauman) Original Release
*/
public abstract class ControlCommandAbstract implements ControlCommand {
protected boolean debug = true;
private ControlParameters controlParameters;
public ControlParameters getControlParameters() {return controlParameters;}
public ControlCommandAbstract(ControlParameters controlParameters) {
this.controlParameters = controlParameters;
}
}
import java.util.*;
/**
* Description : ControlCommandExit, exit command
* @author dbauman
* @since Jun 11, 2004
* Jun 11, 2004 (DBauman) Original Release
*/
public class ControlCommandExit extends ControlCommandAbstract {
public ControlCommandExit(ControlParameters controlParameters) {
super(controlParameters);
}
public boolean processCommand(ControlProcessing controlProcessing) {
ControlParameters controlParameters = getControlParameters();
if (debug) System.out.println("Exit");
System.exit(0);
return true;
}
}
import java.util.*;
/**
* Description : ControlCommandGetItem, get item command
* @author dbauman
* @since Jun 11, 2004
* Jun 11, 2004 (DBauman) Original Release
*/
public class ControlCommandGetItem extends ControlCommandAbstract {
public ControlCommandGetItem(ControlParameters controlParameters) {
super(controlParameters);
}
public boolean processCommand(ControlProcessing controlProcessing) {
ControlParameters controlParameters = getControlParameters();
if (!controlParameters.hasNext()) return false;
String map = (controlParameters.nextToken()).trim();
if (!controlParameters.hasNext()) return false;
String section = (controlParameters.nextToken()).trim();
if (!controlParameters.hasNext()) return false;
String item = (controlParameters.nextToken()).trim();
if (debug) System.out.println("getitem: "+map+", "+section+", "+item);
String val = "itemValue";
// DO THE WORK HERE!!!
// val = helper.getAppMapItem(map, section, item);
// we can cast because we know that we are of this 'interface' type
((ControlProcessingUI1)controlProcessing).setAppMapItem(val);
return true;
}
}
import java.util.*;
/**
* Description : ControlCommandOpenMap, open map command
* @author dbauman
* @since Jun 11, 2004
* Jun 11, 2004 (DBauman) Original Release
*/
public class ControlCommandOpenMap extends ControlCommandAbstract {
public ControlCommandOpenMap(ControlParameters controlParameters) {
super(controlParameters);
}
public boolean processCommand(ControlProcessing controlProcessing) {
ControlParameters controlParameters = getControlParameters();
if (!controlParameters.hasNext()) return false;
String map = (controlParameters.nextToken()).trim();
if (debug) System.out.println("Openmap: "+map);
String statusCode = "OK";
// DO THE WORK HERE!!!
// statusCode = helper.openMap(map);
try { // simulate that the commands takes real time
Thread.sleep(3000);
} catch (InterruptedException ie) {}
//
// we can cast because we know that we are of this 'interface' type
((ControlProcessingUI1)controlProcessing).setStatusCode(statusCode);
return true;
}
}
import java.util.*;
/**
* Description : ControlObservable, extends Observable, implements Runnable.
* This is the 'other thread' which sends data to the Control portion.
* Implement Runnable so that our 'run' method can be the result of
* starting another Thread so that the controler/Observer can receive the notification
* messages without blocking.
* This class does all of the thread stuff, including the 'synchronizing'
* @author dbauman
* @since DEC 17, 2003
* DEC 17, 2003 (DBauman) Original Release
* DEC 17, 2003 (DBauman) we also
* implement ControlProcessing so that we can tell the GUI when we are done processing.
*/
public class ControlObservable extends Observable implements Runnable {
private ControlProcessing controlProcessing;
/** constructor, starts our thread **/
ControlObservable (ControlProcessing controlProcessing) {
this.controlProcessing = controlProcessing;
// start the processing thread
new Thread(this).start();
}
/** a queue of commands to notify the observer with.
** The observer is on another thread, so we use this to
** pass the commands from one thread to another.
**/
private ArrayList cmds = new ArrayList();
public boolean isEmpty () {
return cmds.isEmpty(); // no need to be sychronized
}
public void addCommand (Object cmd) {
synchronized(cmds) {
cmds.add(cmd);
}
}
/** Purpose: run method of another thread. Used
** solely by the notifyOurObserver method via the 'cmds'. It is best to keep
** the observer (controller) in a separate thread from the GUI (view) because
** if the user presses a button twice during a test then nothing will happen.
* Side Effects: 'cmds', a command is grabbed from this queue
* State Read: 'cmds'
* Assumptions: We sleep for 100 ms between commands inside an infinite loop.
**/
public void run () {
for(;;) {
Object next = null;
if (!cmds.isEmpty()) { // do this twice for efficiency
synchronized(cmds) {
if (!cmds.isEmpty()) { // have to do here inside the 'synchronized' at the very least
next = cmds.get(0);
}
}
}
if (next != null) {
setChanged();
notifyObservers(next);
clearChanged();
}
boolean empty = false;
synchronized(cmds) {
if (!cmds.isEmpty()) {
cmds.remove(0); // finally remove the element
}
empty = cmds.isEmpty();
}
// processing complete, based on 'empty' flag
// make sure not to do this inside the 'sychronized' block because it could be slow
controlProcessing.processingComplete(empty);
try {
Thread.sleep(100);
} catch (InterruptedException ie) {}
}
}
}
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
/**
* Description : ControlObserver, used to control something, and acts as an observer
* @author dbauman
* @since DEC 15, 2003
* DEC 15, 2003 (DBauman) Original Release
* a controller : it uses Class.forName to load the 'instanceName' class which is the Observable
* to our Observer. Our 'update' method gets the commands from
* that GUI and executes them.
*/
public class ControlObserver extends ControlObserverUpdate {
/** the instance name of the GUI **/
public static String instanceName = "ControlObservableUI";
/** Purpose: main method
* @param args, String[],
*
args[0]: can be:
*
instanceName
**/
public static void main (String[] args) {
ControlObserver control = new ControlObserver();
if (args.length>0) {
control.instanceName = args[0];
}
System.out.println("instanceName (for GUI class): "+instanceName);
control.debug = true;
control.instanceGui(instanceName);
control.start();
}
}
import java.io.*;
import java.util.*;
import java.lang.reflect.*;
/**
* Description : ControlObserver, used to control something, and acts as an observer, abstract method to be extended
* @author dbauman
* @since DEC 15, 2003
* DEC 15, 2003 (DBauman) Original Release
* Jun 11, 2004 (DBauman) was moved to this class
* abstract reusable part of our controller : it uses Class.forName to load the 'instanceName' class which is the Observable
* to our Observer. Our 'update' method gets the commands from
* that GUI and executes them.
*
*/
public abstract class ControlObserverUpdate implements Observer {
protected boolean debug=false;
protected ControlProcessing instance = null;
public void start() {
instance.start();
}
/** Tries to instance a Gui
* @param instanceName, String
* @return instance
**/
public ControlProcessing instanceGui (String instanceName) {
String methodName = "ControlObserver.instanceGui: ";
try { // next try using Class.forName...
if (debug) System.out.println(methodName+"trying :"+instanceName);
Class guiClass = Class.forName(instanceName);
if (debug) System.out.println(methodName+"guiClass: "+guiClass.getName());
instance = (ControlProcessing) guiClass.newInstance();
instance.addObserver(this);
return instance;
} catch (NoClassDefFoundError nc) {
System.err.println(methodName+"no class definition found: "+instanceName);
} catch (ClassCastException cc) {
System.err.println(methodName+"can't Cast class: "+instanceName);
} catch (InstantiationException ie) {
System.err.println(methodName+"can't instantiate class: "+instanceName);
} catch (ClassNotFoundException ex) {
System.err.println(methodName+"can't find class: "+instanceName);
} catch (IllegalAccessException iae) {
System.err.println(methodName+iae.toString());
}
return null;
}
/**
Purpose: this class is called when a GUI sends us data
* @param obs, Observable
* @param arg, Object
**/
public void update(Observable obs, Object arg) {
ControlParameters st = (ControlParameters) arg;
ControlCommand command = st.getCommand();
if (debug) System.out.println("NEXT: "+command);
boolean result = command.processCommand(instance);
if (debug) System.out.println("RESULT: "+result);
}
}
import java.util.*;
/**
* Description : ControlParameters, contains objects passed to the control
* @author dbauman
* @since DEC 17, 2003
*
* DEC 17, 2003 (DBauman) Original Release
*/
public class ControlParameters {
private ControlCommand command;
public ControlCommand getCommand() {iterator=params.iterator(); return command;}
public void setCommand(ControlCommand command) {this.command=command;}
private Collection params = new LinkedList();
private Iterator iterator;
public void addParam(Object param) {params.add(param);}
public boolean hasNext () {return iterator.hasNext();}
public Object next() {return iterator.next();}
public String nextToken() {return (String)next();}
}
import java.util.*;
/**
* Description : ControlProcessing interface, can indicate when processing is complete
* @author dbauman
* @since DEC 17, 2003
* DEC 17, 2003 (DBauman) Original Release
*/
public interface ControlProcessing {
public void processingComplete (boolean pc);
/** pass along to 'controlObservable'
** with a line like this:
** controlObservable.addObserver(observer);
**/
public void addObserver(Observer observer);
public void start();
}
public interface ControlProcessingUI1 extends ControlProcessing {
/** set the text of the 'statusCode' text field **/
public void setStatusCode(String status);
/** set the text of the 'appMapItem' text field **/
public void setAppMapItem(String val);
}
import java.util.*;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
/**
* Description : ControlObservableUI, used to control an engine by sending step commands.
* This is the GUI, we contain an Observable (instance of ControlObservable).
* When our buttons are pressed, we send commands to the Observer (Controller)
* Implement ActionListener so that our actionPerformed method can
* react to the buttons.
* Implement Runnable so that our 'run' method can be the result of
* starting another Thread so that the controler/Observer can receive the notification
* messages without blocking our GUI thread.
* @author dbauman
* @since DEC 15, 2003
* DEC 15, 2003 (DBauman) Original Release
* DEC 17, 2003 (DBauman) changed to contain an ControlObservable.
*/
public class ControlObservableUI implements ActionListener, ControlProcessingUI1 {
/** set the text of the 'statusCode' text field **/
public void setStatusCode(String status) {this.statusCode.setText(status);}
/** set the text of the 'appMapItem' text field **/
public void setAppMapItem(String val) {this.appMapItem.setText(val);}
/** startup the observable thread **/
private ControlObservable controlObservable = new ControlObservable(this);
/** all of the GUI elements **/
private JFrame frame;
private JPanel top;
private JLabel lab7;
private JTextField map;
private JTextField section;
private JTextField item;
private JTextField appMapItem;
private JTextField statusCode;
public static final String CENTER = "Center";
private String BUSY = "Please wait until the last command is finished.";
private static final String BLANKSPACE = " ";
private String lab7text = "Processing Command";
private String lab7tail= "..."+BLANKSPACE;
/**Construct the Panel*/
public ControlObservableUI() {
top = new JPanel();
Dimension dim = new Dimension(588, 160);
top.setSize(dim);
top.setPreferredSize(dim);
JPanel panC = new JPanel();
panC.setBorder(BorderFactory.createTitledBorder("Application Map"));
JPanel pan8 = new JPanel();
JPanel pan9 = new JPanel();
JPanel pan10 = new JPanel();
JPanel pan11 = new JPanel();
JPanel pan12 = new JPanel();
JPanel pan13 = new JPanel();
lab7 = new JLabel(BLANKSPACE);
JLabel lab5 = new JLabel("Application Map"+": ");
JLabel lab10 = new JLabel("Status Code"+": ");
JLabel lab11 = new JLabel("Section"+": ");
JLabel lab12 = new JLabel("Item"+": ");
JLabel lab13 = new JLabel("Item Value"+": ");
map = new JTextField();
section = new JTextField();
item = new JTextField();
appMapItem = new JTextField();
statusCode = new JTextField();
map.setColumns(28);
section.setColumns(28);
item.setColumns(28);
appMapItem.setColumns(28);
statusCode.setColumns(28);
JButton b2 = new JButton("OpenMap");
JButton b3 = new JButton("Clear");
JButton b4 = new JButton("Exit");
JButton b6 = new JButton("Get Item");
JButton b6b = new JButton("Get Item Now");
b2.setActionCommand("OpenMap");
b2.addActionListener(this);
b3.setActionCommand("Clear");
b3.addActionListener(this);
b4.setActionCommand("Exit");
b4.addActionListener(this);
b6.setActionCommand("GetItem");
b6.addActionListener(this);
b6b.setActionCommand("GetItemNow");
b6b.addActionListener(this);
panC.setLayout(new BoxLayout(panC, BoxLayout.Y_AXIS));
pan8.setLayout(new BoxLayout(pan8, BoxLayout.X_AXIS));
pan9.setLayout(new BoxLayout(pan9, BoxLayout.X_AXIS));
pan10.setLayout(new BoxLayout(pan10, BoxLayout.X_AXIS));
pan11.setLayout(new BoxLayout(pan11, BoxLayout.X_AXIS));
pan12.setLayout(new BoxLayout(pan12, BoxLayout.X_AXIS));
pan13.setLayout(new BoxLayout(pan13, BoxLayout.X_AXIS));
pan8.add(lab5, CENTER);
pan8.add(map, CENTER);
pan9.add(lab11, CENTER);
pan9.add(section, CENTER);
pan10.add(lab12, CENTER);
pan10.add(item, CENTER);
pan11.add(lab13, CENTER);
pan11.add(appMapItem, CENTER);
pan12.add(lab10, CENTER);
pan12.add(statusCode, CENTER);
pan13.add(lab7, CENTER);
pan13.add(b2, CENTER);
pan13.add(b3, CENTER);
pan13.add(b4, CENTER);
pan13.add(b6, CENTER);
pan13.add(b6b, CENTER);
top.setLayout(new BoxLayout(top, BoxLayout.Y_AXIS));
top.add(panC);
panC.add(pan8);
panC.add(pan9);
panC.add(pan10);
panC.add(pan11);
panC.add(pan12);
panC.add(pan13);
}
/** starts up the frame and adds the 'top' component to it;
** also starts up the observable thread (ControlObservable)
**/
public void start () {
System.out.println("start");
frame = new JFrame("ControlObservableUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
//notifyOurObserver("Exit");
System.exit(1); // for the impatient user, otherwise would have to wait for cmd
}
});
frame.getContentPane().add(top, CENTER);
frame.pack();
frame.setVisible(true);
}
/** pass along to 'controlObservable'**/
public void addObserver(Observer observer) {
System.out.println("adding: "+observer);
controlObservable.addObserver(observer);
System.out.println("done adding: "+observer);
}
/** show an information popup dialog using JOptionPane
** @param msg, String
**/
public void popupMessage (String msg) {
JOptionPane.showMessageDialog(frame, msg,
msg, JOptionPane.INFORMATION_MESSAGE);
}
/** processing complete will be called by ControlObservable class run thread **/
public void processingComplete (boolean pc) {
if (lab7 != null) {
if (pc) {
lab7.setText(BLANKSPACE);
} else {
lab7.setText(lab7text + lab7tail);
}
}
}
/** notify the observers by placing 'cmd' on the 'cmds' queue
** @param cmd, String
**/
private void notifyOurObserver (Object cmd) {
lab7.setText(lab7text + lab7tail);
controlObservable.addCommand(cmd);
}
/** notify the observers of the event.getActionCommand()
** with the params
**/
public void actionPerformed(ActionEvent event) {
ControlParameters buf = new ControlParameters();
if (event.getActionCommand().equalsIgnoreCase("OpenMap")) {
if (!controlObservable.isEmpty()) {popupMessage(BUSY); return;}
buf.setCommand(new ControlCommandOpenMap(buf));
buf.addParam(map.getText());
} else if (event.getActionCommand().equalsIgnoreCase("GetItem")) {
if (!controlObservable.isEmpty()) {popupMessage(BUSY); return;}
buf.setCommand(new ControlCommandGetItem(buf));
buf.addParam(map.getText());
buf.addParam(section.getText());
buf.addParam(item.getText());
} else if (event.getActionCommand().equalsIgnoreCase("GetItemNow")) {
//if (!controlObservable.isEmpty()) {popupMessage(BUSY); return;}
buf.setCommand(new ControlCommandGetItem(buf));
buf.addParam(map.getText());
buf.addParam(section.getText());
buf.addParam(item.getText());
} else if (event.getActionCommand().equalsIgnoreCase("Clear")) {
map.setText("");
section.setText("");
item.setText("");
statusCode.setText("");
appMapItem.setText("");
return; // because we don't need to 'notify'
} else if (event.getActionCommand().equalsIgnoreCase("Exit")) {
if (!controlObservable.isEmpty()) {popupMessage(BUSY); return;}
buf.setCommand(new ControlCommandExit(buf));
}
notifyOurObserver(buf);
}
}