Using JMS 2.0 APIs to access Azure Service Bus
Published Feb 11 2021 02:30 PM 8,126 Views
Microsoft

[Created on 12 August, 2020, and updated on 22 January, 2021]

Original post is on Medium.

https://logico-jp.medium.com/using-jms-2-0-apis-to-access-azure-service-bus-9f458ec2bf20

 

Japanese edition is here.
https://logico-jp.io/2020/08/12/using-jms-2-0-apis-to-access-azure-service-bus/

 

As you may know, support for JMS 2.0 APIs on Azure Service Bus Premium Tier is generally available. This feature allows us to interact with Azure Service Bus through JMS over AMQP 1.0.

 

Announcing general availability support for Java Message Service (JMS) 2.0 API on Azure Service Bus Premium

https://azure.microsoft.com/updates/announcing-general-availability-support-for-java-message-service...

 

As of 22 January, 2021, “preview” still exists in the document title, but it will be modified shortly.

 

Use Java Message Service 2.0 API with Azure Service Bus Premium
https://docs.microsoft.com/azure/service-bus-messaging/how-to-use-java-message-service-20

 

Note that the following document title is similar to the previous one, but this document does not cover JMS 2.0 APIs but JMS 1.1 APIs in Standard tier.

 

Use the Java Message Service (JMS) with Azure Service Bus and AMQP 1.0
https://docs.microsoft.com/azure/service-bus-messaging/service-bus-java-how-to-use-jms-api-amqp

 

In fact, we can use JMS 1.1 APIs to connect Azure Service Bus standard tier, but support for JMS 1.1 APIs is limited as you see the warning message in the document.

 

Warning
The below guide caters to limited support for Java Message Service (JMS) 1.1 API and exists for Azure Service Bus standard tier only.
Full support for the Java Message Service (JMS) 2.0 API is available only on the Azure Service Bus Premium tier in preview, which is highly recommended.

 

Which tier of Azure Service Bus supports JMS 2.0 APIs?

Premium tier only supports JMS 2.0 APIs. If using JMS 2.0 APIs to interact with Azure Service Bus Standard or Basic tier, the following exception is thrown with the message of “Full JMS 2.0 parity over AMQP is a feature supported only by a Premium Messaging namespace”.

image.png

Which JMS features are supported?

You can find supported features in the following URL. Note that distributed transaction is not supported.

 

What JMS features are supported?
https://docs.microsoft.com/azure/service-bus-messaging/how-to-use-java-message-service-20#what-jms-f...

Dependencies

As of 22 January, 2021, the latest version is 0.0.7. Please check the latest one in maven central repository. You can either use jar file to build your applications, or resolve dependencies through Maven or Gradle.

 

azure-servicebus-jms – ServiceBus ConnectionFactory for JMS users
https://search.maven.org/artifact/com.microsoft.azure/azure-servicebus-jms

<dependency>
  <groupId>com.microsoft.azure</groupId>
  <artifactId>azure-servicebus-jms</artifactId>
  <version>0.0.9</version>
</dependency>
 
 

Give it a try!

Following the document pointed earlier, you can do it easily. Let me show you examples using JMSContext.

First of all, connection factory should be instantiated in Azure Service Bus specific manner.

import com.microsoft.azure.servicebus.jms.ServiceBusJmsConnectionFactory;
import com.microsoft.azure.servicebus.jms.ServiceBusJmsConnectionFactorySettings;

...

ServiceBusJmsConnectionFactorySettings connectionFactorySettings = new ServiceBusJmsConnectionFactorySettings();
connectionFactorySettings.setConnectionIdleTimeoutMS(20000);
ConnectionFactory factory = new ServiceBusJmsConnectionFactory("CONNECTION_STRING", connectionFactorySettings);
Then, application(s) can be implemented in the usual manner of JMS 2.0 APIs. The following snippet is an example to send a text message to a queue.
try (JMSContext jmsContext = factory.createContext() ) {
    // Create the queue and topic
    Queue queue = jmsContext.createQueue("QUEUE_NAME");
    // Create the JMS message producer
    JMSProducer producer = jmsContext.createProducer();
    // Create textmessage
    TextMessage msg = jmsContext.createTextMessage(String.format("message sent at %s", (new Date()).toString()));
    // send the message to the queue
    producer.send(queue, msg);
}
catch (JMSRuntimeException e) {
    e.printStackTrace();
}
 

The next snippet is an example to receive text messages from a queue.

try (JMSContext jmsContext = factory.createContext() ) {
    // Create the queue and topic
    Queue queue = jmsContext.createQueue("QUEUE_NAME");
    // set Message Listener
    JMSConsumer consumer = jmsContext.createConsumer(queue);
    // Listener implements MessageListener.
    consumer.setMessageListener(new Listener());
    System.out.println("Receiver is ready, waiting for messages...");
    System.out.println("press Ctrl+c to shutdown...");
    while (true) {
        Thread.sleep(1000);
    }
} catch(InterruptedException e) {
    e.printStackTrace();
}
Here is a code for message listener used in the sample listed above. It is pretty simple since it is used for checking messages only.
 
public class Listener implements MessageListener {
    public void onMessage(Message m) {
        try {
            TextMessage msg = (TextMessage) m;
            // Show message
            System.out.printf("[Dequeued message at %s] %s\n", (new Date()).toString(), msg.getText());
        } catch (JMSRuntimeException e) {
            e.printStackTrace();
        }
    }
}

Subscription name scheme

In case of using topic, we have generally to subscribe a topic in order to wait for messages and creating subscription in advance is required. If not created yet, a subscription is automatically created when creating a JMSConsumer object and generated subscription is deleted when closing JMSConsumer object. As of January 10, 2021, subscription name is generated with the following scheme.

1. JMSContext::createConsumer

In case of createConsumer method, subscription name is created as follows.

 

<GUID>$$ND

 

$ is a delimiter, and “ND” would stand for “non durable”. As createConsumer method doesn’t have any way to specify subscription name, GUID is used as an alternative subscription name. Even if setting clientID to JMSContext object, the specified clientID is not used in the subscription name.

 

image.png

2. JMSContext::createDurableConsumer

In case of createDurableConsumer method, subscription name is created as follows.

 

<subscriptionName>$<clientID>$D

 

$ is a delimiter, and “D” would stand for “durable”. Both subscriptionName and clientID are mandatory and should be set to JMSContext object in the application. As you know, calling createDurableConsumer method without ClientID specified result in IllegalStateRuntimeException.

 

image.png

3. JMSContext::createSharedConsumer

In case of createSharedConsumer method, subscription name is created as follows.

 

<subscriptionName>$<clientID>$ND

 

$ is a delimiter, and “ND” would stand for “non durable”. And subscriptionName is mandatory, while clientID is optional.

 

image.png

 

So, two delimiters “$$” can be found in a subscription name when calling createSharedConsumer method without ClientID specified.

 

image.png

4. JMSContext::createSharedDurableConsumer

With clientID specified, subscription name is created as follows (subscriptionName is mandatory).

 

<subscriptionName>$<clientID>$D

 

$ is a delimiter, and “D” would stand for “durable”. This scheme is the same as the scheme of JMSContext::createDurableConsumer.

Without clientID specified, subscription name is created as follows (subscriptionName is mandatory).

 

<subscriptionName>

 

image.png

Here is the table to describe relationship between subscription name specified in codes and subscription name displayed in Azure Portal.

 
Method used
in creating a consumer
<A>
subscription name
specified in codes
<B>
Client ID
Subscription Name
in Azure Portal
createConsumer N/A Optional <GUID>$$ND
createDurableConsumer Mandatory Mandatory <A>$<B>$D
createSharedConsumer Mandatory Mandatory <A>$<B>$ND
createSharedDurableConsumer Mandatory Mandatory <A> or <A>$<B>$D

 

What benefits for you?

When migrating existing Java applications running on application servers to cloud, some customers tend to choose “lift to IaaS” strategy rather than “modernization”. Such customers tend to describe the reasons why they made such decisions.

 

“Our company has no mind to migrate their applications to PaaS since huge migration work are required.”

 

“We decided to keep our applications as it was and not to modernize them, so we chose only lift to IaaS rather than migration to PaaS in order to decrease OPEX.”

 

“We have to continue to use application servers to host our applications since the applications heavily rely on JMS and application server’s features. As of now, just simple migration to IaaS would be the best option for us.”

 

“Distribution transactions are mandatory…”

If a) a managed message broker is required, b) JMS 2.0 APIs are used in existing applications, and c) you have a plan to modernize your applications running on application servers, Azure Service Bus might fit you. Furthermore, if you are familiar with JMS 2.0 APIs, you don’t have to spend lots of time to learn how to develop applications with Azure Service Bus.

 

Conclusion

I confirmed Java application could interact with Azure Service Bus through JMS 2.0 APIs.

My sample codes are available on GitHub.

 

Access Azure Service Bus through JMS 2.0 APIs

https://github.com/anishi1222/Azure-Service-Bus-through-JMS-2.0-APIs

6 Comments
Co-Authors
Version history
Last update:
‎Apr 05 2022 06:19 AM
Updated by: