Category Archives: ActiveMQ

AMQP with mTLS with AMQPNETLite

Every now and then you are thrown into projects were you might not be the perfect pick from start. I seldom work with .NET and this project was just that 🙂 I was asked to create a small .NET proof-of-concept application in C# that fetches messages from a AMQP broker using mTLS authentication. I post the solution so it might benefit someone else (did not find much about this on Google)
Here is the result:

using Amqp;
using Amqp.Sasl;
using Microsoft.Extensions.Logging;


namespace DotNETApps
{
    class Program
    {
        static async Task Main(string[] args)
        {
            using var loggerFactory = LoggerFactory.Create(builder =>
            {
                builder
                    .AddConsole()
                    .SetMinimumLevel(LogLevel.Debug);
            });

            ILogger logger = loggerFactory.CreateLogger<Program>();

            logger.LogInformation("Application started.");

            Address address = new Address("amqps://mydomain:5671");

            var factory = new ConnectionFactory();
            factory.SSL.ClientCertificates.Add(new 
                  System.Security.Cryptography.X509Certificates
                         .X509Certificate2("c:\\myclientcert.pfx", "secret"));

            factory.SASL.Profile = SaslProfile.Anonymous;

            try {
                logger.LogInformation("Connecting to broker...");
                Connection connection = await factory.CreateAsync(address);
                logger.LogInformation("Connected to broker.");

                Session session = new Session(connection);
                ReceiverLink receiver = 
                         new ReceiverLink(session, "receiver-link", "MYQUEU");

                Console.WriteLine("Receiver connected to broker.");

                Message message = await Task.Run(() => 
                          receiver.Receive(TimeSpan.FromMilliseconds(2000)));

                if (message == null)
                {
                    Console.WriteLine("No message received.");
                    receiver.Close();
                    session.Close();
                    connection.Close();
                    return;
                }

                Console.WriteLine("Received " + message.Body);
                receiver.Accept(message);

                receiver.Close();
                session.Close();
                connection.Close();
            }
            catch (Exception e)
            {
                logger.LogError(e, "An error while processing messages.");
            }

            logger.LogInformation("Application ended.");
        }
    }
}

Tested on Windows 10, AMQPNETLite v2.4.11, .NET 8.0 and Visual Studio Code 1.97.0

Simple JMS Producer

Here is a JMS Producer template to use when I forget how to write them. It uses ActiveMQ as JMS provider and JNDI for connection propereties:

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageProducer;
import javax.jms.Session;
import javax.naming.InitialContext;

public class Producer {

    public static void main(String[] args) throws Exception {

        InitialContext context = new InitialContext();
        ConnectionFactory factory = 
                 (ConnectionFactory) context.lookup("ConnectionFactory");

        Connection connection = factory.createConnection();
        connection.start();

        // Start a non-transacted session for sending messages
        Session session = 
               connection.createSession(false, Session.AUTO_ACKNOWLEDGE);

        Destination destination = (Destination) context.lookup("test");
        MessageProducer consumer = session.createProducer(destination);

        // Create text message
        Message message = session.createTextMessage("Hello World");

        // Send 10 "Hello World" messages to queue
        for (int i = 0; i < 10; i++) {
            consumer.send(message);
        }

        // Clean up
        session.close();
        connection.close();
        context.close();

    }
}

jndi.properties:

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

# Use the following property to configure the default connector
java.naming.provider.url = tcp://localhost:61616

# Register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.test = NIKLAS.TEST

ActiveMQ Client lib dependency pom:

<dependency>
     <groupid>org.apache.activemq</groupid>
     <artifactid>activemq-client</artifactid>
     <version>5.7.0</version>
</dependency>

Tested on Windows 10, Maven 3.8.4, Java 11.0.18 and ActiveMQ Client 5.7.0

Simple transacted JMS consumer

Ever looked for a simple JMS Consumer template – here is one and it is transacted too 🙂

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.Session;
import javax.naming.InitialContext;


public class Consumer {

    public static void main(String[] args) throws Exception {

        InitialContext context = new InitialContext();
        ConnectionFactory factory = 
                       (ConnectionFactory) context.lookup("ConnectionFactory");

        Connection connection = factory.createConnection();
        connection.start();

        // Start the transaction
        Session session = 
                    connection.createSession(true, Session.SESSION_TRANSACTED);

        Destination destination = (Destination) context.lookup("test");
        MessageConsumer consumer = session.createConsumer(destination);

        Message message;

        try {
            // Get all messages of the queue
            while ((message = consumer.receive(3000)) != null) {
                System.out.println("Message: " + message);
            }
            // All is well - commit transaction
            session.commit();

        } catch (Exception e) {
            e.printStackTrace();
            // Something is wrong - rollback transaction
            session.rollback();
        }

        // Cleanup
        session.close();
        connection.close();
        context.close();

    }
}

This solution depends on JNDI so here is the jndi.properties also:

java.naming.factory.initial = org.apache.activemq.jndi.ActiveMQInitialContextFactory

# Use the following property to configure the default connector
java.naming.provider.url = tcp://localhost:61616

# Register some queues in JNDI using the form
# queue.[jndiName] = [physicalName]
queue.test = NIKLAS.TEST

I’m using an ActiveMQ server as JMS provider which works good with the ActiveMQ client:
pom.xml

 
       
            org.apache.activemq
            activemq-client
            5.7.0
        

Tested on Windows 10, Maven 3.8.4, Java 11.0.18 and ActiveMQ Client 5.7.0