Jump to content

class dependency linking


Recommended Posts

I have run into a problem with passing messages as objects between applications.  My architecture is similar to AF in that messages have an execute (do) method that is run by the recipient of the message.  For this to work, both the sender and the recipient must have a copy of the class.  I am also trying to send messages between applications.  In my application, I have a process (actor) dedicated to receiving messages.  That way, I can quickly dispatch the message to another process and be ready to receive the next message. (kinda like the event loop in a producer/consumer architecture)  This also allows me to take several actions when a message is received, such as passing some of the data to one internal process and some to another (via more messages).

The problem I have run into is how the messages are linked to one another.  Since the sender application must construct the message and send it, they need a copy of the message class.  On the receiver application side, the message is executed and within that method, I create the other messages to be sent to internal processes, populate their properties and send them.  Due to this, my original message contains a static link to the class of every message it will send internally.  And if those messages in turn send other messages as part of their execute methods, then those will also be statically linked.

The end result is my sender application has dependencies on nearly every message class in my receiver.  Something I definitely do not want.

This seems like a situation that AF users might run into so I am wondering if there is a way to break this dependency so the sender only needs the message class of the object that will be sent to the other application.  I tried to think of a way to do this with dynamic loading classes, but the need to set the properties of the message to propagate means that I still need to cast the object and am therefore creating a static link again.

 

Thanks for any ideas.

 

-John

Link to comment

Move all the receiving logic into a separate class, Receiver, that mirrors the message structure (you'll need one method per type of message that you want to receive), similar to the Visitor pattern that was recently discussed in another thread. Add a method to the message class that takes, as a parameter, a class of the receiver type, and calls a method inside that receiver class, passing itself (the message) as a parameter. Then all the dependencies are inside the receiving class. The parent receiving class can basically be a no-op on the sending side with no dependencies since it should never be called there. On the receiving side, you implement a child receiver that has all the logic and links.

 

Say we have an instance of Message of type Message1, and an instance of Receiver (both are classes). Upon receipt of a message, the following happens:

1) code calls Message.Receive(Receiver). This dynamically dispatches to the correct instance for Message1.

2) the implementation of Receive for Message1 calls Receiver.ReceiveMessage1(Message).

3) ReceiveMessage now has strictly-typed instances of both Receiver and Message, and can do the correct operations to handle that message.

Link to comment

Thanks for the reply.  I am not entirely sure how to combine this with my current code but I think I might understand it after I read a few more times.

If you have a moment, take a look at the Message System Client Example and Message System Server Example code that I posted in this thread:

http://lavag.org/topic/16683-yet-another-messaging-systemarchitecture/

 

The way I am sending messages now is to call a remote VI in the receiver and give it the message object and the name of the receiver's process that the message is directed at.  The receiver code then puts the message in the queue for the correct process, which then de-queues it and dynamic dispatches to the execute method in the message's class.

 

As a result, my messages do not know if they are sent between applications or just within an application.  It sounds like I need to put another layer in that translates the received message into an internal only message and then passes it to the proper internal process.  Am I understanding your idea correctly?

Link to comment

Ok, so I have thought about this and I am still not sure how to fit this into my code.  For purposes of clarity, I and going to call the sender app the Server and the receiver app the Client.  The Server still has to construct the message and set it's attributes (properties/data).  So, both Server and Client will need a copy of that message class.

But, in the execute method of the message, I need to call this new receiver class and pass it the message.  The receiver class then has a child class that gets called via dynamic dispatch where I implement to passing of the message to the appropriate internal processes via Client side messages only.  That disconnects the received message from the internal messages.

But I am not sure how the receiver class will work.  How can I get the dynamic dispatch to work when I am passing a message object?  If I create a generic method that gets overridden by the child receiver for that message, what triggers the dispatch?  Where does the original receiver child object get created to allow the dispatch to happen?

Maybe I am just confused.

Link to comment

That's quite the framework you've built - a lot of functionality and still readable enough that I could understand what it's doing pretty quickly.

Here's the discussion about the Visitor pattern: http://lavag.org/topic/16696-ah-yes-another-oo-architecture-question/

The way I am sending messages now is to call a remote VI in the receiver and give it the message object and the name of the receiver's process that the message is directed at.  The receiver code then puts the message in the queue for the correct process, which then de-queues it and dynamic dispatches to the execute method in the message's class.

 

As a result, my messages do not know if they are sent between applications or just within an application.  It sounds like I need to put another layer in that translates the received message into an internal only message and then passes it to the proper internal process.  Am I understanding your idea correctly?

You don't need separate internal messages; the idea is that the messages stay the same with the exception of adding a Receive method and possibly an accessor or two if needed. In Remote Send (inside the Remote Extensions library), put a constant of the child (implemented) Receiver class on the block diagram and pass it to the Receive method of the message that arrives. The message class only needs to be linked to the parent Receiver class, and all the dependencies should be in the children that actually implement receiving the message. If I've understood correctly, that accomplishes your goal.

 

If you're only going to have one receiver class then you don't strictly need the two layers of dynamic dispatch, although I think it helps keep things modular. It also allows you to add new actions on Messages fairly easily - you could handle sending the same way. You'd just want to name the method in Message something more generic than Receive, since it could do any action that's passed to it (in the form of a class).



But I am not sure how the receiver class will work.  How can I get the dynamic dispatch to work when I am passing a message object?  If I create a generic method that gets overridden by the child receiver for that message, what triggers the dispatch?  Where does the original receiver child object get created to allow the dispatch to happen?

There's a manual programming step that makes this work. Inside the message's Receive method, it needs to make a call to the specific Receive method for that message type. That is, a message of type Message1 has a Receive method that calls Receiver.ReceiveMessage1. Message2 calls Receiver.ReceiveMessage2, and can't call ReceiveMessage1 because the connectors don't match (it has a connector for Message2, not for Message1). You don't have a separate Receiver for each type of Message; you have one child Receiver that has a separate method for each message type. That child Receiver can be a constant on the block diagram of the VI that gets called through VI Server.

Link to comment

Ok.  I think I got it.

So, my parent message class needs a receive method that each message can override.

In each message that I want to receive remotely, I implement the receive method.  The receive method takes an input of type receiver class. In the Remote Send.vi, I need to call the receive method of the message sent and pass it the child of the receiver class for this application.  I don't want to use a static call to the child because that makes Remote Send.vi specific to this application.  Instead, I need to store the child receiver in the private data of the system class and extract it in Remote Send.vi and then pass it on to the message Receiver method.

In the receive method of the message, I need to use the receiver object (cast it to the child receiver for this application) and call the specific method for this message in the child receiver class.

Inside those specific Receiver methods I place the code that passes the data in the message to the new internal message within my application.

So, my message is statically linked to the Receiver child class for the application because I need to call the receiver method from the message.recieve method.  And that Receiver class is statically linked to the internal message class.  So, don't I still have a linking problem?

Maybe I still don't get it.  I cannot see how the linking get separated.

Link to comment

The message class is statically linked to the parent Receiver class, which doesn't actually implement anything. When you receive a message you use the child Receiver class, which contains all the logic and links to other classes.

 

No cast is necessary to get the correct child Receiver class; it will just work through the magic of class inheritance and dynamic dispatch, because you will dynamically dispatch on the Receiver class when you call the specific Receive method for that particular message type.

Edited by ned
Link to comment

Yes, that's exactly right. Take a look at the Visitor example I linked - the parent Visitor class has a method for each type of DataItem, but they don't do anything. All the real work is in the Visitor child implementations. This allows you to call any Receiver class from within Message, without knowing the specific Receiver implementation.

 

The pattern also allows you to easily drop in a new receiver for a different application, which it sounds like is desirable for you. You just override all the parent's methods in a new class with the appropriate logic, and add a constant of that new receiver class as the desired implementation.

Link to comment

Ok. I think I got it working and in a way that is generic enough that only applications that need this feature will be affected.  Here is what I did:

 

I created a virtual class called 'Execute Remote Message'.  This class has no properties or methods. (this is so my architecture is not tied to a specific project's implementation or messages)

In the "System (Remote Enabled)" class, I added the 'Execute Remote Message' class to the private data and created accessors.  I put it here because only systems that do remote messaging need this feature.

I then created a child of this class for my application that contains a method for each remote message (both those sent from the Client and those sent from the Server).  All these methods are dynamic dispatch and NOP.

Next, I created a child of the NOP class just for the Client.  In this class, for each message the Client is intended to receive, I created an override method with the actual execution code in it (that links to other parts of the Client system).  I only needed to override the methods that relate to messages the Client will execute.

After that, I created another child of the NOP class but this time for the Server.  Here I only implement overrides for messages the Server will execute.

 

When my main VI constructs the system, I place the appropriate child class (Either Client or Server) on the diagram and wire it to the generic 'Execute Remote Message' property of the "System (Remote Enabled)" class.

 

Inside the execute method of the messages sent between the systems, I extract the 'Execute Remote Message' object from the "System (Remote Enabled)" class and then cast it to the NOP class so I can call the specific method for this message.

When the message is executed at runtime, dynamic dispatch will call the appropriate child implementation of the execute method based on which class I provided the system at the time of creation.

And, since the code with the linking lives in the the child execution classes which only live in the separate applications, my Server is no longer linked to all the messages and classes in my Client.

 

Thanks again for all the help.  This one really twisted my brain but I learned a lot and am happy with the solution.  I owe ned and kugr (who sent me some additional ideas) a :beer_mug: at the next NI Week or CLA Summit.  Thanks guys.  I would not have solved this without your help and LAVA!

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.