Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for QueueBrowser - #49 #50

Merged
merged 1 commit into from
Feb 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ your own error handling or logging.
* Set a message property of type string, int, double or boolean - [messageproperties_test.go](messageproperties_test.go)
* Get by CorrelationID - [getbycorrelid_test.go](getbycorrelid_test.go)
* Get by JMSMessageID - [getbymsgid_test.go](getbymsgid_test.go)
* Browse messages non-destructively using a QueueBrowser - [queuebrowser_test.go](queuebrowser_test.go)
* Request/reply messaging pattern - [requestreply_test.go](requestreply_test.go)
* Send and receive under a local transaction - [local_transaction_test.go](local_transaction_test.go)
* Sending a message that expires after a period of time - [timetolive_test.go](timetolive_test.go)
Expand Down
4 changes: 4 additions & 0 deletions jms20subset/JMSContext.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ type JMSContext interface {
// name and different parameters we must use a different function name.
CreateConsumerWithSelector(dest Destination, selector string) (JMSConsumer, JMSException)

// CreateBrowser creates a consumer for the specified Destination so that
// an application can look at messages without removing them.
CreateBrowser(dest Destination) (QueueBrowser, JMSException)

// CreateQueue creates a queue object which encapsulates a provider specific
// queue name.
//
Expand Down
20 changes: 20 additions & 0 deletions jms20subset/MessageIterator.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Derived from the Eclipse Project for JMS, available at;
// https://github.com/eclipse-ee4j/jms-api
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0, which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

// Package jms20subset provides interfaces for messaging applications in the style of the Java Message Service (JMS) API.
package jms20subset

// MessageIterator provides the ability for the application to consume
// a sequence of Messages.
type MessageIterator interface {

// GetNext returns the next Message that is available
// or else nil if no messages are available.
GetNext() (Message, JMSException)
}
24 changes: 24 additions & 0 deletions jms20subset/QueueBrowser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Derived from the Eclipse Project for JMS, available at;
// https://github.com/eclipse-ee4j/jms-api
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0, which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

// Package jms20subset provides interfaces for messaging applications in the style of the Java Message Service (JMS) API.
package jms20subset

// QueueBrowser provides the ability for an application to look at messages on
// a queue without removing them.
type QueueBrowser interface {

// GetEnumeration returns an iterator for browsing the current
// queue messages in the order they would be received.
GetEnumeration() (MessageIterator, JMSException)

// Closes the QueueBrowser in order to free up any resources that were
// allocated by the provider.
Close()
}
56 changes: 56 additions & 0 deletions mqjms/BrowserImpl.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright (c) IBM Corporation 2022.
//
// This program and the accompanying materials are made available under the
// terms of the Eclipse Public License 2.0, which is available at
// http://www.eclipse.org/legal/epl-2.0.
//
// SPDX-License-Identifier: EPL-2.0

// Package mqjms provides the implementation of the JMS style Golang interfaces to communicate with IBM MQ.
package mqjms

import (
"github.com/ibm-messaging/mq-golang-jms20/jms20subset"
ibmmq "github.com/ibm-messaging/mq-golang/v5/ibmmq"
)

// BrowserImpl represents the JMS QueueBrowser object that allows applications
// to peek at messages on a queue without destructively consuming them.
type BrowserImpl struct {
browseOption *int32
ConsumerImpl // Browser is a specialized form of consumer
}

// GetEnumeration returns an iterator for browsing the current
// queue messages in the order they would be received.
//
// In this implementation there is exactly one Enumeration per
// QueueBrowser. If an application wants to browse two independent
// copies of the messages it must create two QueueBrowsers.
func (browser *BrowserImpl) GetEnumeration() (jms20subset.MessageIterator, jms20subset.JMSException) {

// A browser is just an alternative view of a Consumer that
// presents slightly different functions + behaviour.
return browser, nil

}

// GetNext returns the next Message that is available
// or else nil if no messages are available.
func (browser *BrowserImpl) GetNext() (jms20subset.Message, jms20subset.JMSException) {

// Like a ReceiveNoWait, but with Browse turned on.
gmo := ibmmq.NewMQGMO()
gmo.Options |= *browser.browseOption

msg, err := browser.receiveInternal(gmo)

if err == nil {
// After we have browsed the first message successfully we move on to asking
// for the "next" message from this point onwards.
brse := int32(ibmmq.MQGMO_BROWSE_NEXT)
browser.browseOption = &brse
}

return msg, err
}
48 changes: 48 additions & 0 deletions mqjms/ContextImpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,54 @@ func (ctx ContextImpl) CreateConsumerWithSelector(dest jms20subset.Destination,
return consumer, retErr
}

// CreateBrowser creates a consumer for the specified Destination so that
// an application can look at messages without removing them.
func (ctx ContextImpl) CreateBrowser(dest jms20subset.Destination) (jms20subset.QueueBrowser, jms20subset.JMSException) {

// Set up the necessary objects to open the queue
mqod := ibmmq.NewMQOD()
var openOptions int32
openOptions = ibmmq.MQOO_FAIL_IF_QUIESCING
openOptions |= ibmmq.MQOO_INPUT_AS_Q_DEF
openOptions |= ibmmq.MQOO_BROWSE // This is the important part for browsing!
mqod.ObjectType = ibmmq.MQOT_Q
mqod.ObjectName = dest.GetDestinationName()

var retErr jms20subset.JMSException
var browser jms20subset.QueueBrowser

// Invoke the MQ command to open the queue.
qObject, err := ctx.qMgr.Open(mqod, openOptions)

if err == nil {

// Success - store the necessary objects away for later use to receive
// messages.
consumer := ConsumerImpl{
ctx: ctx,
qObject: qObject,
}

brse := int32(ibmmq.MQGMO_BROWSE_FIRST)

browser = &BrowserImpl{
browseOption: &brse,
ConsumerImpl: consumer,
}

} else {

// Error occurred - extract the failure details and return to the caller.
rcInt := int(err.(*ibmmq.MQReturn).MQRC)
errCode := strconv.Itoa(rcInt)
reason := ibmmq.MQItoString("RC", rcInt)
retErr = jms20subset.CreateJMSException(reason, errCode, err)

}

return browser, retErr
}

// CreateTextMessage is a JMS standard mechanism for creating a TextMessage.
func (ctx ContextImpl) CreateTextMessage() jms20subset.TextMessage {

Expand Down
Loading