As anyone who has read my blog previously, you will know that I am a big fan of Actor Framework. It is a fantastic way of creating highly robust and scalable asynchronous process applications.
Having said all that, my biggest reservation about Actor has always been that because of the way the messaging between Actors works, out of the box Actors are strongly coupled. In a lot, maybe most instances this is not an issue as you may be putting together an application whereby the different Actors benefit from being strongly coupled or there is no benefit to decoupling them, but I’ve also come across a few use cases where I want to be able to completely decouple individual Actors for testing, and to allow multiple people to work on the same application.
One solution to this is abstract message classes, and one of the places where I’ve found this comes in really useful is adding a TCP/IP socket onto an existing Actor.
Initially this came from working on a project where I’d created a no abstract messages TCP/IP Actor, but then another project came along that also required TCP/IP control so I refactored my TCP/IP Actor with abstract messages to re-use it.
How this worked in practice is that in the original coupled TCP/IP Actor to communicate with its caller, I enqueued two messages to report the TCP/IP Actors status in terms of clients connected, and also to communicate messages received to the caller. The caller was then able to ‘Do’ these messages, and enqueue a message on the TCP/IP Actor to communicate back to a client.
The process to convert a non-abstract message to abstract is fairly straightforward using the following process:-
- Create your message as usual using the Actor Framework Message Maker
- Remove the ‘Do’ and ‘Send’ methods from the Message Class.
- In the class properties, under the ‘Inheritiance’ Category, check ‘Transfer all Must Override requirements to descendant classes’.
- To understand why you need to do this, open Message.lvclass from the ActorFramework directory under vi.lib. Under Item Settings in the class properties, if you select ‘Do.vi’ you will notice that the checkbox ‘Require descendant classes to override this dynamic dispatch VI’ is checked. This forces any classes that inherit from Message.lvclass to have to implement this method, by using ‘Transfer all Must Override requirements to descendant classes’ it removes this requirement from the class you are inheriting into, but pushes the requirement down to any child classes of itself and allows the class to compile.
- Next you need to expose any properties of the Abstract Message, as we no longer have a send method to encapsulate these (although there’s no reason why you couldn’t create a new one and pass in the class type) so we will have to set them via property nodes and will use the Enqueue.vi directly.
- Because the Do method has been removed, if the TCP/IP Actor wants to send the message to its caller, there won’t be anything to execute, so now you have to create a message class that inherits from the abstract class and create an instance of the Do method. This will be specific for the particular caller Actor you want to use it with.
- Now you’ve inherited these Concrete classes from the Abstract classes, you now need to tell the TCP/IP Actor to use these classes at runtime, I personally tend to do this using a Constructor and passing in the concrete classes to be held in private data.
- This means that now, when you want to send what was originally a specific caller message, you now have to pull what class the caller specified to use out of private data, populate its properties and enqueue it on the callers message queue.
- You obviously also need to go back to your new Concrete classes and populate their Do methods for anything to happen.
Exploring the demo
If you follow the link below, you can find a zip file of a TCP – IP Test Actor, interfacing to my abstract TCP/IP Actor with abstract messages.
Where to start.
Open up TCP – IP Actors.lvproj.
This contains 3 lvlibs – a TCP – IP Client GUI Actor, the TCP – IP Remote Control Actor, and a TCP – IP Test Actor.
Start by running Main.vi from TCP – IP Test Actor.lvlib to bring up the Test Actor.
Then run Main.vi from TCP – IP Client GUI Actor.lvlib.
On the TCP – IP Client GUI the available commands are populated from TCP – IP Remote Control Actor\TCP – IP Client GUI Actor and are in a tsv format.
From the Remote Client GUI you should first of all click ‘Open’ to begin a session with the TCP – IP Remote Actor. You should notice that as well as the light on the Remote Client GUI lighting up, you should also see the Connections light on the TCP – IP Test Actor GUI also light up, and the No. Clients indicator show 1. NOTE: you can now open up another Remote Client GUI and do the same again, and this should increment to 2.
Now a session is open, you can select commands from the pulldown, and populate the parameters and these will update those on the TCP IP Test Actor, or alternatively if you use the GetNumeric, it will return the value of the Numeric Indicator.
The key to all of this working is the TCP – IP Test Actor.lvclass:Handle Remote Command.vi. This is called from the Do method of the Concrete class Remote Command handler MSG.lvclass, and there is an equivalent VI called from the Do method of Remote Connection Status Msg.lvclass.
You will also find a VI called ‘Basic Example.vi’ under TCP – IP Remote Control Actor.lvlib\Test that demonstrates how to make single writes to the remote actor.
There’s probably not much more to add so please have an explore of the code, and message me if you have any questions, problems, or recommendations. Feel free to re-use any parts of this demo, as by design you should be able to pick up the client GUI and remote control Actor and attach it to any of your own Actors, but please remember give me credit if you do 🙂 Thanks, Dave.