Anatomy of a Script
This file is last updated Thu Sep 2 16:08:21 EDT 1999
The Basics
Default Imports
The Functions The Script Creates/Overrides
Things Available For You To Use
Finally, I am writing this (much needed) document ...
Some of the fields in the script is fairly intuitive: since we are talking about a FSM, so naturally we'd have the States, StartState, FinalStates, Rules. Variables, InititateBy, Events, and Functions are the supporting fields, and they are discussed later in this page.
package agent.coordinate; import java.util.*; import java.io.*; import taems.*; import taems.parser.*; import utilities.*; import agent.base.*; import agent.simplest.Log; import agent.mass.State; import agent.mass.ProblemSolver;
When an unknown msg or unknown event is received at the coordination bean, the bean will attemp to call this static function and check if it returns a non-null value. The returned object should be an object of yourFSM type.
In your script, the InitiateBy:
field specify pairs such as
event:MyEventType -> MyEventFunction, or
msg:MyMsgType -> MyMsgFunction
This is the place that processes that information. Basically, if an unknown MyEventType event or MyMsgType msg is received, the constructor (Log, State) will be called to instantiate a newfsm object. Then, the function newfsm.MyFunction will be called.
MyEventFunction has to be void MyEventFunction(FSMEvent).
MyMsgFunction has to be void MyMsgFunction(KQMLMessage).
These two updates all Variables: objects in each FSM pulse.
public void deliverMessages(Vector)
These two functions dictate what types of FSMEvent/KQMLMessage this FSM receives. Each works as a filter, looking at the Vector and constructing a subset.
There are two places in your script that contains info for : deliverEvents().
First, the Events: slot specifies pairs such as
event:MyEventType -> MyEvtCondition
This information is used here: basically, if MyEventType
FSMEvent appears in the Vector, you check if
MyCondition(FSMEvent) is true. If so, this FSMEvent is
delivered to this FSM. Clearly, the
MyEvtCondition function must be
boolean MyEvtCondition(FSMEvent)
A second, but simpler case, it that when you use
Event("MyEventType") as the precondition of a
transition rule (don't forget the "", and don't leave any space
in the expression. In that case, if MyEventType is not already
defined in Event: slot, any FSMEvent of MyEventType
in the Vector will be delivered to this FSM. Notice in this
case you don't have a MyCondition function, which may be an
unexpected effect. Personally, I don't think you should use
Event("MyEventType") as the precondition
without defining MyEventType in the Event:
slot of your script.
For KQMLMessages, deliverMessages() only looks at the
Events: slot of your script and check for this:
msg:MyMsgType -> MyMsgCondition.
Clearly, MyMsgCondition has to be
boolean MyMsgCondition(KQMLMessage)
These functions handle the Rules: part of your script.
In my opinion, each and every rule should be in this
format:
StateA | MyRuleCondition(...) -> MyAction(...) | StateB.
There are features such as AND/OR combinations in the rule firing condition part, but for clarity you would be better off just group the combinations in a separate function called MyRuleCondition(...). The parameters in () must be exactly the same as if it is a Java function call (be careful you need to put "" in your Strings), and don't leave any space in the (...) part. The same for MyAction(...). Here MyRuleCondition(...) must be a function that returns boolean.
Similarly, if you use Message("myMsgType"), you can use the currentmsg variable to access the KQMLMessage you just found.
KQMLMessage MessageReceived(String msgtype)
FSMEvent EventReceived(String evttype)
Unlike Event(String), these return the objects instead of boolean values, so you have to define some script-wide local Variables to store the results. Another important thing is that MessageReceived and EventReceived removes the found object from the queue, (so they couldn't be processed twice), but Event(String) or Message does not remove the event/msg from the queue (may lead to the same event processed twice). Personally I'd avoid using Event(String) Message(String) unless you are sure the event/msg won't cause later trouble.
Since MessageReceived is used so often, you can use MessageReceived(String msgtype) as the rule firing condition. This is the only exception that the rule firing condition does not have to be a boolean expression. The return KQMLMessage is stored in a variable named reply_to, which is defined in FSM.java. How convenient! :)
public void FSMsendMessage(KQMLMessage send, KQMLMessage rply_to) { // First grab the FSMId from reply_to String replyID; if (rply_to != null) replyID = rply_to.getField("reply-with"); else replyID = new String("-1"); log.log("ReplyID = "+replyID,1); send.addField("deliver-to-fsm", replyID); send.addField("reply-with", Integer.toString(ID)); sendMessages.addElement(send); }