ActiveMQ via C# Part 2
In my part 1 of this series, I discussed the basics of JMS and messaging schematics: publish/subscribe and sender/receiver. I introduced Apache.NMS and the ActiveMQ client for NMS, Apache.NMS.ActiveMQ. I created client classes for publishing messages to ActiveMQ via topics and subscribing to a topic to receive messages. Finally, I tested the classes by writing a unit test that contained a publisher that sent messages to a topic and a subscriber that wrote the output to the console. In this example, I will expand on C# client by writing a simple, reusable configuration based API for sending and receiving messages using ActiveMQ and Apache.NMS.
In situations where you have multiple projects in need of a common messaging infrastructure, relatively low messaging domain knowledge across teams and an integration requirement between .NET and other Java based systems, a simple wrapper over a more complex JMS/NMS API can quicken client development. Additionally, the JMS/NMS programming model lends itself to a configuration based API that utilizes factory methods to create configured objects for sending and receiving objects.
The benefit of going with this model is that users of the API can get up and running quickly and need very little understanding of the nuances of JMS/NMS. Also, APIs like this make it easier to manage deployments amongst the different software environments in most organizations: dev, staging, prod, etc.
More Messaging Schematics
JMS provides two major schemes for sending and receiving messages: point-to-point (PTP) and publish/subscribe (Pub/Sub). PTP messaging is always queue based, while the Pub/Sub model uses topics.
In JMS speak topics and queues are simple message destinations or channels that producers send messages to and consumers listen to via notification semantics that messages are available. For topics, each consumer that subscribes to a topic will receive a copy of a message if the consumer is an active subscriber at the time the broker receives the message. If a producer sends a message to a destination and there are ten consumers actively subscribing to the destination, all ten consumers will receive a copy of the message. Pub/Sub is useful in which you want every consumer or client to receive a message sent to a destination by a producer:
On the other hand, queues are like load balancers: if a producer sends a message to the destination, then the message will be kept by the broker until a consumer is available and then the message will be delivered. Note that if there is one producer and ten consumers of the queue, exactly one consumer will receive a copy of the message. The messages are load-balanced in that if another message is sent, the next consumer will receive a copy of the message and then the next, and so on and so forth as messages are sent to the destination. A scenario where this is useful is where you have say a pool of processes and you want each message sent to the pool to be received by a single process and each subsequent message to be processed by exactly one other, different process within the pool.
In part 1 I created a consumer and producer of messages using pub/Sub schematics, in this example I will augment this API with classes for sending message using PTP messaging schematics. These classes will allow clients to send and receive messages to queues with consumers of these messages receiving at most one copy of the message that was sent from a producer. Additionally, I’ll provide a simplified API for using ActiveMQ across multiple projects.
Utilizing Queues – PTP Messaging
As I stated previously, queue based messaging is always PTP; a producer sends a message to a queue and exactly one consumer will receive a copy of the message. For our API we will define a producer and a consumer of messages. First the producer:
This is simple class takes a session and a string identifying the destination or queue that we will be sending messages to as constructor arguments. Usage is even simpler, just call the SendMessage method and pass in a string to send. Note that this could be augmented to send more complex message types, but for simplicity I have omitted anything other than string messages.
The consumer class is likewise rather simple and has a constructor that takes the same two arguments, a session and a string identifier of the queue that messages will be received from:
The QueueReceiver requires that you register with a delegate that is fired when a message is received by the consumer. The client starts listening to the by calling the Start method and passing in a string that uniquely identifies the client. Like subscribers (and all other message consumers), the QueueReceiver should be a long-lived object, with a lifetime of the entire application.
The entire API, looks like the following:
Usage is very simple, provide a long-lived consumer object with a queue as its destination and then create shorter lived producer objects that send messages to the broker. The following unit test shows an example of the round-robin way that messages are received by the registered consumers of a queue: