From 2cfc9e664fc7fccf505234910ffed1ea02866f86 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 16:25:46 +0530 Subject: [PATCH 01/39] Add basic pub sub support --- ballerina/constants.bal | 44 +++++++++++ ballerina/destination.bal | 24 +++++- ballerina/errors.bal | 13 ++- ballerina/queue_manager.bal | 9 ++- ballerina/types.bal | 12 ++- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 47 ++++++++++- .../lib/ibm.ibmmq/MQThreadFactory.java | 29 +++++++ .../ballerina/lib/ibm.ibmmq/QueueManager.java | 18 +++++ .../io/ballerina/lib/ibm.ibmmq/Topic.java | 79 +++++++++++++++++++ 9 files changed, 268 insertions(+), 7 deletions(-) create mode 100644 ballerina/constants.bal create mode 100644 native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java create mode 100644 native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java diff --git a/ballerina/constants.bal b/ballerina/constants.bal new file mode 100644 index 0000000..c0df91e --- /dev/null +++ b/ballerina/constants.bal @@ -0,0 +1,44 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// +// 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. + +// Option to indicate whether the topic is being opened for either publication or subscription. +public const OPEN_AS_SUBSCRIPTION = 1; +public const OPEN_AS_PUBLICATION = 2; + +// Options that control the opening of the topic for either publication or subscription. +public const MQOO_ALTERNATE_USER_AUTHORITY = 4096; +public const MQOO_BIND_AS_Q_DEF = 0; +public const MQOO_FAIL_IF_QUIESCING = 8192; +public const MQOO_OUTPUT = 16; +public const MQOO_PASS_ALL_CONTEXT = 512; +public const MQOO_PASS_IDENTITY_CONTEXT = 256; +public const MQOO_SET_ALL_CONTEXT = 2048; +public const MQOO_SET_IDENTITY_CONTEXT = 1024; + +// Options related to the the get message in a topic. +public const MQGMO_WAIT = 1; +public const MQGMO_NO_WAIT = 0; +public const MQGMO_SYNCPOINT = 2; +public const MQGMO_NO_SYNCPOINT = 4; +public const MQGMO_BROWSE_FIRST = 16; +public const MQGMO_BROWSE_NEXT = 32; +public const MQGMO_BROWSE_MSG_UNDER_CURSOR = 2048; +public const MQGMO_MSG_UNDER_CURSOR = 256; +public const MQGMO_LOCK = 512; +public const MQGMO_UNLOCK = 1024; +public const MQGMO_ACCEPT_TRUNCATED_MSG = 64; +public const MQGMO_FAIL_IF_QUIESCING = 8192; +public const MQGMO_CONVERT = 16384; \ No newline at end of file diff --git a/ballerina/destination.bal b/ballerina/destination.bal index b214c94..b87ec53 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -13,17 +13,37 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. +import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; - remote function get() returns Message|Error?; + remote function get(GetMessageOptions options = {}) returns Message|Error?; }; public type Queue distinct client object { *Destination; }; -public type Topic distinct client object { +public client class Topic { *Destination; + + remote function put(Message message) returns Error? { + return self.externPut(message); + }; + + remote function get(GetMessageOptions options = {}) returns Message|Error { + return self.externGet(options); + }; + + private isolated function externPut(Message message) returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + } external; + + private isolated function externGet(GetMessageOptions options) returns Message|Error = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + } external; }; + diff --git a/ballerina/errors.bal b/ballerina/errors.bal index 70643ec..2438af3 100644 --- a/ballerina/errors.bal +++ b/ballerina/errors.bal @@ -14,4 +14,15 @@ // specific language governing permissions and limitations // under the License. -public type Error distinct error; +public type Error distinct error; + +# The error details type for the module. +# +# + reasonCode - The reason code for the error +# + errorCode - The error code for the error +# + completionCode - The completion code for the error +public type ErrorDetails record {| + int reasonCode?; + string errorCode?; + int completionCode?; +|}; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 2d63fca..64ffecb 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -31,7 +31,12 @@ public isolated class QueueManager { return error Error("Not implemented"); } - public isolated function accessTopic(string topicName, string topicString, ConnectionOpenOptions options) returns Topic|Error { - return error Error("Not implemented"); + public isolated function accessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error { + return self.externAccessTopic(topicName, topicString, openAs, options); } + + private isolated function externAccessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" + } external; } diff --git a/ballerina/types.bal b/ballerina/types.bal index 47e7f4d..4aed9d7 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -14,6 +14,9 @@ // specific language governing permissions and limitations // under the License. +public type GM_OPTIONS MQGMO_WAIT|MQGMO_NO_WAIT|MQGMO_SYNCPOINT|MQGMO_NO_SYNCPOINT|MQGMO_BROWSE_FIRST|MQGMO_BROWSE_MSG_UNDER_CURSOR|MQGMO_MSG_UNDER_CURSOR|MQGMO_LOCK|MQGMO_UNLOCK|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_BROWSE_NEXT|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_FAIL_IF_QUIESCING|MQGMO_CONVERT; +public type OPEN_AS_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION; + public type QueueManagerConfiguration record {| string name; string host; @@ -24,12 +27,19 @@ public type QueueManagerConfiguration record {| |}; public enum ConnectionOpenOptions { - MQOO_OUTPUT = "MQOO_OUTPUT", + // MQOO_OUTPUT = "MQOO_OUTPUT", MQOO_INPUT_AS_Q_DEF = "MQOO_INPUT_AS_Q_DEF", MQOO_INPUT_EXCLUSIVE = "MQOO_INPUT_EXCLUSIVE", MQOO_INPUT_SHARED = "MQOO_INPUT_SHARED" } +public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT; + +public type GetMessageOptions record {| + GM_OPTIONS options = MQGMO_NO_SYNCPOINT; + int waitInterval = 0; +|}; + public type Property record {| map descriptor; boolean|byte|byte[]|decimal|float|int|string property; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 6d354df..00564b3 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -18,23 +18,68 @@ package io.ballerina.lib.ibm.ibmmq; +import com.ibm.mq.MQException; +import com.ibm.mq.MQMessage; import io.ballerina.runtime.api.creators.ErrorCreator; +import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BString; +import java.io.IOException; import java.util.Optional; +import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; +import static io.ballerina.lib.ibm.ibmmq.ModuleUtils.getModule; + /** * {@code CommonUtils} contains the common utility functions for the Ballerina IBM MQ connector. */ public class CommonUtils { + public static final String BTOPIC = "TOPIC"; + public static final String TOPIC_OBJECT = "TOPIC_OBJECT"; + + private static final String ERROR_DETAILS = "ErrorDetails"; + private static final BString ERROR_REASON_CODE = StringUtils.fromString("ErrorDetails"); + private static final BString ERROR_ERROR_CODE = StringUtils.fromString("ErrorDetails"); + private static final BString ERROR_COMPLETION_CODE = StringUtils.fromString("ErrorDetails"); + private static final BString MESSAGE_PAYLOAD = StringUtils.fromString("payload"); + private static final BString MESSAGE_PROPERTIES = StringUtils.fromString("properties"); + + public static MQMessage getMqMessage(BMap bMessage) { + byte[] payload = bMessage.getArrayValue(MESSAGE_PAYLOAD).getBytes(); + BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); + + MQMessage mqMessage = new MQMessage(); + try { + mqMessage.write(payload); + } catch (IOException e) { + throw createError(IBMMQ_ERROR, + String.format("Error occurred while populating payload: %s", e.getMessage()), e); + } + for (BString key : properties.getKeys()) { + try { + mqMessage.setObjectProperty(key.getValue(), properties.get(key)); + } catch (MQException e) { + throw createError(IBMMQ_ERROR, + String.format("Error occurred while setting message properties: %s", e.getMessage()), e); + } + } + return new MQMessage(); + } + public static BError createError(String errorType, String message, Throwable throwable) { BError cause = ErrorCreator.createError(throwable); + BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); + if (throwable instanceof MQException) { + errorDetails.put(ERROR_REASON_CODE, ((MQException) throwable).getReason()); + errorDetails.put(ERROR_ERROR_CODE, ((MQException) throwable).getErrorCode()); + errorDetails.put(ERROR_COMPLETION_CODE, ((MQException) throwable).getCompCode()); + } return ErrorCreator.createError( - ModuleUtils.getModule(), errorType, StringUtils.fromString(message), cause, null); + ModuleUtils.getModule(), errorType, StringUtils.fromString(message), cause, errorDetails); } public static Optional getOptionalStringProperty(BMap config, BString fieldName) { diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java new file mode 100644 index 0000000..0f2789e --- /dev/null +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + */ + +package io.ballerina.lib.ibm.ibmmq; + +public class MQThreadFactory implements java.util.concurrent.ThreadFactory { + @Override + public Thread newThread(Runnable runnable) { + Thread ibmMqClientThread = new Thread(runnable); + ibmMqClientThread.setName("balx-ibm-mq-client-network-thread"); + return ibmMqClientThread; + } + +} diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index c067909..ce8be07 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -20,7 +20,10 @@ import com.ibm.mq.MQException; import com.ibm.mq.MQQueueManager; +import com.ibm.mq.MQTopic; import com.ibm.mq.constants.MQConstants; +import io.ballerina.runtime.api.Environment; +import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; @@ -64,6 +67,21 @@ public static Object init(BObject queueManager, BMap configurat return null; } + public static Object externAccessTopic(Environment env, BObject queueManagerObject, BString topicName, + BString topicString, Long openAs, Long options) { + MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); + try { + MQTopic mqTopic = queueManager.accessTopic(topicName.getValue(), topicString.getValue(), + openAs.intValue(), options.intValue()); + BObject bTopic = ValueCreator.createObjectValue(ModuleUtils.getModule(), CommonUtils.BTOPIC); + bTopic.addNativeData(CommonUtils.TOPIC_OBJECT, mqTopic); + return bTopic; + } catch (MQException e) { + return createError(IBMMQ_ERROR, + String.format("Error occurred while accessing topic: %s", e.getMessage()), e); + } + } + private static Hashtable getConnectionProperties(BMap configurations) { Hashtable properties = new Hashtable<>(); String host = configurations.getStringValue(HOST).getValue(); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java new file mode 100644 index 0000000..a1380c2 --- /dev/null +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + */ + +package io.ballerina.lib.ibm.ibmmq; + +import com.ibm.mq.MQGetMessageOptions; +import com.ibm.mq.MQMessage; +import com.ibm.mq.MQTopic; +import io.ballerina.runtime.api.Environment; +import io.ballerina.runtime.api.Future; +import io.ballerina.runtime.api.utils.StringUtils; +import io.ballerina.runtime.api.values.BMap; +import io.ballerina.runtime.api.values.BObject; +import io.ballerina.runtime.api.values.BString; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +public class Topic { + private static final ExecutorService topicExecutorService = Executors.newCachedThreadPool(new MQThreadFactory()); + + private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); + private static final BString OPTIONS = StringUtils.fromString("options"); + + public static Object externPut(Environment environment, BObject topicObject, BMap message) { + MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); + MQMessage mqMessage = CommonUtils.getMqMessage(message); + Future future = environment.markAsync(); + topicExecutorService.execute(() -> { + try { + topic.put(mqMessage); + future.complete(null); + } catch (Exception e) { + future.complete(e); + } + }); + return null; + } + + public static Object externGet(Environment environment, BObject topicObject, BMap options) { + MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); + MQGetMessageOptions getMessageOptions = getGetMessageOptions(options); + Future future = environment.markAsync(); + topicExecutorService.execute(() -> { + try { + MQMessage message = new MQMessage(); + topic.get(message, getMessageOptions); + future.complete(message); + } catch (Exception e) { + future.complete(e); + } + }); + return null; + } + + private static MQGetMessageOptions getGetMessageOptions(BMap bOptions) { + int waitInterval = bOptions.getIntValue(WAIT_INTERVAL).intValue(); + int options = bOptions.getIntValue(OPTIONS).intValue(); + MQGetMessageOptions getMessageOptions = new MQGetMessageOptions(); + getMessageOptions.waitInterval = waitInterval; + getMessageOptions.options = options; + return getMessageOptions; + } +} From f52cdd31144b7a76f8cdb7c9f317b73879a9842a Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 16:26:31 +0530 Subject: [PATCH 02/39] Add newline --- ballerina/constants.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/constants.bal b/ballerina/constants.bal index c0df91e..eeb706f 100644 --- a/ballerina/constants.bal +++ b/ballerina/constants.bal @@ -41,4 +41,4 @@ public const MQGMO_LOCK = 512; public const MQGMO_UNLOCK = 1024; public const MQGMO_ACCEPT_TRUNCATED_MSG = 64; public const MQGMO_FAIL_IF_QUIESCING = 8192; -public const MQGMO_CONVERT = 16384; \ No newline at end of file +public const MQGMO_CONVERT = 16384; From fd4999fbbc1f20ee5eb34772a812489c20ee3a32 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 16:39:17 +0530 Subject: [PATCH 03/39] Add bmessage creator util --- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 26 +++++++++++++++++-- .../io/ballerina/lib/ibm.ibmmq/Topic.java | 4 +-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 00564b3..acb23e2 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -28,6 +28,8 @@ import io.ballerina.runtime.api.values.BString; import java.io.IOException; +import java.util.Collections; +import java.util.Enumeration; import java.util.Optional; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; @@ -47,8 +49,9 @@ public class CommonUtils { private static final BString ERROR_COMPLETION_CODE = StringUtils.fromString("ErrorDetails"); private static final BString MESSAGE_PAYLOAD = StringUtils.fromString("payload"); private static final BString MESSAGE_PROPERTIES = StringUtils.fromString("properties"); + private static final String BMESSAGE_NAME = "Message"; - public static MQMessage getMqMessage(BMap bMessage) { + public static MQMessage getMqMessageFromMessage(BMap bMessage) { byte[] payload = bMessage.getArrayValue(MESSAGE_PAYLOAD).getBytes(); BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); @@ -67,7 +70,26 @@ public static MQMessage getMqMessage(BMap bMessage) { String.format("Error occurred while setting message properties: %s", e.getMessage()), e); } } - return new MQMessage(); + return mqMessage; + } + + public static BMap getBMessageFromMQMessage(MQMessage mqMessage) { + BMap bMessage = ValueCreator.createRecordValue(getModule(), BMESSAGE_NAME); + try { + byte[] payload = new byte[mqMessage.getDataLength()]; + mqMessage.readFully(payload); + bMessage.put(MESSAGE_PAYLOAD, payload); + BMap properties = ValueCreator.createRecordValue(getModule(), MESSAGE_PROPERTIES.getValue()); + Enumeration propertyNames = mqMessage.getPropertyNames("%"); + for (String propertyName : Collections.list(propertyNames)) { + properties.put(StringUtils.fromString(propertyName), mqMessage.getObjectProperty(propertyName)); + } + bMessage.put(MESSAGE_PROPERTIES, properties); + return bMessage; + } catch (MQException | IOException e) { + throw createError(IBMMQ_ERROR, + String.format("Error occurred while reading the message: %s", e.getMessage()), e); + } } public static BError createError(String errorType, String message, Throwable throwable) { diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index a1380c2..5fcfcff 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -39,7 +39,7 @@ public class Topic { public static Object externPut(Environment environment, BObject topicObject, BMap message) { MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); - MQMessage mqMessage = CommonUtils.getMqMessage(message); + MQMessage mqMessage = CommonUtils.getMqMessageFromMessage(message); Future future = environment.markAsync(); topicExecutorService.execute(() -> { try { @@ -60,7 +60,7 @@ public static Object externGet(Environment environment, BObject topicObject, BMa try { MQMessage message = new MQMessage(); topic.get(message, getMessageOptions); - future.complete(message); + future.complete(CommonUtils.getBMessageFromMQMessage(message)); } catch (Exception e) { future.complete(e); } From 970f23591546d20236444487ebbc6138e7320a21 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 16:44:58 +0530 Subject: [PATCH 04/39] Fix review comments --- ballerina/destination.bal | 14 ++++---------- ballerina/types.bal | 1 + .../io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 3 ++- .../ballerina/lib/ibm.ibmmq/MQThreadFactory.java | 13 +++++++++++-- .../java/io/ballerina/lib/ibm.ibmmq/Topic.java | 3 ++- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index b87ec53..72710f9 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -28,21 +28,15 @@ public type Queue distinct client object { public client class Topic { *Destination; - remote function put(Message message) returns Error? { - return self.externPut(message); - }; - - remote function get(GetMessageOptions options = {}) returns Message|Error { - return self.externGet(options); - }; - - private isolated function externPut(Message message) returns Error? = + remote function put(Message message) returns Error? = @java:Method { + name: "externPut", 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - private isolated function externGet(GetMessageOptions options) returns Message|Error = + remote function get(GetMessageOptions options = {}) returns Message|Error = @java:Method { + name: "externGet", 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; }; diff --git a/ballerina/types.bal b/ballerina/types.bal index 4aed9d7..226d647 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -15,6 +15,7 @@ // under the License. public type GM_OPTIONS MQGMO_WAIT|MQGMO_NO_WAIT|MQGMO_SYNCPOINT|MQGMO_NO_SYNCPOINT|MQGMO_BROWSE_FIRST|MQGMO_BROWSE_MSG_UNDER_CURSOR|MQGMO_MSG_UNDER_CURSOR|MQGMO_LOCK|MQGMO_UNLOCK|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_BROWSE_NEXT|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_FAIL_IF_QUIESCING|MQGMO_CONVERT; + public type OPEN_AS_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION; public type QueueManagerConfiguration record {| diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index acb23e2..42b78bb 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -79,7 +79,8 @@ public static BMap getBMessageFromMQMessage(MQMessage mqMessage byte[] payload = new byte[mqMessage.getDataLength()]; mqMessage.readFully(payload); bMessage.put(MESSAGE_PAYLOAD, payload); - BMap properties = ValueCreator.createRecordValue(getModule(), MESSAGE_PROPERTIES.getValue()); + BMap properties = ValueCreator.createRecordValue(getModule(), + MESSAGE_PROPERTIES.getValue()); Enumeration propertyNames = mqMessage.getPropertyNames("%"); for (String propertyName : Collections.list(propertyNames)) { properties.put(StringUtils.fromString(propertyName), mqMessage.getObjectProperty(propertyName)); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java index 0f2789e..ab95b27 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java @@ -18,11 +18,20 @@ package io.ballerina.lib.ibm.ibmmq; -public class MQThreadFactory implements java.util.concurrent.ThreadFactory { +import java.util.concurrent.ThreadFactory; + +public class MQThreadFactory implements ThreadFactory { + + private final String threadGroupName; + + public MQThreadFactory(String threadGroupName) { + this.threadGroupName = threadGroupName; + } + @Override public Thread newThread(Runnable runnable) { Thread ibmMqClientThread = new Thread(runnable); - ibmMqClientThread.setName("balx-ibm-mq-client-network-thread"); + ibmMqClientThread.setName(threadGroupName); return ibmMqClientThread; } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index 5fcfcff..daa417b 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -32,7 +32,8 @@ import java.util.concurrent.Executors; public class Topic { - private static final ExecutorService topicExecutorService = Executors.newCachedThreadPool(new MQThreadFactory()); + private static final ExecutorService topicExecutorService = + Executors.newCachedThreadPool(new MQThreadFactory("balx-ibm-mq-client-network-thread")); private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); private static final BString OPTIONS = StringUtils.fromString("options"); From b3238a39bd30e0d05af754a304d8c49d80eafb17 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 18:20:18 +0530 Subject: [PATCH 05/39] Add message property handling logic --- ballerina/types.bal | 4 +- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 130 +++++++++++++++--- .../io/ballerina/lib/ibm.ibmmq/Topic.java | 2 +- 3 files changed, 112 insertions(+), 24 deletions(-) diff --git a/ballerina/types.bal b/ballerina/types.bal index 226d647..8bbc6f1 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -42,8 +42,8 @@ public type GetMessageOptions record {| |}; public type Property record {| - map descriptor; - boolean|byte|byte[]|decimal|float|int|string property; + map descriptor?; + boolean|byte|byte[]|decimal|float|int|string value; |}; public type Message record {| diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 42b78bb..096fd7a 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -20,7 +20,9 @@ import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; +import com.ibm.mq.MQPropertyDescriptor; import io.ballerina.runtime.api.creators.ErrorCreator; +import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BError; @@ -44,17 +46,27 @@ public class CommonUtils { public static final String TOPIC_OBJECT = "TOPIC_OBJECT"; private static final String ERROR_DETAILS = "ErrorDetails"; - private static final BString ERROR_REASON_CODE = StringUtils.fromString("ErrorDetails"); - private static final BString ERROR_ERROR_CODE = StringUtils.fromString("ErrorDetails"); - private static final BString ERROR_COMPLETION_CODE = StringUtils.fromString("ErrorDetails"); + private static final BString ERROR_REASON_CODE = StringUtils.fromString("reasonCode"); + private static final BString ERROR_ERROR_CODE = StringUtils.fromString("errorCode"); + private static final BString ERROR_COMPLETION_CODE = StringUtils.fromString("completionCode"); private static final BString MESSAGE_PAYLOAD = StringUtils.fromString("payload"); private static final BString MESSAGE_PROPERTIES = StringUtils.fromString("properties"); + private static final BString MESSAGE_PROPERTY = StringUtils.fromString("property"); + private static final String BPROPERTY = "Property"; private static final String BMESSAGE_NAME = "Message"; + private static final BString PD_VERSION = StringUtils.fromString("version"); + private static final BString PD_COPY_OPTIONS = StringUtils.fromString("copyOptions"); + private static final BString PD_OPTIONS = StringUtils.fromString("options"); + private static final BString PD_SUPPORT = StringUtils.fromString("support"); + private static final BString PD_CONTEXT = StringUtils.fromString("context"); + private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); + private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); - public static MQMessage getMqMessageFromMessage(BMap bMessage) { - byte[] payload = bMessage.getArrayValue(MESSAGE_PAYLOAD).getBytes(); - BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); + private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor(); + + public static MQMessage getMqMessageFromBMessage(BMap bMessage) { + byte[] payload = bMessage.getArrayValue(MESSAGE_PAYLOAD).getBytes(); MQMessage mqMessage = new MQMessage(); try { mqMessage.write(payload); @@ -62,14 +74,8 @@ public static MQMessage getMqMessageFromMessage(BMap bMessage) throw createError(IBMMQ_ERROR, String.format("Error occurred while populating payload: %s", e.getMessage()), e); } - for (BString key : properties.getKeys()) { - try { - mqMessage.setObjectProperty(key.getValue(), properties.get(key)); - } catch (MQException e) { - throw createError(IBMMQ_ERROR, - String.format("Error occurred while setting message properties: %s", e.getMessage()), e); - } - } + BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); + populateMQProperties(properties, mqMessage); return mqMessage; } @@ -79,13 +85,7 @@ public static BMap getBMessageFromMQMessage(MQMessage mqMessage byte[] payload = new byte[mqMessage.getDataLength()]; mqMessage.readFully(payload); bMessage.put(MESSAGE_PAYLOAD, payload); - BMap properties = ValueCreator.createRecordValue(getModule(), - MESSAGE_PROPERTIES.getValue()); - Enumeration propertyNames = mqMessage.getPropertyNames("%"); - for (String propertyName : Collections.list(propertyNames)) { - properties.put(StringUtils.fromString(propertyName), mqMessage.getObjectProperty(propertyName)); - } - bMessage.put(MESSAGE_PROPERTIES, properties); + bMessage.put(MESSAGE_PROPERTY, getBProperties(mqMessage)); return bMessage; } catch (MQException | IOException e) { throw createError(IBMMQ_ERROR, @@ -93,6 +93,94 @@ public static BMap getBMessageFromMQMessage(MQMessage mqMessage } } + private static BMap getBProperties(MQMessage mqMessage) throws MQException { + BMap properties = ValueCreator.createMapValue(TypeCreator + .createMapType(TypeCreator.createRecordType(BPROPERTY, getModule(), 0, false, 0))); + Enumeration propertyNames = mqMessage.getPropertyNames("%"); + for (String propertyName : Collections.list(propertyNames)) { + BMap property = ValueCreator.createRecordValue(getModule(), BPROPERTY); + MQPropertyDescriptor propertyDescriptor = new MQPropertyDescriptor(); + Object propertyObject = mqMessage.getObjectProperty(propertyName, propertyDescriptor); + if (propertyObject instanceof Integer) { + property.put(PROPERTY_VALUE, ((Integer) propertyObject).longValue()); + } else if (propertyObject instanceof String) { + property.put(PROPERTY_VALUE, StringUtils.fromString((String) propertyObject)); + } else { + property.put(PROPERTY_VALUE, propertyObject); + } + property.put(PROPERTY_DESCRIPTOR, + populateDescriptorFromMQPropertyDescriptor(propertyDescriptor)); + properties.put(StringUtils.fromString(propertyName), property); + } + return properties; + } + + private static void populateMQProperties(BMap properties, MQMessage mqMessage) { + for (BString key : properties.getKeys()) { + try { + handlePropertyValue(properties, mqMessage, key); + } catch (MQException e) { + throw createError(IBMMQ_ERROR, + String.format("Error occurred while setting message properties: %s", e.getMessage()), e); + } + } + } + + private static void handlePropertyValue(BMap properties, MQMessage mqMessage, BString key) + throws MQException { + BMap property = (BMap) properties.getMapValue(key); + MQPropertyDescriptor propertyDescriptor = defaultPropertyDescriptor; + if (property.containsKey(PROPERTY_DESCRIPTOR)) { + propertyDescriptor = getMQPropertyDescriptor(properties.getMapValue(PROPERTY_DESCRIPTOR)); + } + Object value = property.get(PROPERTY_VALUE); + if (value instanceof Long) { + mqMessage.setIntProperty(key.getValue(), propertyDescriptor, ((Long) properties.get(key)).intValue()); + } else if (value instanceof Boolean) { + mqMessage.setBooleanProperty(key.getValue(), propertyDescriptor, ((Boolean) properties.get(key))); + } else if (value instanceof Byte) { + mqMessage.setByteProperty(key.getValue(), propertyDescriptor, (Byte) properties.get(key)); + } else if (value instanceof byte[]) { + mqMessage.setBytesProperty(key.getValue(), propertyDescriptor, ((byte[]) properties.get(key))); + } else if (value instanceof Float) { + mqMessage.setFloatProperty(key.getValue(), propertyDescriptor, (Float) properties.get(key)); + } else if (value instanceof Double) { + mqMessage.setDoubleProperty(key.getValue(), propertyDescriptor, (Double) properties.get(key)); + } else if (value instanceof BString) { + mqMessage.setStringProperty(key.getValue(), propertyDescriptor, ((BString) properties.get(key)).getValue()); + } + } + + private static MQPropertyDescriptor getMQPropertyDescriptor(BMap descriptor) { + MQPropertyDescriptor propertyDescriptor = new MQPropertyDescriptor(); + if (descriptor.containsKey(PD_VERSION)) { + propertyDescriptor.version = ((Long) descriptor.get(PD_VERSION)).intValue(); + } + if (descriptor.containsKey(PD_COPY_OPTIONS)) { + propertyDescriptor.copyOptions = ((Long) descriptor.get(PD_COPY_OPTIONS)).intValue(); + } + if (descriptor.containsKey(PD_OPTIONS)) { + propertyDescriptor.options = ((Long) descriptor.get(PD_OPTIONS)).intValue(); + } + if (descriptor.containsKey(PD_SUPPORT)) { + propertyDescriptor.support = ((Long) descriptor.get(PD_SUPPORT)).intValue(); + } + if (descriptor.containsKey(PD_CONTEXT)) { + propertyDescriptor. context = ((Long) descriptor.get(PD_CONTEXT)).intValue(); + } + return propertyDescriptor; + } + + private static BMap populateDescriptorFromMQPropertyDescriptor(MQPropertyDescriptor propertyDescriptor) { + BMap descriptor = ValueCreator.createMapValue(); + descriptor.put(PD_VERSION, propertyDescriptor.version); + descriptor.put(PD_COPY_OPTIONS, propertyDescriptor.copyOptions); + descriptor.put(PD_OPTIONS, propertyDescriptor.options); + descriptor.put(PD_SUPPORT, propertyDescriptor.support); + descriptor.put(PD_CONTEXT, propertyDescriptor.context); + return descriptor; + } + public static BError createError(String errorType, String message, Throwable throwable) { BError cause = ErrorCreator.createError(throwable); BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index daa417b..fe7fa48 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -40,7 +40,7 @@ public class Topic { public static Object externPut(Environment environment, BObject topicObject, BMap message) { MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); - MQMessage mqMessage = CommonUtils.getMqMessageFromMessage(message); + MQMessage mqMessage = CommonUtils.getMqMessageFromBMessage(message); Future future = environment.markAsync(); topicExecutorService.execute(() -> { try { From 213acaecfb740d8ded9a642d6714be0e537e98c8 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 18:28:09 +0530 Subject: [PATCH 06/39] Restructure project --- ballerina/init.bal | 2 +- .../main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java | 6 ++++-- native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java | 3 ++- .../io/ballerina/lib/ibm.ibmmq/{ => utils}/CommonUtils.java | 6 +++--- .../io/ballerina/lib/ibm.ibmmq/{ => utils}/ModuleUtils.java | 2 +- 5 files changed, 11 insertions(+), 8 deletions(-) rename native/src/main/java/io/ballerina/lib/ibm.ibmmq/{ => utils}/CommonUtils.java (98%) rename native/src/main/java/io/ballerina/lib/ibm.ibmmq/{ => utils}/ModuleUtils.java (96%) diff --git a/ballerina/init.bal b/ballerina/init.bal index 4741e40..c3f43f8 100644 --- a/ballerina/init.bal +++ b/ballerina/init.bal @@ -21,5 +21,5 @@ isolated function init() { } isolated function setModule() = @java:Method { - 'class: "io.ballerina.lib.ibm.ibmmq.ModuleUtils" + 'class: "io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils" } external; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index ce8be07..5f9bb43 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -22,6 +22,8 @@ import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQTopic; import com.ibm.mq.constants.MQConstants; +import io.ballerina.lib.ibm.ibmmq.utils.CommonUtils; +import io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; @@ -31,8 +33,8 @@ import java.util.Hashtable; -import static io.ballerina.lib.ibm.ibmmq.CommonUtils.createError; -import static io.ballerina.lib.ibm.ibmmq.CommonUtils.getOptionalStringProperty; +import static io.ballerina.lib.ibm.ibmmq.utils.CommonUtils.createError; +import static io.ballerina.lib.ibm.ibmmq.utils.CommonUtils.getOptionalStringProperty; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; import static io.ballerina.lib.ibm.ibmmq.Constants.NATIVE_QUEUE_MANAGER; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index fe7fa48..6c860c6 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -21,6 +21,7 @@ import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQTopic; +import io.ballerina.lib.ibm.ibmmq.utils.CommonUtils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.utils.StringUtils; @@ -33,7 +34,7 @@ public class Topic { private static final ExecutorService topicExecutorService = - Executors.newCachedThreadPool(new MQThreadFactory("balx-ibm-mq-client-network-thread")); + Executors.newCachedThreadPool(new MQThreadFactory("balx-ibmmq-topic-client-network-thread")); private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); private static final BString OPTIONS = StringUtils.fromString("options"); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java similarity index 98% rename from native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java rename to native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java index 096fd7a..3eb98eb 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.lib.ibm.ibmmq; +package io.ballerina.lib.ibm.ibmmq.utils; import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; @@ -35,7 +35,7 @@ import java.util.Optional; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; -import static io.ballerina.lib.ibm.ibmmq.ModuleUtils.getModule; +import static io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils.getModule; /** * {@code CommonUtils} contains the common utility functions for the Ballerina IBM MQ connector. @@ -166,7 +166,7 @@ private static MQPropertyDescriptor getMQPropertyDescriptor(BMap descriptor) { propertyDescriptor.support = ((Long) descriptor.get(PD_SUPPORT)).intValue(); } if (descriptor.containsKey(PD_CONTEXT)) { - propertyDescriptor. context = ((Long) descriptor.get(PD_CONTEXT)).intValue(); + propertyDescriptor.context = ((Long) descriptor.get(PD_CONTEXT)).intValue(); } return propertyDescriptor; } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java similarity index 96% rename from native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java rename to native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java index 80462df..c1507f1 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.lib.ibm.ibmmq; +package io.ballerina.lib.ibm.ibmmq.utils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Module; From 6b2e6dcab681de782861e6259b97841f54cb7f46 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 19:54:01 +0530 Subject: [PATCH 07/39] Apply suggestions from review --- ballerina/destination.bal | 2 -- ballerina/init.bal | 2 +- ballerina/queue_manager.bal | 6 +----- .../lib/ibm.ibmmq/{utils => }/CommonUtils.java | 12 ++++++------ .../lib/ibm.ibmmq/{utils => }/ModuleUtils.java | 2 +- .../io/ballerina/lib/ibm.ibmmq/QueueManager.java | 6 ++---- .../main/java/io/ballerina/lib/ibm.ibmmq/Topic.java | 5 ++--- 7 files changed, 13 insertions(+), 22 deletions(-) rename native/src/main/java/io/ballerina/lib/ibm.ibmmq/{utils => }/CommonUtils.java (95%) rename native/src/main/java/io/ballerina/lib/ibm.ibmmq/{utils => }/ModuleUtils.java (96%) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 72710f9..df202ce 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -30,13 +30,11 @@ public client class Topic { remote function put(Message message) returns Error? = @java:Method { - name: "externPut", 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; remote function get(GetMessageOptions options = {}) returns Message|Error = @java:Method { - name: "externGet", 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; }; diff --git a/ballerina/init.bal b/ballerina/init.bal index c3f43f8..4741e40 100644 --- a/ballerina/init.bal +++ b/ballerina/init.bal @@ -21,5 +21,5 @@ isolated function init() { } isolated function setModule() = @java:Method { - 'class: "io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils" + 'class: "io.ballerina.lib.ibm.ibmmq.ModuleUtils" } external; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 64ffecb..adab5e2 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -31,11 +31,7 @@ public isolated class QueueManager { return error Error("Not implemented"); } - public isolated function accessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error { - return self.externAccessTopic(topicName, topicString, openAs, options); - } - - private isolated function externAccessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error = + public isolated function accessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java similarity index 95% rename from native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java rename to native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 3eb98eb..679aee8 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.lib.ibm.ibmmq.utils; +package io.ballerina.lib.ibm.ibmmq; import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; @@ -35,7 +35,7 @@ import java.util.Optional; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; -import static io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils.getModule; +import static io.ballerina.lib.ibm.ibmmq.ModuleUtils.getModule; /** * {@code CommonUtils} contains the common utility functions for the Ballerina IBM MQ connector. @@ -184,10 +184,10 @@ private static BMap populateDescriptorFromMQPropertyDescriptor(MQPropertyDescrip public static BError createError(String errorType, String message, Throwable throwable) { BError cause = ErrorCreator.createError(throwable); BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); - if (throwable instanceof MQException) { - errorDetails.put(ERROR_REASON_CODE, ((MQException) throwable).getReason()); - errorDetails.put(ERROR_ERROR_CODE, ((MQException) throwable).getErrorCode()); - errorDetails.put(ERROR_COMPLETION_CODE, ((MQException) throwable).getCompCode()); + if (throwable instanceof MQException exception) { + errorDetails.put(ERROR_REASON_CODE, exception.getReason()); + errorDetails.put(ERROR_ERROR_CODE, exception.getErrorCode()); + errorDetails.put(ERROR_COMPLETION_CODE, exception.getCompCode()); } return ErrorCreator.createError( ModuleUtils.getModule(), errorType, StringUtils.fromString(message), cause, errorDetails); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java similarity index 96% rename from native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java rename to native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java index c1507f1..80462df 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/utils/ModuleUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/ModuleUtils.java @@ -16,7 +16,7 @@ * under the License. */ -package io.ballerina.lib.ibm.ibmmq.utils; +package io.ballerina.lib.ibm.ibmmq; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Module; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 5f9bb43..ce8be07 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -22,8 +22,6 @@ import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQTopic; import com.ibm.mq.constants.MQConstants; -import io.ballerina.lib.ibm.ibmmq.utils.CommonUtils; -import io.ballerina.lib.ibm.ibmmq.utils.ModuleUtils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; @@ -33,8 +31,8 @@ import java.util.Hashtable; -import static io.ballerina.lib.ibm.ibmmq.utils.CommonUtils.createError; -import static io.ballerina.lib.ibm.ibmmq.utils.CommonUtils.getOptionalStringProperty; +import static io.ballerina.lib.ibm.ibmmq.CommonUtils.createError; +import static io.ballerina.lib.ibm.ibmmq.CommonUtils.getOptionalStringProperty; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; import static io.ballerina.lib.ibm.ibmmq.Constants.NATIVE_QUEUE_MANAGER; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index 6c860c6..decba79 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -21,7 +21,6 @@ import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQTopic; -import io.ballerina.lib.ibm.ibmmq.utils.CommonUtils; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.utils.StringUtils; @@ -39,7 +38,7 @@ public class Topic { private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); private static final BString OPTIONS = StringUtils.fromString("options"); - public static Object externPut(Environment environment, BObject topicObject, BMap message) { + public static Object put(Environment environment, BObject topicObject, BMap message) { MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); MQMessage mqMessage = CommonUtils.getMqMessageFromBMessage(message); Future future = environment.markAsync(); @@ -54,7 +53,7 @@ public static Object externPut(Environment environment, BObject topicObject, BMa return null; } - public static Object externGet(Environment environment, BObject topicObject, BMap options) { + public static Object get(Environment environment, BObject topicObject, BMap options) { MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); MQGetMessageOptions getMessageOptions = getGetMessageOptions(options); Future future = environment.markAsync(); From c2e5002fdf81683fa73e2542bd09e7034e39c934 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 20:06:20 +0530 Subject: [PATCH 08/39] Update method name --- .../src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index ce8be07..b468651 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -67,7 +67,7 @@ public static Object init(BObject queueManager, BMap configurat return null; } - public static Object externAccessTopic(Environment env, BObject queueManagerObject, BString topicName, + public static Object accessTopic(Environment env, BObject queueManagerObject, BString topicName, BString topicString, Long openAs, Long options) { MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); try { From 11b8d83fc814489b1bf22704596a4eae9ce7a6c6 Mon Sep 17 00:00:00 2001 From: Dilan Sachintha Nayanajith Date: Fri, 27 Oct 2023 20:16:06 +0530 Subject: [PATCH 09/39] Update ballerina/destination.bal Co-authored-by: Ayesh Almeida <77491511+ayeshLK@users.noreply.github.com> --- ballerina/destination.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index df202ce..7c77369 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -18,7 +18,7 @@ import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; - remote function get(GetMessageOptions options = {}) returns Message|Error?; + remote function get(*GetMessageOptions options) returns Message|Error?; }; public type Queue distinct client object { From 3de7cef096894fb9021fa8f29b597a07718699b9 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 20:25:43 +0530 Subject: [PATCH 10/39] Update property map type --- ballerina/destination.bal | 2 +- ballerina/types.bal | 4 ++-- .../main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 5 +++-- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 7c77369..25ca342 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -33,7 +33,7 @@ public client class Topic { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - remote function get(GetMessageOptions options = {}) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; diff --git a/ballerina/types.bal b/ballerina/types.bal index 8bbc6f1..b9a8dba 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -37,12 +37,12 @@ public enum ConnectionOpenOptions { public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT; public type GetMessageOptions record {| - GM_OPTIONS options = MQGMO_NO_SYNCPOINT; + GM_OPTIONS gmOptions = MQGMO_NO_SYNCPOINT; int waitInterval = 0; |}; public type Property record {| - map descriptor?; + map descriptor?; boolean|byte|byte[]|decimal|float|int|string value; |}; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 679aee8..1b4a567 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -21,6 +21,7 @@ import com.ibm.mq.MQException; import com.ibm.mq.MQMessage; import com.ibm.mq.MQPropertyDescriptor; +import io.ballerina.runtime.api.PredefinedTypes; import io.ballerina.runtime.api.creators.ErrorCreator; import io.ballerina.runtime.api.creators.TypeCreator; import io.ballerina.runtime.api.creators.ValueCreator; @@ -62,7 +63,6 @@ public class CommonUtils { private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); - private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor(); public static MQMessage getMqMessageFromBMessage(BMap bMessage) { @@ -172,7 +172,8 @@ private static MQPropertyDescriptor getMQPropertyDescriptor(BMap descriptor) { } private static BMap populateDescriptorFromMQPropertyDescriptor(MQPropertyDescriptor propertyDescriptor) { - BMap descriptor = ValueCreator.createMapValue(); + BMap descriptor = ValueCreator.createMapValue(TypeCreator + .createMapType(PredefinedTypes.TYPE_INT)); descriptor.put(PD_VERSION, propertyDescriptor.version); descriptor.put(PD_COPY_OPTIONS, propertyDescriptor.copyOptions); descriptor.put(PD_OPTIONS, propertyDescriptor.options); From 30067cb953234144643407265618d5681edf1a48 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Fri, 27 Oct 2023 21:08:01 +0530 Subject: [PATCH 11/39] Fix suggestions --- ballerina/queue_manager.bal | 2 +- ballerina/types.bal | 2 +- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 39 +++++++++---------- .../io/ballerina/lib/ibm.ibmmq/Constants.java | 2 + .../lib/ibm.ibmmq/MQThreadFactory.java | 1 - .../ballerina/lib/ibm.ibmmq/QueueManager.java | 12 +++--- .../io/ballerina/lib/ibm.ibmmq/Topic.java | 4 +- 7 files changed, 30 insertions(+), 32 deletions(-) diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index adab5e2..65a03d8 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -31,7 +31,7 @@ public isolated class QueueManager { return error Error("Not implemented"); } - public isolated function accessTopic(string topicName, string topicString, OPEN_AS_OPTION openAs, AccessTopicOptions options) returns Topic|Error = + public isolated function accessTopic(string topicName, string topicString, OPEN_TOPIC_OPTION openTopicOption, AccessTopicOptions options) returns Topic|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; diff --git a/ballerina/types.bal b/ballerina/types.bal index b9a8dba..669ccd9 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -16,7 +16,7 @@ public type GM_OPTIONS MQGMO_WAIT|MQGMO_NO_WAIT|MQGMO_SYNCPOINT|MQGMO_NO_SYNCPOINT|MQGMO_BROWSE_FIRST|MQGMO_BROWSE_MSG_UNDER_CURSOR|MQGMO_MSG_UNDER_CURSOR|MQGMO_LOCK|MQGMO_UNLOCK|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_BROWSE_NEXT|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_FAIL_IF_QUIESCING|MQGMO_CONVERT; -public type OPEN_AS_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION; +public type OPEN_TOPIC_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION; public type QueueManagerConfiguration record {| string name; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 1b4a567..8401733 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -43,9 +43,6 @@ */ public class CommonUtils { - public static final String BTOPIC = "TOPIC"; - public static final String TOPIC_OBJECT = "TOPIC_OBJECT"; - private static final String ERROR_DETAILS = "ErrorDetails"; private static final BString ERROR_REASON_CODE = StringUtils.fromString("reasonCode"); private static final BString ERROR_ERROR_CODE = StringUtils.fromString("errorCode"); @@ -101,10 +98,10 @@ private static BMap getBProperties(MQMessage mqMessage) throws BMap property = ValueCreator.createRecordValue(getModule(), BPROPERTY); MQPropertyDescriptor propertyDescriptor = new MQPropertyDescriptor(); Object propertyObject = mqMessage.getObjectProperty(propertyName, propertyDescriptor); - if (propertyObject instanceof Integer) { - property.put(PROPERTY_VALUE, ((Integer) propertyObject).longValue()); - } else if (propertyObject instanceof String) { - property.put(PROPERTY_VALUE, StringUtils.fromString((String) propertyObject)); + if (propertyObject instanceof Integer intProperty) { + property.put(PROPERTY_VALUE, intProperty.longValue()); + } else if (propertyObject instanceof String stringProperty) { + property.put(PROPERTY_VALUE, StringUtils.fromString(stringProperty)); } else { property.put(PROPERTY_VALUE, propertyObject); } @@ -134,20 +131,20 @@ private static void handlePropertyValue(BMap properties, MQMess propertyDescriptor = getMQPropertyDescriptor(properties.getMapValue(PROPERTY_DESCRIPTOR)); } Object value = property.get(PROPERTY_VALUE); - if (value instanceof Long) { - mqMessage.setIntProperty(key.getValue(), propertyDescriptor, ((Long) properties.get(key)).intValue()); - } else if (value instanceof Boolean) { - mqMessage.setBooleanProperty(key.getValue(), propertyDescriptor, ((Boolean) properties.get(key))); - } else if (value instanceof Byte) { - mqMessage.setByteProperty(key.getValue(), propertyDescriptor, (Byte) properties.get(key)); - } else if (value instanceof byte[]) { - mqMessage.setBytesProperty(key.getValue(), propertyDescriptor, ((byte[]) properties.get(key))); - } else if (value instanceof Float) { - mqMessage.setFloatProperty(key.getValue(), propertyDescriptor, (Float) properties.get(key)); - } else if (value instanceof Double) { - mqMessage.setDoubleProperty(key.getValue(), propertyDescriptor, (Double) properties.get(key)); - } else if (value instanceof BString) { - mqMessage.setStringProperty(key.getValue(), propertyDescriptor, ((BString) properties.get(key)).getValue()); + if (value instanceof Long longValue) { + mqMessage.setIntProperty(key.getValue(), propertyDescriptor, longValue.intValue()); + } else if (value instanceof Boolean booleanValue) { + mqMessage.setBooleanProperty(key.getValue(), propertyDescriptor, booleanValue); + } else if (value instanceof Byte byteValue) { + mqMessage.setByteProperty(key.getValue(), propertyDescriptor, byteValue); + } else if (value instanceof byte[] bytesValue) { + mqMessage.setBytesProperty(key.getValue(), propertyDescriptor, bytesValue); + } else if (value instanceof Float floatValue) { + mqMessage.setFloatProperty(key.getValue(), propertyDescriptor, floatValue); + } else if (value instanceof Double doubleValue) { + mqMessage.setDoubleProperty(key.getValue(), propertyDescriptor, doubleValue); + } else if (value instanceof BString stringValue) { + mqMessage.setStringProperty(key.getValue(), propertyDescriptor, stringValue.getValue()); } } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java index d9ad77b..2145199 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java @@ -24,4 +24,6 @@ public interface Constants { // Native properties in respective ballerina objects public static final String NATIVE_QUEUE_MANAGER = "queueManager"; + + public static final String NATIVE_TOPIC = "topic"; } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java index ab95b27..1f7ab82 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java @@ -34,5 +34,4 @@ public Thread newThread(Runnable runnable) { ibmMqClientThread.setName(threadGroupName); return ibmMqClientThread; } - } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index b468651..d51f9c8 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -22,7 +22,6 @@ import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQTopic; import com.ibm.mq.constants.MQConstants; -import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.creators.ValueCreator; import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BMap; @@ -46,6 +45,7 @@ public class QueueManager { private static final BString CHANNEL = StringUtils.fromString("channel"); private static final BString USER_ID = StringUtils.fromString("userID"); private static final BString PASSWORD = StringUtils.fromString("password"); + private static final String BTOPIC = "Topic"; /** * Creates a JMS connection with the provided configurations. @@ -67,14 +67,14 @@ public static Object init(BObject queueManager, BMap configurat return null; } - public static Object accessTopic(Environment env, BObject queueManagerObject, BString topicName, - BString topicString, Long openAs, Long options) { + public static Object accessTopic(BObject queueManagerObject, BString topicName, + BString topicString, Long openTopicOption, Long options) { MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); try { MQTopic mqTopic = queueManager.accessTopic(topicName.getValue(), topicString.getValue(), - openAs.intValue(), options.intValue()); - BObject bTopic = ValueCreator.createObjectValue(ModuleUtils.getModule(), CommonUtils.BTOPIC); - bTopic.addNativeData(CommonUtils.TOPIC_OBJECT, mqTopic); + openTopicOption.intValue(), options.intValue()); + BObject bTopic = ValueCreator.createObjectValue(ModuleUtils.getModule(), BTOPIC); + bTopic.addNativeData(Constants.NATIVE_TOPIC, mqTopic); return bTopic; } catch (MQException e) { return createError(IBMMQ_ERROR, diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index decba79..f960775 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -39,7 +39,7 @@ public class Topic { private static final BString OPTIONS = StringUtils.fromString("options"); public static Object put(Environment environment, BObject topicObject, BMap message) { - MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); + MQTopic topic = (MQTopic) topicObject.getNativeData(Constants.NATIVE_TOPIC); MQMessage mqMessage = CommonUtils.getMqMessageFromBMessage(message); Future future = environment.markAsync(); topicExecutorService.execute(() -> { @@ -54,7 +54,7 @@ public static Object put(Environment environment, BObject topicObject, BMap mess } public static Object get(Environment environment, BObject topicObject, BMap options) { - MQTopic topic = (MQTopic) topicObject.getNativeData(CommonUtils.TOPIC_OBJECT); + MQTopic topic = (MQTopic) topicObject.getNativeData(Constants.NATIVE_TOPIC); MQGetMessageOptions getMessageOptions = getGetMessageOptions(options); Future future = environment.markAsync(); topicExecutorService.execute(() -> { From 64312fccaa6bc4ccb059e319bcf156f7d41d31b4 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 27 Oct 2023 21:52:51 +0530 Subject: [PATCH 12/39] Improve queue manager to enable queue connection --- ballerina/constants.bal | 6 +++ ballerina/queue_manager.bal | 7 +-- ballerina/types.bal | 8 +--- .../io/ballerina/lib/ibm.ibmmq/Constants.java | 6 +-- .../ballerina/lib/ibm.ibmmq/QueueManager.java | 45 ++++++++++++------- 5 files changed, 44 insertions(+), 28 deletions(-) diff --git a/ballerina/constants.bal b/ballerina/constants.bal index eeb706f..f5e4b0e 100644 --- a/ballerina/constants.bal +++ b/ballerina/constants.bal @@ -18,6 +18,12 @@ public const OPEN_AS_SUBSCRIPTION = 1; public const OPEN_AS_PUBLICATION = 2; +// Options that control the opening of the queue for a consumer. +public const MQOO_BROWSE = 8; +public const MQOO_INPUT_AS_Q_DEF = 1; +public const MQOO_INPUT_EXCLUSIVE = 4; +public const MQOO_INPUT_SHARED = 2; + // Options that control the opening of the topic for either publication or subscription. public const MQOO_ALTERNATE_USER_AUTHORITY = 4096; public const MQOO_BIND_AS_Q_DEF = 0; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 65a03d8..c13f5f9 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -27,9 +27,10 @@ public isolated class QueueManager { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; - public isolated function accessQueue(string queueName, ConnectionOpenOptions options) returns Queue|Error { - return error Error("Not implemented"); - } + public isolated function accessQueue(string queueName, AccessQueueOptions options) returns Queue|Error = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" + } external; public isolated function accessTopic(string topicName, string topicString, OPEN_TOPIC_OPTION openTopicOption, AccessTopicOptions options) returns Topic|Error = @java:Method { diff --git a/ballerina/types.bal b/ballerina/types.bal index 669ccd9..f8e4547 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -27,13 +27,7 @@ public type QueueManagerConfiguration record {| string password?; |}; -public enum ConnectionOpenOptions { - // MQOO_OUTPUT = "MQOO_OUTPUT", - MQOO_INPUT_AS_Q_DEF = "MQOO_INPUT_AS_Q_DEF", - MQOO_INPUT_EXCLUSIVE = "MQOO_INPUT_EXCLUSIVE", - MQOO_INPUT_SHARED = "MQOO_INPUT_SHARED" -} - +public type AccessQueueOptions MQOO_OUTPUT|MQOO_BROWSE|MQOO_INPUT_AS_Q_DEF|MQOO_INPUT_EXCLUSIVE|MQOO_INPUT_SHARED; public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT; public type GetMessageOptions record {| diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java index 2145199..699bac9 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Constants.java @@ -23,7 +23,7 @@ public interface Constants { public static final String IBMMQ_ERROR = "Error"; // Native properties in respective ballerina objects - public static final String NATIVE_QUEUE_MANAGER = "queueManager"; - - public static final String NATIVE_TOPIC = "topic"; + String NATIVE_QUEUE_MANAGER = "queueManager"; + String NATIVE_TOPIC = "topic"; + String NATIVE_QUEUE = "queue"; } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index d51f9c8..d2fbc8f 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -19,6 +19,7 @@ package io.ballerina.lib.ibm.ibmmq; import com.ibm.mq.MQException; +import com.ibm.mq.MQQueue; import com.ibm.mq.MQQueueManager; import com.ibm.mq.MQTopic; import com.ibm.mq.constants.MQConstants; @@ -46,6 +47,7 @@ public class QueueManager { private static final BString USER_ID = StringUtils.fromString("userID"); private static final BString PASSWORD = StringUtils.fromString("password"); private static final String BTOPIC = "Topic"; + private static final String BQUEUE = "Queue"; /** * Creates a JMS connection with the provided configurations. @@ -67,21 +69,6 @@ public static Object init(BObject queueManager, BMap configurat return null; } - public static Object accessTopic(BObject queueManagerObject, BString topicName, - BString topicString, Long openTopicOption, Long options) { - MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); - try { - MQTopic mqTopic = queueManager.accessTopic(topicName.getValue(), topicString.getValue(), - openTopicOption.intValue(), options.intValue()); - BObject bTopic = ValueCreator.createObjectValue(ModuleUtils.getModule(), BTOPIC); - bTopic.addNativeData(Constants.NATIVE_TOPIC, mqTopic); - return bTopic; - } catch (MQException e) { - return createError(IBMMQ_ERROR, - String.format("Error occurred while accessing topic: %s", e.getMessage()), e); - } - } - private static Hashtable getConnectionProperties(BMap configurations) { Hashtable properties = new Hashtable<>(); String host = configurations.getStringValue(HOST).getValue(); @@ -96,4 +83,32 @@ private static Hashtable getConnectionProperties(BMap properties.put(MQConstants.PASSWORD_PROPERTY, password)); return properties; } + + public static Object accessQueue(BObject queueManagerObject, BString queueName, Long options) { + MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); + try { + MQQueue mqQueue = queueManager.accessQueue(queueName.getValue(), options.intValue()); + BObject bQueue = ValueCreator.createObjectValue(ModuleUtils.getModule(), BQUEUE); + bQueue.addNativeData(Constants.NATIVE_TOPIC, mqQueue); + return bQueue; + } catch (MQException e) { + return createError(IBMMQ_ERROR, + String.format("Error occurred while accessing queue: %s", e.getMessage()), e); + } + } + + public static Object accessTopic(BObject queueManagerObject, BString topicName, + BString topicString, Long openTopicOption, Long options) { + MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); + try { + MQTopic mqTopic = queueManager.accessTopic(topicName.getValue(), topicString.getValue(), + openTopicOption.intValue(), options.intValue()); + BObject bTopic = ValueCreator.createObjectValue(ModuleUtils.getModule(), BTOPIC); + bTopic.addNativeData(Constants.NATIVE_TOPIC, mqTopic); + return bTopic; + } catch (MQException e) { + return createError(IBMMQ_ERROR, + String.format("Error occurred while accessing topic: %s", e.getMessage()), e); + } + } } From 71cd6eebb9afd100782e97a076ffb6b651730834 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 27 Oct 2023 22:01:52 +0530 Subject: [PATCH 13/39] Include queue related capabilities to the connector --- ballerina/destination.bal | 16 ++++- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 12 ++++ .../io/ballerina/lib/ibm.ibmmq/Queue.java | 70 +++++++++++++++++++ .../ballerina/lib/ibm.ibmmq/QueueManager.java | 2 +- .../io/ballerina/lib/ibm.ibmmq/Topic.java | 22 ++---- 5 files changed, 102 insertions(+), 20 deletions(-) create mode 100644 native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 25ca342..25e864d 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -21,11 +21,21 @@ public type Destination distinct client object { remote function get(*GetMessageOptions options) returns Message|Error?; }; -public type Queue distinct client object { +public isolated client class Queue { *Destination; -}; -public client class Topic { + remote function put(Message message) returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Queue" + } external; + + remote function get(*GetMessageOptions options) returns Message|Error = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Queue" + } external; +} + +public isolated client class Topic { *Destination; remote function put(Message message) returns Error? = diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 8401733..b4688cd 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -19,6 +19,7 @@ package io.ballerina.lib.ibm.ibmmq; import com.ibm.mq.MQException; +import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQPropertyDescriptor; import io.ballerina.runtime.api.PredefinedTypes; @@ -59,6 +60,8 @@ public class CommonUtils { private static final BString PD_CONTEXT = StringUtils.fromString("context"); private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); + private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); + private static final BString OPTIONS = StringUtils.fromString("options"); private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor(); @@ -179,6 +182,15 @@ private static BMap populateDescriptorFromMQPropertyDescriptor(MQPropertyDescrip return descriptor; } + public static MQGetMessageOptions getGetMessageOptions(BMap bOptions) { + int waitInterval = bOptions.getIntValue(WAIT_INTERVAL).intValue(); + int options = bOptions.getIntValue(OPTIONS).intValue(); + MQGetMessageOptions getMessageOptions = new MQGetMessageOptions(); + getMessageOptions.waitInterval = waitInterval; + getMessageOptions.options = options; + return getMessageOptions; + } + public static BError createError(String errorType, String message, Throwable throwable) { BError cause = ErrorCreator.createError(throwable); BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java new file mode 100644 index 0000000..01681fe --- /dev/null +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. + * + * 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. + */ + +package io.ballerina.lib.ibm.ibmmq; + +import com.ibm.mq.MQGetMessageOptions; +import com.ibm.mq.MQMessage; +import com.ibm.mq.MQQueue; +import io.ballerina.runtime.api.Environment; +import io.ballerina.runtime.api.Future; +import io.ballerina.runtime.api.values.BMap; +import io.ballerina.runtime.api.values.BObject; +import io.ballerina.runtime.api.values.BString; + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * Representation of {@link com.ibm.mq.MQQueue} with utility methods to invoke as inter-op functions. + */ +public class Queue { + private static final ExecutorService QUEUE_EXECUTOR_SERVICE = Executors.newCachedThreadPool( + new MQThreadFactory("balx-ibmmq-queue-client-network-thread")); + + public static Object put(Environment environment, BObject queueObject, BMap message) { + MQQueue queue = (MQQueue) queueObject.getNativeData(Constants.NATIVE_QUEUE); + MQMessage mqMessage = CommonUtils.getMqMessageFromBMessage(message); + Future future = environment.markAsync(); + QUEUE_EXECUTOR_SERVICE.execute(() -> { + try { + queue.put(mqMessage); + future.complete(null); + } catch (Exception e) { + future.complete(e); + } + }); + return null; + } + + public static Object get(Environment environment, BObject queueObject, BMap options) { + MQQueue queue = (MQQueue) queueObject.getNativeData(Constants.NATIVE_QUEUE); + MQGetMessageOptions getMessageOptions = CommonUtils.getGetMessageOptions(options); + Future future = environment.markAsync(); + QUEUE_EXECUTOR_SERVICE.execute(() -> { + try { + MQMessage message = new MQMessage(); + queue.get(message, getMessageOptions); + future.complete(CommonUtils.getBMessageFromMQMessage(message)); + } catch (Exception e) { + future.complete(e); + } + }); + return null; + } +} diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index d2fbc8f..52e5ab8 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -50,7 +50,7 @@ public class QueueManager { private static final String BQUEUE = "Queue"; /** - * Creates a JMS connection with the provided configurations. + * Creates a IBM MQ queue manager with the provided configurations. * * @param queueManager Ballerina queue-manager object * @param configurations IBM MQ connection configurations diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index f960775..fe0d979 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -23,7 +23,6 @@ import com.ibm.mq.MQTopic; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; -import io.ballerina.runtime.api.utils.StringUtils; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; @@ -31,12 +30,12 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +/** + * Representation of {@link com.ibm.mq.MQTopic} with utility methods to invoke as inter-op functions. + */ public class Topic { - private static final ExecutorService topicExecutorService = - Executors.newCachedThreadPool(new MQThreadFactory("balx-ibmmq-topic-client-network-thread")); - - private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); - private static final BString OPTIONS = StringUtils.fromString("options"); + private static final ExecutorService topicExecutorService = Executors.newCachedThreadPool( + new MQThreadFactory("balx-ibmmq-topic-client-network-thread")); public static Object put(Environment environment, BObject topicObject, BMap message) { MQTopic topic = (MQTopic) topicObject.getNativeData(Constants.NATIVE_TOPIC); @@ -55,7 +54,7 @@ public static Object put(Environment environment, BObject topicObject, BMap mess public static Object get(Environment environment, BObject topicObject, BMap options) { MQTopic topic = (MQTopic) topicObject.getNativeData(Constants.NATIVE_TOPIC); - MQGetMessageOptions getMessageOptions = getGetMessageOptions(options); + MQGetMessageOptions getMessageOptions = CommonUtils.getGetMessageOptions(options); Future future = environment.markAsync(); topicExecutorService.execute(() -> { try { @@ -68,13 +67,4 @@ public static Object get(Environment environment, BObject topicObject, BMap bOptions) { - int waitInterval = bOptions.getIntValue(WAIT_INTERVAL).intValue(); - int options = bOptions.getIntValue(OPTIONS).intValue(); - MQGetMessageOptions getMessageOptions = new MQGetMessageOptions(); - getMessageOptions.waitInterval = waitInterval; - getMessageOptions.options = options; - return getMessageOptions; - } } From 27df8a5cde74fc64c6b989e38e3f583c8346af5c Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 27 Oct 2023 22:05:36 +0530 Subject: [PATCH 14/39] Refactor the code-base --- ballerina/queue_manager.bal | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index c13f5f9..19261df 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -32,7 +32,8 @@ public isolated class QueueManager { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; - public isolated function accessTopic(string topicName, string topicString, OPEN_TOPIC_OPTION openTopicOption, AccessTopicOptions options) returns Topic|Error = + public isolated function accessTopic(string topicName, string topicString, OPEN_TOPIC_OPTION openTopicOption, + AccessTopicOptions options) returns Topic|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; From 0a45010f879181d37971b4dd8e6f07dc3eccb74b Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Fri, 27 Oct 2023 23:49:27 +0530 Subject: [PATCH 15/39] Incorporate review suggestions --- .../main/java/io/ballerina/lib/ibm.ibmmq/Queue.java | 12 ++++++++++-- .../main/java/io/ballerina/lib/ibm.ibmmq/Topic.java | 12 ++++++++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java index 01681fe..27e9fe2 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java @@ -23,6 +23,7 @@ import com.ibm.mq.MQQueue; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; +import io.ballerina.runtime.api.values.BError; import io.ballerina.runtime.api.values.BMap; import io.ballerina.runtime.api.values.BObject; import io.ballerina.runtime.api.values.BString; @@ -30,6 +31,9 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import static io.ballerina.lib.ibm.ibmmq.CommonUtils.createError; +import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; + /** * Representation of {@link com.ibm.mq.MQQueue} with utility methods to invoke as inter-op functions. */ @@ -46,7 +50,9 @@ public static Object put(Environment environment, BObject queueObject, BMap Date: Sat, 28 Oct 2023 06:34:47 +0530 Subject: [PATCH 16/39] Update doc-comment for the class --- .../main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java index 1f7ab82..462f1c9 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/MQThreadFactory.java @@ -20,6 +20,10 @@ import java.util.concurrent.ThreadFactory; + +/** + * A {@link ThreadFactory} object that creates new threads on demand for IBM MQ queue or topic actions. + */ public class MQThreadFactory implements ThreadFactory { private final String threadGroupName; From 4f7759b5376c64187708101991fbbc592e5cc564 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 10:08:18 +0530 Subject: [PATCH 17/39] [Automated] Update the native jar versions --- ballerina/Dependencies.toml | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 1932986..7e95fda 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -15,12 +15,35 @@ modules = [ {org = "ballerina", packageName = "jballerina.java", moduleName = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.error" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + +[[package]] +org = "ballerina" +name = "test" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.error"} +] +modules = [ + {org = "ballerina", packageName = "test", moduleName = "test"} +] + [[package]] org = "ballerinax" name = "ibm.ibmmq" version = "0.1.0" dependencies = [ - {org = "ballerina", name = "jballerina.java"} + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "test"} ] modules = [ {org = "ballerinax", packageName = "ibm.ibmmq", moduleName = "ibm.ibmmq"} From f667d46a5c7927e52b54a2b286640a55ad72b925 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 10:35:43 +0530 Subject: [PATCH 18/39] [Automated] Update the native jar versions --- ballerina/Dependencies.toml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 7e95fda..748703b 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -7,6 +7,19 @@ dependencies-toml-version = "2" distribution-version = "2201.8.0" +[[package]] +org = "ballerina" +name = "io" +version = "1.6.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"}, + {org = "ballerina", name = "lang.value"} +] +modules = [ + {org = "ballerina", packageName = "io", moduleName = "io"} +] + [[package]] org = "ballerina" name = "jballerina.java" @@ -24,6 +37,15 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"} ] +[[package]] +org = "ballerina" +name = "lang.value" +version = "0.0.0" +scope = "testOnly" +dependencies = [ + {org = "ballerina", name = "jballerina.java"} +] + [[package]] org = "ballerina" name = "test" @@ -42,6 +64,7 @@ org = "ballerinax" name = "ibm.ibmmq" version = "0.1.0" dependencies = [ + {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "test"} ] From 8a20cb00eb45ba5ce84a6d862a01f273ccb0cd54 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 10:51:45 +0530 Subject: [PATCH 19/39] [Automated] Update the native jar versions --- ballerina/Dependencies.toml | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/ballerina/Dependencies.toml b/ballerina/Dependencies.toml index 748703b..7e95fda 100644 --- a/ballerina/Dependencies.toml +++ b/ballerina/Dependencies.toml @@ -7,19 +7,6 @@ dependencies-toml-version = "2" distribution-version = "2201.8.0" -[[package]] -org = "ballerina" -name = "io" -version = "1.6.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"}, - {org = "ballerina", name = "lang.value"} -] -modules = [ - {org = "ballerina", packageName = "io", moduleName = "io"} -] - [[package]] org = "ballerina" name = "jballerina.java" @@ -37,15 +24,6 @@ dependencies = [ {org = "ballerina", name = "jballerina.java"} ] -[[package]] -org = "ballerina" -name = "lang.value" -version = "0.0.0" -scope = "testOnly" -dependencies = [ - {org = "ballerina", name = "jballerina.java"} -] - [[package]] org = "ballerina" name = "test" @@ -64,7 +42,6 @@ org = "ballerinax" name = "ibm.ibmmq" version = "0.1.0" dependencies = [ - {org = "ballerina", name = "io"}, {org = "ballerina", name = "jballerina.java"}, {org = "ballerina", name = "test"} ] From 139c10b2e6e8eddd93b983ceaec50af70fc4eaea Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 11:07:54 +0530 Subject: [PATCH 20/39] Add basic pub sub test case --- ballerina/build.gradle | 94 +++++++++---------- ballerina/constants.bal | 1 + ballerina/queue_manager.bal | 2 +- ballerina/tests/pub_sub_tests.bal | 19 ++++ ballerina/tests/resources/docker-compose.yaml | 11 +++ ballerina/types.bal | 8 +- .../ballerina/lib/ibm.ibmmq/CommonUtils.java | 11 ++- .../ballerina/lib/ibm.ibmmq/QueueManager.java | 2 +- 8 files changed, 91 insertions(+), 57 deletions(-) create mode 100644 ballerina/tests/pub_sub_tests.bal create mode 100644 ballerina/tests/resources/docker-compose.yaml diff --git a/ballerina/build.gradle b/ballerina/build.gradle index 24b2730..3b1cce2 100644 --- a/ballerina/build.gradle +++ b/ballerina/build.gradle @@ -102,51 +102,51 @@ task commitTomlFiles { } } -// task startActiveMQServer() { -// doLast { -// if (!Os.isFamily(Os.FAMILY_WINDOWS)) { -// def stdOut = new ByteArrayOutputStream() -// exec { -// commandLine 'sh', '-c', "docker ps --filter name=activemq-test" -// standardOutput = stdOut -// } -// if (!stdOut.toString().contains("activemq-test")) { -// println "Starting ActiveMQ server." -// exec { -// commandLine 'sh', '-c', "docker-compose -f tests/resources/docker-compose.yaml up -d" -// standardOutput = stdOut -// } -// println stdOut.toString() -// sleep(5 * 1000) -// } else { -// println "ActiveMQ server is already running." -// } -// } -// } -// } - -// task stopActiveMQServer() { -// doLast { -// if (!Os.isFamily(Os.FAMILY_WINDOWS)) { -// def stdOut = new ByteArrayOutputStream() -// exec { -// commandLine 'sh', '-c', "docker ps --filter name=activemq-test" -// standardOutput = stdOut -// } -// if (stdOut.toString().contains("activemq-test")) { -// println "Stopping ActiveMQ server." -// exec { -// commandLine 'sh', '-c', "docker-compose -f tests/resources/docker-compose.yaml rm -svf" -// standardOutput = stdOut -// } -// println stdOut.toString() -// sleep(5 * 1000) -// } else { -// println "ActiveMQ server is not started." -// } -// } -// } -// } + task startIBMMQServer() { + doLast { + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + def stdOut = new ByteArrayOutputStream() + exec { + commandLine 'sh', '-c', "docker ps --filter name=ibmmq-test" + standardOutput = stdOut + } + if (!stdOut.toString().contains("ibmmq-test")) { + println "Starting IBMMQ server." + exec { + commandLine 'sh', '-c', "docker-compose -f tests/resources/docker-compose.yaml up -d" + standardOutput = stdOut + } + println stdOut.toString() + sleep(5 * 1000) + } else { + println "IBMMQ server is already running." + } + } + } + } + + task stopIBMMQServer() { + doLast { + if (!Os.isFamily(Os.FAMILY_WINDOWS)) { + def stdOut = new ByteArrayOutputStream() + exec { + commandLine 'sh', '-c', "docker ps --filter name=ibmmq-test" + standardOutput = stdOut + } + if (stdOut.toString().contains("ibmmq-test")) { + println "Stopping IBMMQ server." + exec { + commandLine 'sh', '-c', "docker-compose -f tests/resources/docker-compose.yaml rm -svf" + standardOutput = stdOut + } + println stdOut.toString() + sleep(5 * 1000) + } else { + println "IBMMQ server is not started." + } + } + } + } publishing { publications { @@ -168,8 +168,8 @@ publishing { updateTomlFiles.dependsOn copyStdlibs -// test.dependsOn startActiveMQServer -// build.finalizedBy stopActiveMQServer + test.dependsOn startIBMMQServer + build.finalizedBy stopIBMMQServer build.dependsOn ":ibm.ibmmq-native:build" build.dependsOn "generatePomFileForMavenPublication" diff --git a/ballerina/constants.bal b/ballerina/constants.bal index f5e4b0e..15729b7 100644 --- a/ballerina/constants.bal +++ b/ballerina/constants.bal @@ -33,6 +33,7 @@ public const MQOO_PASS_ALL_CONTEXT = 512; public const MQOO_PASS_IDENTITY_CONTEXT = 256; public const MQOO_SET_ALL_CONTEXT = 2048; public const MQOO_SET_IDENTITY_CONTEXT = 1024; +public const MQSO_CREATE = 2; // Options related to the the get message in a topic. public const MQGMO_WAIT = 1; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 19261df..8b5e752 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -22,7 +22,7 @@ public isolated class QueueManager { check self.externInit(configurations); } - isolated function externInit(QueueManagerConfiguration configurations) returns Error? = @java:Method { + private isolated function externInit(QueueManagerConfiguration configurations) returns Error? = @java:Method { name: "init", 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal new file mode 100644 index 0000000..0a7b43e --- /dev/null +++ b/ballerina/tests/pub_sub_tests.bal @@ -0,0 +1,19 @@ +import ballerina/test; + +@test:Config {} +function basicPublisherSubscriberTest() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic subTopic = check queueManager.accessTopic("", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + future messageFuture = start getMessageFromTopic(subTopic); + Topic pubTopic = check queueManager.accessTopic("", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check pubTopic->put({ + payload: "Hello World".toBytes() + }); + Message message = check wait messageFuture; + test:assertEquals(string:fromBytes(message.payload), "Hello World"); +} + + +function getMessageFromTopic(Topic topic) returns Message|Error { + return topic->get(); +} \ No newline at end of file diff --git a/ballerina/tests/resources/docker-compose.yaml b/ballerina/tests/resources/docker-compose.yaml new file mode 100644 index 0000000..cba3df0 --- /dev/null +++ b/ballerina/tests/resources/docker-compose.yaml @@ -0,0 +1,11 @@ +version: "3.9" + +services: + mq: + image: icr.io/ibm-messaging/mq:latest + ports: + - "1414:1414" + - "9443:9443" + environment: + - LICENSE=accept + - MQ_QMGR_NAME=QM1 diff --git a/ballerina/types.bal b/ballerina/types.bal index f8e4547..63194db 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -28,11 +28,11 @@ public type QueueManagerConfiguration record {| |}; public type AccessQueueOptions MQOO_OUTPUT|MQOO_BROWSE|MQOO_INPUT_AS_Q_DEF|MQOO_INPUT_EXCLUSIVE|MQOO_INPUT_SHARED; -public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT; +public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT|MQSO_CREATE; public type GetMessageOptions record {| - GM_OPTIONS gmOptions = MQGMO_NO_SYNCPOINT; - int waitInterval = 0; + GM_OPTIONS gmOptions = MQGMO_WAIT; + int waitInterval = -1; |}; public type Property record {| @@ -41,6 +41,6 @@ public type Property record {| |}; public type Message record {| - map properties; + map properties?; byte[] payload; |}; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index b4688cd..29de4f7 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; +import java.util.Objects; import java.util.Optional; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; @@ -61,7 +62,7 @@ public class CommonUtils { private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); - private static final BString OPTIONS = StringUtils.fromString("options"); + private static final BString OPTIONS = StringUtils.fromString("gmOptions"); private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor(); @@ -75,7 +76,9 @@ public static MQMessage getMqMessageFromBMessage(BMap bMessage) String.format("Error occurred while populating payload: %s", e.getMessage()), e); } BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); - populateMQProperties(properties, mqMessage); + if (Objects.nonNull(properties)) { + populateMQProperties(properties, mqMessage); + } return mqMessage; } @@ -84,7 +87,7 @@ public static BMap getBMessageFromMQMessage(MQMessage mqMessage try { byte[] payload = new byte[mqMessage.getDataLength()]; mqMessage.readFully(payload); - bMessage.put(MESSAGE_PAYLOAD, payload); + bMessage.put(MESSAGE_PAYLOAD, ValueCreator.createArrayValue(payload)); bMessage.put(MESSAGE_PROPERTY, getBProperties(mqMessage)); return bMessage; } catch (MQException | IOException e) { @@ -196,7 +199,7 @@ public static BError createError(String errorType, String message, Throwable thr BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); if (throwable instanceof MQException exception) { errorDetails.put(ERROR_REASON_CODE, exception.getReason()); - errorDetails.put(ERROR_ERROR_CODE, exception.getErrorCode()); + errorDetails.put(ERROR_ERROR_CODE, StringUtils.fromString(exception.getErrorCode())); errorDetails.put(ERROR_COMPLETION_CODE, exception.getCompCode()); } return ErrorCreator.createError( diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 52e5ab8..1c034c5 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -74,7 +74,7 @@ private static Hashtable getConnectionProperties(BMap Date: Sat, 28 Oct 2023 11:10:04 +0530 Subject: [PATCH 21/39] Add newline --- ballerina/tests/pub_sub_tests.bal | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index 0a7b43e..a18972e 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -13,7 +13,6 @@ function basicPublisherSubscriberTest() returns error? { test:assertEquals(string:fromBytes(message.payload), "Hello World"); } - function getMessageFromTopic(Topic topic) returns Message|Error { return topic->get(); -} \ No newline at end of file +} From fa63c93a8d6866224a3c536b674731c31ddaa824 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 23:28:48 +0530 Subject: [PATCH 22/39] Add close disconnect apis --- ballerina/destination.bal | 16 ++++++++++++++-- ballerina/queue_manager.bal | 5 +++++ .../java/io/ballerina/lib/ibm.ibmmq/Queue.java | 17 +++++++++++++++++ .../ballerina/lib/ibm.ibmmq/QueueManager.java | 11 +++++++++++ .../java/io/ballerina/lib/ibm.ibmmq/Topic.java | 17 +++++++++++++++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 25e864d..53aa24b 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -18,7 +18,9 @@ import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; - remote function get(*GetMessageOptions options) returns Message|Error?; + remote function get(*GetMessageOptions options) returns Message|Error; + + remote function close() returns Error?; }; public isolated client class Queue { @@ -33,6 +35,11 @@ public isolated client class Queue { @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; + + remote function close() returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + } external; } public isolated client class Topic { @@ -43,7 +50,12 @@ public isolated client class Topic { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - remote function get(*GetMessageOptions options) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + } external; + + remote function close() returns Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 8b5e752..acce8b6 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -37,4 +37,9 @@ public isolated class QueueManager { @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; + + public isolated function disconnect() returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" + } external; } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java index 27e9fe2..f1c5997 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java @@ -18,6 +18,7 @@ package io.ballerina.lib.ibm.ibmmq; +import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQQueue; @@ -75,4 +76,20 @@ public static Object get(Environment environment, BObject queueObject, BMap { + try { + queue.close(); + future.complete(null); + } catch (MQException e) { + BError bError = createError(IBMMQ_ERROR, + String.format("Error occurred while closing the queue: %s", e.getMessage()), e); + future.complete(bError); + } + }); + return null; + } } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 1c034c5..8517841 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -111,4 +111,15 @@ public static Object accessTopic(BObject queueManagerObject, BString topicName, String.format("Error occurred while accessing topic: %s", e.getMessage()), e); } } + + public static Object disconnect(BObject queueManagerObject) { + MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); + try { + queueManager.disconnect(); + return null; + } catch (MQException e) { + return createError(IBMMQ_ERROR, + String.format("Error occurred while disconnecting queue manager: %s", e.getMessage()), e); + } + } } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index d1ecabe..a1f279e 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -18,6 +18,7 @@ package io.ballerina.lib.ibm.ibmmq; +import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQTopic; @@ -75,4 +76,20 @@ public static Object get(Environment environment, BObject topicObject, BMap { + try { + topic.close(); + future.complete(null); + } catch (MQException e) { + BError bError = createError(IBMMQ_ERROR, + String.format("Error occurred while closing the topic: %s", e.getMessage()), e); + future.complete(bError); + } + }); + return null; + } } From a091bdff04f5208bc49fe70e8ab2ff02561d3810 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 23:29:04 +0530 Subject: [PATCH 23/39] Add negative tests cases --- ballerina/tests/pub_sub_tests.bal | 166 +++++++++++++++++- ballerina/tests/resources/docker-compose.yaml | 1 + 2 files changed, 161 insertions(+), 6 deletions(-) diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index a18972e..1aee56c 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -3,16 +3,170 @@ import ballerina/test; @test:Config {} function basicPublisherSubscriberTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic subTopic = check queueManager.accessTopic("", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - future messageFuture = start getMessageFromTopic(subTopic); - Topic pubTopic = check queueManager.accessTopic("", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); check pubTopic->put({ payload: "Hello World".toBytes() }); - Message message = check wait messageFuture; + Message message = check subTopic->get(); test:assertEquals(string:fromBytes(message.payload), "Hello World"); + check subTopic->close(); + check queueManager.disconnect(); } -function getMessageFromTopic(Topic topic) returns Message|Error { - return topic->get(); +@test:Config {} +function pubSubMultipleMessagesInOrderTest() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + foreach int i in 0 ... 4 { + check pubTopic->put({ + payload: i.toString().toBytes() + }); + } + foreach int i in 0 ... 4 { + Message message = check subTopic->get(waitInterval = 2); + test:assertEquals(string:fromBytes(message.payload), i.toString()); + } + check subTopic->close(); + check queueManager.disconnect(); +} + +@test:Config {} +function subscribeWithFiniteTimeout() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check pubTopic->put({ + payload: "Hello World".toBytes() + }); + Message message = check subTopic->get(waitInterval = 5); + test:assertEquals(string:fromBytes(message.payload), "Hello World"); + check subTopic->close(); + check queueManager.disconnect(); +} + +@test:Config {} +function subscribeWithoutPublish() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Message|Error result = subTopic->get(waitInterval = 5, gmOptions = MQGMO_NO_WAIT); + if result is Error { + test:assertEquals(result.message(), "Error occurred while getting a message from the topic: MQJE001: Completion Code '2', Reason '2033'."); + test:assertEquals(result.detail().reasonCode, 2033); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check subTopic->close(); + check queueManager.disconnect(); +} + +@test:Config {} +function publishToNonExistingTopic() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic|Error result = queueManager.accessTopic("dev", "NON.EXISTING.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + if result is Error { + test:assertEquals(result.message(), "Error occurred while accessing topic: MQJE001: Completion Code '2', Reason '2085'."); + test:assertEquals(result.detail().reasonCode, 2085); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); +} + +@test:Config {} +function subscribeToNonExistingTopic() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic|Error result = queueManager.accessTopic("dev", "NON.EXISTING.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + if result is Error { + test:assertEquals(result.message(), "Error occurred while accessing topic: MQJE001: Completion Code '2', Reason '2085'."); + test:assertEquals(result.detail().reasonCode, 2085); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); +} + +@test:Config {} +function subscribeWithInvalidTopicName() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic|Error result = queueManager.accessTopic("dev", "INVALID TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + if result is Error { + test:assertEquals(result.message(), "Error occurred while accessing topic: MQJE001: Completion Code '2', Reason '2152'."); + test:assertEquals(result.detail().reasonCode, 2152); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); +} + +@test:Config {} +function publishWithInvalidTopicName() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic|Error result = queueManager.accessTopic("dev", "INVALID TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + if result is Error { + test:assertEquals(result.message(), "Error occurred while accessing topic: MQJE001: Completion Code '2', Reason '2085'."); + test:assertEquals(result.detail().reasonCode, 2085); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); +} + +@test:Config {} +function accessTopicAfterQMDisconnect() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + check queueManager.disconnect(); + Topic|Error result = queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + if result is Error { + test:assertEquals(result.message(), "Error occurred while accessing topic: MQJE001: An MQException " + + "occurred: Completion Code '2', Reason '2018'\n'MQJI002: Not connected to a queue manager.'."); + test:assertEquals(result.detail().reasonCode, 2018); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } +} + +@test:Config {} +function putToTopicAfterTopicClose() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check pubTopic->close(); + Error? result = pubTopic->put({ + payload: "Hello World".toBytes() + }); + if result is Error { + test:assertEquals(result.message(), "Error occurred while putting a message to the topic: MQJE001: " + + "An MQException occurred: Completion Code '2', Reason '2019'\n'MQJI027: The queue has been closed.'."); + test:assertEquals(result.detail().reasonCode, 2019); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); +} + +@test:Config {} +function putToTopicAfterQMDisconnect() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check queueManager.disconnect(); + Error? result = pubTopic->put({ + payload: "Hello World".toBytes() + }); + if result is Error { + test:assertEquals(result.message(), "Error occurred while putting a message to the topic: MQJE001: An MQException " + + "occurred: Completion Code '2', Reason '2018'\n'MQJI002: Not connected to a queue manager.'."); + test:assertEquals(result.detail().reasonCode, 2018); + test:assertEquals(result.detail().completionCode, 2); + } else { + test:assertFail("Expected an error"); + } + check queueManager.disconnect(); } diff --git a/ballerina/tests/resources/docker-compose.yaml b/ballerina/tests/resources/docker-compose.yaml index cba3df0..87f9597 100644 --- a/ballerina/tests/resources/docker-compose.yaml +++ b/ballerina/tests/resources/docker-compose.yaml @@ -3,6 +3,7 @@ version: "3.9" services: mq: image: icr.io/ibm-messaging/mq:latest + container_name: ibmmq-test ports: - "1414:1414" - "9443:9443" From 65f26570125614aeae3d0998aa6b81602f315be0 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sat, 28 Oct 2023 23:31:28 +0530 Subject: [PATCH 24/39] Update test names --- ballerina/tests/pub_sub_tests.bal | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index 1aee56c..23f0015 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -33,7 +33,7 @@ function pubSubMultipleMessagesInOrderTest() returns error? { } @test:Config {} -function subscribeWithFiniteTimeout() returns error? { +function subscribeWithFiniteTimeoutTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); @@ -47,7 +47,7 @@ function subscribeWithFiniteTimeout() returns error? { } @test:Config {} -function subscribeWithoutPublish() returns error? { +function subscribeWithoutPublishTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); Message|Error result = subTopic->get(waitInterval = 5, gmOptions = MQGMO_NO_WAIT); @@ -63,7 +63,7 @@ function subscribeWithoutPublish() returns error? { } @test:Config {} -function publishToNonExistingTopic() returns error? { +function publishToNonExistingTopicTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic|Error result = queueManager.accessTopic("dev", "NON.EXISTING.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); if result is Error { @@ -77,7 +77,7 @@ function publishToNonExistingTopic() returns error? { } @test:Config {} -function subscribeToNonExistingTopic() returns error? { +function subscribeToNonExistingTopicTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic|Error result = queueManager.accessTopic("dev", "NON.EXISTING.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); if result is Error { @@ -91,7 +91,7 @@ function subscribeToNonExistingTopic() returns error? { } @test:Config {} -function subscribeWithInvalidTopicName() returns error? { +function subscribeWithInvalidTopicNameTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic|Error result = queueManager.accessTopic("dev", "INVALID TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); if result is Error { @@ -105,7 +105,7 @@ function subscribeWithInvalidTopicName() returns error? { } @test:Config {} -function publishWithInvalidTopicName() returns error? { +function publishWithInvalidTopicNameTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic|Error result = queueManager.accessTopic("dev", "INVALID TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); if result is Error { @@ -119,7 +119,7 @@ function publishWithInvalidTopicName() returns error? { } @test:Config {} -function accessTopicAfterQMDisconnect() returns error? { +function accessTopicAfterQMDisconnectTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); check queueManager.disconnect(); Topic|Error result = queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); @@ -134,7 +134,7 @@ function accessTopicAfterQMDisconnect() returns error? { } @test:Config {} -function putToTopicAfterTopicClose() returns error? { +function putToTopicAfterTopicCloseTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); check pubTopic->close(); @@ -153,7 +153,7 @@ function putToTopicAfterTopicClose() returns error? { } @test:Config {} -function putToTopicAfterQMDisconnect() returns error? { +function putToTopicAfterQMDisconnectTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); check queueManager.disconnect(); From ed334b95ff703147ec399b1b9ad765033d4d64e4 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sun, 29 Oct 2023 11:34:27 +0530 Subject: [PATCH 25/39] Update java package name --- ballerina/destination.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 53aa24b..620044f 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -38,7 +38,7 @@ public isolated client class Queue { remote function close() returns Error? = @java:Method { - 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; } From afe99196bf32231b5a88624971416b3217cefe14 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sun, 29 Oct 2023 11:36:07 +0530 Subject: [PATCH 26/39] Add license header --- ballerina/destination.bal | 1 + ballerina/tests/pub_sub_tests.bal | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 620044f..081dd05 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -13,6 +13,7 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. + import ballerina/jballerina.java; public type Destination distinct client object { diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index 23f0015..05c821f 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -1,3 +1,19 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// +// 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/test; @test:Config {} From 5f7de1d8e067ce3d4def7bb5c5b327d47f866457 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Sun, 29 Oct 2023 21:22:56 +0530 Subject: [PATCH 27/39] Fix review comments --- ballerina/tests/pub_sub_tests.bal | 49 ++++++++++--------- .../ballerina/lib/ibm.ibmmq/QueueManager.java | 2 +- 2 files changed, 27 insertions(+), 24 deletions(-) diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index 05c821f..81a8579 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -19,54 +19,57 @@ import ballerina/test; @test:Config {} function basicPublisherSubscriberTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); - check pubTopic->put({ + Topic subscriber = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic publisher = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check publisher->put({ payload: "Hello World".toBytes() }); - Message message = check subTopic->get(); + Message message = check subscriber->get(); test:assertEquals(string:fromBytes(message.payload), "Hello World"); - check subTopic->close(); + check subscriber->close(); + check publisher->close(); check queueManager.disconnect(); } @test:Config {} function pubSubMultipleMessagesInOrderTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + Topic subscriber = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic publisher = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); foreach int i in 0 ... 4 { - check pubTopic->put({ + check publisher->put({ payload: i.toString().toBytes() }); } foreach int i in 0 ... 4 { - Message message = check subTopic->get(waitInterval = 2); + Message message = check subscriber->get(waitInterval = 2); test:assertEquals(string:fromBytes(message.payload), i.toString()); } - check subTopic->close(); + check subscriber->close(); + check publisher->close(); check queueManager.disconnect(); } @test:Config {} function subscribeWithFiniteTimeoutTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); - check pubTopic->put({ + Topic subscriber = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Topic publisher = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check publisher->put({ payload: "Hello World".toBytes() }); - Message message = check subTopic->get(waitInterval = 5); + Message message = check subscriber->get(waitInterval = 5); test:assertEquals(string:fromBytes(message.payload), "Hello World"); - check subTopic->close(); + check subscriber->close(); + check publisher->close(); check queueManager.disconnect(); } @test:Config {} function subscribeWithoutPublishTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic subTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - Message|Error result = subTopic->get(waitInterval = 5, gmOptions = MQGMO_NO_WAIT); + Topic subscriber = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); + Message|Error result = subscriber->get(waitInterval = 5, gmOptions = MQGMO_NO_WAIT); if result is Error { test:assertEquals(result.message(), "Error occurred while getting a message from the topic: MQJE001: Completion Code '2', Reason '2033'."); test:assertEquals(result.detail().reasonCode, 2033); @@ -74,7 +77,7 @@ function subscribeWithoutPublishTest() returns error? { } else { test:assertFail("Expected an error"); } - check subTopic->close(); + check subscriber->close(); check queueManager.disconnect(); } @@ -152,9 +155,9 @@ function accessTopicAfterQMDisconnectTest() returns error? { @test:Config {} function putToTopicAfterTopicCloseTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); - check pubTopic->close(); - Error? result = pubTopic->put({ + Topic publisher = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + check publisher->close(); + Error? result = publisher->put({ payload: "Hello World".toBytes() }); if result is Error { @@ -171,9 +174,9 @@ function putToTopicAfterTopicCloseTest() returns error? { @test:Config {} function putToTopicAfterQMDisconnectTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Topic pubTopic = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); + Topic publisher = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_PUBLICATION, MQOO_OUTPUT); check queueManager.disconnect(); - Error? result = pubTopic->put({ + Error? result = publisher->put({ payload: "Hello World".toBytes() }); if result is Error { diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 8517841..85a4780 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -116,10 +116,10 @@ public static Object disconnect(BObject queueManagerObject) { MQQueueManager queueManager = (MQQueueManager) queueManagerObject.getNativeData(NATIVE_QUEUE_MANAGER); try { queueManager.disconnect(); - return null; } catch (MQException e) { return createError(IBMMQ_ERROR, String.format("Error occurred while disconnecting queue manager: %s", e.getMessage()), e); } + return null; } } From 77883a4087e494120263426c4fa0649aa6921481 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Mon, 30 Oct 2023 09:16:59 +0530 Subject: [PATCH 28/39] Update get api to be non blocking --- ballerina/destination.bal | 6 ++-- ballerina/tests/pub_sub_tests.bal | 35 +++++++++++-------- ballerina/types.bal | 4 +-- .../io/ballerina/lib/ibm.ibmmq/Topic.java | 14 +++++--- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 081dd05..aa76ad4 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -19,7 +19,7 @@ import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; - remote function get(*GetMessageOptions options) returns Message|Error; + remote function get(*GetMessageOptions options) returns Message|Error?; remote function close() returns Error?; }; @@ -32,7 +32,7 @@ public isolated client class Queue { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; - remote function get(*GetMessageOptions options) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; @@ -51,7 +51,7 @@ public isolated client class Topic { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - remote function get(*GetMessageOptions options) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; diff --git a/ballerina/tests/pub_sub_tests.bal b/ballerina/tests/pub_sub_tests.bal index 81a8579..297ad62 100644 --- a/ballerina/tests/pub_sub_tests.bal +++ b/ballerina/tests/pub_sub_tests.bal @@ -13,7 +13,6 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. - import ballerina/test; @test:Config {} @@ -24,8 +23,12 @@ function basicPublisherSubscriberTest() returns error? { check publisher->put({ payload: "Hello World".toBytes() }); - Message message = check subscriber->get(); - test:assertEquals(string:fromBytes(message.payload), "Hello World"); + Message? message = check subscriber->get(); + if message !is () { + test:assertEquals(string:fromBytes(message.payload), "Hello World"); + } else { + test:assertFail("Expected a value for message"); + } check subscriber->close(); check publisher->close(); check queueManager.disconnect(); @@ -42,8 +45,12 @@ function pubSubMultipleMessagesInOrderTest() returns error? { }); } foreach int i in 0 ... 4 { - Message message = check subscriber->get(waitInterval = 2); - test:assertEquals(string:fromBytes(message.payload), i.toString()); + Message? message = check subscriber->get(waitInterval = 2); + if message !is () { + test:assertEquals(string:fromBytes(message.payload), i.toString()); + } else { + test:assertFail("Expected a value for message"); + } } check subscriber->close(); check publisher->close(); @@ -58,8 +65,12 @@ function subscribeWithFiniteTimeoutTest() returns error? { check publisher->put({ payload: "Hello World".toBytes() }); - Message message = check subscriber->get(waitInterval = 5); - test:assertEquals(string:fromBytes(message.payload), "Hello World"); + Message? message = check subscriber->get(waitInterval = 5); + if message !is () { + test:assertEquals(string:fromBytes(message.payload), "Hello World"); + } else { + test:assertFail("Expected a value for message"); + } check subscriber->close(); check publisher->close(); check queueManager.disconnect(); @@ -69,14 +80,8 @@ function subscribeWithFiniteTimeoutTest() returns error? { function subscribeWithoutPublishTest() returns error? { QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); Topic subscriber = check queueManager.accessTopic("dev", "DEV.BASE.TOPIC", OPEN_AS_SUBSCRIPTION, MQSO_CREATE); - Message|Error result = subscriber->get(waitInterval = 5, gmOptions = MQGMO_NO_WAIT); - if result is Error { - test:assertEquals(result.message(), "Error occurred while getting a message from the topic: MQJE001: Completion Code '2', Reason '2033'."); - test:assertEquals(result.detail().reasonCode, 2033); - test:assertEquals(result.detail().completionCode, 2); - } else { - test:assertFail("Expected an error"); - } + Message|Error? result = subscriber->get(waitInterval = 5); + test:assertTrue(result is ()); check subscriber->close(); check queueManager.disconnect(); } diff --git a/ballerina/types.bal b/ballerina/types.bal index 63194db..d5cdb6a 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -31,8 +31,8 @@ public type AccessQueueOptions MQOO_OUTPUT|MQOO_BROWSE|MQOO_INPUT_AS_Q_DEF|MQOO_ public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT|MQSO_CREATE; public type GetMessageOptions record {| - GM_OPTIONS gmOptions = MQGMO_WAIT; - int waitInterval = -1; + GM_OPTIONS gmOptions = MQGMO_NO_WAIT; + int waitInterval = 0; |}; public type Property record {| diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index a1f279e..b608ffe 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -22,6 +22,7 @@ import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQTopic; +import com.ibm.mq.constants.CMQC; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.values.BError; @@ -68,10 +69,15 @@ public static Object get(Environment environment, BObject topicObject, BMap Date: Mon, 30 Oct 2023 09:17:44 +0530 Subject: [PATCH 29/39] Remove public from extern init --- ballerina/queue_manager.bal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index acce8b6..f65bedc 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -22,7 +22,7 @@ public isolated class QueueManager { check self.externInit(configurations); } - private isolated function externInit(QueueManagerConfiguration configurations) returns Error? = @java:Method { + isolated function externInit(QueueManagerConfiguration configurations) returns Error? = @java:Method { name: "init", 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; From ef48153c08706687e82acaced905cc6a8be9a564 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Mon, 30 Oct 2023 09:54:47 +0530 Subject: [PATCH 30/39] Add close and disconnect apis --- ballerina/constants.bal | 1 + ballerina/destination.bal | 14 +++++++++++++- ballerina/queue_manager.bal | 5 +++++ ballerina/types.bal | 6 +++--- .../io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 10 +++++++--- .../java/io/ballerina/lib/ibm.ibmmq/Queue.java | 17 +++++++++++++++++ .../ballerina/lib/ibm.ibmmq/QueueManager.java | 13 ++++++++++++- .../java/io/ballerina/lib/ibm.ibmmq/Topic.java | 17 +++++++++++++++++ 8 files changed, 75 insertions(+), 8 deletions(-) diff --git a/ballerina/constants.bal b/ballerina/constants.bal index f5e4b0e..15729b7 100644 --- a/ballerina/constants.bal +++ b/ballerina/constants.bal @@ -33,6 +33,7 @@ public const MQOO_PASS_ALL_CONTEXT = 512; public const MQOO_PASS_IDENTITY_CONTEXT = 256; public const MQOO_SET_ALL_CONTEXT = 2048; public const MQOO_SET_IDENTITY_CONTEXT = 1024; +public const MQSO_CREATE = 2; // Options related to the the get message in a topic. public const MQGMO_WAIT = 1; diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 25e864d..0229f08 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -13,12 +13,15 @@ // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. + import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; remote function get(*GetMessageOptions options) returns Message|Error?; + + remote function close() returns Error?; }; public isolated client class Queue { @@ -33,6 +36,11 @@ public isolated client class Queue { @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; + + remote function close() returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Queue" + } external; } public isolated client class Topic { @@ -47,5 +55,9 @@ public isolated client class Topic { @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; -}; + remote function close() returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.Topic" + } external; +}; diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index 19261df..f65bedc 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -37,4 +37,9 @@ public isolated class QueueManager { @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; + + public isolated function disconnect() returns Error? = + @java:Method { + 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" + } external; } diff --git a/ballerina/types.bal b/ballerina/types.bal index f8e4547..d5cdb6a 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -28,10 +28,10 @@ public type QueueManagerConfiguration record {| |}; public type AccessQueueOptions MQOO_OUTPUT|MQOO_BROWSE|MQOO_INPUT_AS_Q_DEF|MQOO_INPUT_EXCLUSIVE|MQOO_INPUT_SHARED; -public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT; +public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT|MQSO_CREATE; public type GetMessageOptions record {| - GM_OPTIONS gmOptions = MQGMO_NO_SYNCPOINT; + GM_OPTIONS gmOptions = MQGMO_NO_WAIT; int waitInterval = 0; |}; @@ -41,6 +41,6 @@ public type Property record {| |}; public type Message record {| - map properties; + map properties?; byte[] payload; |}; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index b4688cd..47536d2 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -34,6 +34,7 @@ import java.io.IOException; import java.util.Collections; import java.util.Enumeration; +import java.util.Objects; import java.util.Optional; import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR; @@ -61,7 +62,7 @@ public class CommonUtils { private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); - private static final BString OPTIONS = StringUtils.fromString("options"); + private static final BString OPTIONS = StringUtils.fromString("gmOptions"); private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor(); @@ -75,6 +76,9 @@ public static MQMessage getMqMessageFromBMessage(BMap bMessage) String.format("Error occurred while populating payload: %s", e.getMessage()), e); } BMap properties = (BMap) bMessage.getMapValue(MESSAGE_PROPERTIES); + if (Objects.nonNull(properties)) { + populateMQProperties(properties, mqMessage); + } populateMQProperties(properties, mqMessage); return mqMessage; } @@ -84,7 +88,7 @@ public static BMap getBMessageFromMQMessage(MQMessage mqMessage try { byte[] payload = new byte[mqMessage.getDataLength()]; mqMessage.readFully(payload); - bMessage.put(MESSAGE_PAYLOAD, payload); + bMessage.put(MESSAGE_PAYLOAD, ValueCreator.createArrayValue(payload)); bMessage.put(MESSAGE_PROPERTY, getBProperties(mqMessage)); return bMessage; } catch (MQException | IOException e) { @@ -196,7 +200,7 @@ public static BError createError(String errorType, String message, Throwable thr BMap errorDetails = ValueCreator.createRecordValue(getModule(), ERROR_DETAILS); if (throwable instanceof MQException exception) { errorDetails.put(ERROR_REASON_CODE, exception.getReason()); - errorDetails.put(ERROR_ERROR_CODE, exception.getErrorCode()); + errorDetails.put(ERROR_ERROR_CODE, StringUtils.fromString(exception.getErrorCode())); errorDetails.put(ERROR_COMPLETION_CODE, exception.getCompCode()); } return ErrorCreator.createError( diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java index 27e9fe2..f1c5997 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java @@ -18,6 +18,7 @@ package io.ballerina.lib.ibm.ibmmq; +import com.ibm.mq.MQException; import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQQueue; @@ -75,4 +76,20 @@ public static Object get(Environment environment, BObject queueObject, BMap { + try { + queue.close(); + future.complete(null); + } catch (MQException e) { + BError bError = createError(IBMMQ_ERROR, + String.format("Error occurred while closing the queue: %s", e.getMessage()), e); + future.complete(bError); + } + }); + return null; + } } diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 52e5ab8..85a4780 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -74,7 +74,7 @@ private static Hashtable getConnectionProperties(BMap { + try { + topic.close(); + future.complete(null); + } catch (MQException e) { + BError bError = createError(IBMMQ_ERROR, + String.format("Error occurred while closing the topic: %s", e.getMessage()), e); + future.complete(bError); + } + }); + return null; + } } From b85c485d93f0f239534f47eeb9f293f980fbadd1 Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Mon, 30 Oct 2023 09:57:17 +0530 Subject: [PATCH 31/39] Remove duplicated util function --- native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 1 - 1 file changed, 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 47536d2..29de4f7 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -79,7 +79,6 @@ public static MQMessage getMqMessageFromBMessage(BMap bMessage) if (Objects.nonNull(properties)) { populateMQProperties(properties, mqMessage); } - populateMQProperties(properties, mqMessage); return mqMessage; } From e6d4778e43bc6512da58af07406a4ce1fe78568e Mon Sep 17 00:00:00 2001 From: dilanSachi Date: Mon, 30 Oct 2023 10:00:56 +0530 Subject: [PATCH 32/39] Add nil value handling in topic get --- ballerina/destination.bal | 4 ++-- .../java/io/ballerina/lib/ibm.ibmmq/Topic.java | 14 ++++++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 0229f08..33d0fbf 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -32,7 +32,7 @@ public isolated client class Queue { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; - remote function get(*GetMessageOptions options) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; @@ -51,7 +51,7 @@ public isolated client class Topic { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - remote function get(*GetMessageOptions options) returns Message|Error = + remote function get(*GetMessageOptions options) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java index a1f279e..b608ffe 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Topic.java @@ -22,6 +22,7 @@ import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQTopic; +import com.ibm.mq.constants.CMQC; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.values.BError; @@ -68,10 +69,15 @@ public static Object get(Environment environment, BObject topicObject, BMap Date: Mon, 30 Oct 2023 10:18:43 +0530 Subject: [PATCH 33/39] Update wait-time configuration value --- ballerina/types.bal | 2 +- .../src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ballerina/types.bal b/ballerina/types.bal index d5cdb6a..5f692d1 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -32,7 +32,7 @@ public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF| public type GetMessageOptions record {| GM_OPTIONS gmOptions = MQGMO_NO_WAIT; - int waitInterval = 0; + int waitInterval = 10; |}; public type Property record {| diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index 29de4f7..d441506 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -189,7 +189,7 @@ public static MQGetMessageOptions getGetMessageOptions(BMap bOp int waitInterval = bOptions.getIntValue(WAIT_INTERVAL).intValue(); int options = bOptions.getIntValue(OPTIONS).intValue(); MQGetMessageOptions getMessageOptions = new MQGetMessageOptions(); - getMessageOptions.waitInterval = waitInterval; + getMessageOptions.waitInterval = waitInterval * 1000; getMessageOptions.options = options; return getMessageOptions; } From ae193a6d10fd5e22de046892294f374bc20080c7 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 30 Oct 2023 10:20:53 +0530 Subject: [PATCH 34/39] Update queue native API to return nil if no message is available --- .../java/io/ballerina/lib/ibm.ibmmq/Queue.java | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java index f1c5997..ecb72d5 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/Queue.java @@ -22,6 +22,7 @@ import com.ibm.mq.MQGetMessageOptions; import com.ibm.mq.MQMessage; import com.ibm.mq.MQQueue; +import com.ibm.mq.constants.CMQC; import io.ballerina.runtime.api.Environment; import io.ballerina.runtime.api.Future; import io.ballerina.runtime.api.values.BError; @@ -50,7 +51,7 @@ public static Object put(Environment environment, BObject queueObject, BMap Date: Mon, 30 Oct 2023 16:06:16 +0530 Subject: [PATCH 35/39] Remove restrictions added on option types --- ballerina/queue_manager.bal | 4 ++-- ballerina/types.bal | 7 +------ 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/ballerina/queue_manager.bal b/ballerina/queue_manager.bal index f65bedc..2e6635f 100644 --- a/ballerina/queue_manager.bal +++ b/ballerina/queue_manager.bal @@ -27,13 +27,13 @@ public isolated class QueueManager { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; - public isolated function accessQueue(string queueName, AccessQueueOptions options) returns Queue|Error = + public isolated function accessQueue(string queueName, int options) returns Queue|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; public isolated function accessTopic(string topicName, string topicString, OPEN_TOPIC_OPTION openTopicOption, - AccessTopicOptions options) returns Topic|Error = + int options) returns Topic|Error = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.QueueManager" } external; diff --git a/ballerina/types.bal b/ballerina/types.bal index d5cdb6a..69d2856 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -14,8 +14,6 @@ // specific language governing permissions and limitations // under the License. -public type GM_OPTIONS MQGMO_WAIT|MQGMO_NO_WAIT|MQGMO_SYNCPOINT|MQGMO_NO_SYNCPOINT|MQGMO_BROWSE_FIRST|MQGMO_BROWSE_MSG_UNDER_CURSOR|MQGMO_MSG_UNDER_CURSOR|MQGMO_LOCK|MQGMO_UNLOCK|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_BROWSE_NEXT|MQGMO_ACCEPT_TRUNCATED_MSG|MQGMO_FAIL_IF_QUIESCING|MQGMO_CONVERT; - public type OPEN_TOPIC_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION; public type QueueManagerConfiguration record {| @@ -27,11 +25,8 @@ public type QueueManagerConfiguration record {| string password?; |}; -public type AccessQueueOptions MQOO_OUTPUT|MQOO_BROWSE|MQOO_INPUT_AS_Q_DEF|MQOO_INPUT_EXCLUSIVE|MQOO_INPUT_SHARED; -public type AccessTopicOptions MQOO_ALTERNATE_USER_AUTHORITY|MQOO_BIND_AS_Q_DEF|MQOO_FAIL_IF_QUIESCING|MQOO_OUTPUT|MQOO_PASS_ALL_CONTEXT|MQOO_PASS_IDENTITY_CONTEXT|MQOO_SET_ALL_CONTEXT|MQOO_SET_IDENTITY_CONTEXT|MQSO_CREATE; - public type GetMessageOptions record {| - GM_OPTIONS gmOptions = MQGMO_NO_WAIT; + int gmOptions = MQGMO_NO_WAIT; int waitInterval = 0; |}; From 62017d1d38477581ab9386ae0190fd222f65e451 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 30 Oct 2023 16:20:47 +0530 Subject: [PATCH 36/39] Add basic test case for queue producer and consumer --- .../tests/queue_producer_consumer_tests.bal | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 ballerina/tests/queue_producer_consumer_tests.bal diff --git a/ballerina/tests/queue_producer_consumer_tests.bal b/ballerina/tests/queue_producer_consumer_tests.bal new file mode 100644 index 0000000..69651c6 --- /dev/null +++ b/ballerina/tests/queue_producer_consumer_tests.bal @@ -0,0 +1,38 @@ +// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. +// +// 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/test; + +@test:Config { + groups: ["ibmq-queue"] +} +function basicQueueProducerConsumerTest() returns error? { + QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); + Queue producer = check queueManager.accessQueue("DEV.QUEUE.1", MQOO_OUTPUT); + Queue consumer = check queueManager.accessQueue("DEV.QUEUE.1", MQOO_INPUT_AS_Q_DEF); + check producer->put({ + payload: "Hello World".toBytes() + }); + Message? message = check consumer->get(); + if message !is () { + test:assertEquals(string:fromBytes(message.payload), "Hello World"); + } else { + test:assertFail("Expected a value for message"); + } + check producer->close(); + check consumer->close(); + check queueManager.disconnect(); +} From 8db5a92457d6e6bfcba42f1ec48c66bc4833b804 Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 30 Oct 2023 16:21:34 +0530 Subject: [PATCH 37/39] Revert "Add basic test case for queue producer and consumer" This reverts commit 62017d1d38477581ab9386ae0190fd222f65e451. --- .../tests/queue_producer_consumer_tests.bal | 38 ------------------- 1 file changed, 38 deletions(-) delete mode 100644 ballerina/tests/queue_producer_consumer_tests.bal diff --git a/ballerina/tests/queue_producer_consumer_tests.bal b/ballerina/tests/queue_producer_consumer_tests.bal deleted file mode 100644 index 69651c6..0000000 --- a/ballerina/tests/queue_producer_consumer_tests.bal +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) 2023, WSO2 LLC. (http://www.wso2.org) All Rights Reserved. -// -// 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/test; - -@test:Config { - groups: ["ibmq-queue"] -} -function basicQueueProducerConsumerTest() returns error? { - QueueManager queueManager = check new QueueManager(name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN"); - Queue producer = check queueManager.accessQueue("DEV.QUEUE.1", MQOO_OUTPUT); - Queue consumer = check queueManager.accessQueue("DEV.QUEUE.1", MQOO_INPUT_AS_Q_DEF); - check producer->put({ - payload: "Hello World".toBytes() - }); - Message? message = check consumer->get(); - if message !is () { - test:assertEquals(string:fromBytes(message.payload), "Hello World"); - } else { - test:assertFail("Expected a value for message"); - } - check producer->close(); - check consumer->close(); - check queueManager.disconnect(); -} From 03e6498fec5acdb9acaca78e8cdf43b1034f7b8b Mon Sep 17 00:00:00 2001 From: ayeshLK Date: Mon, 30 Oct 2023 16:20:23 +0530 Subject: [PATCH 38/39] Fix logic issue in saving native-queue in the bobject --- .../src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java index 85a4780..846b102 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/QueueManager.java @@ -89,7 +89,7 @@ public static Object accessQueue(BObject queueManagerObject, BString queueName, try { MQQueue mqQueue = queueManager.accessQueue(queueName.getValue(), options.intValue()); BObject bQueue = ValueCreator.createObjectValue(ModuleUtils.getModule(), BQUEUE); - bQueue.addNativeData(Constants.NATIVE_TOPIC, mqQueue); + bQueue.addNativeData(Constants.NATIVE_QUEUE, mqQueue); return bQueue; } catch (MQException e) { return createError(IBMMQ_ERROR, From 84aad4393a034fe91df7f524bf5056ebca8f7aee Mon Sep 17 00:00:00 2001 From: Dilan Sachintha Nayanajith Date: Tue, 31 Oct 2023 09:42:50 +0530 Subject: [PATCH 39/39] Update get message variable name --- ballerina/destination.bal | 6 +++--- ballerina/types.bal | 2 +- .../main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ballerina/destination.bal b/ballerina/destination.bal index 33d0fbf..2e48a4e 100644 --- a/ballerina/destination.bal +++ b/ballerina/destination.bal @@ -19,7 +19,7 @@ import ballerina/jballerina.java; public type Destination distinct client object { remote function put(Message message) returns Error?; - remote function get(*GetMessageOptions options) returns Message|Error?; + remote function get(*GetMessageOptions getMessageOptions) returns Message|Error?; remote function close() returns Error?; }; @@ -32,7 +32,7 @@ public isolated client class Queue { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; - remote function get(*GetMessageOptions options) returns Message|Error? = + remote function get(*GetMessageOptions getMessageOptions) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Queue" } external; @@ -51,7 +51,7 @@ public isolated client class Topic { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; - remote function get(*GetMessageOptions options) returns Message|Error? = + remote function get(*GetMessageOptions getMessageOptions) returns Message|Error? = @java:Method { 'class: "io.ballerina.lib.ibm.ibmmq.Topic" } external; diff --git a/ballerina/types.bal b/ballerina/types.bal index dd0d5a3..ecb6bba 100644 --- a/ballerina/types.bal +++ b/ballerina/types.bal @@ -26,7 +26,7 @@ public type QueueManagerConfiguration record {| |}; public type GetMessageOptions record {| - int gmOptions = MQGMO_NO_WAIT; + int options = MQGMO_NO_WAIT; int waitInterval = 10; |}; diff --git a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java index d441506..295a071 100644 --- a/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java +++ b/native/src/main/java/io/ballerina/lib/ibm.ibmmq/CommonUtils.java @@ -62,7 +62,7 @@ public class CommonUtils { private static final BString PROPERTY_VALUE = StringUtils.fromString("value"); private static final BString PROPERTY_DESCRIPTOR = StringUtils.fromString("descriptor"); private static final BString WAIT_INTERVAL = StringUtils.fromString("waitInterval"); - private static final BString OPTIONS = StringUtils.fromString("gmOptions"); + private static final BString OPTIONS = StringUtils.fromString("options"); private static final MQPropertyDescriptor defaultPropertyDescriptor = new MQPropertyDescriptor();