Tuesday, June 10, 2014

Control Observer

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);
  }

}

No comments:

Post a Comment