Skip to content

Commit

Permalink
Merge pull request #27 from dilanSachi/add-mqiih
Browse files Browse the repository at this point in the history
Add MQIIH header support
  • Loading branch information
dilanSachi committed Nov 15, 2023
2 parents 5fdf426 + c4e86f9 commit 5bda24c
Show file tree
Hide file tree
Showing 10 changed files with 253 additions and 36 deletions.
6 changes: 3 additions & 3 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
org = "ballerinax"
name = "ibm.ibmmq"
version = "0.1.1"
version = "0.1.2"
authors = ["Ballerina"]
keywords = ["ibm-mq"]
repository = "https://github.com/ballerina-platform/module-ballerinax-ibm.ibmmq"
Expand All @@ -12,8 +12,8 @@ distribution = "2201.8.0"
[[platform.java17.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "ibm.ibmmq-native"
version = "0.1.1"
path = "../native/build/libs/ibm.ibmmq-native-0.1.1.jar"
version = "0.1.2"
path = "../native/build/libs/ibm.ibmmq-native-0.1.2-SNAPSHOT.jar"

[[platform.java17.dependency]]
groupId = "org.json"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ modules = [
[[package]]
org = "ballerinax"
name = "ibm.ibmmq"
version = "0.1.1"
version = "0.1.2"
dependencies = [
{org = "ballerina", name = "crypto"},
{org = "ballerina", name = "jballerina.java"},
Expand Down
2 changes: 2 additions & 0 deletions ballerina/constants.bal
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ public const int MQGMO_CONVERT = 16384;
# Subscribe Option create
public const int MQSO_CREATE = 2;

const string DEFAULT_BLANK_VALUE = " ";

// SSL cipher suite related constants

# SSL cipher suite using ECDHE-ECDSA for key exchange with 3DES encryption and SHA integrity.
Expand Down
93 changes: 86 additions & 7 deletions ballerina/tests/topic_publisher_subscriber_tests.bal
Original file line number Diff line number Diff line change
Expand Up @@ -358,9 +358,6 @@ function publishSubscribeWithMQCIHHeadersTest() returns error? {
'function: "test",
abendCode: "code",
authenticator: "authenti",
reserved1: "reserve1",
reserved2: "reserve2",
reserved3: "reserve3",
replyToFormat: "reformat",
remoteSysId: "rSId",
remoteTransId: "rTId",
Expand Down Expand Up @@ -405,9 +402,6 @@ function publishSubscribeWithMQCIHHeadersTest() returns error? {
'function: "test",
abendCode: "code",
authenticator: "authenti",
reserved1: "reserve1",
reserved2: "reserve2",
reserved3: "reserve3",
replyToFormat: "reformat",
remoteSysId: "rSId",
remoteTransId: "rTId",
Expand All @@ -428,6 +422,64 @@ function publishSubscribeWithMQCIHHeadersTest() returns error? {
check queueManager.disconnect();
}

@test:Config {
groups: ["ibmmqTopic"]
}
function publishSubscribeWithMQIIHHeadersTest() returns error? {
QueueManager queueManager = check new (name = "QM1", host = "localhost", channel = "DEV.APP.SVRCONN");
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(),
headers: [
{
flags: 12,
lTermOverride: "ltorride",
mfsMapName: "mfsmapnm",
replyToFormat: "reformat",
authenticator: "authenti",
tranInstanceId: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
tranState: "t",
commitMode: "c",
securityScope: "s"
}
]
});
Message? message = check subscriber->get();
if message !is () {
test:assertEquals(string:fromBytes(message.payload), "Hello World");
Header[]? headers = message.headers;
if headers is () {
test:assertFail("Expected MQIIH headers");
}
Header header = headers[0];
if header is MQIIH {
test:assertEquals(header, {
flags: 12,
encoding: 273,
strucId:"IIH ",
strucLength:84,
version:1,
codedCharSetId:0,
format:" ",
lTermOverride: "ltorride",
mfsMapName: "mfsmapnm",
replyToFormat: "reformat",
authenticator: "authenti",
tranInstanceId: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
tranState: "t",
commitMode: "c",
securityScope: "s"
});
}
} else {
test:assertFail("Expected a value for message");
}
check subscriber->close();
check publisher->close();
check queueManager.disconnect();
}

@test:Config {
groups: ["ibmmqTopic"]
}
Expand Down Expand Up @@ -455,6 +507,17 @@ function publishSubscribeWithMultipleHeaderTypesTest() returns error? {
{
flags: 15,
nameValuePairs: {"pair1": "value1", "pair2": "value2"}
},
{
flags: 12,
lTermOverride: "ltorride",
mfsMapName: "mfsmapnm",
replyToFormat: "reformat",
authenticator: "authenti",
tranInstanceId: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16],
tranState: "t",
commitMode: "c",
securityScope: "s"
}
]
});
Expand All @@ -465,25 +528,41 @@ function publishSubscribeWithMultipleHeaderTypesTest() returns error? {
if headers is () {
test:assertFail("Expected MQCIH headers");
}
test:assertTrue(headers.length() == 3);
test:assertTrue(headers.length() == 4);
Header header = headers[0];
if header is MQCIH {
test:assertEquals(header.facility, "facility".toBytes());
test:assertEquals(header.'function, "test");
test:assertEquals(header.abendCode, "code");
test:assertEquals(header.authenticator, "authenti");
} else {
test:assertFail("Expected MQCIH header");
}
header = headers[1];
if header is MQRFH2 {
test:assertEquals(header.flags, 12);
test:assertEquals(header.fieldValues.get(["mcd", "Msd"]), {folder: "mcd", 'field: "Msd", value: "TestMcdValue"});
test:assertEquals(header.fieldValues.get(["jms", "Dlv"]), {folder: "jms", 'field: "Dlv", value: 134});
test:assertEquals(header.fieldValues.get(["mqps", "Ret"]), {folder: "mqps", 'field: "Ret", value: "1"});
} else {
test:assertFail("Expected MQRFH2 header");
}
header = headers[2];
if header is MQRFH {
test:assertEquals(header.flags, 15);
test:assertEquals(header.nameValuePairs, {"pair1": "value1", "pair2": "value2"});
} else {
test:assertFail("Expected MQRFH header");
}
header = headers[3];
if header is MQIIH {
test:assertEquals(header.flags, 12);
test:assertEquals(header.lTermOverride, "ltorride");
test:assertEquals(header.replyToFormat, "reformat");
test:assertEquals(header.authenticator, "authenti");
test:assertEquals(header.commitMode, "c");
} else {
test:assertFail("Expected MQIIH header");
}
} else {
test:assertFail("Expected a value for message");
Expand Down
50 changes: 40 additions & 10 deletions ballerina/types.bal
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import ballerina/crypto;
public type OPEN_TOPIC_OPTION OPEN_AS_SUBSCRIPTION|OPEN_AS_PUBLICATION;

# Header types that are provided in the IBM MQ message.
public type Header MQRFH2|MQRFH|MQCIH;
public type Header MQRFH2|MQRFH|MQCIH|MQIIH;

# The SSL Cipher Suite to be used for secure communication with the IBM MQ server.
public type SslCipherSuite SSL_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA|SSL_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
Expand Down Expand Up @@ -152,7 +152,7 @@ public type MQRFH2 record {|
int nameValueCCSID = 1208;
byte[] nameValueData = [];
int nameValueLength = 0;
string format = " ";
string format = DEFAULT_BLANK_VALUE;
string strucId = "RFH ";
int strucLength = 36;
int version = 2;
Expand Down Expand Up @@ -187,7 +187,7 @@ public type MQRFH record {|
int strucLength = 32;
int version = 1;
int codedCharSetId = 0;
string format = " ";
string format = DEFAULT_BLANK_VALUE;
map<string> nameValuePairs = {};
|};

Expand All @@ -214,9 +214,6 @@ public type MQRFH record {|
# + 'function - field description
# + abendCode - Abend code
# + authenticator - Password or passticket
# + reserved1 - Reserved
# + reserved2 - Reserved
# + reserved3 - Reserved
# + replyToFormat - MQ format name of reply message
# + remoteSysId - Remote CICS system Id to use
# + remoteTransId - CICS RTRANSID to use
Expand All @@ -231,7 +228,7 @@ public type MQCIH record {|
int flags = 0;
int encoding = 0;
int codedCharSetId = 0;
string format = " ";
string format = DEFAULT_BLANK_VALUE;
string strucId = "CIH ";
int strucLength = 180;
int version = 2;
Expand All @@ -249,9 +246,6 @@ public type MQCIH record {|
string 'function = "";
string abendCode = "";
string authenticator = "";
string reserved1 = "";
string reserved2 = "";
string reserved3 = "";
string replyToFormat = "";
string remoteSysId = "";
string remoteTransId = "";
Expand All @@ -263,3 +257,39 @@ public type MQCIH record {|
string nextTransactionId = "";
int inputItem = 0;
|};

# Header record representing the MQIIH structure.
#
# + flags - Flag of the header
# + encoding - Numeric encoding of data that follows NameValueString
# + strucId - Structure identifier
# + strucLength - Length of the structure
# + version - Structure version number
# + codedCharSetId - Character set identifier of data that follows NameValueString
# + format - Format name of data that follows NameValueString
# + lTermOverride - The logical terminal override, placed in the IO PCB field
# + mfsMapName - The message format services map name, placed in the IO PCB field
# + replyToFormat - This is the MQ format name of the reply message that is sent
# in response to the current message
# + authenticator - The RACF® password or PassTicket
# + tranInstanceId - This is the transaction instance identifier
# + tranState - This indicates the IMS conversation state
# + commitMode - IMS commit mode
# + securityScope - This indicates the IMS security processing required
public type MQIIH record {|
int flags = 0;
int encoding = 0;
string strucId = "IIH ";
int strucLength = 84;
int version = 1;
int codedCharSetId = 0;
string format = DEFAULT_BLANK_VALUE;
string lTermOverride = DEFAULT_BLANK_VALUE;
string mfsMapName = DEFAULT_BLANK_VALUE;
string replyToFormat = DEFAULT_BLANK_VALUE;
string authenticator = DEFAULT_BLANK_VALUE;
byte[] tranInstanceId = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
string:Char tranState = " ";
string:Char commitMode = "0";
string:Char securityScope = "C";
|};
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
import static io.ballerina.lib.ibm.ibmmq.Constants.FORMAT_FIELD;
import static io.ballerina.lib.ibm.ibmmq.Constants.IBMMQ_ERROR;
import static io.ballerina.lib.ibm.ibmmq.Constants.MQCIH_RECORD_NAME;
import static io.ballerina.lib.ibm.ibmmq.Constants.MQIIH_RECORD_NAME;
import static io.ballerina.lib.ibm.ibmmq.Constants.MQRFH2_RECORD_NAME;
import static io.ballerina.lib.ibm.ibmmq.Constants.MQRFH_RECORD_NAME;
import static io.ballerina.lib.ibm.ibmmq.Constants.MESSAGE_HEADERS;
Expand All @@ -80,7 +81,8 @@
import static io.ballerina.lib.ibm.ibmmq.Constants.REPLY_TO_QUEUE_NAME_FIELD;
import static io.ballerina.lib.ibm.ibmmq.Constants.WAIT_INTERVAL;
import static io.ballerina.lib.ibm.ibmmq.ModuleUtils.getModule;
import static io.ballerina.lib.ibm.ibmmq.headers.MQCHIHHeader.createMQCIHHeaderFromBHeader;
import static io.ballerina.lib.ibm.ibmmq.headers.MQCIHHeader.createMQCIHHeaderFromBHeader;
import static io.ballerina.lib.ibm.ibmmq.headers.MQIIHHeader.createMQIIHHeaderFromBHeader;
import static io.ballerina.lib.ibm.ibmmq.headers.MQRFH2Header.createMQRFH2HeaderFromBHeader;
import static io.ballerina.lib.ibm.ibmmq.headers.MQRFHHeader.createMQRFHHeaderFromBHeader;

Expand All @@ -94,7 +96,8 @@ public class CommonUtils {
TypeCreator.createUnionType(List.of(
TypeCreator.createRecordType(MQRFH2_RECORD_NAME, getModule(), SymbolFlags.PUBLIC, true, 0),
TypeCreator.createRecordType(MQRFH_RECORD_NAME, getModule(), SymbolFlags.PUBLIC, true, 0),
TypeCreator.createRecordType(MQCIH_RECORD_NAME, getModule(), SymbolFlags.PUBLIC, true, 0))));
TypeCreator.createRecordType(MQCIH_RECORD_NAME, getModule(), SymbolFlags.PUBLIC, true, 0),
TypeCreator.createRecordType(MQIIH_RECORD_NAME, getModule(), SymbolFlags.PUBLIC, true, 0))));

public static MQMessage getMqMessageFromBMessage(BMap<BString, Object> bMessage) {
MQMessage mqMessage = new MQMessage();
Expand Down Expand Up @@ -266,6 +269,7 @@ private static void populateMQHeaders(BArray bHeaders, MQMessage mqMessage) {
case MQRFH2 -> headerList.add(createMQRFH2HeaderFromBHeader(bHeader));
case MQRFH -> headerList.add(createMQRFHHeaderFromBHeader(bHeader));
case MQCIH -> headerList.add(createMQCIHHeaderFromBHeader(bHeader));
case MQIIH -> headerList.add(createMQIIHHeaderFromBHeader(bHeader));
default -> throw createError(IBMMQ_ERROR, String.format("Error occurred while populating headers: " +
"Unsupported header type %s", headerType), null);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public interface Constants {
String MQCIH_RECORD_NAME = "MQCIH";
String MQRFH2_RECORD_NAME = "MQRFH2";
String MQRFH_RECORD_NAME = "MQRFH";
String MQIIH_RECORD_NAME = "MQIIH";

String MQRFH2FIELD_RECORD_NAME = "MQRFH2Field";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@
/**
* Header class with util methods for handling MQCHIH headers.
*/
public class MQCHIHHeader {
public class MQCIHHeader {

private static final BString RETURN_CODE_FIELD = StringUtils.fromString("returnCode");
private static final BString COMP_CODE_FIELD = StringUtils.fromString("compCode");
Expand All @@ -59,9 +59,6 @@ public class MQCHIHHeader {
private static final BString FUNCTION_FIELD = StringUtils.fromString("function");
private static final BString ABEND_CODE_FIELD = StringUtils.fromString("abendCode");
private static final BString AUTHENTICATOR_FIELD = StringUtils.fromString("authenticator");
private static final BString RESERVED1_FIELD = StringUtils.fromString("reserved1");
private static final BString RESERVED2_FIELD = StringUtils.fromString("reserved2");
private static final BString RESERVED3_FIELD = StringUtils.fromString("reserved3");
private static final BString REPLY_TO_FORMAT_FIELD = StringUtils.fromString("replyToFormat");
private static final BString REMOTE_SYS_ID_FIELD = StringUtils.fromString("remoteSysId");
private static final BString REMOTE_TRANS_ID_FIELD = StringUtils.fromString("remoteTransId");
Expand All @@ -74,7 +71,7 @@ public class MQCHIHHeader {
private static final BString INPUT_ITEM_FIELD = StringUtils.fromString("inputItem");


private MQCHIHHeader() {}
private MQCIHHeader() {}

public static void decodeHeader(Runtime runtime, MQMessage msg, ArrayList<BMap<BString, Object>> headers)
throws IOException {
Expand All @@ -86,7 +83,7 @@ public static void decodeHeader(Runtime runtime, MQMessage msg, ArrayList<BMap<B
MQRFH2Header.decodeHeader(runtime, msg, headers);
} catch (MQDataException e) {
msg.seek(dataOffset);
HeaderUtils.decodeUnSupportedHeaders(runtime, msg, headers);
MQIIHHeader.decodeHeader(runtime, msg, headers);
}
}

Expand All @@ -113,9 +110,6 @@ private static BMap<BString, Object> getBHeaderFromMQCIH(MQCIH mqcih) {
header.put(FUNCTION_FIELD, StringUtils.fromString(mqcih.getFunction()));
header.put(ABEND_CODE_FIELD, StringUtils.fromString(mqcih.getAbendCode()));
header.put(AUTHENTICATOR_FIELD, StringUtils.fromString(mqcih.getAuthenticator()));
header.put(RESERVED1_FIELD, StringUtils.fromString(mqcih.getReserved1()));
header.put(RESERVED2_FIELD, StringUtils.fromString(mqcih.getReserved2()));
header.put(RESERVED3_FIELD, StringUtils.fromString(mqcih.getReserved3()));
header.put(REPLY_TO_FORMAT_FIELD, StringUtils.fromString(mqcih.getReplyToFormat()));
header.put(REMOTE_SYS_ID_FIELD, StringUtils.fromString(mqcih.getRemoteSysId()));
header.put(REMOTE_TRANS_ID_FIELD, StringUtils.fromString(mqcih.getRemoteTransId()));
Expand Down Expand Up @@ -149,9 +143,6 @@ public static Object createMQCIHHeaderFromBHeader(BMap<BString, Object> bHeader)
header.setFunction(bHeader.getStringValue(FUNCTION_FIELD).getValue());
header.setAbendCode(bHeader.getStringValue(ABEND_CODE_FIELD).getValue());
header.setAuthenticator(bHeader.getStringValue(AUTHENTICATOR_FIELD).getValue());
header.setReserved1(bHeader.getStringValue(RESERVED1_FIELD).getValue());
header.setReserved2(bHeader.getStringValue(RESERVED2_FIELD).getValue());
header.setReserved3(bHeader.getStringValue(RESERVED3_FIELD).getValue());
header.setReplyToFormat(bHeader.getStringValue(REPLY_TO_FORMAT_FIELD).getValue());
header.setRemoteSysId(bHeader.getStringValue(REMOTE_SYS_ID_FIELD).getValue());
header.setRemoteTransId(bHeader.getStringValue(REMOTE_TRANS_ID_FIELD).getValue());
Expand Down
Loading

0 comments on commit 5bda24c

Please sign in to comment.