Skip to content

Commit 044c73a

Browse files
authored
Merge pull request #52 from ibm-messaging/header-properties
Support for selected header properties - #51
2 parents 2bfa860 + 95d7aa3 commit 044c73a

12 files changed

+1267
-47
lines changed

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,16 +124,51 @@ your own error handling or logging.
124124
* Request/reply messaging pattern - [requestreply_test.go](requestreply_test.go)
125125
* Send and receive under a local transaction - [local_transaction_test.go](local_transaction_test.go)
126126
* Sending a message that expires after a period of time - [timetolive_test.go](timetolive_test.go)
127+
* Sending a message with a specified priority - [priority_test.go](priority_test.go)
127128
* Handle error codes returned by the queue manager - [sample_errorhandling_test.go](sample_errorhandling_test.go)
128129
* Set the application name (ApplName) on connections - [applname_test.go](applname_test.go)
129130
* Receive messages over 32kb in size by setting the receive buffer size - [largemessage_test.go](largemessage_test.go)
130131
* Asynchronous put - [asyncput_test.go](asyncput_test.go)
132+
* Special header properties such as JMS_IBM_Format - [specialproperties_test.go](specialproperties_test.go)
131133

132134
As normal with Go, you can run any individual testcase by executing a command such as;
133135
```bash
134136
go test -run TestSampleSendReceiveWithErrorHandling
135137
```
136138

139+
### Special header properties supported
140+
The following special header properties are supported for Get, Put or both as listed below.
141+
142+
```
143+
Field name Example Notes
144+
---------------------------------------------------------------------------------------------------------------------------------------------------------
145+
JMS_IBM_PutDate msg.GetStringProperty("JMS_IBM_PutDate") YYYYMMDD
146+
JMS_IBM_PutTime msg.GetStringProperty("JMS_IBM_PutTime") HHMMSSTH
147+
JMS_IBM_Format msg.GetStringProperty("JMS_IBM_Format") MQSTR
148+
msg.SetStringProperty("JMS_IBM_Format", "MYFMT")
149+
JMS_IBM_MQMD_Format msg.GetStringProperty("JMS_IBM_MQMD_Format") MQSTR
150+
msg.SetStringProperty("JMS_IBM_MQMD_Format", "MYFMT")
151+
JMS_IBM_PutApplType msg.GetIntProperty("JMS_IBM_PutApplType")
152+
JMS_IBM_Encoding msg.GetIntProperty("JMS_IBM_Encoding")
153+
msg.SetIntProperty("JMS_IBM_Encoding", 273)
154+
JMS_IBM_Character_Set msg.GetIntProperty("JMS_IBM_Character_Set")
155+
msg.SetIntProperty("JMS_IBM_Character_Set", 1208)
156+
JMS_IBM_MQMD_CodedCharSetId msg.GetIntProperty("JMS_IBM_MQMD_CodedCharSetId")
157+
msg.SetIntProperty("JMS_IBM_MQMD_CodedCharSetId", 1208)
158+
JMS_IBM_MsgType msg.GetIntProperty("JMS_IBM_MsgType")
159+
msg.SetIntProperty("JMS_IBM_MsgType", 8)
160+
JMS_IBM_MQMD_MsgType msg.GetIntProperty("JMS_IBM_MQMD_MsgType")
161+
msg.SetIntProperty("JMS_IBM_MQMD_MsgType", 8)
162+
JMS_IBM_MQMD_MsgId msg.GetJMSMessageID()
163+
JMS_IBM_MQMD_ApplOriginData msg.GetStringProperty("JMS_IBM_MQMD_ApplOriginData")
164+
JMSExpiration msg.GetJMSExpiration()
165+
JMSXAppID msg.GetStringProperty("JMSXAppID") JMSXAppID / PutApplName is set using ConnectionFactory.ApplName
166+
JMSXGroupID msg.GetStringProperty("JMSXGroupID")
167+
JMSXGroupSeq msg.GetIntProperty("JMSXGroupSeq")
168+
JMS_IBM_Last_Msg_In_Group msg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
169+
```
170+
171+
137172

138173
## Getting started
139174

applname_test.go

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,10 @@ func TestApplName(t *testing.T) {
5858
assert.Nil(t, errRvc)
5959
assert.NotNil(t, rcvMsg)
6060

61-
messageImpl, ok := rcvMsg.(*mqjms.TextMessageImpl)
62-
assert.True(t, ok)
63-
6461
// Check that the application name was successfully stored in the message
6562
// that we sent.
66-
assert.Equal(t, applName, messageImpl.GetApplName())
63+
gotAppName, err := rcvMsg.GetStringProperty("JMSXAppID")
64+
assert.Nil(t, err)
65+
assert.Equal(t, applName, *gotAppName)
6766

6867
}

jms20subset/JMSProducer.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,11 @@ type JMSProducer interface {
5959
// GetTimeToLive returns the time to live (in milliseconds) that will be
6060
// applied to messages that are sent using this JMSProducer.
6161
GetTimeToLive() int
62+
63+
// SetPriority sets the message priority for all messages sent by this producer.
64+
SetPriority(priority int) JMSProducer
65+
66+
// GetPriority returns the priority for all messages sent by this producer.
67+
// Default priority is 4.
68+
GetPriority() int
6269
}

jms20subset/Message.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ type Message interface {
2525
// handed off to the provider to be sent.
2626
GetJMSTimestamp() int64
2727

28+
// GetJMSExpiration returns the timestamp at which the message is due to
29+
// expire.
30+
GetJMSExpiration() int64
31+
2832
// SetJMSCorrelationID sets the correlation ID for the message which can be
2933
// used to link on message to another. A typical use is to link a response
3034
// message with its request message.
@@ -48,6 +52,9 @@ type Message interface {
4852
// jms20subset.DeliveryMode_PERSISTENT and jms20subset.DeliveryMode_NON_PERSISTENT
4953
GetJMSDeliveryMode() int
5054

55+
// GetJMSPriority returns the priority that is specified for this message.
56+
GetJMSPriority() int
57+
5158
// SetStringProperty enables an application to set a string-type message property.
5259
//
5360
// value is *string which allows a nil value to be specified, to unset an individual

jms20subset/Priority.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Derived from the Eclipse Project for JMS, available at;
2+
// https://github.com/eclipse-ee4j/jms-api
3+
//
4+
// This program and the accompanying materials are made available under the
5+
// terms of the Eclipse Public License 2.0, which is available at
6+
// http://www.eclipse.org/legal/epl-2.0.
7+
//
8+
// SPDX-License-Identifier: EPL-2.0
9+
10+
// Package jms20subset provides interfaces for messaging applications in the style of the Java Message Service (JMS) API.
11+
package jms20subset
12+
13+
// Go doesn't allow constants in structs so the naming of this file is only for
14+
// logical grouping purposes. The constants are package scoped, but we use a
15+
// prefix to the naming in order to maintain similarity with Java JMS.
16+
17+
// Priority_DEFAULT is the default priority for messages sent using a Producer.
18+
const Priority_DEFAULT int = 4

messagegroup_test.go

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
/*
2+
* Copyright (c) IBM Corporation 2022
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0, which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* SPDX-License-Identifier: EPL-2.0
9+
*/
10+
package main
11+
12+
import (
13+
"testing"
14+
15+
"github.com/ibm-messaging/mq-golang-jms20/mqjms"
16+
"github.com/stretchr/testify/assert"
17+
)
18+
19+
/*
20+
* Test the behaviour of message groups.
21+
*
22+
* JMSXGroupID
23+
* JMSXGroupSeq
24+
* JMS_IBM_Last_Msg_In_Group
25+
*
26+
* https://www.ibm.com/docs/en/ibm-mq/9.2?topic=ordering-grouping-logical-messages
27+
*/
28+
func TestMessageGroup(t *testing.T) {
29+
30+
// Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
31+
cf, cfErr := mqjms.CreateConnectionFactoryFromDefaultJSONFiles()
32+
assert.Nil(t, cfErr)
33+
34+
// Creates a connection to the queue manager, using defer to close it automatically
35+
// at the end of the function (if it was created successfully)
36+
context, ctxErr := cf.CreateContext()
37+
assert.Nil(t, ctxErr)
38+
if context != nil {
39+
defer context.Close()
40+
}
41+
42+
// Set up objects for send/receive
43+
queue := context.CreateQueue("DEV.QUEUE.1")
44+
consumer, errCons := context.CreateConsumer(queue)
45+
if consumer != nil {
46+
defer consumer.Close()
47+
}
48+
assert.Nil(t, errCons)
49+
50+
// Since we need more work to support the "set" operations (see big comment below)
51+
// lets just do a short test of the "get" behaviour.
52+
53+
txtMsg1 := context.CreateTextMessage()
54+
55+
// Force the population of the MQMD field.
56+
myFormat := "MYFMT"
57+
txtMsg1.SetStringProperty("JMS_IBM_Format", &myFormat)
58+
59+
groupId, err := txtMsg1.GetStringProperty("JMSXGroupID")
60+
assert.Nil(t, err)
61+
assert.Nil(t, groupId)
62+
63+
groupSeq, err := txtMsg1.GetIntProperty("JMSXGroupSeq")
64+
assert.Nil(t, err)
65+
assert.Equal(t, 1, groupSeq)
66+
67+
gotLastMsg, err := txtMsg1.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
68+
assert.Equal(t, false, gotLastMsg)
69+
70+
myGroup := "hello"
71+
err = txtMsg1.SetStringProperty("JMSXGroupID", &myGroup)
72+
assert.NotNil(t, err)
73+
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())
74+
75+
err = txtMsg1.SetIntProperty("JMSXGroupSeq", 2)
76+
assert.NotNil(t, err)
77+
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())
78+
79+
err = txtMsg1.SetBooleanProperty("JMS_IBM_Last_Msg_In_Group", true)
80+
assert.NotNil(t, err)
81+
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())
82+
83+
/*
84+
* Setting these properties requires an MQMD V2 header and is also
85+
* not supported for PUT1 operations so there is some more extensive
86+
* implementation work required in order to enable the "set" scenarios
87+
* for these Group properties.
88+
89+
// Create a TextMessage and check that we can populate it
90+
txtMsg1 := context.CreateTextMessage()
91+
txtMsg1.SetText(msgBody)
92+
txtMsg1.SetStringProperty("JMSXGroupID", &groupID)
93+
txtMsg1.SetIntProperty("JMSXGroupSeq", 1)
94+
errSend := producer.Send(queue, txtMsg1)
95+
assert.Nil(t, errSend)
96+
97+
txtMsg2 := context.CreateTextMessage()
98+
txtMsg2.SetText(msgBody)
99+
txtMsg2.SetStringProperty("JMSXGroupID", &groupID)
100+
txtMsg2.SetIntProperty("JMSXGroupSeq", 2)
101+
errSend = producer.Send(queue, txtMsg2)
102+
assert.Nil(t, errSend)
103+
104+
txtMsg3 := context.CreateTextMessage()
105+
txtMsg3.SetText(msgBody)
106+
txtMsg3.SetStringProperty("JMSXGroupID", &groupID)
107+
txtMsg3.SetIntProperty("JMSXGroupSeq", 3)
108+
txtMsg3.SetBooleanProperty("JMS_IBM_Last_Msg_In_Group", true)
109+
errSend = producer.Send(queue, txtMsg3)
110+
assert.Nil(t, errSend)
111+
112+
// Check the first message.
113+
rcvMsg, errRvc := consumer.ReceiveNoWait()
114+
assert.Nil(t, errRvc)
115+
assert.NotNil(t, rcvMsg)
116+
assert.Equal(t, txtMsg1.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
117+
gotGroupIDValue, gotErr := rcvMsg.GetStringProperty("JMSXGroupID")
118+
assert.Nil(t, gotErr)
119+
assert.Equal(t, groupID, *gotGroupIDValue)
120+
gotSeqValue, gotErr := rcvMsg.GetIntProperty("JMSXGroupSeq")
121+
assert.Equal(t, 1, gotSeqValue)
122+
gotLastMsgValue, gotErr := rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
123+
assert.Equal(t, false, gotLastMsgValue)
124+
125+
// Check the second message.
126+
rcvMsg, errRvc = consumer.ReceiveNoWait()
127+
assert.Nil(t, errRvc)
128+
assert.NotNil(t, rcvMsg)
129+
assert.Equal(t, txtMsg2.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
130+
gotGroupIDValue, gotErr = rcvMsg.GetStringProperty("JMSXGroupID")
131+
assert.Nil(t, gotErr)
132+
assert.Equal(t, groupID, *gotGroupIDValue)
133+
gotSeqValue, gotErr = rcvMsg.GetIntProperty("JMSXGroupSeq")
134+
assert.Equal(t, 2, gotSeqValue)
135+
gotLastMsgValue, gotErr = rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
136+
assert.Equal(t, false, gotLastMsgValue)
137+
138+
// Check the third message.
139+
rcvMsg, errRvc = consumer.ReceiveNoWait()
140+
assert.Nil(t, errRvc)
141+
assert.NotNil(t, rcvMsg)
142+
assert.Equal(t, txtMsg3.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
143+
gotGroupIDValue, gotErr = rcvMsg.GetStringProperty("JMSXGroupID")
144+
assert.Nil(t, gotErr)
145+
assert.Equal(t, groupID, *gotGroupIDValue)
146+
gotSeqValue, gotErr = rcvMsg.GetIntProperty("JMSXGroupSeq")
147+
assert.Equal(t, 3, gotSeqValue)
148+
gotLastMsgValue, gotErr = rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
149+
assert.Equal(t, true, gotLastMsgValue)
150+
*/
151+
152+
}

mqjms/ContextImpl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func (ctx ContextImpl) CreateProducer() jms20subset.JMSProducer {
4949
producer := ProducerImpl{
5050
ctx: ctx,
5151
deliveryMode: jms20subset.DeliveryMode_PERSISTENT,
52+
priority: jms20subset.Priority_DEFAULT,
5253
}
5354

5455
return &producer

0 commit comments

Comments
 (0)