[Date Prev][Date Next][Thread Prev][Thread Next][Author Index][Date Index][Thread Index]

creating a new messageHandler


The way we currently have transceivers and messageHandlers set up
to transmit message sends requires a handler class (subclass of
MessageHandler in xpp/handlerx.*xx) for each abstract message
signature that might be sent over the wire.  Here, "abstract"
refers to the fact that each handler deals with all the messages
that have the same argument types, return type, and receiver
type, with the types being "abstracted up to the `root' of their
superclass tree."  For instance, there is one handler class
(Heaper_IntVar_Handler) that is used by all the messages (to
Heapers) that take one IntegerVar argument and return some kind
of Heaper.

The abstract types that Stubble currently knows about are Heaper,
IntegerVar, BooleanVar, HeaperStar, IEEEDoubleVar and the two
return types void and noWait.  For obvious reasons ;-), I haven't
implemented the handlers for all the possible combinations of
signature types, and that's the reason for this note.  At some
point, some of you will add a new message to a Proxy class that
has a signature that hasn't been used before, and you'll get a
error message while compiling the stubble-generated output
that'll look something like this:

        "permits.cxx", line 718: error: Heaper_HeaperBool_Handler 
        theKeyMaster_newWaldo19Handler : Heaper_HeaperBool_Handler is
        not a type name.

The error message will be produced when the compiler detects that
there's no class by the name that Stubble generated from your
declarations.  At that point you have to create a new handler class.
If you just look at the ones that are there, it should be pretty
obvious what to do, but just for the record, I'm going to describe
what needs to be done so you can look it up when you need it.  I
suggest filing this away until you need it--unless you want to
proofread my instructions.

Writing the declaration of the new Handler

In order to add a new handler class, you need to add a declaration of
the class and implementations of the methods.  The declaration
looks something like this:

    CLASS(Heaper_IntVar_Handler,MessageHandler) {
        LEAF void processMessage(Heaper *rcvr, CommXcvr* trans);
        LEAF SPTR(Heaper) handleSend(CommHandler*, IntegerVar,
        Category* myReturnType;
        SPTR(Heaper) (Heaper::*myMembFn)(IntegerVar);
        char *myMsgName;
        Heaper_IntVar_Handler(Category*, char*, Category*,
                              SPTR(Heaper) (Heaper::*membFnPtr) (IntegerVar));

The messageHandlers' constructors require arguments to specify the
receiver type, the name of the message, the return type, the argument
types, and a pointer to the member function which is being described.
The types are omitted whenever the abstract type uniquely identifies
the actual type.  (i.e. The types are only given for Heaper
subclasses, since nothing else has subclasses.)  

Each of the arguments to the constructor must be stored in an instance
variable, so you have to declare the instance variables for all the
arguments except the category of the receiver (and the name of the
message?) which is stored by MessageHandler.  handleSend() takes a
list of arguments which are the same as the message being described,
but preceded by a CommHandler and an object identifier.  The return
type of handleSend() is the same (abstract) type as the messages being
described.  The declaration of processMessage() doesn't change.

The syntax for declaring the pointer to member function is a bit
odd, but you should be able to get it right by looking at the
ones that are there already.  In the above example,

      SPTR(Heaper) (Heaper::*myMembFn)(IntegerVar);

declares that myMembFn is a pointer to a member function that
returns SPTR(Heaper) and takes one IntegerVar as an argument.
the constructor has a similar pointer to a member function as
its last argument.    

Writing the methods of the New Handler

There are three methods that must be written for each new Handler
class: processMessage(), handleSend(), and the constructor.  The
constructor just assigns its arguments to the appropriate instance
variables, so that should be no problem.  processMessage() is run on
the platform on which the proxied object lives.  It is in charge of
getting the getting the message specification from the transceiver,
checking all the types, actually sending the message, and returning
the result back to the transceiver.  handleSend() gets run on the
same platform as the proxy; it describes the message to the
transceiver, then (usually) waits for the result to be computed and
sent back to it so it can give the result to the proxy.

processMessage() starts with declarations of the return value and the
arguments.  Heaper arguments and results should be declared simply as
Heapers, while all else should be their actual types.  The next part
of the method is the retrieval of the arguments from the transceiver.
This is straightforward; the only thing to watch out for when copying
the code is that the syntax for receiving a Heaper is:

        inArg1 = trans->receive(cat_Heaper);

while for IntVars, Booleans, etc. it's:


The next piece of processMessage() sends the message.  Since this part
has to be protected from embedded blasts, it's also the place where
all the type checking in this method takes place.  noWait messages
don't do any type-checking, but for other messages, you should be able
to copy a reasonable example in a straightforward way.

handleSend() is simpler.  It begins with the declaration of the result
if there is one and of the transceiver.  Each of the Heaper arguments'
type is checked, and then they are sent to the transceiver.
trans->over() is sent to tell the transceiver that all the parts have
been sent, and results are collected off the wire.  (Again, notice
that the receive syntax varies between Heapers and other sorts of

The right way to go at this is to find a class that has a signature
that's pretty close to the one you need and modify it a bit.  If that
isn't clear, compare two similar classes to see how the addition of an
extra Heaper or Boolean argument changes things.  If the return type
is void or noWait, make sure you follow a model that has that aspect.
Empty argument lists are pretty easy to get right.  There aren't any
current examples using IEEE or HeaperStar, so if you're the first to
use one of these, you'll have to figure out how they should get
handled--they're probably just like IntegerVars, but since there
aren't any current uses, I left them out.