From ae70f6049681a03dddc42188d28a17ef3e611915 Mon Sep 17 00:00:00 2001 From: RDPerera Date: Wed, 23 Aug 2023 11:48:05 +0530 Subject: [PATCH 01/10] Add DLQ receive/complete support --- ballerina/receiver.bal | 105 +++++---- .../asb/receiver/MessageReceiver.java | 216 +++++++++++++----- .../org/ballerinax/asb/util/ASBConstants.java | 18 +- .../org/ballerinax/asb/util/ASBUtils.java | 153 +++++++------ 4 files changed, 312 insertions(+), 180 deletions(-) diff --git a/ballerina/receiver.bal b/ballerina/receiver.bal index 11816914..012cb07f 100644 --- a/ballerina/receiver.bal +++ b/ballerina/receiver.bal @@ -1,6 +1,6 @@ -// Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). // -// WSO2 Inc. licenses this file to you under the Apache License, +// WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except // in compliance with the License. // You may obtain a copy of the License at @@ -20,15 +20,14 @@ import ballerina/jballerina.java as java; # Service Bus API provides data access to highly reliable queues and publish/subscribe topics of Azure Service Bus with deep feature capabilities. @display {label: "Azure Service Bus Message Receiver", iconPath: "icon.png"} public isolated client class MessageReceiver { - - private string connectionString; + + private string connectionString; private string queueName; private string subscriptionName; private string topicName; private string receiveMode; private int maxAutoLockRenewDuration; private LogLevel logLevel; - final handle receiverHandle; # Initializes the connector. During initialization you can pass the [Shared Access Signature (SAS) authentication credentials](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-sas) # Create an [Azure account](https://docs.microsoft.com/en-us/learn/modules/create-an-azure-account/) and @@ -58,26 +57,23 @@ public isolated client class MessageReceiver { self.receiveMode = config.receiveMode; self.maxAutoLockRenewDuration = config.maxAutoLockRenewDuration; self.logLevel = customConfiguration.logLevel; - handle|Error initResult = initMessageReceiver(java:fromString(self.connectionString), + check initializeReceiver(self, java:fromString(self.connectionString), java:fromString(self.queueName), java:fromString(self.topicName), java:fromString(self.subscriptionName), java:fromString(self.receiveMode), self.maxAutoLockRenewDuration, java:fromString(self.logLevel), config.amqpRetryOptions); - if initResult is Error { - return initResult; - } - - self.receiverHandle = initResult; } # Receive message from queue or subscription. - # + # # + serverWaitTime - Specified server wait time in seconds to receive message (optional) # + T - Expected type of the message. This can be either a `asb:Message` or a subtype of it. + # + deadLettered - If set to `true`, messages from dead-letter queue will be received. (optional) # + return - A `asb:Message` record if message is received, `()` if no message is in the queue or else an `asb:Error` - # if failed to receive message + # if failed to receive message @display {label: "Receive Message"} isolated remote function receive(@display {label: "Server Wait Time"} int? serverWaitTime = 60, - @display {label: "Expected Type"} typedesc T = <>) - returns @display {label: "Message"} T|Error? = @java:Method { + @display {label: "Expected Type"} typedesc T = <>, + @display {label: "Dead-Lettered Messages"} boolean deadLettered = false) + returns @display {label: "Message"} T|Error? = @java:Method { 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; @@ -85,36 +81,41 @@ public isolated client class MessageReceiver { # # + serverWaitTime - Specified server wait time in seconds to receive message (optional) # + T - Expected type of the message. This can be any subtype of `anydata` type + # + deadLettered - If set to `true`, messages from dead-letter queue will be received. (optional) # + return - A `asb:Message` record if message is received, `()` if no message is in the queue or else an `asb:Error` - # if failed to receive message + # if failed to receive message @display {label: "Receive Message Payload"} - isolated remote function receivePayload(@display {label: "Server Wait Time"} int? serverWaitTime = 60, - @display {label: "Expected Type"} typedesc T = <>) + isolated remote function receivePayload(@display {label: "Server Wait Time"} int? serverWaitTime = 60, + @display {label: "Expected Type"} typedesc T = <>, + @display {label: "Dead-Lettered Messages"} boolean deadLettered = false) returns @display {label: "Message Payload"} T|Error = @java:Method { 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; # Receive batch of messages from queue or subscription. - # + # # + maxMessageCount - Maximum message count to receive in a batch # + serverWaitTime - Specified server wait time in seconds to receive message (optional) + # + deadLettered - If set to `true`, messages from dead-letter queue will be received. (optional) # + return - A `asb:MessageBatch` record if batch is received, `()` if no batch is in the queue or else an `asb:Error` - # if failed to receive batch + # if failed to receive batch @display {label: "Receive Batch Message"} - isolated remote function receiveBatch(@display {label: "Maximum Message Count"} int maxMessageCount, - @display {label: "Server Wait Time"} int? serverWaitTime = ()) - returns @display {label: "Batch Message"} MessageBatch|Error? { - MessageBatch|Error? receivedMessages = receiveBatch(self, maxMessageCount, serverWaitTime); + isolated remote function receiveBatch(@display {label: "Maximum Message Count"} int maxMessageCount, + @display {label: "Server Wait Time"} int? serverWaitTime = (), + @display {label: "Dead-Lettered Messages"} boolean deadLettered = false) + returns @display {label: "Batch Message"} MessageBatch|Error? { + MessageBatch|Error? receivedMessages = receiveBatch(self, maxMessageCount, serverWaitTime, deadLettered); return receivedMessages; } # Complete message from queue or subscription based on messageLockToken. Declares the message processing to be # successfully completed, removing the message from the queue. - # + # # + message - `asb:Message` record # + return - An `asb:Error` if failed to complete message or else `()` @display {label: "Complete Message"} - isolated remote function complete(@display {label: "Message"} Message message) returns Error? { + isolated remote function complete(@display {label: "Message"} Message message) + returns Error? { if message?.lockToken.toString() != DEFAULT_MESSAGE_LOCK_TOKEN { return complete(self, message?.lockToken.toString()); } @@ -124,7 +125,7 @@ public isolated client class MessageReceiver { # Abandon message from queue or subscription based on messageLockToken. Abandon processing of the message for # the time being, returning the message immediately back to the queue to be picked up by another (or the same) # receiver. - # + # # + message - `asb:Message` record # + return - An `asb:Error` if failed to abandon message or else `()` @display {label: "Abandon Message"} @@ -137,18 +138,18 @@ public isolated client class MessageReceiver { # Dead-Letter the message & moves the message to the Dead-Letter Queue based on messageLockToken. Transfer # the message from the primary queue into a special "dead-letter sub-queue". - # + # # + message - `asb:Message` record # + deadLetterReason - The deadletter reason (optional) # + deadLetterErrorDescription - The deadletter error description (optional) # + return - An `asb:Error` if failed to deadletter message or else `()` @display {label: "Dead Letter Message"} - isolated remote function deadLetter(@display {label: "Message"} Message message, - @display {label: "Dead Letter Reason"} string? deadLetterReason = (), - @display{label: "Dead Letter Description"} + isolated remote function deadLetter(@display {label: "Message"} Message message, + @display {label: "Dead Letter Reason"} string? deadLetterReason = "MANUALLY_DEADLETTERED", + @display {label: "Dead Letter Description"} string? deadLetterErrorDescription = ()) returns Error? { if message?.lockToken.toString() != DEFAULT_MESSAGE_LOCK_TOKEN { - return deadLetter(self, message?.lockToken.toString(), deadLetterReason, + return deadLetter(self, message?.lockToken.toString(), deadLetterReason, deadLetterErrorDescription); } return createError("Failed to deadletter message with ID " + message?.messageId.toString()); @@ -156,33 +157,32 @@ public isolated client class MessageReceiver { # Defer the message in a Queue or Subscription based on messageLockToken. It prevents the message from being # directly received from the queue by setting it aside such that it must be received by sequence number. - # + # # + message - `asb:Message` record # + return - An `asb:Error` if failed to defer message or else sequence number @display {label: "Defer Message"} - isolated remote function defer(@display {label: "Message"} Message message) - returns @display {label: "Deferred Msg Seq Num"} int|Error { + isolated remote function defer(@display {label: "Message"} Message message) + returns @display {label: "Deferred Msg Seq Num"} int|Error { check defer(self, message?.lockToken.toString()); - return message?.sequenceNumber; + return message?.sequenceNumber; } # Receives a deferred Message. Deferred messages can only be received by using sequence number and return # Message object. - # + # # + sequenceNumber - Unique number assigned to a message by Service Bus. The sequence number is a unique 64-bit - # integer assigned to a message as it is accepted and stored by the broker and functions as - # its true identifier. + # integer assigned to a message as it is accepted and stored by the broker and functions as + # its true identifier. # + return - An `asb:Error` if failed to receive deferred message, a Message record if successful or else `()` @display {label: "Receive Deferred Message"} - isolated remote function receiveDeferred(@display {label: "Deferred Msg Seq Num"} - int sequenceNumber) - returns @display {label: "Deferred Message"} Message|Error? { - Message? message = check receiveDeferred(self, sequenceNumber); - return message; - } + isolated remote function receiveDeferred(@display {label: "Deferred Msg Seq Num"} + int sequenceNumber) + returns @display {label: "Deferred Message"} Message|Error? = @java:Method { + 'class: "org.ballerinax.asb.receiver.MessageReceiver" + } external; # The operation renews lock on a message in a queue or subscription based on messageLockToken. - # + # # + message - `asb:Message` record # + return - An `asb:Error` if failed to renew message or else `()` @display {label: "Renew Lock On Message"} @@ -203,14 +203,13 @@ public isolated client class MessageReceiver { } external; } -isolated function initMessageReceiver(handle connectionString, handle queueName, handle topicName, - handle subscriptionName, handle receiveMode, int maxAutoLockRenewDuration, handle isLogActive, AmqpRetryOptions retryOptions) returns handle|Error = @java:Method { - name: "initializeReceiver", +isolated function initializeReceiver(MessageReceiver receiverClient, handle connectionString, handle queueName, handle topicName, + handle subscriptionName, handle receiveMode, int maxAutoLockRenewDuration, handle isLogActive, AmqpRetryOptions retryOptions) returns Error? = @java:Method { 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; -isolated function receiveBatch(MessageReceiver endpointClient, int? maxMessageCount, int? serverWaitTime) - returns MessageBatch|Error? = @java:Method { +isolated function receiveBatch(MessageReceiver endpointClient, int? maxMessageCount, int? serverWaitTime, boolean deadLettered) + returns MessageBatch|Error? = @java:Method { 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; @@ -222,8 +221,8 @@ isolated function abandon(MessageReceiver endpointClient, string lockToken) retu 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; -isolated function deadLetter(MessageReceiver endpointClient, string lockToken, string? deadLetterReason, string? deadLetterErrorDescription) returns - Error? = @java:Method { +isolated function deadLetter(MessageReceiver endpointClient, string lockToken, string? deadLetterReason, string? deadLetterErrorDescription) returns + Error? = @java:Method { 'class: "org.ballerinax.asb.receiver.MessageReceiver" } external; diff --git a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java index 4bfc0bed..c4c34ddc 100644 --- a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java +++ b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java @@ -29,6 +29,7 @@ import com.azure.messaging.servicebus.ServiceBusReceiverClient; import com.azure.messaging.servicebus.models.DeadLetterOptions; import com.azure.messaging.servicebus.models.ServiceBusReceiveMode; +import com.azure.messaging.servicebus.models.SubQueue; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; @@ -39,7 +40,6 @@ import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.values.BError; -import io.ballerina.runtime.api.values.BHandle; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; @@ -73,6 +73,7 @@ import static org.ballerinax.asb.util.ASBConstants.LOCK_TOKEN; import static org.ballerinax.asb.util.ASBConstants.MESSAGE_ID; import static org.ballerinax.asb.util.ASBConstants.PARTITION_KEY; +import static org.ballerinax.asb.util.ASBConstants.RECEIVER_CLIENT; import static org.ballerinax.asb.util.ASBConstants.RECEIVE_AND_DELETE; import static org.ballerinax.asb.util.ASBConstants.REPLY_TO; import static org.ballerinax.asb.util.ASBConstants.REPLY_TO_SESSION_ID; @@ -109,7 +110,7 @@ public class MessageReceiver { * @throws ServiceBusException on failure initiating IMessage Receiver in Azure * Service Bus instance. */ - public static Object initializeReceiver(String connectionString, String queueName, + public static Object initializeReceiver(BObject receiverClient, String connectionString, String queueName, String topicName, String subscriptionName, String receiveMode, long maxAutoLockRenewDuration, String logLevel, BMap retryConfigs) { @@ -141,7 +142,10 @@ public static Object initializeReceiver(String connectionString, String queueNam } } LOGGER.debug("ServiceBusReceiverClient initialized"); - return receiverClientBuilder.buildClient(); + setInitData(receiverClient, connectionString, queueName, topicName, subscriptionName, receiveMode, + maxAutoLockRenewDuration, logLevel, retryConfigs); + setClient(receiverClient, receiverClientBuilder.buildClient()); + return null; } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -156,15 +160,20 @@ public static Object initializeReceiver(String connectionString, String queueNam * is given as a parameter and * server wait time in seconds to receive message and return Message object. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param serverWaitTime Specified server wait time in seconds to receive * message. * @return Message Object of the received message. */ - public static Object receive(BObject endpointClient, Object serverWaitTime, - BTypedesc expectedType) { + public static Object receive(BObject receiverClient, Object serverWaitTime, + BTypedesc expectedType, Object deadLettered) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver; + if ((boolean) deadLettered) { + receiver = (ServiceBusReceiverClient) getDeadLetterMessageReceiverFromBObject(receiverClient); + } else { + receiver = getReceiverFromBObject(receiverClient); + } IterableStream receivedMessages; if (serverWaitTime != null) { receivedMessages = receiver.receiveMessages(1, Duration.ofSeconds((long) serverWaitTime)); @@ -182,7 +191,7 @@ public static Object receive(BObject endpointClient, Object serverWaitTime, LOGGER.debug("Received message with messageId: " + receivedMessage.getMessageId()); RecordType expectedRecordType = ASBUtils.getRecordType(expectedType); - return constructExpectedMessageRecord(endpointClient, receivedMessage, expectedRecordType); + return constructExpectedMessageRecord(receiverClient, receivedMessage, expectedRecordType); } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -195,15 +204,20 @@ public static Object receive(BObject endpointClient, Object serverWaitTime, /** * Returns only the message payload(i.e. body) for the given endpoint client. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param serverWaitTime Specified server wait time in seconds to receive message * @return message payload */ - public static Object receivePayload(BObject endpointClient, Object serverWaitTime, - BTypedesc expectedType) { + public static Object receivePayload(BObject receiverClient, Object serverWaitTime, + BTypedesc expectedType, Object deadLettered) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver; + if ((boolean) deadLettered) { + receiver = (ServiceBusReceiverClient) getDeadLetterMessageReceiverFromBObject(receiverClient); + } else { + receiver = getReceiverFromBObject(receiverClient); + } IterableStream receivedMessages; if (serverWaitTime != null) { receivedMessages = receiver.receiveMessages(1, Duration.ofSeconds((long) serverWaitTime)); @@ -244,18 +258,24 @@ public static Object receivePayload(BObject endpointClient, Object serverWaitTim * maximum message count in a batch as int, server wait time in seconds and * return Batch Message object. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param maxMessageCount Maximum no. of messages in a batch. * @param serverWaitTime Server wait time. * @return Batch Message Object of the received batch of messages. */ - public static Object receiveBatch(BObject endpointClient, Object maxMessageCount, Object serverWaitTime) { + public static Object receiveBatch(BObject receiverClient, Object maxMessageCount, Object serverWaitTime + , Object deadLettered) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver; + if ((boolean) deadLettered) { + receiver = (ServiceBusReceiverClient) getDeadLetterMessageReceiverFromBObject(receiverClient); + } else { + receiver = getReceiverFromBObject(receiverClient); + } if (LOGGER.isDebugEnabled()) { LOGGER.debug("Waiting up to 'serverWaitTime' seconds for messages from " + receiver.getEntityPath()); } - return getReceivedMessageBatch(endpointClient, maxMessageCount, serverWaitTime); + return getReceivedMessageBatch(receiverClient, maxMessageCount, serverWaitTime, deadLettered); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return null; @@ -271,15 +291,20 @@ public static Object receiveBatch(BObject endpointClient, Object maxMessageCount /** * Completes Messages from Queue or Subscription based on messageLockToken. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param lockToken Message lock token. * @return An error if failed to complete the message. */ - public static Object complete(BObject endpointClient, BString lockToken) { + public static Object complete(BObject receiverClient, BString lockToken) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); - ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) endpointClient + ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) receiverClient .getNativeData(lockToken.getValue()); + ServiceBusReceiverClient receiver; + if (message.getDeadLetterReason() != null) { + receiver = (ServiceBusReceiverClient) getDeadLetterMessageReceiverFromBObject(receiverClient); + } else { + receiver = getReceiverFromBObject(receiverClient); + } receiver.complete(message); LOGGER.debug("Completed the message(Id: " + message.getMessageId() + ") with lockToken " + lockToken); return null; @@ -295,14 +320,14 @@ public static Object complete(BObject endpointClient, BString lockToken) { /** * Abandons message & make available again for processing from Queue or Subscription, based on messageLockToken. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param lockToken Message lock token. * @return An error if failed to abandon the message. */ - public static Object abandon(BObject endpointClient, BString lockToken) { + public static Object abandon(BObject receiverClient, BString lockToken) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); - ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) endpointClient + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); + ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) receiverClient .getNativeData(lockToken.getValue()); receiver.abandon(message); LOGGER.debug(String.format("Done abandoning a message(Id: %s) using its lock token from %n%s", @@ -320,17 +345,17 @@ public static Object abandon(BObject endpointClient, BString lockToken) { /** * Dead-Letter the message & moves the message to the Dead-Letter Queue based on messageLockToken. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param lockToken Message lock token. * @param deadLetterReason The dead letter reason. * @param deadLetterErrorDescription The dead letter error description. * @return An error if failed to dead letter the message. */ - public static Object deadLetter(BObject endpointClient, BString lockToken, Object deadLetterReason, + public static Object deadLetter(BObject receiverClient, BString lockToken, Object deadLetterReason, Object deadLetterErrorDescription) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); - ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) endpointClient + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); + ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) receiverClient .getNativeData(lockToken.getValue()); DeadLetterOptions options = new DeadLetterOptions() .setDeadLetterErrorDescription(ASBUtils.convertString(deadLetterErrorDescription)); @@ -351,14 +376,14 @@ public static Object deadLetter(BObject endpointClient, BString lockToken, Objec /** * Defer the message in a Queue or Subscription based on messageLockToken. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param lockToken Message lock token. * @return An error if failed to defer the message. */ - public static Object defer(BObject endpointClient, BString lockToken) { + public static Object defer(BObject receiverClient, BString lockToken) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); - ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) endpointClient + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); + ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) receiverClient .getNativeData(lockToken.getValue()); receiver.defer(message); LOGGER.debug(String.format("Done deferring a message(Id: %s) using its lock token from %s", @@ -377,7 +402,7 @@ public static Object defer(BObject endpointClient, BString lockToken) { * Receives a deferred Message. Deferred messages can only be received by using sequence number and return * Message object. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param sequenceNumber Unique number assigned to a message by Service Bus. The * sequence number is a unique 64-bit * integer assigned to a message as it is accepted and @@ -385,15 +410,15 @@ public static Object defer(BObject endpointClient, BString lockToken) { * its true identifier. * @return The received Message or null if there is no message for given sequence number. */ - public static Object receiveDeferred(BObject endpointClient, int sequenceNumber) { + public static Object receiveDeferred(BObject receiverClient, Object sequenceNumber) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); - ServiceBusReceivedMessage receivedMessage = receiver.receiveDeferredMessage(sequenceNumber); + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); + ServiceBusReceivedMessage receivedMessage = receiver.receiveDeferredMessage((long) sequenceNumber); if (receivedMessage == null) { return null; } LOGGER.debug("Received deferred message using its sequenceNumber from " + receiver.getEntityPath()); - return constructExpectedMessageRecord(endpointClient, receivedMessage, null); + return constructExpectedMessageRecord(receiverClient, receivedMessage, null); } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -407,15 +432,15 @@ public static Object receiveDeferred(BObject endpointClient, int sequenceNumber) * The operation renews lock on a message in a queue or subscription based on * messageLockToken. * - * @param endpointClient Ballerina ASB client object + * @param receiverClient Ballerina ASB client object * @param lockToken Message lock token. * @return An error if failed to renewLock of the message. */ - public static Object renewLock(BObject endpointClient, BString lockToken) { + public static Object renewLock(BObject receiverClient, BString lockToken) { try { - ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) endpointClient + ServiceBusReceivedMessage message = (ServiceBusReceivedMessage) receiverClient .getNativeData(lockToken.getValue()); - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); receiver.renewMessageLock(message); LOGGER.debug(String.format("Done renewing a message(Id: %s) using its lock token from %s", message.getMessageId(), receiver.getEntityPath())); @@ -434,9 +459,9 @@ public static Object renewLock(BObject endpointClient, BString lockToken) { * * @return An error if failed to close the receiver. */ - public static Object closeReceiver(BObject endpointClient) { + public static Object closeReceiver(BObject receiverClient) { try { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver = getReceiverFromBObject(receiverClient); receiver.close(); LOGGER.debug("Closed the receiver"); return null; @@ -453,10 +478,10 @@ public static Object closeReceiver(BObject endpointClient) { * Converts the received message to the contextually expected Ballerina record type (or to anydata, if not * specified). * - * @param endpointClient Ballerina client object + * @param receiverClient Ballerina client object * @param message Received Message */ - private static BMap constructExpectedMessageRecord(BObject endpointClient, + private static BMap constructExpectedMessageRecord(BObject receiverClient, ServiceBusReceivedMessage message, RecordType expectedType) { Map map = populateOptionalFieldsMap(message); @@ -471,7 +496,7 @@ private static BMap constructExpectedMessageRecord(BObject endp } else { map.put(BODY, messageBody); } - endpointClient.addNativeData(message.getLockToken(), message); + receiverClient.addNativeData(message.getLockToken(), message); return createBRecordValue(map, expectedType); } @@ -531,10 +556,15 @@ private static Object getMessagePayload(ServiceBusReceivedMessage receivedMessag } } - private static BMap getReceivedMessageBatch(BObject endpointClient, Object maxMessageCount, - Object serverWaitTime) + private static BMap getReceivedMessageBatch(BObject receiverClient, Object maxMessageCount, + Object serverWaitTime, Object deadLettered) throws InterruptedException, ServiceBusException { - ServiceBusReceiverClient receiver = getReceiverFromBObject(endpointClient); + ServiceBusReceiverClient receiver; + if ((boolean) deadLettered) { + receiver = (ServiceBusReceiverClient) getDeadLetterMessageReceiverFromBObject(receiverClient); + } else { + receiver = getReceiverFromBObject(receiverClient); + } int maxCount = Long.valueOf(maxMessageCount.toString()).intValue(); IterableStream receivedMessageStream; if (serverWaitTime != null) { @@ -545,7 +575,7 @@ private static BMap getReceivedMessageBatch(BObject endpointCli LinkedList receivedMessages = new LinkedList<>(); for (ServiceBusReceivedMessage receivedMessage : receivedMessageStream) { - BMap recordMap = constructExpectedMessageRecord(endpointClient, receivedMessage, null); + BMap recordMap = constructExpectedMessageRecord(receiverClient, receivedMessage, null); receivedMessages.add(createRecordValue(ModuleUtils.getModule(), ASBConstants.MESSAGE_RECORD, recordMap)); } @@ -597,7 +627,89 @@ private static void populateApplicationProperty(BMap applicatio } private static ServiceBusReceiverClient getReceiverFromBObject(BObject receiverObject) { - BHandle receiverHandle = (BHandle) receiverObject.get(StringUtils.fromString("receiverHandle")); - return (ServiceBusReceiverClient) receiverHandle.getValue(); + return (ServiceBusReceiverClient) receiverObject.getNativeData(RECEIVER_CLIENT); + } + + private static Object getDeadLetterMessageReceiverFromBObject(BObject receiverObject) { + if (receiverObject.getNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT) != null) { + return receiverObject.getNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT); + } else { + String connectionString = (String) receiverObject.getNativeData( + ASBConstants.RECEIVER_CLIENT_CONNECTION_STRING); + String queueName = (String) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_QUEUE_NAME); + String topicName = (String) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_TOPIC_NAME); + String subscriptionName = (String) receiverObject.getNativeData( + ASBConstants.RECEIVER_CLIENT_SUBSCRIPTION_NAME); + String receiveMode = (String) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_RECEIVE_MODE); + long maxAutoLockRenewDuration = (long) receiverObject.getNativeData( + ASBConstants.RECEIVER_CLIENT_MAX_AUTO_LOCK_RENEW_DURATION); + BMap retryConfigs = + (BMap) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS); + try { + AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); + ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() + .connectionString(connectionString) + .retryOptions(retryOptions) + .receiver(); + if (!queueName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .queueName(queueName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .queueName(queueName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .topicName(topicName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .subscriptionName(subscriptionName); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .topicName(topicName) + .subscriptionName(subscriptionName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } + LOGGER.debug("ServiceBusReceiverClient initialized"); + setDeadLetterClient(receiverObject, receiverClientBuilder.buildClient()); + return receiverObject.getNativeData( + ASBConstants.DEAD_LETTER_RECEIVER_CLIENT); + } catch (BError e) { + return ASBErrorCreator.fromBError(e); + } catch (ServiceBusException e) { + return ASBErrorCreator.fromASBException(e); + } catch (Exception e) { + return ASBErrorCreator.fromUnhandledException(e); + } + } + } + + private static void setInitData(BObject receiverObject, String connectionString, String queueName, + String topicName, String subscriptionName, + String receiveMode, long maxAutoLockRenewDuration, + String logLevel, BMap retryConfigs) { + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_CONNECTION_STRING, connectionString); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_QUEUE_NAME, queueName); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_TOPIC_NAME, topicName); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_SUBSCRIPTION_NAME, subscriptionName); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_RECEIVE_MODE, receiveMode); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_MAX_AUTO_LOCK_RENEW_DURATION, + maxAutoLockRenewDuration); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_LOG_LEVEL, logLevel); + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS, retryConfigs); + } + + private static void setClient(BObject receiverObject, ServiceBusReceiverClient client) { + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT, client); + } + + private static void setDeadLetterClient(BObject receiverObject, ServiceBusReceiverClient client) { + receiverObject.addNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT, client); } } diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java b/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java index 7c404598..fa8abc87 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -26,6 +26,20 @@ */ public class ASBConstants { + //Clients + public static final String RECEIVER_CLIENT = "RECEIVER_CLIENT"; + public static final String DEAD_LETTER_RECEIVER_CLIENT = "DEAD_LETTER_RECEIVER_CLIENT"; + + //Client Init Data + public static final String RECEIVER_CLIENT_CONNECTION_STRING = "CONNECTION_STRING"; + public static final String RECEIVER_CLIENT_RECEIVE_MODE = "RECEIVE_MODE"; + public static final String RECEIVER_CLIENT_TOPIC_NAME = "TOPIC_NAME"; + public static final String RECEIVER_CLIENT_SUBSCRIPTION_NAME = "SUBSCRIPTION_NAME"; + public static final String RECEIVER_CLIENT_QUEUE_NAME = "QUEUE_NAME"; + public static final String RECEIVER_CLIENT_MAX_AUTO_LOCK_RENEW_DURATION = "MAX_AUTO_LOCK_RENEW_DURATION"; + public static final String RECEIVER_CLIENT_LOG_LEVEL = "LOG_LEVEL"; + public static final String RECEIVER_CLIENT_RETRY_CONFIGS = "RETRY_CONFIGS"; + // Message constant fields public static final String MESSAGE_RECORD = "Message"; public static final String APPLICATION_PROPERTY_TYPE = "ApplicationProperties"; diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java index 834c02f3..894f63bb 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -254,65 +254,65 @@ public static RecordType getRecordType(BTypedesc bTypedesc) { */ public static CreateSubscriptionOptions getCreateSubscriptionPropertiesFromBObject(BMap subscriptionConfig) { - CreateSubscriptionOptions subscriptionOptions = new CreateSubscriptionOptions(); - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_AUTO_DELETE_ON_IDLE)) { - subscriptionOptions.setAutoDeleteOnIdle( - getDurationFromBObject(subscriptionConfig.getMapValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_AUTO_DELETE_ON_IDLE))); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEFAULT_MESSAGE_TIME_TO_LIVE)) { - subscriptionOptions.setDefaultMessageTimeToLive( - getDurationFromBObject(subscriptionConfig.getMapValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEFAULT_MESSAGE_TIME_TO_LIVE))); - } - if (subscriptionConfig.containsKey( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEAD_LETTERING_ON_MESSAGE_EXPIRATION)) { - subscriptionOptions.setDeadLetteringOnMessageExpiration( - subscriptionConfig.getBooleanValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEAD_LETTERING_ON_MESSAGE_EXPIRATION)); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_ENABLE_BATCHED_OPERATIONS)) { - subscriptionOptions.setBatchedOperationsEnabled( - subscriptionConfig.getBooleanValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_ENABLE_BATCHED_OPERATIONS)); - } - if (subscriptionConfig.containsKey( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_DEAD_LETTERED_MESSAGES_TO)) { - subscriptionOptions.setForwardDeadLetteredMessagesTo( - subscriptionConfig.getStringValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_DEAD_LETTERED_MESSAGES_TO).getValue()); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_TO)) { - subscriptionOptions.setForwardTo( - subscriptionConfig.getStringValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_TO).getValue()); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_LOCK_DURATION)) { - subscriptionOptions.setLockDuration( - getDurationFromBObject(subscriptionConfig.getMapValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_LOCK_DURATION))); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_MAX_DELIVERY_COUNT)) { - subscriptionOptions.setMaxDeliveryCount( - subscriptionConfig.getIntValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_MAX_DELIVERY_COUNT).intValue()); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_STATUS)) { - subscriptionOptions.setStatus(EntityStatus.fromString( - subscriptionConfig.getStringValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_STATUS).getValue())); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_USER_METADATA)) { - subscriptionOptions.setUserMetadata( - subscriptionConfig.getStringValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_USER_METADATA).getValue()); - } - if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_SESSION_REQUIRED)) { - subscriptionOptions.setSessionRequired( - subscriptionConfig.getBooleanValue( - ASBConstants.SUBSCRIPTION_RECORD_FIELD_SESSION_REQUIRED)); - } - return subscriptionOptions; + CreateSubscriptionOptions subscriptionOptions = new CreateSubscriptionOptions(); + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_AUTO_DELETE_ON_IDLE)) { + subscriptionOptions.setAutoDeleteOnIdle( + getDurationFromBObject(subscriptionConfig.getMapValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_AUTO_DELETE_ON_IDLE))); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEFAULT_MESSAGE_TIME_TO_LIVE)) { + subscriptionOptions.setDefaultMessageTimeToLive( + getDurationFromBObject(subscriptionConfig.getMapValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEFAULT_MESSAGE_TIME_TO_LIVE))); + } + if (subscriptionConfig.containsKey( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEAD_LETTERING_ON_MESSAGE_EXPIRATION)) { + subscriptionOptions.setDeadLetteringOnMessageExpiration( + subscriptionConfig.getBooleanValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_DEAD_LETTERING_ON_MESSAGE_EXPIRATION)); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_ENABLE_BATCHED_OPERATIONS)) { + subscriptionOptions.setBatchedOperationsEnabled( + subscriptionConfig.getBooleanValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_ENABLE_BATCHED_OPERATIONS)); + } + if (subscriptionConfig.containsKey( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_DEAD_LETTERED_MESSAGES_TO)) { + subscriptionOptions.setForwardDeadLetteredMessagesTo( + subscriptionConfig.getStringValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_DEAD_LETTERED_MESSAGES_TO).getValue()); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_TO)) { + subscriptionOptions.setForwardTo( + subscriptionConfig.getStringValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_FORWARD_TO).getValue()); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_LOCK_DURATION)) { + subscriptionOptions.setLockDuration( + getDurationFromBObject(subscriptionConfig.getMapValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_LOCK_DURATION))); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_MAX_DELIVERY_COUNT)) { + subscriptionOptions.setMaxDeliveryCount( + subscriptionConfig.getIntValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_MAX_DELIVERY_COUNT).intValue()); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_STATUS)) { + subscriptionOptions.setStatus(EntityStatus.fromString( + subscriptionConfig.getStringValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_STATUS).getValue())); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_USER_METADATA)) { + subscriptionOptions.setUserMetadata( + subscriptionConfig.getStringValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_USER_METADATA).getValue()); + } + if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_SESSION_REQUIRED)) { + subscriptionOptions.setSessionRequired( + subscriptionConfig.getBooleanValue( + ASBConstants.SUBSCRIPTION_RECORD_FIELD_SESSION_REQUIRED)); + } + return subscriptionOptions; } /** @@ -321,7 +321,7 @@ public static CreateSubscriptionOptions getCreateSubscriptionPropertiesFromBObje * @param topicConfig BMap containing the updated topic configurations. * @return TopicProperties object. */ - public static TopicProperties getUpdatedTopicPropertiesFromBObject(BMap topicConfig , + public static TopicProperties getUpdatedTopicPropertiesFromBObject(BMap topicConfig, TopicProperties topicProperties) { if (topicConfig.containsKey(ASBConstants.TOPIC_RECORD_FIELD_AUTO_DELETE_ON_IDLE)) { topicProperties.setAutoDeleteOnIdle( @@ -378,7 +378,7 @@ public static TopicProperties getUpdatedTopicPropertiesFromBObject(BMap subscriptionConfig , SubscriptionProperties subscriptionProperties) { + BMap subscriptionConfig, SubscriptionProperties subscriptionProperties) { if (subscriptionConfig.containsKey(ASBConstants.SUBSCRIPTION_RECORD_FIELD_AUTO_DELETE_ON_IDLE)) { subscriptionProperties.setAutoDeleteOnIdle( getDurationFromBObject(subscriptionConfig.getMapValue( @@ -446,7 +446,7 @@ public static SubscriptionProperties getUpdatedSubscriptionPropertiesFromBObject * @param ruleConfig BMap containing the queue configurations. * @return RuleProperties object. */ - public static RuleProperties getUpdatedRulePropertiesFromBObject(BMap ruleConfig , + public static RuleProperties getUpdatedRulePropertiesFromBObject(BMap ruleConfig, RuleProperties ruleProp) { if (ruleConfig.containsKey(ASBConstants.RECORD_FIELD_ACTION)) { ruleProp.setAction(new SqlRuleAction( @@ -465,7 +465,7 @@ public static RuleProperties getUpdatedRulePropertiesFromBObject(BMap queueConfig , + public static QueueProperties getUpdatedQueuePropertiesFromBObject(BMap queueConfig, QueueProperties updateQueueOptions) { if (queueConfig.containsKey(ASBConstants.QUEUE_RECORD_FIELD_FORWARD_TO)) { updateQueueOptions.setForwardTo( @@ -537,6 +537,7 @@ public static QueueProperties getUpdatedQueuePropertiesFromBObject(BMap durationConfig) { long nanoseconds = durationConfig.getIntValue(ASBConstants.DURATION_FIELD_NANOSECONDS); return Duration.ofSeconds(seconds).plusNanos(nanoseconds); } + /** * Converts AMPQ Body value to Java objects. * @@ -862,14 +868,14 @@ private static Object getValueWithIntendedTypeRecursive(byte[] value, Type type) * @param type Type to be checked * @return True if the given type is a union type of two member types, including nil type. */ - private static boolean isSupportedUnionType(Type type) { - if (type.getTag() != UNION_TAG) { - return false; - } - UnionType unionType = (UnionType) type; - return unionType.getMemberTypes().size() == 2 - && unionType.getMemberTypes().stream().anyMatch(memberType -> memberType.getTag() == NULL_TAG); + private static boolean isSupportedUnionType(Type type) { + if (type.getTag() != UNION_TAG) { + return false; } + UnionType unionType = (UnionType) type; + return unionType.getMemberTypes().size() == 2 + && unionType.getMemberTypes().stream().anyMatch(memberType -> memberType.getTag() == NULL_TAG); + } public static Type getExpectedTypeFromNilableType(Type type) { if (!(type instanceof UnionType)) { @@ -899,6 +905,7 @@ public static void addMessageFieldIfPresent(Map map, String key, map.put(key, receivedProperty); } } + public static void addFieldIfPresent(Map map, String key, Object receivedProperty) { if (receivedProperty != null) { map.put(key, receivedProperty); From 060a29887f608a3596d5054a550ce87fae698ebb Mon Sep 17 00:00:00 2001 From: RDPerera Date: Wed, 23 Aug 2023 11:55:27 +0530 Subject: [PATCH 02/10] Add DLQ receive/complete tests --- .../asb_sender_receiver_negative_tests.bal | 2 +- ballerina/tests/asb_sender_receiver_tests.bal | 296 +++++++++++++++++- 2 files changed, 293 insertions(+), 5 deletions(-) diff --git a/ballerina/tests/asb_sender_receiver_negative_tests.bal b/ballerina/tests/asb_sender_receiver_negative_tests.bal index 8226a9c8..d4ba4267 100644 --- a/ballerina/tests/asb_sender_receiver_negative_tests.bal +++ b/ballerina/tests/asb_sender_receiver_negative_tests.bal @@ -1,4 +1,4 @@ -// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). // // WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except diff --git a/ballerina/tests/asb_sender_receiver_tests.bal b/ballerina/tests/asb_sender_receiver_tests.bal index 575f51ae..0325dfb3 100644 --- a/ballerina/tests/asb_sender_receiver_tests.bal +++ b/ballerina/tests/asb_sender_receiver_tests.bal @@ -1,6 +1,6 @@ -// Copyright (c) 2023 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). // -// WSO2 Inc. licenses this file to you under the Apache License, +// WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except // in compliance with the License. // You may obtain a copy of the License at @@ -186,6 +186,45 @@ function testSendAndReceiveMessagePayloadFromQueueOperation() returns error? { dependsOn: [testSendAndReceiveMessagePayloadFromQueueOperation], enable: true } +function testReceiveMessagePayloadFromDeadLetterQueueOperation() returns error? { + log:printInfo("[[testReceiveMessagePayloadFromDeadLetterQueueOperation]]"); + log:printInfo("Creating Asb message sender and receiver."); + MessageSender messageSender = check new (senderConfig); + MessageReceiver messageReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check messageSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + Message|error? messageReceived = messageReceiver->receive(serverWaitTime); + + if (messageReceived is Message) { + check messageReceiver->deadLetter(messageReceived); + byte[]|error? bytePayload = messageReceiver->receivePayload(serverWaitTime, deadLettered = true); + if (bytePayload is byte[]) { + string receivedContent = check string:fromBytes(bytePayload); + test:assertEquals(receivedContent, stringContent, msg = "Sent & received payload are not equal."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed."); + } + } else if (messageReceived is ()) { + test:assertFail("No message in the dead-letter queue."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check messageSender->close(); + + log:printInfo("Closing Asb receiver client."); + check messageReceiver->close(); +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testReceiveMessagePayloadFromDeadLetterQueueOperation], + enable: true +} function testSendAndReceiveBatchFromQueueOperation() returns error? { log:printInfo("[[testSendAndReceiveBatchFromQueueOperation]]"); @@ -229,7 +268,66 @@ function testSendAndReceiveBatchFromQueueOperation() returns error? { @test:Config { groups: ["asb_sender_receiver"], - dependsOn: [testSendAndReceiveBatchFromQueueOperation], + dependsOn: [testSendAndReceiveMessagePayloadFromQueueOperation], + enable: true +} +function testSendAndReceiveBatchFromDeadLetterQueueOperation() returns error? { + log:printInfo("[[testSendAndReceiveBatchFromQueueOperation]]"); + + log:printInfo("Initializing Asb sender client."); + MessageSender messageSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + MessageReceiver messageReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender."); + check messageSender->sendBatch(messages); + + log:printInfo("Receiving from Asb receiver."); + MessageBatch|error? messageReceived = messageReceiver->receiveBatch(messages.length() + 5); + + if (messageReceived is MessageBatch) { + log:printInfo(messageReceived.toString()); + test:assertEquals(messageReceived.messages.length(), messages.length(), msg = "Sent & received message counts are not equal."); + foreach Message message in messageReceived.messages { + if (message.toString() != "") { + string msg = check string:fromBytes(message.body); + test:assertEquals(msg, stringContent, msg = "Sent & received message are not equal."); + check messageReceiver->deadLetter(message); + } + } + } else if (messageReceived is ()) { + test:assertFail("No message in the queue."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed." + messageReceived.toString()); + } + log:printInfo("Receiving from Asb dead-letter receiver."); + MessageBatch|error? receivedDeadletterMessages = messageReceiver->receiveBatch(messages.length() + 5, deadLettered = true); + if (receivedDeadletterMessages is MessageBatch) { + log:printInfo(receivedDeadletterMessages.toString()); + test:assertEquals(receivedDeadletterMessages.messages.length(), messages.length(), msg = "Sent & received message counts are not equal."); + foreach Message message in receivedDeadletterMessages.messages { + if (message.toString() != "") { + string msg = check string:fromBytes(message.body); + test:assertEquals(msg, stringContent, msg = "Sent & received dead-letter message are not equal."); + } + } + } else if (receivedDeadletterMessages is ()) { + test:assertFail("No message in the queue."); + } else { + test:assertFail("Receiving message via Asb dead-letter receiver connection failed." + receivedDeadletterMessages.toString()); + } + + log:printInfo("Closing Asb sender. "); + check messageSender->close(); + + log:printInfo("Closing Asb receiver."); + check messageReceiver->close(); +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testSendAndReceiveBatchFromDeadLetterQueueOperation], enable: true } function testCompleteMessageFromQueueOperation() returns error? { @@ -271,6 +369,68 @@ function testCompleteMessageFromQueueOperation() returns error? { dependsOn: [testCompleteMessageFromQueueOperation], enable: true } +function testCompleteDeadLetterMessageFromQueueOperation() returns error? { + log:printInfo("[[testCompleteDeadLetterMessageFromQueueOperation]]"); + + log:printInfo("Initializing Asb sender client."); + MessageSender messageSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + MessageReceiver messageReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender."); + check messageSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + Message|error? messageReceived = messageReceiver->receive(serverWaitTime); + + if (messageReceived is Message) { + check messageReceiver->deadLetter(messageReceived); + log:printInfo("Receiving from DLQ via Asb receiver client."); + Message|error? messageReceivedFromDLQ = messageReceiver->receive(serverWaitTime, deadLettered = true); + if (messageReceivedFromDLQ is Message) { + log:printInfo("Message received from DLQ."); + string? message_id_dl = messageReceivedFromDLQ.messageId; + + log:printInfo("Completing the DLQ message."); + check messageReceiver->complete(messageReceivedFromDLQ); + + log:printInfo("Receiving from DLQ via Asb receiver client after complete."); + Message|error? checkReceivingDLQAfterComplete = messageReceiver->receive(serverWaitTime, deadLettered = true); + if (checkReceivingDLQAfterComplete is Message) { //if there are any messages in the DLQ + log:printInfo("Message received from DLQ."); + string? message_id_top = checkReceivingDLQAfterComplete.messageId; + if (message_id_top is string) && (message_id_dl is string) { + test:assertNotEquals(message_id_top, message_id_dl, msg = "Message id of the message received from DLQ is same as the message id of the message sent to DLQ."); + } else { + test:assertFail("Message id of the message received from DLQ is null."); + } + } else { + test:assertEquals(checkReceivingDLQAfterComplete, (), msg = "Message received from DLQ after complete."); + } + } else if (messageReceivedFromDLQ is ()) { + test:assertFail("No message in the DLQ."); + } else { + test:assertFail("Receiving message via ASBReceiver:DLQ connection failed."); + } + } else if (messageReceived is ()) { + test:assertFail("No message in the queue."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check messageSender->close(); + + log:printInfo("Closing Asb receiver client."); + check messageSender->close(); +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testCompleteDeadLetterMessageFromQueueOperation], + enable: true +} function testAbandonMessageFromQueueOperation() returns error? { log:printInfo("[[testAbandonMessageFromQueueOperation]]"); @@ -351,6 +511,42 @@ function testDeadletterMessageFromQueueOperation() returns error? { dependsOn: [testDeadletterMessageFromQueueOperation], enable: true } +function testReceiveDeadLetterQueueMessages() returns error? { + log:printInfo("[[testReceiveDeadLetterQueueMessages]]"); + + log:printInfo("Initializing Asb receiver client."); + MessageReceiver queueReceiver = check new (receiverConfig); + + log:printInfo("Receiving from Asb receiver."); + Message|error? message = queueReceiver->receive(serverWaitTime, deadLettered = true); + + if (message is Message) { + string receivedContent = check string:fromBytes(message.body); + test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); + } else if (message is ()) { + log:printError("No dead letter message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Receiving from Asb receiver.(for test usage of already creaated dead letter queue receiver)"); + message = queueReceiver->receive(serverWaitTime, deadLettered = true); + + if (message is Message) { + string receivedContent = check string:fromBytes(message.body); + test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); + } else if (message is ()) { + log:printError("No dead letter message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testReceiveDeadLetterQueueMessages], + enable: true +} function testDeferMessageFromQueueOperation() returns error? { log:printInfo("[[testDeferMessageFromQueueOperation]]"); @@ -473,7 +669,63 @@ function testSendAndReceiveBatchFromSubscriptionOperation() returns error? { @test:Config { groups: ["asb_sender_receiver"], - dependsOn: [testSendAndReceiveBatchFromSubscriptionOperation], + dependsOn: [testSendAndReceiveMessageFromSubscriptionOperation], + enable: true +} +function testSendAndReceiveBatchFromDeadLetterSubscriptionOperation() returns error? { + log:printInfo("[[testSendAndReceiveBatchFromDeadLetterSubscriptionOperation]]"); + + log:printInfo("Initializing Asb sender client."); + MessageSender topicSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + MessageReceiver subscriptionReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check topicSender->sendBatch(messages); + + log:printInfo("Receiving from Asb receiver client."); + MessageBatch|error? messageReceived = subscriptionReceiver->receiveBatch(maxMessageCount, serverWaitTime); + + if (messageReceived is MessageBatch) { + foreach Message message in messageReceived.messages { + if (message.toString() != "") { + string msg = check string:fromBytes(message.body); + test:assertEquals(msg, stringContent, msg = "Sent & received message not equal."); + check subscriptionReceiver->deadLetter(message); + } + } + } else if (messageReceived is ()) { + test:assertFail("No message in the subscription."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Receiving from Asb dead-letter receiver client."); + MessageBatch|error? receivedDeadletterMessages = subscriptionReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); + + if (receivedDeadletterMessages is MessageBatch) { + foreach Message message in receivedDeadletterMessages.messages { + if (message.toString() != "") { + string msg = check string:fromBytes(message.body); + test:assertEquals(msg, stringContent, msg = "Sent & received deadl-letter message not equal."); + } + } + } else if (receivedDeadletterMessages is ()) { + test:assertFail("No message in the subscription."); + } else { + test:assertFail("Receiving message via Asb receiver connection failed."); + } + log:printInfo("Closing Asb sender client."); + check topicSender->close(); + + log:printInfo("Closing Asb receiver client."); + check subscriptionReceiver->close(); +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testSendAndReceiveBatchFromDeadLetterSubscriptionOperation], enable: true } function testCompleteMessageFromSubscriptionOperation() returns error? { @@ -591,6 +843,42 @@ function testDeadletterMessageFromSubscriptionOperation() returns error? { dependsOn: [testDeadletterMessageFromSubscriptionOperation], enable: true } +function testReceiveDeadLetterSubscriptionMessages() returns error? { + log:printInfo("[[testReceiveDeadLetterSubscriptionMessages]]"); + + log:printInfo("Initializing Asb receiver client."); + MessageReceiver queueReceiver = check new (receiverConfig); + + log:printInfo("Receiving from Asb receiver."); + Message|error? message = queueReceiver->receive(serverWaitTime, deadLettered = true); + + if (message is Message) { + string receivedContent = check string:fromBytes(message.body); + test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); + } else if (message is ()) { + log:printError("No dead letter message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Receiving from Asb receiver.(for test usage of already creaated dead letter queue receiver)"); + message = queueReceiver->receive(serverWaitTime, deadLettered = true); + + if (message is Message) { + string receivedContent = check string:fromBytes(message.body); + test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); + } else if (message is ()) { + log:printError("No dead letter message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } +} + +@test:Config { + groups: ["asb_sender_receiver"], + dependsOn: [testReceiveDeadLetterSubscriptionMessages], + enable: true +} function testDeferMessageFromSubscriptionOperation() returns error? { log:printInfo("[[testDeferMessageFromSubscriptionOperation]]"); From e020940d07196f0ea723cd718f760d114d7517ee Mon Sep 17 00:00:00 2001 From: RDPerera Date: Wed, 23 Aug 2023 12:00:53 +0530 Subject: [PATCH 03/10] Add DLQ receive/complete, payload-receive examples --- ...omplete_message_from_dead_letter_queue.bal | 126 ++++++++++++++++++ ...eceive_messages_from_dead_letter_queue.bal | 97 ++++++++++++++ ...messages_from_dead_letter_subscription.bal | 100 ++++++++++++++ ...receive_payload_from_dead_letter_queue.bal | 93 +++++++++++++ ..._batch_messages_from_dead_letter_queue.bal | 114 ++++++++++++++++ ...messages_from_dead_letter_subscription.bal | 116 ++++++++++++++++ .../send_and_receive_payload.bal | 74 ++++++++++ ...to_topic_and_receive_from_subscription.bal | 1 - 8 files changed, 720 insertions(+), 1 deletion(-) create mode 100644 examples/sender_reciever/complete_message_from_dead_letter_queue.bal create mode 100644 examples/sender_reciever/receive_messages_from_dead_letter_queue.bal create mode 100644 examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal create mode 100644 examples/sender_reciever/receive_payload_from_dead_letter_queue.bal create mode 100644 examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal create mode 100644 examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal create mode 100644 examples/sender_reciever/send_and_receive_payload.bal diff --git a/examples/sender_reciever/complete_message_from_dead_letter_queue.bal b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal new file mode 100644 index 00000000..49c9db12 --- /dev/null +++ b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal @@ -0,0 +1,126 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLS. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string queueName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a message to a queue using message sender, receive that message using message receiver with PEEKLOCK mode, +// then move the message in a DLQ (dead letter queue) +// After moving to DLQ, recieve the DQL message using receive(deadLettered = true) +// Then complete the DLQ message and receive the dlq messages again to check whether the message is settled from DLQ +public function main() returns error? { + + // Input values + string stringContent = "This is message goes to DLQ."; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + + asb:ApplicationProperties applicationProperties = { + properties: {a: "propertyValue1", b: "propertyValue2"} + }; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive, + applicationProperties: applicationProperties + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: queueName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + queueName: queueName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender queueSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver queueReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check queueSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); + + if (messageReceived is asb:Message) { + + //deadLetter the message + check queueReceiver->deadLetter(messageReceived); + + //get message from DLQ + log:printInfo("Receiving from DLQ via Asb receiver client."); + asb:Message|error? messageReceivedFromDLQ = queueReceiver->receive(serverWaitTime, deadLettered = true); + if (messageReceivedFromDLQ is asb:Message) { + + //Check whether the message received from DLQ + log:printInfo("Message received from DLQ."); + string? message_id = messageReceivedFromDLQ.messageId; + if (message_id is string) { + log:printInfo("DLQ Top Message ID: " + message_id); + } + + //Complete the DLQ Message + log:printInfo("Completing the DLQ message."); + check queueReceiver->complete(messageReceivedFromDLQ, deadLettered = true); + + //Receive the message from DLQ after complete + log:printInfo("Receiving from DLQ via Asb receiver client after complete."); + asb:Message|error? checkReceivingDLQAfterComplete = queueReceiver->receive(serverWaitTime, deadLettered = true); + if (checkReceivingDLQAfterComplete is asb:Message) { //if there are any messages in the DLQ + log:printInfo("Message received from DLQ."); + message_id = checkReceivingDLQAfterComplete.messageId; + string source = checkReceivingDLQAfterComplete.deadLetterSource; + if (message_id is string) { + log:printInfo("DLQ Top Message ID: " + message_id + source); + } + } else if (checkReceivingDLQAfterComplete is ()) { //if there are no messages in the DLQ + log:printError("No message in the deadletter queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + } else if (messageReceivedFromDLQ is ()) { + log:printError("No message in the DLQ."); + } else { + log:printError("Receiving message via ASBReceiver:DLQ connection failed."); + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check queueSender->close(); + + log:printInfo("Closing Asb receiver client."); + check queueReceiver->close(); +} diff --git a/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal b/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal new file mode 100644 index 00000000..547a868a --- /dev/null +++ b/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal @@ -0,0 +1,97 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLS. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string queueName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a message to a queue using message sender, receive that message using message receiver with PEEKLOCK mode, +// then move the message in a DLQ (dead letter queue) +// After moving to DLQ, recieve the DQL message using receive(deadLettered = true) +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + + asb:ApplicationProperties applicationProperties = { + properties: {a: "propertyValue1", b: "propertyValue2"} + }; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive, + applicationProperties: applicationProperties + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: queueName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + queueName: queueName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender queueSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver queueReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check queueSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); + + if (messageReceived is asb:Message) { + check queueReceiver->deadLetter(messageReceived); + asb:Message|error? messageReceivedFromDLQ = queueReceiver->receive(serverWaitTime, deadLettered = true); + + if (messageReceivedFromDLQ is asb:Message) { + log:printInfo("Message received from DLQ."); + string message_str = check string:fromBytes(messageReceivedFromDLQ.body); + log:printInfo("DLQ Message content: " + message_str); + } else if (messageReceivedFromDLQ is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check queueSender->close(); + + log:printInfo("Closing Asb receiver client."); + check queueReceiver->close(); +} diff --git a/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal b/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal new file mode 100644 index 00000000..ff7b9e8b --- /dev/null +++ b/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal @@ -0,0 +1,100 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLS. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string topicName = ?; +configurable string subscriptionName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a message to a topic using message sender, +// receive a messsage from a subcription using subscription receiver with PEEK_LOCK mode +// then move the message in a dead letter subscription +// After moving to dead letter subscription,dead letter message will be received using receive(deadLettered = true) +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + + asb:ApplicationProperties applicationProperties = { + properties: {a: "propertyValue1", b: "propertyValue2"} + }; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive, + applicationProperties: applicationProperties + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:TOPIC, + topicOrQueueName: topicName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + topicName: topicName, + subscriptionName: subscriptionName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender topicSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver subscriptionReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check topicSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); + + if (messageReceived is asb:Message) { + check subscriptionReceiver->deadLetter(messageReceived); + asb:Message|error? messageReceivedFromDLQ = subscriptionReceiver->receive(serverWaitTime, deadLettered = true); + + if (messageReceivedFromDLQ is asb:Message) { + log:printInfo("Message received from DLQ."); + string message_str = check string:fromBytes(messageReceivedFromDLQ.body); + log:printInfo("DLQ Message content: " + message_str); + } else if (messageReceivedFromDLQ is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check topicSender->close(); + + log:printInfo("Closing Asb receiver client."); + check subscriptionReceiver->close(); +} diff --git a/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal b/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal new file mode 100644 index 00000000..985b3579 --- /dev/null +++ b/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal @@ -0,0 +1,93 @@ + +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLS. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string queueName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a message to a queue using message sender, receive that message using message receiver with PEEKLOCK mode, +// then move the message in a DLQ (dead letter queue) +// After moving to DLQ, recieve the DQL message payload using receivePayload method +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + + asb:ApplicationProperties applicationProperties = { + properties: {a: "propertyValue1", b: "propertyValue2"} + }; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive, + applicationProperties: applicationProperties + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: queueName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + queueName: queueName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender queueSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver queueReceiver = check new (receiverConfig); + + log:printInfo("Sending via Asb sender client."); + check queueSender->send(message1); + + log:printInfo("Receiving from Asb receiver client."); + asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); + + if (messageReceived is asb:Message) { + check queueReceiver->deadLetter(messageReceived); + byte[]|error? bytePayload = queueReceiver->receivePayload(serverWaitTime, deadLettered = true); + if (bytePayload is byte[]) { + log:printInfo("Received message from DLQ: " + bytePayload.toString()); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check queueSender->close(); + + log:printInfo("Closing Asb receiver client."); + check queueReceiver->close(); +} diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal new file mode 100644 index 00000000..4f312e97 --- /dev/null +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal @@ -0,0 +1,114 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string queueName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a batch of messages to a queue using message sender, receive batch of messsages using message receiver with PEEK_LOCK mode +// then dead-letter the received messages and agian receive the dead-lettered messages using message receiver. +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + int maxMessageCount = 2; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive + }; + + asb:Message message2 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive + }; + + asb:MessageBatch messages = { + messageCount: 2, + messages: [message1, message2] + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: queueName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + queueName: queueName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender queueSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver queueReceiver = check new (receiverConfig); + + // Sending messages + log:printInfo("Sending via Asb sender client."); + check queueSender->sendBatch(messages); + + // Receiving messages + log:printInfo("Receiving from Asb receiver client."); + asb:MessageBatch|error? messageReceived = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime); + + if (messageReceived is asb:MessageBatch) { + foreach asb:Message message in messageReceived.messages { + if (message.toString() != "") { + log:printInfo("Reading Received Message : " + message.toString()); + // Dead-lettering the received message + check queueReceiver->deadLetter(message); + } + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + // Receiving dead-lettered messages + log:printInfo("Receiving from Asb dead-letter receiver client."); + asb:MessageBatch|error? receivedDeadletterMessages = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); + + if (receivedDeadletterMessages is asb:MessageBatch) { + foreach asb:Message message in receivedDeadletterMessages.messages { + if (message.toString() != "") { + log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); + } + } + } else if (receivedDeadletterMessages is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + log:printInfo("Closing Asb sender client."); + check queueSender->close(); + + log:printInfo("Closing Asb receiver client."); + check queueReceiver->close(); +} diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal new file mode 100644 index 00000000..712e4d70 --- /dev/null +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal @@ -0,0 +1,116 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLC. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string topicName = ?; +configurable string subscriptionName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a batch of messages to a subscription using message sender, receive batch of messsages using message receiver with PEEK_LOCK mode +// then dead-letter the received messages and agian receive the dead-lettered messages using message receiver. +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int timeToLive = 60; // In seconds + int serverWaitTime = 60; // In seconds + int maxMessageCount = 2; + + asb:Message message1 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive + }; + + asb:Message message2 = { + body: byteContent, + contentType: asb:TEXT, + timeToLive: timeToLive + }; + + asb:MessageBatch messages = { + messageCount: 2, + messages: [message1, message2] + }; + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: topicName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + topicName: topicName, + subscriptionName: subscriptionName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender queueSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver queueReceiver = check new (receiverConfig); + + // Sending messages + log:printInfo("Sending via Asb sender client."); + check queueSender->sendBatch(messages); + + // Receiving messages + log:printInfo("Receiving from Asb receiver client."); + asb:MessageBatch|error? messageReceived = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime); + + if (messageReceived is asb:MessageBatch) { + foreach asb:Message message in messageReceived.messages { + if (message.toString() != "") { + log:printInfo("Reading Received Message : " + message.toString()); + // Dead-lettering the received message + check queueReceiver->deadLetter(message); + } + } + } else if (messageReceived is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + // Receiving dead-lettered messages + log:printInfo("Receiving from Asb dead-letter receiver client."); + asb:MessageBatch|error? receivedDeadletterMessages = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); + + if (receivedDeadletterMessages is asb:MessageBatch) { + foreach asb:Message message in receivedDeadletterMessages.messages { + if (message.toString() != "") { + log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); + } + } + } else if (receivedDeadletterMessages is ()) { + log:printError("No message in the queue."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + log:printInfo("Closing Asb sender client."); + check queueSender->close(); + + log:printInfo("Closing Asb receiver client."); + check queueReceiver->close(); +} diff --git a/examples/sender_reciever/send_and_receive_payload.bal b/examples/sender_reciever/send_and_receive_payload.bal new file mode 100644 index 00000000..b0a96e56 --- /dev/null +++ b/examples/sender_reciever/send_and_receive_payload.bal @@ -0,0 +1,74 @@ +// Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). +// +// WSO2 LLS. licenses this file to you under the Apache License, +// Version 2.0 (the "License"); you may not use this file except +// in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +import ballerina/log; +import ballerinax/asb; + +// Connection Configurations +configurable string connectionString = ?; +configurable string queueName = ?; + +// This sample demonstrates a scneario where azure service bus connecter is used to +// send a payload to a queue and receive the same payload from the queue. +public function main() returns error? { + + // Input values + string stringContent = "This is My Message Body"; + byte[] byteContent = stringContent.toBytes(); + int serverWaitTime = 60; // In seconds + + asb:ASBServiceSenderConfig senderConfig = { + connectionString: connectionString, + entityType: asb:QUEUE, + topicOrQueueName: queueName + }; + + asb:ASBServiceReceiverConfig receiverConfig = { + connectionString: connectionString, + entityConfig: { + queueName: queueName + }, + receiveMode: asb:PEEK_LOCK + }; + + log:printInfo("Initializing Asb sender client."); + asb:MessageSender messageSender = check new (senderConfig); + + log:printInfo("Initializing Asb receiver client."); + asb:MessageReceiver messageReceiver = check new (receiverConfig); + + //Sending payload. payload can be either nil, boolean, int, float, string, json, byte[], xml, map, record + log:printInfo("Sending via Asb sender client."); + check messageSender->sendPayload(byteContent); + + //Receiving payload. payload can be either nil, boolean, int, float, string, json, byte[], xml, map, record + log:printInfo("Receiving from Asb receiver client."); + byte[]|error? bytePayload = messageReceiver->receivePayload(serverWaitTime); + + log:printInfo("Asserting received payloads."); + if (bytePayload is byte[]) { + string stringPayload = check string:fromBytes(bytePayload); + log:printInfo("Received message: " + stringPayload); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + + log:printInfo("Closing Asb sender client."); + check messageSender->close(); + + log:printInfo("Closing Asb receiver client."); + check messageReceiver->close(); +} diff --git a/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal b/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal index 19fcf462..04b271ee 100644 --- a/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal +++ b/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal @@ -31,7 +31,6 @@ public function main() returns error? { // Input values string stringContent = "This is My Message Body"; byte[] byteContent = stringContent.toBytes(); - map properties = {a: "propertyValue1", b: "propertyValue2"}; int timeToLive = 60; // In seconds int serverWaitTime = 60; // In seconds int maxMessageCount = 2; From 332da17b2ee42249ca9d8ae4aebd85d72113a25e Mon Sep 17 00:00:00 2001 From: RDPerera Date: Wed, 23 Aug 2023 14:41:05 +0530 Subject: [PATCH 04/10] Fix Complete-DLQ example --- .../complete_message_from_dead_letter_queue.bal | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/sender_reciever/complete_message_from_dead_letter_queue.bal b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal index 49c9db12..27f0b0c1 100644 --- a/examples/sender_reciever/complete_message_from_dead_letter_queue.bal +++ b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal @@ -90,7 +90,7 @@ public function main() returns error? { //Complete the DLQ Message log:printInfo("Completing the DLQ message."); - check queueReceiver->complete(messageReceivedFromDLQ, deadLettered = true); + check queueReceiver->complete(messageReceivedFromDLQ); //Receive the message from DLQ after complete log:printInfo("Receiving from DLQ via Asb receiver client after complete."); @@ -98,9 +98,8 @@ public function main() returns error? { if (checkReceivingDLQAfterComplete is asb:Message) { //if there are any messages in the DLQ log:printInfo("Message received from DLQ."); message_id = checkReceivingDLQAfterComplete.messageId; - string source = checkReceivingDLQAfterComplete.deadLetterSource; if (message_id is string) { - log:printInfo("DLQ Top Message ID: " + message_id + source); + log:printInfo("DLQ Top Message ID: " + message_id); } } else if (checkReceivingDLQAfterComplete is ()) { //if there are no messages in the DLQ log:printError("No message in the deadletter queue."); From 4d0e5a0b8b6288e294686f5e3e3e55372700a53e Mon Sep 17 00:00:00 2001 From: RDPerera Date: Thu, 24 Aug 2023 09:57:54 +0530 Subject: [PATCH 05/10] Refector if statements --- ballerina/tests/asb_sender_receiver_tests.bal | 122 +++++++++--------- .../abandon_message_from_queue.bal | 6 +- .../abandon_message_from_subscription.bal | 6 +- ...omplete_message_from_dead_letter_queue.bal | 16 +-- .../complete_message_from_queue.bal | 4 +- .../complete_message_from_subscription.bal | 4 +- .../sender_reciever/deadletter_from_queue.bal | 6 +- .../deadletter_from_subscription.bal | 6 +- examples/sender_reciever/defer_from_queue.bal | 6 +- .../defer_from_subscription.bal | 6 +- ...eceive_messages_from_dead_letter_queue.bal | 8 +- ...messages_from_dead_letter_subscription.bal | 8 +- ...receive_payload_from_dead_letter_queue.bal | 7 +- .../renew_lock_on_message_from_queue.bal | 4 +- ...enew_lock_on_message_from_subscription.bal | 10 +- .../send_and_receive_batch_from_queue.bal | 6 +- ..._batch_messages_from_dead_letter_queue.bal | 12 +- ...messages_from_dead_letter_subscription.bal | 12 +- .../send_and_receive_message_from_queue.bal | 4 +- .../send_and_receive_payload.bal | 2 +- ...to_topic_and_receive_from_subscription.bal | 2 +- ...to_topic_and_receive_from_subscription.bal | 4 +- 22 files changed, 132 insertions(+), 129 deletions(-) diff --git a/ballerina/tests/asb_sender_receiver_tests.bal b/ballerina/tests/asb_sender_receiver_tests.bal index 0325dfb3..61d526e3 100644 --- a/ballerina/tests/asb_sender_receiver_tests.bal +++ b/ballerina/tests/asb_sender_receiver_tests.bal @@ -98,12 +98,12 @@ function testSendAndReceiveMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check messageReceiver->complete(messageReceived); test:assertEquals(result, (), msg = "Complete message not successful."); float mapValue = check getApplicationPropertyByName(messageReceived, "f").ensureType(); test:assertEquals(mapValue, properties["f"], "Retrieving application properties failed"); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -198,16 +198,16 @@ function testReceiveMessagePayloadFromDeadLetterQueueOperation() returns error? log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { check messageReceiver->deadLetter(messageReceived); byte[]|error? bytePayload = messageReceiver->receivePayload(serverWaitTime, deadLettered = true); - if (bytePayload is byte[]) { + if bytePayload is byte[] { string receivedContent = check string:fromBytes(bytePayload); test:assertEquals(receivedContent, stringContent, msg = "Sent & received payload are not equal."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the dead-letter queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -244,16 +244,16 @@ function testSendAndReceiveBatchFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver."); MessageBatch|error? messageReceived = messageReceiver->receiveBatch(messages.length() + 5); - if (messageReceived is MessageBatch) { + if messageReceived is MessageBatch { log:printInfo(messageReceived.toString()); test:assertEquals(messageReceived.messages.length(), messages.length(), msg = "Sent & received message counts are not equal."); foreach Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received message are not equal."); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed." + messageReceived.toString()); @@ -286,33 +286,33 @@ function testSendAndReceiveBatchFromDeadLetterQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver."); MessageBatch|error? messageReceived = messageReceiver->receiveBatch(messages.length() + 5); - if (messageReceived is MessageBatch) { + if messageReceived is MessageBatch { log:printInfo(messageReceived.toString()); test:assertEquals(messageReceived.messages.length(), messages.length(), msg = "Sent & received message counts are not equal."); foreach Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received message are not equal."); check messageReceiver->deadLetter(message); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed." + messageReceived.toString()); } log:printInfo("Receiving from Asb dead-letter receiver."); MessageBatch|error? receivedDeadletterMessages = messageReceiver->receiveBatch(messages.length() + 5, deadLettered = true); - if (receivedDeadletterMessages is MessageBatch) { + if receivedDeadletterMessages is MessageBatch { log:printInfo(receivedDeadletterMessages.toString()); test:assertEquals(receivedDeadletterMessages.messages.length(), messages.length(), msg = "Sent & received message counts are not equal."); foreach Message message in receivedDeadletterMessages.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received dead-letter message are not equal."); } } - } else if (receivedDeadletterMessages is ()) { + } else if receivedDeadletterMessages is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb dead-letter receiver connection failed." + receivedDeadletterMessages.toString()); @@ -347,11 +347,11 @@ function testCompleteMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { log:printInfo("messgae" + messageReceived.toString()); var result = check messageReceiver->complete(messageReceived); test:assertEquals(result, (), msg = "Complete message not successful."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -384,11 +384,11 @@ function testCompleteDeadLetterMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { check messageReceiver->deadLetter(messageReceived); log:printInfo("Receiving from DLQ via Asb receiver client."); Message|error? messageReceivedFromDLQ = messageReceiver->receive(serverWaitTime, deadLettered = true); - if (messageReceivedFromDLQ is Message) { + if messageReceivedFromDLQ is Message { log:printInfo("Message received from DLQ."); string? message_id_dl = messageReceivedFromDLQ.messageId; @@ -397,10 +397,10 @@ function testCompleteDeadLetterMessageFromQueueOperation() returns error? { log:printInfo("Receiving from DLQ via Asb receiver client after complete."); Message|error? checkReceivingDLQAfterComplete = messageReceiver->receive(serverWaitTime, deadLettered = true); - if (checkReceivingDLQAfterComplete is Message) { //if there are any messages in the DLQ + if checkReceivingDLQAfterComplete is Message { //if there are any messages in the DLQ log:printInfo("Message received from DLQ."); string? message_id_top = checkReceivingDLQAfterComplete.messageId; - if (message_id_top is string) && (message_id_dl is string) { + if message_id_top is string && (message_id_dl is string) { test:assertNotEquals(message_id_top, message_id_dl, msg = "Message id of the message received from DLQ is same as the message id of the message sent to DLQ."); } else { test:assertFail("Message id of the message received from DLQ is null."); @@ -408,12 +408,12 @@ function testCompleteDeadLetterMessageFromQueueOperation() returns error? { } else { test:assertEquals(checkReceivingDLQAfterComplete, (), msg = "Message received from DLQ after complete."); } - } else if (messageReceivedFromDLQ is ()) { + } else if messageReceivedFromDLQ is () { test:assertFail("No message in the DLQ."); } else { test:assertFail("Receiving message via ASBReceiver:DLQ connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -446,18 +446,18 @@ function testAbandonMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check messageReceiver->abandon(messageReceived); test:assertEquals(result, (), msg = "Abandon message not successful."); Message|error? messageReceivedAgain = messageReceiver->receive(serverWaitTime); - if (messageReceivedAgain is Message) { + if messageReceivedAgain is Message { test:assertEquals(messageReceivedAgain?.messageId, messageReceived?.messageId, msg = "Abandon message not successful."); check messageReceiver->complete(messageReceivedAgain); } else { test:assertFail("Abandon message not successful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -490,10 +490,10 @@ function testDeadletterMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check messageReceiver->deadLetter(messageReceived); test:assertEquals(result, (), msg = "Deadletter message not successful."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -520,10 +520,10 @@ function testReceiveDeadLetterQueueMessages() returns error? { log:printInfo("Receiving from Asb receiver."); Message|error? message = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (message is Message) { + if message is Message { string receivedContent = check string:fromBytes(message.body); test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); - } else if (message is ()) { + } else if message is () { log:printError("No dead letter message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -532,10 +532,10 @@ function testReceiveDeadLetterQueueMessages() returns error? { log:printInfo("Receiving from Asb receiver.(for test usage of already creaated dead letter queue receiver)"); message = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (message is Message) { + if message is Message { string receivedContent = check string:fromBytes(message.body); test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); - } else if (message is ()) { + } else if message is () { log:printError("No dead letter message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -562,16 +562,16 @@ function testDeferMessageFromQueueOperation() returns error? { log:printInfo("Receiving from Asb receiver."); Message|error? messageReceived = messageReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { int result = check messageReceiver->defer(messageReceived); test:assertNotEquals(result, 0, msg = "Defer message not successful."); Message|error? messageReceivedAgain = check messageReceiver->receiveDeferred(result); - if (messageReceivedAgain is Message) { + if messageReceivedAgain is Message { test:assertEquals(messageReceivedAgain?.messageId, messageReceived?.messageId, msg = "Receiving deferred message not succesful."); check messageReceiver->complete(messageReceivedAgain); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -610,11 +610,11 @@ function testSendAndReceiveMessageFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { log:printInfo(messageReceived.toString()); string msg = check string:fromBytes(messageReceived.body); test:assertEquals(msg, stringContent, msg = "Sent & received message not equal."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -647,14 +647,14 @@ function testSendAndReceiveBatchFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); MessageBatch|error? messageReceived = subscriptionReceiver->receiveBatch(maxMessageCount, serverWaitTime); - if (messageReceived is MessageBatch) { + if messageReceived is MessageBatch { foreach Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received message not equal."); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -687,15 +687,15 @@ function testSendAndReceiveBatchFromDeadLetterSubscriptionOperation() returns er log:printInfo("Receiving from Asb receiver client."); MessageBatch|error? messageReceived = subscriptionReceiver->receiveBatch(maxMessageCount, serverWaitTime); - if (messageReceived is MessageBatch) { + if messageReceived is MessageBatch { foreach Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received message not equal."); check subscriptionReceiver->deadLetter(message); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -704,14 +704,14 @@ function testSendAndReceiveBatchFromDeadLetterSubscriptionOperation() returns er log:printInfo("Receiving from Asb dead-letter receiver client."); MessageBatch|error? receivedDeadletterMessages = subscriptionReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); - if (receivedDeadletterMessages is MessageBatch) { + if receivedDeadletterMessages is MessageBatch { foreach Message message in receivedDeadletterMessages.messages { - if (message.toString() != "") { + if message.toString() != "" { string msg = check string:fromBytes(message.body); test:assertEquals(msg, stringContent, msg = "Sent & received deadl-letter message not equal."); } } - } else if (receivedDeadletterMessages is ()) { + } else if receivedDeadletterMessages is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -744,10 +744,10 @@ function testCompleteMessageFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check subscriptionReceiver->complete(messageReceived); test:assertEquals(result, (), msg = "Complete message not successful."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -780,16 +780,16 @@ function testAbandonMessageFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check subscriptionReceiver->abandon(messageReceived); test:assertEquals(result, (), msg = "Abandon message not successful."); Message|error? messageReceivedAgain = subscriptionReceiver->receive(serverWaitTime); - if (messageReceivedAgain is Message) { + if messageReceivedAgain is Message { check subscriptionReceiver->complete(messageReceivedAgain); } else { test:assertFail("Abandon message not succesful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -822,10 +822,10 @@ function testDeadletterMessageFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { var result = check subscriptionReceiver->deadLetter(messageReceived); test:assertEquals(result, (), msg = "Deadletter message not successful."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the subscription."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -852,10 +852,10 @@ function testReceiveDeadLetterSubscriptionMessages() returns error? { log:printInfo("Receiving from Asb receiver."); Message|error? message = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (message is Message) { + if message is Message { string receivedContent = check string:fromBytes(message.body); test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); - } else if (message is ()) { + } else if message is () { log:printError("No dead letter message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -864,10 +864,10 @@ function testReceiveDeadLetterSubscriptionMessages() returns error? { log:printInfo("Receiving from Asb receiver.(for test usage of already creaated dead letter queue receiver)"); message = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (message is Message) { + if message is Message { string receivedContent = check string:fromBytes(message.body); test:assertEquals(receivedContent, stringContent, msg = "Sent & received dead letter message not equal."); - } else if (message is ()) { + } else if message is () { log:printError("No dead letter message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -894,16 +894,16 @@ function testDeferMessageFromSubscriptionOperation() returns error? { log:printInfo("Receiving from Asb receiver client."); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { int result = check subscriptionReceiver->defer(messageReceived); test:assertNotEquals(result, 0, msg = "Defer message not successful."); Message|error? messageReceivedAgain = check subscriptionReceiver->receiveDeferred(result); - if (messageReceivedAgain is Message) { + if messageReceivedAgain is Message { test:assertEquals(messageReceivedAgain?.messageId, messageReceived?.messageId, msg = "Receiving deferred message not successful."); check subscriptionReceiver->complete(messageReceivedAgain); } - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("No message in the queue."); } else { test:assertFail("Receiving message via Asb receiver connection failed."); @@ -950,11 +950,11 @@ function testMessageScheduling() returns error? { log:printInfo("Receiving from Asb receiver client. Max wait = " + serverWaitTime.toString()); Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is Message) { + if messageReceived is Message { log:printInfo(messageReceived.toString()); string msg = check string:fromBytes(messageReceived.body); test:assertEquals(msg, stringContent, msg = "Sent & received message not equal."); - } else if (messageReceived is ()) { + } else if messageReceived is () { test:assertFail("Subscription did not receive message within " + serverWaitTime.toString()); } else { test:assertFail("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/abandon_message_from_queue.bal b/examples/sender_reciever/abandon_message_from_queue.bal index f70edb7d..291161ce 100644 --- a/examples/sender_reciever/abandon_message_from_queue.bal +++ b/examples/sender_reciever/abandon_message_from_queue.bal @@ -71,16 +71,16 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->abandon(messageReceived); asb:Message|error? messageReceivedAgain = queueReceiver->receive(serverWaitTime); - if (messageReceivedAgain is asb:Message) { + if messageReceivedAgain is asb:Message { check queueReceiver->complete(messageReceivedAgain); log:printInfo("Abandon message successful"); } else { log:printError("Abandon message not succesful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/abandon_message_from_subscription.bal b/examples/sender_reciever/abandon_message_from_subscription.bal index 4be73d67..b128b1b3 100644 --- a/examples/sender_reciever/abandon_message_from_subscription.bal +++ b/examples/sender_reciever/abandon_message_from_subscription.bal @@ -74,16 +74,16 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check subscriptionReceiver->abandon(messageReceived); asb:Message|error? messageReceivedAgain = subscriptionReceiver->receive(serverWaitTime); - if (messageReceivedAgain is asb:Message) { + if messageReceivedAgain is asb:Message { check subscriptionReceiver->complete(messageReceivedAgain); log:printInfo("Abandon message successful"); } else { log:printError("Abandon message not succesful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the subscription."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/complete_message_from_dead_letter_queue.bal b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal index 27f0b0c1..f9fa457a 100644 --- a/examples/sender_reciever/complete_message_from_dead_letter_queue.bal +++ b/examples/sender_reciever/complete_message_from_dead_letter_queue.bal @@ -71,7 +71,7 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { //deadLetter the message check queueReceiver->deadLetter(messageReceived); @@ -79,12 +79,12 @@ public function main() returns error? { //get message from DLQ log:printInfo("Receiving from DLQ via Asb receiver client."); asb:Message|error? messageReceivedFromDLQ = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (messageReceivedFromDLQ is asb:Message) { + if messageReceivedFromDLQ is asb:Message { //Check whether the message received from DLQ log:printInfo("Message received from DLQ."); string? message_id = messageReceivedFromDLQ.messageId; - if (message_id is string) { + if message_id is string { log:printInfo("DLQ Top Message ID: " + message_id); } @@ -95,23 +95,23 @@ public function main() returns error? { //Receive the message from DLQ after complete log:printInfo("Receiving from DLQ via Asb receiver client after complete."); asb:Message|error? checkReceivingDLQAfterComplete = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (checkReceivingDLQAfterComplete is asb:Message) { //if there are any messages in the DLQ + if checkReceivingDLQAfterComplete is asb:Message { //if there are any messages in the DLQ log:printInfo("Message received from DLQ."); message_id = checkReceivingDLQAfterComplete.messageId; - if (message_id is string) { + if message_id is string { log:printInfo("DLQ Top Message ID: " + message_id); } - } else if (checkReceivingDLQAfterComplete is ()) { //if there are no messages in the DLQ + } else if checkReceivingDLQAfterComplete is () { //if there are no messages in the DLQ log:printError("No message in the deadletter queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); } - } else if (messageReceivedFromDLQ is ()) { + } else if messageReceivedFromDLQ is () { log:printError("No message in the DLQ."); } else { log:printError("Receiving message via ASBReceiver:DLQ connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/complete_message_from_queue.bal b/examples/sender_reciever/complete_message_from_queue.bal index 8da86547..bfedd5f2 100644 --- a/examples/sender_reciever/complete_message_from_queue.bal +++ b/examples/sender_reciever/complete_message_from_queue.bal @@ -70,10 +70,10 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->complete(messageReceived); log:printInfo("Complete message successful"); - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/complete_message_from_subscription.bal b/examples/sender_reciever/complete_message_from_subscription.bal index ffc50a78..28f96eda 100644 --- a/examples/sender_reciever/complete_message_from_subscription.bal +++ b/examples/sender_reciever/complete_message_from_subscription.bal @@ -72,10 +72,10 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check subscriptionReceiver->complete(messageReceived); log:printInfo("Complete message successful"); - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the subscription."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/deadletter_from_queue.bal b/examples/sender_reciever/deadletter_from_queue.bal index d8ff2c59..ccc874b2 100644 --- a/examples/sender_reciever/deadletter_from_queue.bal +++ b/examples/sender_reciever/deadletter_from_queue.bal @@ -70,15 +70,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->deadLetter(messageReceived); asb:Message|error? messageReceivedAgain = queueReceiver->receive(serverWaitTime); - if (messageReceivedAgain is ()) { + if messageReceivedAgain is () { log:printInfo("Deadletter message successful"); } else { log:printError("Deadletter message not succesful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/deadletter_from_subscription.bal b/examples/sender_reciever/deadletter_from_subscription.bal index 757361f8..112e355d 100644 --- a/examples/sender_reciever/deadletter_from_subscription.bal +++ b/examples/sender_reciever/deadletter_from_subscription.bal @@ -72,15 +72,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check subscriptionReceiver->deadLetter(messageReceived); asb:Message|error? messageReceivedAgain = subscriptionReceiver->receive(serverWaitTime); - if (messageReceivedAgain is ()) { + if messageReceivedAgain is () { log:printInfo("Deadletter message successful"); } else { log:printError("Deadletter message not succesful."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the subscription."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/defer_from_queue.bal b/examples/sender_reciever/defer_from_queue.bal index 6058c2cf..382170e2 100644 --- a/examples/sender_reciever/defer_from_queue.bal +++ b/examples/sender_reciever/defer_from_queue.bal @@ -70,15 +70,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { int sequenceNumber = check queueReceiver->defer(messageReceived); log:printInfo("Defer message successful"); asb:Message|error? messageReceivedAgain = check queueReceiver->receiveDeferred(sequenceNumber); - if (messageReceivedAgain is asb:Message) { + if messageReceivedAgain is asb:Message { log:printInfo("Reading Deferred Message : " + messageReceivedAgain.toString()); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/defer_from_subscription.bal b/examples/sender_reciever/defer_from_subscription.bal index e0f47be7..036194f1 100644 --- a/examples/sender_reciever/defer_from_subscription.bal +++ b/examples/sender_reciever/defer_from_subscription.bal @@ -72,14 +72,14 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { int sequenceNumber = check subscriptionReceiver->defer(messageReceived); log:printInfo("Defer message successful"); asb:Message|error? messageReceivedAgain = subscriptionReceiver->receiveDeferred(sequenceNumber); - if (messageReceivedAgain is asb:Message) { + if messageReceivedAgain is asb:Message { log:printInfo("Reading Deferred Message : " + messageReceivedAgain.toString()); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the subscription."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal b/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal index 547a868a..1b3df075 100644 --- a/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal +++ b/examples/sender_reciever/receive_messages_from_dead_letter_queue.bal @@ -70,20 +70,20 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->deadLetter(messageReceived); asb:Message|error? messageReceivedFromDLQ = queueReceiver->receive(serverWaitTime, deadLettered = true); - if (messageReceivedFromDLQ is asb:Message) { + if messageReceivedFromDLQ is asb:Message { log:printInfo("Message received from DLQ."); string message_str = check string:fromBytes(messageReceivedFromDLQ.body); log:printInfo("DLQ Message content: " + message_str); - } else if (messageReceivedFromDLQ is ()) { + } else if messageReceivedFromDLQ is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal b/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal index ff7b9e8b..ac2edff5 100644 --- a/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal +++ b/examples/sender_reciever/receive_messages_from_dead_letter_subscription.bal @@ -73,20 +73,20 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check subscriptionReceiver->deadLetter(messageReceived); asb:Message|error? messageReceivedFromDLQ = subscriptionReceiver->receive(serverWaitTime, deadLettered = true); - if (messageReceivedFromDLQ is asb:Message) { + if messageReceivedFromDLQ is asb:Message { log:printInfo("Message received from DLQ."); string message_str = check string:fromBytes(messageReceivedFromDLQ.body); log:printInfo("DLQ Message content: " + message_str); - } else if (messageReceivedFromDLQ is ()) { + } else if messageReceivedFromDLQ is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal b/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal index 985b3579..d857276f 100644 --- a/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal +++ b/examples/sender_reciever/receive_payload_from_dead_letter_queue.bal @@ -1,4 +1,3 @@ - // Copyright (c) 2023 WSO2 LLC. (http://www.wso2.org). // // WSO2 LLS. licenses this file to you under the Apache License, @@ -71,15 +70,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->deadLetter(messageReceived); byte[]|error? bytePayload = queueReceiver->receivePayload(serverWaitTime, deadLettered = true); - if (bytePayload is byte[]) { + if bytePayload is byte[] { log:printInfo("Received message from DLQ: " + bytePayload.toString()); } else { log:printError("Receiving message via Asb receiver connection failed."); } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/renew_lock_on_message_from_queue.bal b/examples/sender_reciever/renew_lock_on_message_from_queue.bal index 43d469d8..21a49add 100644 --- a/examples/sender_reciever/renew_lock_on_message_from_queue.bal +++ b/examples/sender_reciever/renew_lock_on_message_from_queue.bal @@ -75,10 +75,10 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check queueReceiver->renewLock(messageReceived); log:printInfo("Renew lock message successful"); - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/renew_lock_on_message_from_subscription.bal b/examples/sender_reciever/renew_lock_on_message_from_subscription.bal index eed2dc37..bcde3fbd 100644 --- a/examples/sender_reciever/renew_lock_on_message_from_subscription.bal +++ b/examples/sender_reciever/renew_lock_on_message_from_subscription.bal @@ -77,11 +77,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|asb:Error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { check subscriptionReceiver->renewLock(messageReceived); asb:Message|asb:Error? messageReceivedAgain = subscriptionReceiver->receive(serverWaitTime); - log:printInfo("Renew lock message successful"); - } else if (messageReceived is ()) { + if messageReceivedAgain is asb:Message { + log:printInfo("Message received again after renewing lock."); + } else { + log:printError("Receiving message via Asb receiver connection failed."); + } + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/send_and_receive_batch_from_queue.bal b/examples/sender_reciever/send_and_receive_batch_from_queue.bal index 0e45a482..d234b07d 100644 --- a/examples/sender_reciever/send_and_receive_batch_from_queue.bal +++ b/examples/sender_reciever/send_and_receive_batch_from_queue.bal @@ -76,13 +76,13 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:MessageBatch|error? messageReceived = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime); - if (messageReceived is asb:MessageBatch) { + if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString( != "") { log:printInfo("Reading Received Message : " + message.toString()); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal index 4f312e97..ed7ada55 100644 --- a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal @@ -78,15 +78,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:MessageBatch|error? messageReceived = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime); - if (messageReceived is asb:MessageBatch) { + if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString( != "") { log:printInfo("Reading Received Message : " + message.toString()); // Dead-lettering the received message check queueReceiver->deadLetter(message); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -95,13 +95,13 @@ public function main() returns error? { log:printInfo("Receiving from Asb dead-letter receiver client."); asb:MessageBatch|error? receivedDeadletterMessages = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); - if (receivedDeadletterMessages is asb:MessageBatch) { + if receivedDeadletterMessages is asb:MessageBatch { foreach asb:Message message in receivedDeadletterMessages.messages { - if (message.toString() != "") { + if message.toString( != "") { log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); } } - } else if (receivedDeadletterMessages is ()) { + } else if receivedDeadletterMessages is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal index 712e4d70..455923be 100644 --- a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal @@ -80,15 +80,15 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:MessageBatch|error? messageReceived = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime); - if (messageReceived is asb:MessageBatch) { + if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString( != "") { log:printInfo("Reading Received Message : " + message.toString()); // Dead-lettering the received message check queueReceiver->deadLetter(message); } } - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); @@ -97,13 +97,13 @@ public function main() returns error? { log:printInfo("Receiving from Asb dead-letter receiver client."); asb:MessageBatch|error? receivedDeadletterMessages = queueReceiver->receiveBatch(maxMessageCount, serverWaitTime, true); - if (receivedDeadletterMessages is asb:MessageBatch) { + if receivedDeadletterMessages is asb:MessageBatch { foreach asb:Message message in receivedDeadletterMessages.messages { - if (message.toString() != "") { + if message.toString( != "") { log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); } } - } else if (receivedDeadletterMessages is ()) { + } else if receivedDeadletterMessages is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/send_and_receive_message_from_queue.bal b/examples/sender_reciever/send_and_receive_message_from_queue.bal index ef8c2ca9..ae8dcb98 100644 --- a/examples/sender_reciever/send_and_receive_message_from_queue.bal +++ b/examples/sender_reciever/send_and_receive_message_from_queue.bal @@ -69,9 +69,9 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|asb:Error? messageReceived = queueReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { log:printInfo("Reading Received Message : " + messageReceived.toString()); - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the queue."); } else { log:printError("Receiving message via Asb receiver connection failed."); diff --git a/examples/sender_reciever/send_and_receive_payload.bal b/examples/sender_reciever/send_and_receive_payload.bal index b0a96e56..c8310412 100644 --- a/examples/sender_reciever/send_and_receive_payload.bal +++ b/examples/sender_reciever/send_and_receive_payload.bal @@ -59,7 +59,7 @@ public function main() returns error? { byte[]|error? bytePayload = messageReceiver->receivePayload(serverWaitTime); log:printInfo("Asserting received payloads."); - if (bytePayload is byte[]) { + if bytePayload is byte[] { string stringPayload = check string:fromBytes(bytePayload); log:printInfo("Received message: " + stringPayload); } else { diff --git a/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal b/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal index c44d2592..af8dfa66 100644 --- a/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal +++ b/examples/sender_reciever/send_batch_to_topic_and_receive_from_subscription.bal @@ -81,7 +81,7 @@ public function main() returns error? { if (messageReceived is asb:MessageBatch) { foreach asb:Message message in messageReceived.messages { - if (message.toString() != "") { + if message.toString() != "" { log:printInfo("Reading Received Message : " + message.toString()); } } diff --git a/examples/sender_reciever/send_to_topic_and_receive_from_subscription.bal b/examples/sender_reciever/send_to_topic_and_receive_from_subscription.bal index 4dd39e66..f65b6656 100644 --- a/examples/sender_reciever/send_to_topic_and_receive_from_subscription.bal +++ b/examples/sender_reciever/send_to_topic_and_receive_from_subscription.bal @@ -72,9 +72,9 @@ public function main() returns error? { log:printInfo("Receiving from Asb receiver client."); asb:Message|error? messageReceived = subscriptionReceiver->receive(serverWaitTime); - if (messageReceived is asb:Message) { + if messageReceived is asb:Message { log:printInfo("Reading Received Message : " + messageReceived.toString()); - } else if (messageReceived is ()) { + } else if messageReceived is () { log:printError("No message in the subscription."); } else { log:printError("Receiving message via Asb receiver connection failed."); From ab8e2e02d8abb2517b1839155b1ea633d590a153 Mon Sep 17 00:00:00 2001 From: RDPerera Date: Thu, 24 Aug 2023 10:07:22 +0530 Subject: [PATCH 06/10] Change to a native data-based client handling approach --- ballerina/admin.bal | 10 +---- ballerina/sender.bal | 40 ++++++------------- .../ballerinax/asb/admin/Administrator.java | 15 ++++--- .../asb/receiver/MessageReceiver.java | 4 +- .../ballerinax/asb/sender/MessageSender.java | 40 ++++++++++--------- .../org/ballerinax/asb/util/ASBConstants.java | 4 +- .../ballerinax/asb/util/ASBErrorCreator.java | 2 +- .../org/ballerinax/asb/util/ASBUtils.java | 2 +- .../org/ballerinax/asb/util/ModuleUtils.java | 4 +- 9 files changed, 55 insertions(+), 66 deletions(-) diff --git a/ballerina/admin.bal b/ballerina/admin.bal index 0848353d..5dff76e2 100644 --- a/ballerina/admin.bal +++ b/ballerina/admin.bal @@ -21,8 +21,6 @@ import ballerina/jballerina.java as java; @display {label: "Azure Service Bus Administrator", iconPath: "icon.png"} public isolated client class Administrator { - final handle adminHandle; - # Initialize the Azure Service Bus Admin client. # Create an [Azure account](https://docs.microsoft.com/en-us/learn/modules/create-an-azure-account/) and # obtain tokens following [this guide](https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-quickstart-portal#get-the-connection-string). @@ -30,11 +28,7 @@ public isolated client class Administrator { # # + connectionString - Azure Service Bus connection string public isolated function init(@display {label: "Azure Service Bus connection string"} string connectionString) returns Error? { - handle|Error initResult = initializeAdmin(java:fromString(connectionString)); - if (initResult is Error) { - return initResult; - } - self.adminHandle = initResult; + check initializeAdministrator(self, java:fromString(connectionString)); } # Create a topic with the given name or name and options. @@ -264,6 +258,6 @@ public isolated client class Administrator { } external; } -isolated function initializeAdmin(handle connectionString) returns handle|Error = @java:Method { +isolated function initializeAdministrator(Administrator adminClient, handle connectionString) returns Error? = @java:Method { 'class: "org.ballerinax.asb.admin.Administrator" } external; diff --git a/ballerina/sender.bal b/ballerina/sender.bal index 9c5f548b..c1591130 100644 --- a/ballerina/sender.bal +++ b/ballerina/sender.bal @@ -1,6 +1,6 @@ -// Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. +// Copyright (c) 2023 WSO2 LLC. // -// WSO2 Inc. licenses this file to you under the Apache License, +// WSO2 LLC. licenses this file to you under the Apache License, // Version 2.0 (the "License"); you may not use this file except // in compliance with the License. // You may obtain a copy of the License at @@ -23,7 +23,6 @@ import ballerina/time; public isolated client class MessageSender { private string connectionString; - final handle senderHandle; private string topicOrQueueName; private string entityType; private LogLevel logLevel; @@ -40,14 +39,9 @@ public isolated client class MessageSender { self.topicOrQueueName = config.topicOrQueueName; self.entityType = config.entityType; self.logLevel = customConfiguration.logLevel; - handle|Error initResult = initMessageSender(java:fromString(self.connectionString), + check initializeSender(self, java:fromString(self.connectionString), java:fromString(self.entityType), java:fromString(self.topicOrQueueName), java:fromString(self.logLevel), config.amqpRetryOptions); - if (initResult is Error) { - return initResult; - } - - self.senderHandle = initResult; } # Send message to queue or topic with a message body. @@ -87,9 +81,9 @@ public isolated client class MessageSender { # # + sequenceNumber - The sequence number of the message to cancel # + return - If the message could not be cancelled - isolated remote function cancel(@display {label: "Sequence Number"} int sequenceNumber) returns Error? { - return cancel(self, sequenceNumber); - } + isolated remote function cancel(@display {label: "Sequence Number"} int sequenceNumber) returns Error? = @java:Method { + 'class: "org.ballerinax.asb.sender.MessageSender" + } external; # Send batch of messages to queue or topic. # @@ -107,32 +101,24 @@ public isolated client class MessageSender { # # + return - An `asb:Error` if failed to close connection or else `()` @display {label: "Close Sender Connection"} - isolated remote function close() returns Error? { - return closeSender(self); - } + isolated remote function close() returns Error? = @java:Method { + 'class: "org.ballerinax.asb.sender.MessageSender" + } external; } -isolated function initMessageSender(handle connectionString, handle entityType, handle topicOrQueueName, handle isLogEnabled, AmqpRetryOptions retryOptions) returns handle|Error = @java:Method { - name: "initializeSender", +isolated function initializeSender(MessageSender senderClient, handle connectionString, handle entityType, handle topicOrQueueName, handle isLogEnabled, AmqpRetryOptions retryOptions) returns Error? = @java:Method { 'class: "org.ballerinax.asb.sender.MessageSender" } external; -isolated function send(MessageSender endpointClient, Message message) returns Error? = @java:Method { +isolated function send(MessageSender senderClient, Message message) returns Error? = @java:Method { 'class: "org.ballerinax.asb.sender.MessageSender" } external; -isolated function sendBatch(MessageSender endpointClient, MessageBatch messages) returns Error? = @java:Method { +isolated function sendBatch(MessageSender senderClient, MessageBatch messages) returns Error? = @java:Method { 'class: "org.ballerinax.asb.sender.MessageSender" } external; -isolated function schedule(MessageSender endpointClient, Message message, time:Civil scheduleTime) returns int|Error = @java:Method { +isolated function schedule(MessageSender senderClient, Message message, time:Civil scheduleTime) returns int|Error = @java:Method { 'class: "org.ballerinax.asb.sender.MessageSender" } external; -isolated function cancel(MessageSender endpointClient, int sequenceNumber) returns Error? = @java:Method { - 'class: "org.ballerinax.asb.sender.MessageSender" -} external; - -isolated function closeSender(MessageSender endpointClient) returns Error? = @java:Method { - 'class: "org.ballerinax.asb.sender.MessageSender" -} external; diff --git a/native/src/main/java/org/ballerinax/asb/admin/Administrator.java b/native/src/main/java/org/ballerinax/asb/admin/Administrator.java index ec9f7c11..c8196ea4 100644 --- a/native/src/main/java/org/ballerinax/asb/admin/Administrator.java +++ b/native/src/main/java/org/ballerinax/asb/admin/Administrator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -42,7 +42,6 @@ import io.ballerina.runtime.api.utils.TypeUtils; import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BError; -import io.ballerina.runtime.api.values.BHandle; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; @@ -74,12 +73,13 @@ public class Administrator { * @param connectionString Azure service bus connection string * @return clientEp Azure Service Bus Administrator instance. */ - public static Object initializeAdmin(String connectionString) { + public static Object initializeAdministrator(BObject administratorClient, String connectionString) { try { ServiceBusAdministrationClientBuilder administratorBuilder = new ServiceBusAdministrationClientBuilder() .connectionString(connectionString); LOGGER.debug("ServiceBusAdministrator initialized"); - return administratorBuilder.buildClient(); + setClient(administratorClient, administratorBuilder.buildClient()); + return null; } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -913,8 +913,7 @@ private static Map populateQueueOptionalFieldsMap(QueuePropertie } private static ServiceBusAdministrationClient getAdminFromBObject(BObject adminObject) { - BHandle adminHandle = (BHandle) adminObject.get(StringUtils.fromString("adminHandle")); - return (ServiceBusAdministrationClient) adminHandle.getValue(); + return (ServiceBusAdministrationClient) adminObject.getNativeData(ASBConstants.ADMINISTRATOR_CLIENT); } private static BMap fromDuration(Duration duration) { @@ -987,6 +986,10 @@ private static BArray constructAuthorizationRuleArray(List au return authorizationRuleArray; } + private static void setClient(BObject administratorObject, ServiceBusAdministrationClient client) { + administratorObject.addNativeData(ASBConstants.ADMINISTRATOR_CLIENT, client); + } + private static BArray constructAccessRightsArray(List accessRights) { BArray accessRightsArray = ValueCreator.createArrayValue( TypeCreator.createArrayType(PredefinedTypes.TYPE_STRING)); diff --git a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java index c265f76d..8225a061 100644 --- a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java +++ b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2021, WSO2 LLC. (http://www.wso2.org). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at diff --git a/native/src/main/java/org/ballerinax/asb/sender/MessageSender.java b/native/src/main/java/org/ballerinax/asb/sender/MessageSender.java index cb74a039..ff794e0b 100644 --- a/native/src/main/java/org/ballerinax/asb/sender/MessageSender.java +++ b/native/src/main/java/org/ballerinax/asb/sender/MessageSender.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at @@ -33,7 +33,6 @@ import io.ballerina.runtime.api.values.BArray; import io.ballerina.runtime.api.values.BDecimal; import io.ballerina.runtime.api.values.BError; -import io.ballerina.runtime.api.values.BHandle; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; @@ -67,8 +66,9 @@ public class MessageSender { * @param topicOrQueueName Queue/topic name * @throws ServiceBusException on failure initiating IMessage Receiver in Azure Service Bus instance. */ - public static Object initializeSender(String connectionString, String entityType, String topicOrQueueName, - String logLevel, BMap retryConfigs) { + public static Object initializeSender(BObject senderClient, String connectionString, String entityType, + String topicOrQueueName, String logLevel, + BMap retryConfigs) { try { AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); ServiceBusSenderClientBuilder senderClientBuilder = new ServiceBusClientBuilder() @@ -81,7 +81,8 @@ public static Object initializeSender(String connectionString, String entityType senderClientBuilder.topicName(topicOrQueueName); } LOGGER.debug("ServiceBusSenderClient initialized"); - return senderClientBuilder.buildClient(); + setClient(senderClient, senderClientBuilder.buildClient()); + return null; } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -97,9 +98,9 @@ public static Object initializeSender(String connectionString, String entityType * @param message Input message record as a BMap * @return An error if failed to send the message */ - public static Object send(BObject endpointClient, BMap message) { + public static Object send(BObject senderClient, BMap message) { try { - ServiceBusSenderClient sender = getSenderFromBObject(endpointClient); + ServiceBusSenderClient sender = getSenderFromBObject(senderClient); ServiceBusMessage messageToSend = constructMessage(message); sender.sendMessage(messageToSend); if (LOGGER.isDebugEnabled()) { @@ -123,10 +124,10 @@ public static Object send(BObject endpointClient, BMap message) * @param scheduleTime Input schedule time record as a BMap * @return An error if failed to send the message */ - public static Object schedule(BObject endpointClient, BMap message, + public static Object schedule(BObject senderClient, BMap message, BMap scheduleTime) { try { - ServiceBusSenderClient sender = getSenderFromBObject(endpointClient); + ServiceBusSenderClient sender = getSenderFromBObject(senderClient); ServiceBusMessage messageToSend = constructMessage(message); Long sequenceNumber = sender.scheduleMessage(messageToSend, constructOffset(scheduleTime)); if (LOGGER.isDebugEnabled()) { @@ -148,9 +149,9 @@ public static Object schedule(BObject endpointClient, BMap mess * @param sequenceNumber The sequence number of the message to cance * @return An error if failed to send the message */ - public static Object cancel(BObject endpointClient, long sequenceNumber) { + public static Object cancel(BObject senderClient, long sequenceNumber) { try { - ServiceBusSenderClient sender = getSenderFromBObject(endpointClient); + ServiceBusSenderClient sender = getSenderFromBObject(senderClient); sender.cancelScheduledMessage(sequenceNumber); if (LOGGER.isDebugEnabled()) { LOGGER.debug("Successfully cancelled scheduled message with sequenceNumber = " + sequenceNumber); @@ -173,9 +174,9 @@ public static Object cancel(BObject endpointClient, long sequenceNumber) { * @param messages Input batch message record as a BMap * @return An error if failed send the message. */ - public static Object sendBatch(BObject endpointClient, BMap messages) { + public static Object sendBatch(BObject senderClient, BMap messages) { try { - ServiceBusSenderClient sender = getSenderFromBObject(endpointClient); + ServiceBusSenderClient sender = getSenderFromBObject(senderClient); Map messagesMap = ASBUtils.toObjectMap(messages); BArray messageArray = (BArray) messagesMap.get("messages"); Collection messageBatch = new ArrayList<>(); @@ -221,9 +222,9 @@ public static Object sendBatch(BObject endpointClient, BMap mes * * @return @return An error if failed close the sender. */ - public static Object closeSender(BObject endpointClient) { + public static Object close(BObject senderClient) { try { - ServiceBusSenderClient sender = getSenderFromBObject(endpointClient); + ServiceBusSenderClient sender = getSenderFromBObject(senderClient); sender.close(); LOGGER.debug("Closed the sender. Identifier=" + sender.getIdentifier()); return null; @@ -330,8 +331,11 @@ private static OffsetDateTime constructOffset(BMap scheduleTime return OffsetDateTime.of(year, month, day, hour, minute, seconds, 0, zoneOffset); } + private static void setClient(BObject senderObject, ServiceBusSenderClient client) { + senderObject.addNativeData(ASBConstants.SENDER_CLIENT, client); + } + private static ServiceBusSenderClient getSenderFromBObject(BObject senderObject) { - BHandle senderHandle = (BHandle) senderObject.get(StringUtils.fromString("senderHandle")); - return (ServiceBusSenderClient) senderHandle.getValue(); + return (ServiceBusSenderClient) senderObject.getNativeData(ASBConstants.SENDER_CLIENT); } } diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java b/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java index 4f3bf2ce..77e11c99 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBConstants.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except @@ -28,6 +28,8 @@ public class ASBConstants { //Clients public static final String RECEIVER_CLIENT = "RECEIVER_CLIENT"; + public static final String ADMINISTRATOR_CLIENT = "ADMINISTRATOR_CLIENT"; + public static final String SENDER_CLIENT = "SENDER_CLIENT"; public static final String DEAD_LETTER_RECEIVER_CLIENT = "DEAD_LETTER_RECEIVER_CLIENT"; //Client Init Data diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBErrorCreator.java b/native/src/main/java/org/ballerinax/asb/util/ASBErrorCreator.java index da5a0e7d..7920e9b1 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBErrorCreator.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBErrorCreator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java index 115af409..a5fa53f8 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org). * * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except diff --git a/native/src/main/java/org/ballerinax/asb/util/ModuleUtils.java b/native/src/main/java/org/ballerinax/asb/util/ModuleUtils.java index c206922c..6a51bca8 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ModuleUtils.java +++ b/native/src/main/java/org/ballerinax/asb/util/ModuleUtils.java @@ -1,7 +1,7 @@ /* - * Copyright (c) 2021 WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * Copyright (c) 2021 WSO2 LLC. (http://www.wso2.org). * - * WSO2 Inc. licenses this file to you under the Apache License, + * WSO2 LLC. licenses this file to you under the Apache License, * Version 2.0 (the "License"); you may not use this file except * in compliance with the License. * You may obtain a copy of the License at From 1056d6b7d6832483e4f2ca5e26708bbc771e91d4 Mon Sep 17 00:00:00 2001 From: RDPerera Date: Thu, 24 Aug 2023 10:12:36 +0530 Subject: [PATCH 07/10] Change deadLetterReason to DEADLETTERED_BY_USER --- ballerina/receiver.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/receiver.bal b/ballerina/receiver.bal index 012cb07f..5a50a15f 100644 --- a/ballerina/receiver.bal +++ b/ballerina/receiver.bal @@ -145,7 +145,7 @@ public isolated client class MessageReceiver { # + return - An `asb:Error` if failed to deadletter message or else `()` @display {label: "Dead Letter Message"} isolated remote function deadLetter(@display {label: "Message"} Message message, - @display {label: "Dead Letter Reason"} string? deadLetterReason = "MANUALLY_DEADLETTERED", + @display {label: "Dead Letter Reason"} string? deadLetterReason = "DEADLETTERED_BY_USER", @display {label: "Dead Letter Description"} string? deadLetterErrorDescription = ()) returns Error? { if message?.lockToken.toString() != DEFAULT_MESSAGE_LOCK_TOKEN { From 94eb29622e9c9f92ed71964bb25c5d62151b9c5e Mon Sep 17 00:00:00 2001 From: RDPerera Date: Thu, 24 Aug 2023 11:10:32 +0530 Subject: [PATCH 08/10] Fix dead-letter examples --- .../sender_reciever/send_and_receive_batch_from_queue.bal | 2 +- ...send_and_receive_batch_messages_from_dead_letter_queue.bal | 4 ++-- ...d_receive_batch_messages_from_dead_letter_subscription.bal | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/sender_reciever/send_and_receive_batch_from_queue.bal b/examples/sender_reciever/send_and_receive_batch_from_queue.bal index d234b07d..549b2d5b 100644 --- a/examples/sender_reciever/send_and_receive_batch_from_queue.bal +++ b/examples/sender_reciever/send_and_receive_batch_from_queue.bal @@ -78,7 +78,7 @@ public function main() returns error? { if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if message.toString( != "") { + if message.toString() != "" { log:printInfo("Reading Received Message : " + message.toString()); } } diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal index ed7ada55..c9956ae2 100644 --- a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_queue.bal @@ -80,7 +80,7 @@ public function main() returns error? { if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if message.toString( != "") { + if message.toString() != ""{ log:printInfo("Reading Received Message : " + message.toString()); // Dead-lettering the received message check queueReceiver->deadLetter(message); @@ -97,7 +97,7 @@ public function main() returns error? { if receivedDeadletterMessages is asb:MessageBatch { foreach asb:Message message in receivedDeadletterMessages.messages { - if message.toString( != "") { + if message.toString() != "" { log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); } } diff --git a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal index 455923be..b71287e5 100644 --- a/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal +++ b/examples/sender_reciever/send_and_receive_batch_messages_from_dead_letter_subscription.bal @@ -82,7 +82,7 @@ public function main() returns error? { if messageReceived is asb:MessageBatch { foreach asb:Message message in messageReceived.messages { - if message.toString( != "") { + if message.toString() != "" { log:printInfo("Reading Received Message : " + message.toString()); // Dead-lettering the received message check queueReceiver->deadLetter(message); @@ -99,7 +99,7 @@ public function main() returns error? { if receivedDeadletterMessages is asb:MessageBatch { foreach asb:Message message in receivedDeadletterMessages.messages { - if message.toString( != "") { + if message.toString() != "" { log:printInfo("Reading Received Dead-Letter Message : " + message.toString()); } } From 8a6b1b4269cecfe39bd7804294dd6edce8e11cf0 Mon Sep 17 00:00:00 2001 From: RDPerera Date: Fri, 25 Aug 2023 07:35:15 +0530 Subject: [PATCH 09/10] Address review changes --- ballerina/receiver.bal | 2 +- .../asb/receiver/MessageReceiver.java | 128 +++++------------- .../org/ballerinax/asb/util/ASBUtils.java | 109 ++++++++++++++- 3 files changed, 140 insertions(+), 99 deletions(-) diff --git a/ballerina/receiver.bal b/ballerina/receiver.bal index 5a50a15f..f2a54daf 100644 --- a/ballerina/receiver.bal +++ b/ballerina/receiver.bal @@ -145,7 +145,7 @@ public isolated client class MessageReceiver { # + return - An `asb:Error` if failed to deadletter message or else `()` @display {label: "Dead Letter Message"} isolated remote function deadLetter(@display {label: "Message"} Message message, - @display {label: "Dead Letter Reason"} string? deadLetterReason = "DEADLETTERED_BY_USER", + @display {label: "Dead Letter Reason"} string deadLetterReason = "DEADLETTERED_BY_RECEIVER", @display {label: "Dead Letter Description"} string? deadLetterErrorDescription = ()) returns Error? { if message?.lockToken.toString() != DEFAULT_MESSAGE_LOCK_TOKEN { diff --git a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java index 8225a061..3942cf2f 100644 --- a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java +++ b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java @@ -22,14 +22,11 @@ import com.azure.core.amqp.models.AmqpAnnotatedMessage; import com.azure.core.amqp.models.AmqpMessageBodyType; import com.azure.core.util.IterableStream; -import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.ServiceBusClientBuilder.ServiceBusReceiverClientBuilder; import com.azure.messaging.servicebus.ServiceBusException; import com.azure.messaging.servicebus.ServiceBusReceivedMessage; import com.azure.messaging.servicebus.ServiceBusReceiverClient; import com.azure.messaging.servicebus.models.DeadLetterOptions; -import com.azure.messaging.servicebus.models.ServiceBusReceiveMode; -import com.azure.messaging.servicebus.models.SubQueue; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; @@ -55,7 +52,6 @@ import java.util.HashMap; import java.util.LinkedList; import java.util.Map; -import java.util.Objects; import java.util.Optional; import static io.ballerina.runtime.api.creators.ValueCreator.createRecordValue; @@ -75,7 +71,6 @@ import static org.ballerinax.asb.util.ASBConstants.MESSAGE_ID; import static org.ballerinax.asb.util.ASBConstants.PARTITION_KEY; import static org.ballerinax.asb.util.ASBConstants.RECEIVER_CLIENT; -import static org.ballerinax.asb.util.ASBConstants.RECEIVE_AND_DELETE; import static org.ballerinax.asb.util.ASBConstants.REPLY_TO; import static org.ballerinax.asb.util.ASBConstants.REPLY_TO_SESSION_ID; import static org.ballerinax.asb.util.ASBConstants.SEQUENCE_NUMBER; @@ -83,11 +78,13 @@ import static org.ballerinax.asb.util.ASBConstants.STATE; import static org.ballerinax.asb.util.ASBConstants.TIME_TO_LIVE; import static org.ballerinax.asb.util.ASBConstants.TO; -import static org.ballerinax.asb.util.ASBUtils.addMessageFieldIfPresent; +import static org.ballerinax.asb.util.ASBUtils.addFieldIfPresent; import static org.ballerinax.asb.util.ASBUtils.convertAMQPToJava; import static org.ballerinax.asb.util.ASBUtils.convertJavaToBValue; +import static org.ballerinax.asb.util.ASBUtils.deadLetterReceiverBuilder; import static org.ballerinax.asb.util.ASBUtils.getRetryOptions; import static org.ballerinax.asb.util.ASBUtils.getValueWithIntendedType; +import static org.ballerinax.asb.util.ASBUtils.receiverBuilder; /** * This facilitates the client operations of MessageReceiver client in @@ -117,35 +114,11 @@ public static Object initializeReceiver(BObject receiverClient, String connectio String logLevel, BMap retryConfigs) { try { AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); - ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() - .connectionString(connectionString) - .retryOptions(retryOptions) - .receiver(); - if (!queueName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .queueName(queueName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .queueName(queueName) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } - } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .topicName(topicName) - .subscriptionName(subscriptionName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .topicName(topicName) - .subscriptionName(subscriptionName) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } - } + ServiceBusReceiverClientBuilder receiverClientBuilder = receiverBuilder(retryOptions, connectionString, + queueName, receiveMode, maxAutoLockRenewDuration, topicName, subscriptionName); LOGGER.debug("ServiceBusReceiverClient initialized"); - setInitData(receiverClient, connectionString, queueName, topicName, subscriptionName, receiveMode, - maxAutoLockRenewDuration, logLevel, retryConfigs); - setClient(receiverClient, receiverClientBuilder.buildClient()); + setClient(receiverClient, connectionString, queueName, topicName, subscriptionName, receiveMode, + maxAutoLockRenewDuration, logLevel, retryConfigs, receiverClientBuilder.buildClient()); return null; } catch (BError e) { return ASBErrorCreator.fromBError(e); @@ -512,26 +485,26 @@ private static BMap constructExpectedMessageRecord(BObject rece private static Map populateOptionalFieldsMap(ServiceBusReceivedMessage message) { Map map = new HashMap<>(); - addMessageFieldIfPresent(map, CONTENT_TYPE, message.getContentType()); - addMessageFieldIfPresent(map, MESSAGE_ID, message.getMessageId()); - addMessageFieldIfPresent(map, TO, message.getTo()); - addMessageFieldIfPresent(map, REPLY_TO, message.getReplyTo()); - addMessageFieldIfPresent(map, REPLY_TO_SESSION_ID, message.getReplyToSessionId()); - addMessageFieldIfPresent(map, LABEL, message.getSubject()); - addMessageFieldIfPresent(map, SESSION_ID, message.getSessionId()); - addMessageFieldIfPresent(map, CORRELATION_ID, message.getCorrelationId()); - addMessageFieldIfPresent(map, PARTITION_KEY, message.getPartitionKey()); - addMessageFieldIfPresent(map, TIME_TO_LIVE, message.getTimeToLive().getSeconds()); - addMessageFieldIfPresent(map, SEQUENCE_NUMBER, message.getSequenceNumber()); - addMessageFieldIfPresent(map, LOCK_TOKEN, message.getLockToken()); - addMessageFieldIfPresent(map, DELIVERY_COUNT, message.getDeliveryCount()); - addMessageFieldIfPresent(map, ENQUEUED_TIME, message.getEnqueuedTime().toString()); - addMessageFieldIfPresent(map, ENQUEUED_SEQUENCE_NUMBER, message.getEnqueuedSequenceNumber()); - addMessageFieldIfPresent(map, DEAD_LETTER_ERROR_DESCRIPTION, message.getDeadLetterErrorDescription()); - addMessageFieldIfPresent(map, DEAD_LETTER_REASON, message.getDeadLetterReason()); - addMessageFieldIfPresent(map, DEAD_LETTER_SOURCE, message.getDeadLetterSource()); - addMessageFieldIfPresent(map, STATE, message.getState().toString()); - addMessageFieldIfPresent(map, APPLICATION_PROPERTY_KEY, getApplicationProperties(message)); + addFieldIfPresent(map, CONTENT_TYPE, message.getContentType()); + addFieldIfPresent(map, MESSAGE_ID, message.getMessageId()); + addFieldIfPresent(map, TO, message.getTo()); + addFieldIfPresent(map, REPLY_TO, message.getReplyTo()); + addFieldIfPresent(map, REPLY_TO_SESSION_ID, message.getReplyToSessionId()); + addFieldIfPresent(map, LABEL, message.getSubject()); + addFieldIfPresent(map, SESSION_ID, message.getSessionId()); + addFieldIfPresent(map, CORRELATION_ID, message.getCorrelationId()); + addFieldIfPresent(map, PARTITION_KEY, message.getPartitionKey()); + addFieldIfPresent(map, TIME_TO_LIVE, message.getTimeToLive().getSeconds()); + addFieldIfPresent(map, SEQUENCE_NUMBER, message.getSequenceNumber()); + addFieldIfPresent(map, LOCK_TOKEN, message.getLockToken()); + addFieldIfPresent(map, DELIVERY_COUNT, message.getDeliveryCount()); + addFieldIfPresent(map, ENQUEUED_TIME, message.getEnqueuedTime().toString()); + addFieldIfPresent(map, ENQUEUED_SEQUENCE_NUMBER, message.getEnqueuedSequenceNumber()); + addFieldIfPresent(map, DEAD_LETTER_ERROR_DESCRIPTION, message.getDeadLetterErrorDescription()); + addFieldIfPresent(map, DEAD_LETTER_REASON, message.getDeadLetterReason()); + addFieldIfPresent(map, DEAD_LETTER_SOURCE, message.getDeadLetterSource()); + addFieldIfPresent(map, STATE, message.getState().toString()); + addFieldIfPresent(map, APPLICATION_PROPERTY_KEY, getApplicationProperties(message)); return map; } @@ -657,39 +630,12 @@ private static Object getDeadLetterMessageReceiverFromBObject(BObject receiverOb (BMap) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS); try { AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); - ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() - .connectionString(connectionString) - .retryOptions(retryOptions) - .receiver(); - if (!queueName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .queueName(queueName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .queueName(queueName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } - } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .topicName(topicName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .subscriptionName(subscriptionName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .topicName(topicName) - .subscriptionName(subscriptionName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } - } + ServiceBusReceiverClientBuilder receiverClientBuilder = deadLetterReceiverBuilder(retryOptions, + connectionString, queueName, receiveMode, maxAutoLockRenewDuration, topicName, + subscriptionName); LOGGER.debug("ServiceBusReceiverClient initialized"); setDeadLetterClient(receiverObject, receiverClientBuilder.buildClient()); - return receiverObject.getNativeData( - ASBConstants.DEAD_LETTER_RECEIVER_CLIENT); + return receiverObject.getNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT); } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -700,10 +646,11 @@ private static Object getDeadLetterMessageReceiverFromBObject(BObject receiverOb } } - private static void setInitData(BObject receiverObject, String connectionString, String queueName, - String topicName, String subscriptionName, - String receiveMode, long maxAutoLockRenewDuration, - String logLevel, BMap retryConfigs) { + private static void setClient(BObject receiverObject, String connectionString, String queueName, + String topicName, String subscriptionName, + String receiveMode, long maxAutoLockRenewDuration, + String logLevel, BMap retryConfigs, + ServiceBusReceiverClient client) { receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_CONNECTION_STRING, connectionString); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_QUEUE_NAME, queueName); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_TOPIC_NAME, topicName); @@ -713,9 +660,6 @@ private static void setInitData(BObject receiverObject, String connectionString, maxAutoLockRenewDuration); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_LOG_LEVEL, logLevel); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS, retryConfigs); - } - - private static void setClient(BObject receiverObject, ServiceBusReceiverClient client) { receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT, client); } diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java index a5fa53f8..27aab5d7 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java @@ -20,6 +20,8 @@ import com.azure.core.amqp.AmqpRetryMode; import com.azure.core.amqp.AmqpRetryOptions; +import com.azure.messaging.servicebus.ServiceBusClientBuilder; +import com.azure.messaging.servicebus.ServiceBusClientBuilder.ServiceBusReceiverClientBuilder; import com.azure.messaging.servicebus.administration.models.CreateQueueOptions; import com.azure.messaging.servicebus.administration.models.CreateRuleOptions; import com.azure.messaging.servicebus.administration.models.CreateSubscriptionOptions; @@ -31,6 +33,8 @@ import com.azure.messaging.servicebus.administration.models.SqlRuleFilter; import com.azure.messaging.servicebus.administration.models.SubscriptionProperties; import com.azure.messaging.servicebus.administration.models.TopicProperties; +import com.azure.messaging.servicebus.models.ServiceBusReceiveMode; +import com.azure.messaging.servicebus.models.SubQueue; import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; @@ -76,6 +80,7 @@ import static org.ballerinax.asb.util.ASBConstants.DELAY; import static org.ballerinax.asb.util.ASBConstants.MAX_DELAY; import static org.ballerinax.asb.util.ASBConstants.MAX_RETRIES; +import static org.ballerinax.asb.util.ASBConstants.RECEIVE_AND_DELETE; import static org.ballerinax.asb.util.ASBConstants.RETRY_MODE; import static org.ballerinax.asb.util.ASBConstants.TRY_TIMEOUT; @@ -144,6 +149,104 @@ public static String convertString(Object value) { return (value == null || Objects.equals(value.toString(), "")) ? null : value.toString(); } + /** + * Build the ServiceBusClientBuilder object. + * + * @param retryOptions Retry options. + * @param connectionString Connection string. + * @param queueName Queue name. + * @param receiveMode Receive mode. + * @param maxAutoLockRenewDuration Max auto lock renew duration. + * @param topicName Topic name. + * @param subscriptionName Subscription name. + * @return ServiceBusReceiverClientBuilder object. + */ + public static ServiceBusReceiverClientBuilder receiverBuilder(AmqpRetryOptions retryOptions, + String connectionString, + String queueName, + String receiveMode, + long maxAutoLockRenewDuration, + String topicName, + String subscriptionName) { + ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() + .connectionString(connectionString) + .retryOptions(retryOptions) + .receiver(); + if (!queueName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .queueName(queueName); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .queueName(queueName) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .topicName(topicName) + .subscriptionName(subscriptionName); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .topicName(topicName) + .subscriptionName(subscriptionName) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } + return receiverClientBuilder; + } + + /** + * Build the ServiceBusClientBuilder object. + * + * @param retryOptions Retry options. + * @param connectionString Connection string. + * @param queueName Queue name. + * @param receiveMode Receive mode. + * @param maxAutoLockRenewDuration Max auto lock renew duration. + * @param topicName Topic name. + * @param subscriptionName Subscription name. + * @return ServiceBusReceiverClientBuilder object. + */ + public static ServiceBusReceiverClientBuilder deadLetterReceiverBuilder(AmqpRetryOptions retryOptions, + String connectionString, + String queueName, + String receiveMode, + long maxAutoLockRenewDuration, + String topicName, + String subscriptionName) { + ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() + .connectionString(connectionString) + .retryOptions(retryOptions) + .receiver(); + if (!queueName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .queueName(queueName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .queueName(queueName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { + if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) + .topicName(topicName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .subscriptionName(subscriptionName); + } else { + receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) + .topicName(topicName) + .subscriptionName(subscriptionName) + .subQueue(SubQueue.DEAD_LETTER_QUEUE) + .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + } + return receiverClientBuilder; + } + /** * Get the map value as string or as empty based on the key. * @@ -900,12 +1003,6 @@ private static Object getValueFromJson(Type type, String stringValue) { * @param key Key of the property * @param receivedProperty Received property */ - public static void addMessageFieldIfPresent(Map map, String key, Object receivedProperty) { - if (receivedProperty != null) { - map.put(key, receivedProperty); - } - } - public static void addFieldIfPresent(Map map, String key, Object receivedProperty) { if (receivedProperty != null) { map.put(key, receivedProperty); From 42c4cbb72284bca873ea3e7828e6a75658547207 Mon Sep 17 00:00:00 2001 From: RDPerera Date: Fri, 25 Aug 2023 14:12:08 +0530 Subject: [PATCH 10/10] Address review changes --- .../asb/receiver/MessageReceiver.java | 39 +++---- .../org/ballerinax/asb/util/ASBUtils.java | 100 +++++------------- 2 files changed, 45 insertions(+), 94 deletions(-) diff --git a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java index 3942cf2f..e79d8fa6 100644 --- a/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java +++ b/native/src/main/java/org/ballerinax/asb/receiver/MessageReceiver.java @@ -22,7 +22,6 @@ import com.azure.core.amqp.models.AmqpAnnotatedMessage; import com.azure.core.amqp.models.AmqpMessageBodyType; import com.azure.core.util.IterableStream; -import com.azure.messaging.servicebus.ServiceBusClientBuilder.ServiceBusReceiverClientBuilder; import com.azure.messaging.servicebus.ServiceBusException; import com.azure.messaging.servicebus.ServiceBusReceivedMessage; import com.azure.messaging.servicebus.ServiceBusReceiverClient; @@ -79,12 +78,11 @@ import static org.ballerinax.asb.util.ASBConstants.TIME_TO_LIVE; import static org.ballerinax.asb.util.ASBConstants.TO; import static org.ballerinax.asb.util.ASBUtils.addFieldIfPresent; +import static org.ballerinax.asb.util.ASBUtils.constructReceiverClient; import static org.ballerinax.asb.util.ASBUtils.convertAMQPToJava; import static org.ballerinax.asb.util.ASBUtils.convertJavaToBValue; -import static org.ballerinax.asb.util.ASBUtils.deadLetterReceiverBuilder; import static org.ballerinax.asb.util.ASBUtils.getRetryOptions; import static org.ballerinax.asb.util.ASBUtils.getValueWithIntendedType; -import static org.ballerinax.asb.util.ASBUtils.receiverBuilder; /** * This facilitates the client operations of MessageReceiver client in @@ -114,11 +112,12 @@ public static Object initializeReceiver(BObject receiverClient, String connectio String logLevel, BMap retryConfigs) { try { AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); - ServiceBusReceiverClientBuilder receiverClientBuilder = receiverBuilder(retryOptions, connectionString, - queueName, receiveMode, maxAutoLockRenewDuration, topicName, subscriptionName); + ServiceBusReceiverClient nativeReceiverClient = constructReceiverClient(retryOptions, connectionString, + queueName, receiveMode, maxAutoLockRenewDuration, topicName, subscriptionName, false); + setClientData(receiverClient, connectionString, queueName, topicName, subscriptionName, receiveMode, + maxAutoLockRenewDuration, logLevel, retryConfigs); + setClient(receiverClient, nativeReceiverClient, false); LOGGER.debug("ServiceBusReceiverClient initialized"); - setClient(receiverClient, connectionString, queueName, topicName, subscriptionName, receiveMode, - maxAutoLockRenewDuration, logLevel, retryConfigs, receiverClientBuilder.buildClient()); return null; } catch (BError e) { return ASBErrorCreator.fromBError(e); @@ -630,12 +629,12 @@ private static Object getDeadLetterMessageReceiverFromBObject(BObject receiverOb (BMap) receiverObject.getNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS); try { AmqpRetryOptions retryOptions = getRetryOptions(retryConfigs); - ServiceBusReceiverClientBuilder receiverClientBuilder = deadLetterReceiverBuilder(retryOptions, + ServiceBusReceiverClient nativeReceiverClient = constructReceiverClient(retryOptions, connectionString, queueName, receiveMode, maxAutoLockRenewDuration, topicName, - subscriptionName); + subscriptionName, true); LOGGER.debug("ServiceBusReceiverClient initialized"); - setDeadLetterClient(receiverObject, receiverClientBuilder.buildClient()); - return receiverObject.getNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT); + setClient(receiverObject, nativeReceiverClient, true); + return nativeReceiverClient; } catch (BError e) { return ASBErrorCreator.fromBError(e); } catch (ServiceBusException e) { @@ -646,11 +645,10 @@ private static Object getDeadLetterMessageReceiverFromBObject(BObject receiverOb } } - private static void setClient(BObject receiverObject, String connectionString, String queueName, - String topicName, String subscriptionName, - String receiveMode, long maxAutoLockRenewDuration, - String logLevel, BMap retryConfigs, - ServiceBusReceiverClient client) { + private static void setClientData(BObject receiverObject, String connectionString, String queueName, + String topicName, String subscriptionName, + String receiveMode, long maxAutoLockRenewDuration, + String logLevel, BMap retryConfigs) { receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_CONNECTION_STRING, connectionString); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_QUEUE_NAME, queueName); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_TOPIC_NAME, topicName); @@ -660,10 +658,13 @@ private static void setClient(BObject receiverObject, String connectionString, S maxAutoLockRenewDuration); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_LOG_LEVEL, logLevel); receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT_RETRY_CONFIGS, retryConfigs); - receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT, client); } - private static void setDeadLetterClient(BObject receiverObject, ServiceBusReceiverClient client) { - receiverObject.addNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT, client); + private static void setClient(BObject receiverObject, ServiceBusReceiverClient client, boolean isDeadLetter) { + if (isDeadLetter) { + receiverObject.addNativeData(ASBConstants.DEAD_LETTER_RECEIVER_CLIENT, client); + } else { + receiverObject.addNativeData(ASBConstants.RECEIVER_CLIENT, client); + } } } diff --git a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java index 27aab5d7..3e51bbe8 100644 --- a/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java +++ b/native/src/main/java/org/ballerinax/asb/util/ASBUtils.java @@ -22,6 +22,7 @@ import com.azure.core.amqp.AmqpRetryOptions; import com.azure.messaging.servicebus.ServiceBusClientBuilder; import com.azure.messaging.servicebus.ServiceBusClientBuilder.ServiceBusReceiverClientBuilder; +import com.azure.messaging.servicebus.ServiceBusReceiverClient; import com.azure.messaging.servicebus.administration.models.CreateQueueOptions; import com.azure.messaging.servicebus.administration.models.CreateRuleOptions; import com.azure.messaging.servicebus.administration.models.CreateSubscriptionOptions; @@ -161,90 +162,39 @@ public static String convertString(Object value) { * @param subscriptionName Subscription name. * @return ServiceBusReceiverClientBuilder object. */ - public static ServiceBusReceiverClientBuilder receiverBuilder(AmqpRetryOptions retryOptions, - String connectionString, - String queueName, - String receiveMode, - long maxAutoLockRenewDuration, - String topicName, - String subscriptionName) { + public static ServiceBusReceiverClient constructReceiverClient(AmqpRetryOptions retryOptions, + String connectionString, + String queueName, + String receiveMode, + long maxAutoLockRenewDuration, + String topicName, + String subscriptionName, + boolean isDeadLetterReceiver) { ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() .connectionString(connectionString) .retryOptions(retryOptions) .receiver(); - if (!queueName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .queueName(queueName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .queueName(queueName) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } - } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .topicName(topicName) - .subscriptionName(subscriptionName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .topicName(topicName) - .subscriptionName(subscriptionName) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } + + ServiceBusReceiveMode mode = Objects.equals(receiveMode, RECEIVE_AND_DELETE) + ? ServiceBusReceiveMode.RECEIVE_AND_DELETE + : ServiceBusReceiveMode.PEEK_LOCK; + + if (isDeadLetterReceiver) { + receiverClientBuilder.subQueue(SubQueue.DEAD_LETTER_QUEUE); } - return receiverClientBuilder; - } - /** - * Build the ServiceBusClientBuilder object. - * - * @param retryOptions Retry options. - * @param connectionString Connection string. - * @param queueName Queue name. - * @param receiveMode Receive mode. - * @param maxAutoLockRenewDuration Max auto lock renew duration. - * @param topicName Topic name. - * @param subscriptionName Subscription name. - * @return ServiceBusReceiverClientBuilder object. - */ - public static ServiceBusReceiverClientBuilder deadLetterReceiverBuilder(AmqpRetryOptions retryOptions, - String connectionString, - String queueName, - String receiveMode, - long maxAutoLockRenewDuration, - String topicName, - String subscriptionName) { - ServiceBusReceiverClientBuilder receiverClientBuilder = new ServiceBusClientBuilder() - .connectionString(connectionString) - .retryOptions(retryOptions) - .receiver(); if (!queueName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .queueName(queueName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .queueName(queueName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } + receiverClientBuilder.queueName(queueName); } else if (!subscriptionName.isEmpty() && !topicName.isEmpty()) { - if (Objects.equals(receiveMode, RECEIVE_AND_DELETE)) { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.RECEIVE_AND_DELETE) - .topicName(topicName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .subscriptionName(subscriptionName); - } else { - receiverClientBuilder.receiveMode(ServiceBusReceiveMode.PEEK_LOCK) - .topicName(topicName) - .subscriptionName(subscriptionName) - .subQueue(SubQueue.DEAD_LETTER_QUEUE) - .maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); - } + receiverClientBuilder.topicName(topicName) + .subscriptionName(subscriptionName); } - return receiverClientBuilder; + + if (mode == ServiceBusReceiveMode.PEEK_LOCK) { + receiverClientBuilder.maxAutoLockRenewDuration(Duration.ofSeconds(maxAutoLockRenewDuration)); + } + + return receiverClientBuilder.receiveMode(mode).buildClient(); } /**