package alma.acs.commandcenter.trace; import java.util.*; import javax.swing.tree.DefaultMutableTreeNode; /** * The base class for flow tracing, subclass this to define a flow. */ public class Flow { // ======= Internal Data Structure ====== protected final Node UNDEF = new Node(""); protected Map<String,Node> name2node = new HashMap<String,Node>(); protected Node node(String name) { Node node = (Node) name2node.get(name); if (node == null) { node = new Node(name); name2node.put(name, node); } return node; } protected class Node extends DefaultMutableTreeNode { protected Node(String name) { super(name); } protected String getName() { return String.valueOf(getUserObject()); } } // ========== for use by subclasses defining a flow ========= public void consistsOf(String parent, String[] kids) { for (int i = 0; i < kids.length; i++) node(parent).add(node(kids[i])); } // ========== for use by workers implementing this flow ========= protected Node latestSuccess = UNDEF; protected Node nowTrying = UNDEF; public String current() { // if the current step was announced, it is easy Node step = nowTrying; // if not, we try to determine it ourselves if (step == UNDEF) { try { // determine step after latest success Node current = latestSuccess; if (current == null) current = node(null); step = (Node) current.getNextLeaf(); //PENDING(msc): this assumption won't hold // otherwise assume first step is the current one if (step == null) step = ((Node) node(null).getChildAt(0)); } catch (Exception exc) { System.err.println("Flow.failure: "+exc); step = UNDEF; } } return step.getName(); } public void reset (Object info) { this.latestSuccess = UNDEF; this.nowTrying = UNDEF; fireReset(info); } public void trying (String step) { this.nowTrying = node(step); fireTrying(step); } public void success (String step) { this.latestSuccess = node(step); this.nowTrying = UNDEF; fireSuccess(step); if (latestSuccess.getNextLeaf() == null) fireCompletion(); } public void failure (Object info) { String failed = current(); fireFailure(failed, info); } // --- helpers for the foregoing section --- protected void fireReset (Object info) { FlowListener[] l = new FlowListener[listeners.size()]; listeners.copyInto(l); for (int i = 0; i < l.length; i++) l[i].reset(this, info); } protected void fireTrying(String step) { FlowListener[] l = new FlowListener[listeners.size()]; listeners.copyInto(l); for (int i = 0; i < l.length; i++) l[i].trying(this, step); } protected void fireSuccess(String step) { FlowListener[] l = new FlowListener[listeners.size()]; listeners.copyInto(l); for (int i = 0; i < l.length; i++) l[i].success(this, step); } protected void fireFailure(String step, Object info) { FlowListener[] l = new FlowListener[listeners.size()]; listeners.copyInto(l); for (int i = 0; i < l.length; i++) l[i].failure(this, step, info); } protected void fireCompletion() { FlowListener[] l = new FlowListener[listeners.size()]; listeners.copyInto(l); for (int i = 0; i < l.length; i++) l[i].completion(this); } // ========== for use by listeners observing this flow ========= protected Vector<FlowListener> listeners = new Vector<FlowListener>(); public void addListener(FlowListener l) { listeners.add(l); } public void removeListener(FlowListener l) { listeners.remove(l); } }