# Is message-oriented middleware applicable for intra-application communication?

I recently developed an application in LabVIEW, but although I'm pretty happy with its design I realised that I might be able to improve one part of it by making the various components of this particular subsystem collaborate with each other using a publisher/subscriber model.

If I do go down this road, I think it's best to develop a "Message Bus" LabVIEW library that I can reuse in various projects including the one I've just made. To get a good idea of how to design this, I've been looking at message-oriented middleware solutions like RabbitMQ and reading through Gregor Hohpe's Enterprise Integration Patterns which focuses on this sort of area.

All of these things keep talking about how MOMs should be used to integrate separate applications (that may or may not be running on the same machine). It just irks me a little that I can't seem to find any discussion about MOMs being used just as simple mediator classes that exist purely within the scope of one instance of a running application and only serve to facilitate communication between objects within that running instance.

Essentially my question is whether it's sensible to develop a message bus for this sort of thing. Can (and should) middleware like RabbitMQ be used for mediating between objects running within the same application?

• I do not know what message oriented middleware is but the way you describe it it reminds me of the actor model. – Giorgio Jul 1 '15 at 19:26
• @Giorgio Actually the design I have in mind for the LabVIEW implementation of a message bus will be heavily based on the Actor Framework, which is the LabVIEW implementation of the actor model - the message bus will be an actor that forms aggregate relationships with subscribers, which will also run as actors. – Tagc Jul 1 '15 at 19:36

There's a few things to consider. If you're talking about "Communicating" inside of a single application, the usual route is to create an object or data structure that holds the data you want to communicate, and simply giving it to the class/method that will use it.

It's fairly common to want to share information between different threads, in which case all threads need to have access to the variable somehow, and you need to deal with concurrency issues.

MOMs usually don't work on the intra-process level, because passing objects/data is far more convenient when considering just one process. A MOM will simplify communication in the case where information has to be shared amongst various processes.

It's sort of like this: You and I use the same language. If you tell me to go refill your cup of coffee, I know how to do it. I might do it begrudgingly, but I know what to do. This kind of communication is what you have inside your own process - everyone understands each other. You just need to figure out a way of getting the right data from one entity to another.

A MOM comes into play when you want to talk to someone who won't understand you(another process). There's a lot of work that goes into transmitting information. You might think it's simple to send a Boolean or an array of integers, but it can get very involved. What is a Boolean? A bit? A byte? An integer? What's an Integer(let alone an integer array)? Are they 8 bits, 16 bits, 32 bits, 64 bits? The MOM on one end will basically take care of the hassle of sending a message that says "I'm sending you an array with 20 values which are 32-bit integers" followed by said array. The receiving MOM understands the message and can process it. The reason you don't use a MOM inside a process is because these kinds of messages take up more space than what's necessary.

If I'm one subroutine and you're another, all I need to do is write the array to an agreed-upon location in memory(a variable), and you'll be able to see the array. We may have agreed upon the size of the array ahead of time(ie pre-compilation) but even that doesn't need to be communicated in some cases. You're effectively using the language, compilation, and typing system as your MOM in this case, because those are the things that give meaning to "The array starts at address 0xDEADBEEF and uses 512 bytes of memory".

Now, you could still use a MOM to send things inside the same process, by pointing the sender and receiver at the loopback address, but this is a lot of overhead when simply passing variables/parameters is what you're really doing.

# Edit: A concrete example with Java

Per OP's coupling concerns, I'd like to present a concrete example of sharing messages in Java that has minimal coupling between components. I've used this on several projects and it's fairly straight forward.

The base of it is to use an object like a BlockingQueue. If you don't want to read the documentation the take-away is that this is a thread-safe queue that allows multiple threads to put things in, and take them out without you having to worry about concurrency. So you'd end up with something like BlockingQueue<Message>. The next step is to get this object in the hands of the threads that will use it. That means you either pass the reference to the object to each thread, or you can wrap the queue itself in a singleton.

A simple implementation where you can pass the reference to a thread:

public class Producer implements Runnable {
BlockingQueue<Message> queue;
@Override
public void run() {
// TODO : Produce messages
}
public void initialize(BlockingQueue<Message> q) {
queue = q;
}
}


And the calling code:

// Just a compile-able example of initializing such a queue:
BlockingQueue<Message> queue = new ArrayBlockingQueue<Message>(200);

// ...

Producer producer = new Producer();
producer.initialize(queue);

Consumers of these messages would look very similar. But you can already see that it becomes very simple to make multiple types of producers(and consumers), and all of these producers/consumers are merely coupled to a queue. Whether it's a MockProducer, DemoProducer, RealProducer, RealConsumer, etc, the only coupling between them is the queue. The 'communication' between producers and consumers is basically whether the queue is full, empty, or somewhere in between. (And what you would do in each of these states is another discussion entirely)