/* File: MessageInterpreter.java * Contains: The interpreter for significant messages * Author: Jeff Dalton * Created: June 2000 * Updated: Wed May 30 18:27:33 2001 by Jeff Dalton * Copyright: (c) 2000, 2001, AIAI, University of Edinburgh */ package ix.ileed; import java.util.*; import ix.util.*; import ix.util.lisp.*; /** * Interprets messages sent during the operation of the CoAX process. */ public class MessageInterpreter { public WatcherListener listener; protected Date creationDate = new Date(); protected Hashtable statusTable = new Hashtable(); /** * Create a MessageInterpreter connected to a WatcherListener. */ public MessageInterpreter(WatcherListener listener) { this.listener = listener; } /** * Change the WatcherListener that the interpreter tells of status changes. */ public void setListener(WatcherListener listener) { this.listener = listener; } public synchronized void reset() { statusTable.clear(); } /** * Determines what, if anything, a message means in terms understood * by a WatcherListener (typically a process model / stepper), by * calling the appropriate WatcherListener method(s). */ public synchronized void interpret(String message) { Debug.noteln("Interpreting", message); Vector cases = (Vector)interpretations.get(message); if (cases == null) { Debug.warn("Cannot understand message " + message); } else for (Enumeration e = cases.elements(); e.hasMoreElements(); ) { handleMessageCase(message, (Case)e.nextElement()); } } // /\/: Some of the status changes in the interpretations table are // redundant, but rather than work out which they are, we filter them // out as we go. We have to do something to avoid sending them to // the WatcherListener, because we don't want to make it look like // something happened twice when it happened only once. protected void handleMessageCase(String message, Case c) { // Here's where we finally send something to the process model. Debug.noteln("Case", c); if (statusTable.get(c.action) == c.status) { Debug.noteln("Redundant change", c); return; } if (c.status == K_COMPLETE) { listener.finishAction(c.action); } else if (c.status == K_EXECUTING) { listener.startAction(c.action); } else { Debug.warn("Unknown status " + c.status); return; } statusTable.put(c.action, c.status); } /* * Interpretation table */ // /\/: Some of the status changes in the interpretations table are // redundant. See handleMessageCase() above. // The MultiHashtable maps a message string to a Vector // of Case objects. public MultiHashtable interpretations = new MultiHashtable(); public static final Symbol K_COMPLETE = Symbol.intern(":complete"), K_EXECUTING = Symbol.intern(":executing"); static class Case { String action; Symbol status; Case(String action, Symbol status) { this.action = action; this.status = status; } public String toString() { return "Case[" + action + ", " + status + "]"; } } public void addCase(String message, String action, Symbol status) { interpretations.put(message, new Case(action, status)); } { addCase("S1M1a", "transmit mission to JFACC [message S1M1a]", K_COMPLETE); addCase("S1M1a", "confirm receipt of S1M1a [message S1M1b]", K_EXECUTING); addCase("S1M1b", "transmit mission to JFACC [message S1M1a]", K_COMPLETE); addCase("S1M1b", "confirm receipt of S1M1a [message S1M1b]", K_COMPLETE); addCase("S1M2a", "transmit JTFC's mission directive to JFACC [message S1M2a]", K_COMPLETE); addCase("S1M2a", "confirm receipt of S1M2a [message S1M2b]", K_EXECUTING); addCase("S1M2b", "transmit JTFC's mission directive to JFACC [message S1M2a]", K_COMPLETE); addCase("S1M2b", "confirm receipt of S1M2a [message S1M2b]", K_COMPLETE); addCase("S1M3a", "transmit JTFC's intent to JFACC [message S1M3a]", // ? K_COMPLETE); addCase("S1M3a", "confirm receipt of S1M3a [message S1M3b]", K_EXECUTING); addCase("S1M3b", "transmit JTFC's intent to JFACC [message S1M3a]", // ? K_COMPLETE); addCase("S1M3b", "confirm receipt of S1M3a [message S1M3b]", K_COMPLETE); addCase("I1a", "request intelligence report [message I1a]", K_COMPLETE); addCase("I1a", "wait for rfi", K_EXECUTING); addCase("I1b", "request intelligence report [message I1a]", K_COMPLETE); addCase("I1b", "provide intelligence [message I1b]", K_COMPLETE); addCase("S1M4a", "request JFACC draft estimate [message S1M4a]", // ? K_COMPLETE); addCase("S1M4a", "provide JFACC draft estimate [message S1M4b]", // ? K_EXECUTING); addCase("S1M4b", "request JFACC draft estimate [message S1M4a]", // ? K_COMPLETE); addCase("S1M4b", "provide JFACC draft estimate [message S1M4b]", // ? K_COMPLETE); addCase("S2M1a", "request information on availability of assets [message S2M1a]", K_COMPLETE); addCase("S2M1a", "provide information on availability of assets [message S2M1b]", K_EXECUTING); addCase("S2M1b", "request information on availability of assets [message S2M1a]", K_COMPLETE); addCase("S2M1b", "provide information on availability of assets [message S2M1b]", K_COMPLETE); addCase("S2M2a", "request for apportionment recommendation [message S2M2a]", K_COMPLETE); addCase("S2M2a", "provide apportionment recommendation [message S2M2b]", K_EXECUTING); addCase("S2M2b", "request for apportionment recommendation [message S2M2a]", K_COMPLETE); addCase("S2M2b", "provide apportionment recommendation [message S2M2b]", K_COMPLETE); } }