Skip to content

Commit

Permalink
Support for GET of GroupID/Seq/LastMsg - #51
Browse files Browse the repository at this point in the history
  • Loading branch information
matrober-uk committed Mar 23, 2022
1 parent 5fade19 commit 95d7aa3
Show file tree
Hide file tree
Showing 3 changed files with 268 additions and 6 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,9 @@ JMS_IBM_MQMD_MsgId msg.GetJMSMessageID()
JMS_IBM_MQMD_ApplOriginData msg.GetStringProperty("JMS_IBM_MQMD_ApplOriginData")
JMSExpiration msg.GetJMSExpiration()
JMSXAppID msg.GetStringProperty("JMSXAppID") JMSXAppID / PutApplName is set using ConnectionFactory.ApplName
JMSXGroupID msg.GetStringProperty("JMSXGroupID")
JMSXGroupSeq msg.GetIntProperty("JMSXGroupSeq")
JMS_IBM_Last_Msg_In_Group msg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
```


Expand Down
152 changes: 152 additions & 0 deletions messagegroup_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/*
* Copyright (c) IBM Corporation 2022
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* SPDX-License-Identifier: EPL-2.0
*/
package main

import (
"testing"

"github.com/ibm-messaging/mq-golang-jms20/mqjms"
"github.com/stretchr/testify/assert"
)

/*
* Test the behaviour of message groups.
*
* JMSXGroupID
* JMSXGroupSeq
* JMS_IBM_Last_Msg_In_Group
*
* https://www.ibm.com/docs/en/ibm-mq/9.2?topic=ordering-grouping-logical-messages
*/
func TestMessageGroup(t *testing.T) {

// Loads CF parameters from connection_info.json and applicationApiKey.json in the Downloads directory
cf, cfErr := mqjms.CreateConnectionFactoryFromDefaultJSONFiles()
assert.Nil(t, cfErr)

// Creates a connection to the queue manager, using defer to close it automatically
// at the end of the function (if it was created successfully)
context, ctxErr := cf.CreateContext()
assert.Nil(t, ctxErr)
if context != nil {
defer context.Close()
}

// Set up objects for send/receive
queue := context.CreateQueue("DEV.QUEUE.1")
consumer, errCons := context.CreateConsumer(queue)
if consumer != nil {
defer consumer.Close()
}
assert.Nil(t, errCons)

// Since we need more work to support the "set" operations (see big comment below)
// lets just do a short test of the "get" behaviour.

txtMsg1 := context.CreateTextMessage()

// Force the population of the MQMD field.
myFormat := "MYFMT"
txtMsg1.SetStringProperty("JMS_IBM_Format", &myFormat)

groupId, err := txtMsg1.GetStringProperty("JMSXGroupID")
assert.Nil(t, err)
assert.Nil(t, groupId)

groupSeq, err := txtMsg1.GetIntProperty("JMSXGroupSeq")
assert.Nil(t, err)
assert.Equal(t, 1, groupSeq)

gotLastMsg, err := txtMsg1.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
assert.Equal(t, false, gotLastMsg)

myGroup := "hello"
err = txtMsg1.SetStringProperty("JMSXGroupID", &myGroup)
assert.NotNil(t, err)
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())

err = txtMsg1.SetIntProperty("JMSXGroupSeq", 2)
assert.NotNil(t, err)
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())

err = txtMsg1.SetBooleanProperty("JMS_IBM_Last_Msg_In_Group", true)
assert.NotNil(t, err)
assert.Equal(t, "Not yet implemented", err.GetLinkedError().Error())

/*
* Setting these properties requires an MQMD V2 header and is also
* not supported for PUT1 operations so there is some more extensive
* implementation work required in order to enable the "set" scenarios
* for these Group properties.
// Create a TextMessage and check that we can populate it
txtMsg1 := context.CreateTextMessage()
txtMsg1.SetText(msgBody)
txtMsg1.SetStringProperty("JMSXGroupID", &groupID)
txtMsg1.SetIntProperty("JMSXGroupSeq", 1)
errSend := producer.Send(queue, txtMsg1)
assert.Nil(t, errSend)
txtMsg2 := context.CreateTextMessage()
txtMsg2.SetText(msgBody)
txtMsg2.SetStringProperty("JMSXGroupID", &groupID)
txtMsg2.SetIntProperty("JMSXGroupSeq", 2)
errSend = producer.Send(queue, txtMsg2)
assert.Nil(t, errSend)
txtMsg3 := context.CreateTextMessage()
txtMsg3.SetText(msgBody)
txtMsg3.SetStringProperty("JMSXGroupID", &groupID)
txtMsg3.SetIntProperty("JMSXGroupSeq", 3)
txtMsg3.SetBooleanProperty("JMS_IBM_Last_Msg_In_Group", true)
errSend = producer.Send(queue, txtMsg3)
assert.Nil(t, errSend)
// Check the first message.
rcvMsg, errRvc := consumer.ReceiveNoWait()
assert.Nil(t, errRvc)
assert.NotNil(t, rcvMsg)
assert.Equal(t, txtMsg1.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
gotGroupIDValue, gotErr := rcvMsg.GetStringProperty("JMSXGroupID")
assert.Nil(t, gotErr)
assert.Equal(t, groupID, *gotGroupIDValue)
gotSeqValue, gotErr := rcvMsg.GetIntProperty("JMSXGroupSeq")
assert.Equal(t, 1, gotSeqValue)
gotLastMsgValue, gotErr := rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
assert.Equal(t, false, gotLastMsgValue)
// Check the second message.
rcvMsg, errRvc = consumer.ReceiveNoWait()
assert.Nil(t, errRvc)
assert.NotNil(t, rcvMsg)
assert.Equal(t, txtMsg2.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
gotGroupIDValue, gotErr = rcvMsg.GetStringProperty("JMSXGroupID")
assert.Nil(t, gotErr)
assert.Equal(t, groupID, *gotGroupIDValue)
gotSeqValue, gotErr = rcvMsg.GetIntProperty("JMSXGroupSeq")
assert.Equal(t, 2, gotSeqValue)
gotLastMsgValue, gotErr = rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
assert.Equal(t, false, gotLastMsgValue)
// Check the third message.
rcvMsg, errRvc = consumer.ReceiveNoWait()
assert.Nil(t, errRvc)
assert.NotNil(t, rcvMsg)
assert.Equal(t, txtMsg3.GetJMSMessageID(), rcvMsg.GetJMSMessageID())
gotGroupIDValue, gotErr = rcvMsg.GetStringProperty("JMSXGroupID")
assert.Nil(t, gotErr)
assert.Equal(t, groupID, *gotGroupIDValue)
gotSeqValue, gotErr = rcvMsg.GetIntProperty("JMSXGroupSeq")
assert.Equal(t, 3, gotSeqValue)
gotLastMsgValue, gotErr = rcvMsg.GetBooleanProperty("JMS_IBM_Last_Msg_In_Group")
assert.Equal(t, true, gotLastMsgValue)
*/

}
119 changes: 113 additions & 6 deletions mqjms/MessageImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ package mqjms

import (
"encoding/hex"
"errors"
"fmt"
"log"
"strconv"
Expand Down Expand Up @@ -301,9 +302,13 @@ func (msg *MessageImpl) SetStringProperty(name string, value *string) jms20subse
var linkedErr error

// Different code path and shortcut for special header properties
isSpecial, _ := msg.setSpecialStringPropertyValue(name, value)
isSpecial, specialErr := msg.setSpecialStringPropertyValue(name, value)
if isSpecial {
return nil

if specialErr != nil {
retErr = jms20subset.CreateJMSException("4125", "MQJMS4125", specialErr)
}
return retErr
}

if value != nil {
Expand Down Expand Up @@ -367,6 +372,15 @@ func (msg *MessageImpl) setSpecialStringPropertyValue(name string, value *string
msg.mqmd.Format = ibmmq.MQFMT_NONE // unset
}

case "JMSXGroupID":
err = errors.New("Not yet implemented")
/* Implementation not yet complete
if value != nil {
groupBytes := convertStringToMQBytes(*value)
msg.mqmd.GroupId = groupBytes
msg.mqmd.MsgFlags |= ibmmq.MQMF_MSG_IN_GROUP
} */

default:
isSpecial = false
}
Expand Down Expand Up @@ -413,6 +427,10 @@ func (msg *MessageImpl) setSpecialIntPropertyValue(name string, value int) (bool
case "JMS_IBM_MQMD_MsgType":
msg.mqmd.MsgType = int32(value)

case "JMSXGroupSeq":
err = errors.New("Not yet implemented")
//msg.mqmd.MsgSeqNumber = int32(value)

default:
isSpecial = false
}
Expand Down Expand Up @@ -498,6 +516,38 @@ func (msg *MessageImpl) getSpecialPropertyValue(name string) (bool, interface{},
value = msg.mqmd.MsgType
}

case "JMSXGroupID":
if msg.mqmd != nil {
valueBytes := msg.mqmd.GroupId

// See whether this is a non-zero response.
nonZeros := false
for _, thisByte := range valueBytes {
if thisByte != 0 {
nonZeros = true
break
}
}

if nonZeros {
value = hex.EncodeToString(valueBytes)
}
}

case "JMSXGroupSeq":
if msg.mqmd != nil {
value = msg.mqmd.MsgSeqNumber
} else {
value = int32(1)
}

case "JMS_IBM_Last_Msg_In_Group":
if msg.mqmd != nil {
value = ((msg.mqmd.MsgFlags & ibmmq.MQMF_LAST_MSG_IN_GROUP) != 0)
} else {
value = false
}

default:
isSpecial = false
}
Expand Down Expand Up @@ -579,9 +629,13 @@ func (msg *MessageImpl) SetIntProperty(name string, value int) jms20subset.JMSEx
var linkedErr error

// Different code path and shortcut for special header properties
isSpecial, _ := msg.setSpecialIntPropertyValue(name, value)
isSpecial, specialErr := msg.setSpecialIntPropertyValue(name, value)
if isSpecial {
return nil

if specialErr != nil {
retErr = jms20subset.CreateJMSException("4125", "MQJMS4125", specialErr)
}
return retErr
}

smpo := ibmmq.NewMQSMPO()
Expand Down Expand Up @@ -696,7 +750,13 @@ func (msg *MessageImpl) GetDoubleProperty(name string) (float64, jms20subset.JMS
impo := ibmmq.NewMQIMPO()
pd := ibmmq.NewMQPD()

_, value, err := msg.msgHandle.InqMP(impo, pd, name)
// Check first if this is a special property
isSpecialProp, value, err := msg.getSpecialPropertyValue(name)

if !isSpecialProp {
// If not then look for a user property
_, value, err = msg.msgHandle.InqMP(impo, pd, name)
}

if err == nil {

Expand Down Expand Up @@ -748,6 +808,16 @@ func (msg *MessageImpl) SetBooleanProperty(name string, value bool) jms20subset.
smpo := ibmmq.NewMQSMPO()
pd := ibmmq.NewMQPD()

// Different code path and shortcut for special header properties
isSpecial, specialErr := msg.setSpecialBooleanPropertyValue(name, value)
if isSpecial {

if specialErr != nil {
retErr = jms20subset.CreateJMSException("4125", "MQJMS4125", specialErr)
}
return retErr
}

linkedErr = msg.msgHandle.SetMP(smpo, name, pd, value)

if linkedErr != nil {
Expand All @@ -760,6 +830,37 @@ func (msg *MessageImpl) SetBooleanProperty(name string, value bool) jms20subset.
return retErr
}

// setSpecialBooleanPropertyValue sets the special header properties of type bool
func (msg *MessageImpl) setSpecialBooleanPropertyValue(name string, value bool) (bool, error) {

// Special properties always start with a known prefix.
if !strings.HasPrefix(name, "JMS") {
return false, nil
}

// Check first that there is an MQMD to write to
if msg.mqmd == nil {
msg.mqmd = ibmmq.NewMQMD()
}

// Assume for now that this property is special as it has passed the basic
// checks, and this value will be set back to false if it doesn't match any
// of the specific fields.
isSpecial := true

var err error

switch name {
case "JMS_IBM_Last_Msg_In_Group":
err = errors.New("Not yet implemented")

default:
isSpecial = false
}

return isSpecial, err
}

// GetBooleanProperty returns the bool value of a named message property.
// Returns false if the named property is not set.
func (msg *MessageImpl) GetBooleanProperty(name string) (bool, jms20subset.JMSException) {
Expand All @@ -770,7 +871,13 @@ func (msg *MessageImpl) GetBooleanProperty(name string) (bool, jms20subset.JMSEx
impo := ibmmq.NewMQIMPO()
pd := ibmmq.NewMQPD()

_, value, err := msg.msgHandle.InqMP(impo, pd, name)
// Check first if this is a special property
isSpecialProp, value, err := msg.getSpecialPropertyValue(name)

if !isSpecialProp {
// If not then look for a user property
_, value, err = msg.msgHandle.InqMP(impo, pd, name)
}

if err == nil {

Expand Down

0 comments on commit 95d7aa3

Please sign in to comment.