Hot questions for Using Azure in azureservicebus

Top Java Programmings / Azure / azureservicebus

Question:


Answer:

According to your description, it sounds like you want to use an on-premise compatiable alternative instead of Azure Service Bus to integrate with your Java app for CI on local.

As I known, there is an alternative named Windows Service Bus before, as the page About Windows Service Bus said as below.

Windows Service Bus (WSB) can be thought of as an on-premises version of Azure Service Bus.

But it's offically dead as the SO thread Is Service Bus for Windows Server dead said. And there is no Service Bus emulator like the SO threads Azure Service Bus Emulator and Test Azure Service Bus locally without any subscription or login (be answered by MSFT) said.

Considering for Azure Service Bus limits and per my experience, I'm not sure there is an alternative software which can instead of it without compatibility issue, so to use the cloud service for CI build is the only choice if you have to.

If you don't have to use Azure Server Bus for messaging, Azure Storage Queue is a good alternative for integrating with your Java App, and you can refer to the offical document Use the Azure storage emulator for development and testing to download the emulator and use it.

Question:

I need to provision a Service Bus queue from code but I can't seem to find any details on how to do it. The Azure Service bus library has a unit test that is creating the queue (link) but the maven library I've referenced doesn't have any of those classes (QueueDescription or ManagementClientAsync).

Has anyone tried creating a queue dynamically from java?

Maven:

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

Answer:

I've referenced doesn't have any of those classes (QueueDescription or ManagementClientAsync).

However this class seem not to be part of azure-core or azure-servicebus librairy and I can seem to find which lib to add to the project to have access to those class.

You mentioned QueueDescription or ManagementClientAsync seems only available in the 2.0.0-PREVIEW version. Please have a try to use the following dependency.

<!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-servicebus -->
<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-servicebus</artifactId>
    <version>2.0.0-PREVIEW-5</version>
</dependency>

Demo code:

String connectionString = "Endpoint=sb://xxxx.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxxx";
ConnectionStringBuilder connectionStringBuilder = new ConnectionStringBuilder(connectionString);
ManagementClient client = new ManagementClient(connectionStringBuilder);
if(!client.queueExists("queueName"))
{
    QueueDescription queue = client.createQueue("queueName");
}

Question:

I am trying to connect to Azure service bus topic using java code. I have created a topic in azure portal .

I am trying to configure using the method configureWithWrapAuthentication which has the parameters namespace,authenticationName,authenticationPassword,serviceBusRootUri,wrapRootUri .

I obtained all the parameter values except wrapRootUri . FYI : I have selected the region as South India

I need to know what is the value of wrapRootUri for South India location .

Please help! Thanks in advance.


Answer:

The service bus team on the change from ACS to SAS. It seems that it no longer works. According to github there is an open issue.

If you want to connect or manage Azure service bus. I recommand that you could use the following SDK.

<!-- https://mvnrepository.com/artifact/com.microsoft.azure/azure-servicebus -->
<dependency>
    <groupId>com.microsoft.azure</groupId>
    <artifactId>azure-servicebus</artifactId>
    <version>2.0.0-PREVIEW-5</version>
</dependency>

Update: add package information.

Demo code

import com.microsoft.azure.servicebus.ClientSettings;
import com.microsoft.azure.servicebus.Message;
import com.microsoft.azure.servicebus.TopicClient;
import com.microsoft.azure.servicebus.management.ManagementClient;
import com.microsoft.azure.servicebus.management.TopicDescription;
import com.microsoft.azure.servicebus.primitives.ConnectionStringBuilder;
import com.microsoft.azure.servicebus.security.SharedAccessSignatureTokenProvider;
import com.microsoft.azure.servicebus.security.TokenProvider;


 String connectionString = "Endpoint=sb://yoursevicebusNamespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=xxxxx";
 ConnectionStringBuilder connectionStringBuilder = new ConnectionStringBuilder(connectionString);
 ManagementClient client = new ManagementClient(connectionStringBuilder);
 //create topic
 if(!client.queueExists("topicName")) 
 {
    TopicDescription topic = client.createTopic("topicName");

 }

 TokenProvider tokenProvider = new SharedAccessSignatureTokenProvider("RootManageSharedAccessKey","xxxxxx",30);
 ClientSettings clientSettings = new ClientSettings(tokenProvider){};
 //create topicClient
 TopicClient topicClient = new TopicClient(connectionStringBuilder.getEndpoint(),"topicName",clientSettings);
 //send message
 topicClient.send(new Message("test message"));

Question:

Configuration config =
                ServiceBusConfiguration.configureWithSASAuthentication(
                        URL,
                        "RootManageSharedAccessKey",
                        token,
                        ".servicebus.windows.net"
                );

This is the code for configuration for java service bus implementation. I am interested in passing a shared access signature not a shared access key. I am not sure if this implementation for the java azure sdk supports this. How exactly would I do this. I keep getting a 401-unauthorized error when I use the shared access signature token in the token variable. Any ideas?


Answer:

According to the source code of Azure Service Bus SDK for Java, the four arguments for the function configureWithSASAuthentication should be the namespace, sasKeyName, sasKey & serviceBusRootUri(default pass ".servicebus.windows.net").

The namespace, sasKeyName & sasKey you can find them via click the CONNECTION INFORMATION button at the bottom of your service bus, please see the figures below.

Fig 1. The CONNECTION INFORMATION button at the bottom of the service bus page

Fig 2. Copy the CONNECTION STRING and extract the namespace, sasKeyName & sasKey

For example, the connection string is Endpoint=sb://abc-ns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=ABCdefg123!@#=, then the namespace, sasKeyName, sasKey are separately abc-ns, RootManageSharedAccessKey, ABCdefg123!@#=.

So the code should be as below.

Configuration config =
                ServiceBusConfiguration.configureWithSASAuthentication(
                        "abc-ns",
                        "RootManageSharedAccessKey",
                        "ABCdefg123!@#=",
                        ".servicebus.windows.net"
                );

And you can also find them at the CONFIGURE tab of your service bus page, please see the figure below.

Fig 3. The CONFIGURE tab

Question:

I try to build Java based Azure Function to be triggered by HTTP and sending data to Topic of Service Bus. This is based on sample code. HTTP Trigger works fine(Hello name is returned), but I don't get any data sent to Service Bus. And I do not get error message. I have tested with C# based Function that that "queueconstring" in local.settings.json is correct.

https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-output?tabs=java

/* 20.3.2020 HTTP Trigger and Topic output binding*/
package com.function;

import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;

/**
 * Azure Functions with HTTP Trigger.
 */
public class HttpTriggerSBOutputJava {
    /**
     * This function listens at endpoint "/api/HttpTriggerSBOutputJava". Two ways to invoke it using 
   "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/HttpTriggerSBOutputJava
     * 2. curl {your host}/api/HttpTriggerSBOutputJava?name=HTTP%20Query
     */


    @FunctionName("HttpTriggerSBOutputJava")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
        @ServiceBusTopicOutput(name = "message", topicName = "ContactInformationChanged", subscriptionName = "Playground", connection = "queueconstring") OutputBinding<String> message,
        final ExecutionContext context) {

        String name = request.getBody().orElse("Azure Functions");

        message.setValue(name);
        return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();

    }

}


Answer:

You can use the below code, it works fine on my side:

Function.java

package com.function;

import java.util.*;
import com.microsoft.azure.functions.annotation.*;
import com.microsoft.azure.functions.*;

/**
 * Azure Functions with HTTP Trigger.
 */
public class Function {
    /**
     * This function listens at endpoint "/api/HttpExample". Two ways to invoke it using "curl" command in bash:
     * 1. curl -d "HTTP Body" {your host}/api/HttpExample
     * 2. curl "{your host}/api/HttpExample?name=HTTP%20Query"
     */
    @FunctionName("HttpExample")
    @ServiceBusTopicOutput(name = "message", topicName = "test", subscriptionName = "test", connection = "ServiceBusConnection")
    public HttpResponseMessage run(
            @HttpTrigger(name = "req", methods = {HttpMethod.GET, HttpMethod.POST}, authLevel = AuthorizationLevel.ANONYMOUS) HttpRequestMessage<Optional<String>> request,
            final ExecutionContext context) {
        context.getLogger().info("Java HTTP trigger processed a request.");

        // Parse query parameter
        String query = request.getQueryParameters().get("name");
        String name = request.getBody().orElse(query);

        if (name == null) {
            return request.createResponseBuilder(HttpStatus.BAD_REQUEST).body("Please pass a name on the query string or in the request body").build();
        } else {
            return request.createResponseBuilder(HttpStatus.OK).body("Hello, " + name).build();
        }
    }
}

local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "",
    "FUNCTIONS_WORKER_RUNTIME": "java",
    "ServiceBusConnection":"Endpoint=sb://bowmantest.servicebus.windows.net/;SharedAccessKeyName=test;SharedAccessKey=xxxxxxxxx"
  }
}

Question:

I am working on receiving pending messages in Azure Service Bus queue. I have created a queue (SampleQueue) in Azure ServiceBus and I am able to send the message successfully in that queue via POSTMAN using a SAS token which I generate with my Java program. I am also getting a 201 created status after hitting my service bus queue api url(below image).

I want to receive the message pending in my Service bus queue. I went through some links about receiving message (https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-java-how-to-use-queues), but this does not contain information about how I can receive and view those messages.

My Java code that receives the message from Service bus queue looks like below[I am a novice in Java]:-

public class Test2 {

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

    String namespace        = "SampleNamespace";
    String sharedKeyName    = "RootManageSharedAccessKey";
    String sharedSecretKey  = "t+U5ERMAnIyxgEUDUouGOKn6ADM/CuLWzEJZtauwVsc=";
    String queueName        = "QueueName";      

    // Azure Service Bus Service
    com.microsoft.windowsazure.Configuration config = ServiceBusConfiguration.configureWithSASAuthentication(namespace, sharedKeyName, sharedSecretKey, ".servicebus.windows.net");
    ServiceBusContract service = ServiceBusService.create(config);

    // Receive and Delete Messages
    ReceiveMessageOptions opts = ReceiveMessageOptions.DEFAULT;
    opts.setReceiveMode(ReceiveMode.RECEIVE_AND_DELETE);

    while (true) {

        ReceiveQueueMessageResult resultQM = service.receiveQueueMessage(queueName , opts);
        BrokeredMessage message = resultQM.getValue();
        if (message != null && message.getMessageId() != null) {
             System.out.println("Body: " + message.toString());
            System.out.println("MessageID: " + message.getMessageId());
        } else {
            System.out.println("No more messages.");
            break;
        }
    }
}
}

But when I run this code, I get the below error:-

    Exception in thread "main" java.lang.NoClassDefFoundError: javax/ws/rs/WebApplicationException
at java.lang.Class.getDeclaredConstructors0(Native Method)
at java.lang.Class.privateGetDeclaredConstructors(Class.java:2671)
at java.lang.Class.getConstructors(Class.java:1651)
at com.microsoft.windowsazure.core.DefaultBuilder.findInjectConstructor(DefaultBuilder.java:67)
at com.microsoft.windowsazure.core.DefaultBuilder.add(DefaultBuilder.java:94)
at com.microsoft.windowsazure.services.servicebus.Exports.register(Exports.java:34)
at com.microsoft.windowsazure.core.DefaultBuilder.create(DefaultBuilder.java:46)
at com.microsoft.windowsazure.Configuration.<init>(Configuration.java:80)
at com.microsoft.windowsazure.Configuration.load(Configuration.java:100)
at com.microsoft.windowsazure.Configuration.getInstance(Configuration.java:90)
at com.microsoft.windowsazure.services.servicebus.ServiceBusConfiguration.configureWithSASAuthentication(ServiceBusConfiguration.java:252)
at com.rocky.servicebus.queue.Test2.main(Test2.java:24)
Caused by: java.lang.ClassNotFoundException: javax.ws.rs.WebApplicationException
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:335)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

Can anyone please help in rectifying what I am doing wrong? Would be greatful for any help.

Thanks, Rudra


Answer:

Based on the tutorial for receiving message, you need to create a queue client, and register a message handler for it.

A) Get connection string.

B) A code sample for sending and receiving messages

public static void registerReceiver(QueueClient queueClient, ExecutorService executorService) throws Exception {
    queueClient.registerMessageHandler(
        new IMessageHandler() {
            public CompletableFuture<Void> onMessageAsync(IMessage message) {
                if (message.getLabel() != null &&
                       message.getContentType() != null &&
                       message.getLabel().contentEquals("TestMessage") &&
                       message.getContentType().contentEquals("text/plain")) {

                    System.out.printf(
                        "\nMessage received: \n -->MessageId = %s\n -->ContentType = %s\n -->Content = %s\n",
                        message.getMessageId(),
                        message.getContentType(),
                        new String(message.getBody())
                    );
                    return queueClient.completeAsync(message.getLockToken());
                }
                return queueClient.abandonAsync(message.getLockToken());
            }

            public void notifyException(Throwable throwable, ExceptionPhase exceptionPhase) {
                System.out.printf(exceptionPhase + "-" + throwable.getMessage());
            }
        },
        new MessageHandlerOptions(1, false, Duration.ofSeconds(10)),
        executorService
    );
}

public static void sendMessages(QueueClient client) throws ServiceBusException, InterruptedException {
    for (int i = 0; i < 100; i++) {
        String messageId = Integer.toString(i);
        Message message = new Message("This is message " + i);
        message.setContentType("text/plain");
        message.setLabel("TestMessage");
        message.setMessageId(messageId);
        message.setTimeToLive(Duration.ofMinutes(10));
        client.send(message);
        System.out.printf("Message sent: Id = %s \n", message.getMessageId());
    }
}

public static void main(String[] args) throws Exception {
    String connectionString = "your_connection_string, Endpoint=sb://j*9.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=V*=";
    String queueName = "your_queue_name, testQueue";

    QueueClient client = new QueueClient(new ConnectionStringBuilder(connectionString, queueName), ReceiveMode.PEEKLOCK);
    sendMessages(client);
    client.close();

    QueueClient receiveClient = new QueueClient(new ConnectionStringBuilder(connectionString, queueName), ReceiveMode.PEEKLOCK);
    ExecutorService executorService = Executors.newSingleThreadExecutor();
    registerReceiver(receiveClient, executorService);

    Thread.sleep(60 * 1000); // Wait for 60 seconds to receive all the messages.
    receiveClient.close();
    executorService.shutdown();
}

Result:

100 messages will be sent.

Message sent: Id = 0 
Message sent: Id = 1 
Message sent: Id = 2 
Message sent: Id = 3 
*
*
*
Message sent: Id = 99 

And then will start to receive messages.

Message received: 
 -->MessageId = 0
 -->ContentType = text/plain
 -->Content = This is message 0

Message received: 
 -->MessageId = 1
 -->ContentType = text/plain
 -->Content = This is message 1

Message received: 
 -->MessageId = 2
 -->ContentType = text/plain
 -->Content = This is message 2
*
*
*
Message received: 
 -->MessageId = 99
 -->ContentType = text/plain
 -->Content = This is message 99

Question:

The Docs of Azure Service Bus have in example picture:

https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-java-how-to-use-queues#configure-your-application-to-use-service-bus

that it uses java 8. Also code samples use Java 8 syntax and functions. I have an environment of java 7 and I am unable to get it work supposedly because java is too old.

Does anyone know a working combination of the Azure Service Bus with Java 7? I would need either the version that works for sure or answer that no version does so.

I test with newest 1.2 version available of Azure Service Bus.


Answer:

I checked the maven repository list of Azure ServiceBus, these versions after 0.9.8 are all built by Java 8 via check the pom.xml file, the version 0.9.8 is built by Java 1.6. Therefore, there is not any released jar files compiled by Java 7 or other ealier Java version for the latest version 1.x.x.

A workaround way for yours is manually to download the source codes of Azure ServiceBus from GitHub repo to compile it in maven by yourself. You can use JDK 7 to do it, even use JDK 8. The only changes you need is use 1.7 instead of 1.8 for the configuration of maven-compiler-plugin in pom.xml, such as below.

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5</version>
    <configuration>
        <source>1.7</source>  <!-- 1.8 -->
        <target>1.7</target>  <!-- 1.8 -->
        <optimize>true</optimize>
        <showDeprecation>true</showDeprecation>
        <showWarnings>true</showWarnings>
    </configuration>
</plugin>

Note: If using JDK 8 to do this above for compiling with the javac parameter -target 1.7 -source 1.7, you must make sure there is not any code of using Java 8 features which will cause compiler error, such as error: lambda expressions are not supported in -source 1.7 for JDK 8. However, I roughly checked its source codes that there seems not to be. For more details about -target or -source for Javac 8, please see https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html.

Question:

NPE while receving messages from Queue. ( Only when messages are present in Queue). I feel like there is an issue with de-serializing the messages.

java.lang.NullPointerException at com.sun.jersey.api.client.ClientResponse.getResponseDate(ClientResponse.java:738) at com.microsoft.windowsazure.services.servicebus.implementation.ServiceBusRestProxy.receiveMessage(ServiceBusRestProxy.java:288) at com.microsoft.windowsazure.services.servicebus.implementation.ServiceBusRestProxy.receiveQueueMessage(ServiceBusRestProxy.java:225) at com.microsoft.windowsazure.services.servicebus.implementation.ServiceBusExceptionProcessor.receiveQueueMessage(ServiceBusExceptionProcessor.java:142)

RECEIVE_AND_DELETE option deletes the messages and throws NPE.

All other operations like create queue , send messages etc working fine. Any thoughts one this ?

Code to receive message

public void receiveMessage(String queueName) {
        try {
            ReceiveMessageOptions opts = ReceiveMessageOptions.DEFAULT;
            opts.setReceiveMode(ReceiveMode.PEEK_LOCK);

            while (true) {
                ReceiveQueueMessageResult resultQM
                        = service.receiveQueueMessage(queueName, opts);
                BrokeredMessage message = resultQM.getValue();
                if (message != null && message.getMessageId() != null) {
                    log.println("MessageID: " + message.getMessageId());
                    // Display the queue message.
                    log.print("From queue: ");
                    byte[] b = new byte[200];
                    String s = null;
                    int numRead = message.getBody().read(b);
                    while (-1 != numRead) {
                        s = new String(b);
                        s = s.trim();
                        System.out.print(s);
                        numRead = message.getBody().read(b);
                    }
                    log.println("");
                    log.println("Custom Property: "
                            + message.getProperty("MyProperty"));
                    // Remove message from queue.
                    log.println("Deleting this message.");
                    //service.deleteMessage(message);
                } else {
                    log.println("Finishing up - no more messages.");
                    break;
                    // Added to handle no more messages.
                    // Could instead wait for more messages to be added.
                }
            }
        } catch (Exception e) {
            log.print(e);
        }
    }

Answer:

Even though it was throwing NPE the actual issue was with the missing jar files. Here is the list of jar files

          <dependencies>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-compute</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-network</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-sql</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-storage</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-websites</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-svc-mgmt-media</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-servicebus</artifactId>
                        <version>0.9.7</version>
                </dependency>
                <dependency>
                        <groupId>com.microsoft.azure</groupId>
                        <artifactId>azure-serviceruntime</artifactId>
                        <version>0.9.7</version>
                </dependency>
        </dependencies>