Skip to content

Commit d8ac717

Browse files
committed
Add InqMap as simpler API for MQINQ operations
1 parent 5a85b13 commit d8ac717

File tree

5 files changed

+420
-0
lines changed

5 files changed

+420
-0
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* Update MQI header files for MQ V9.1.1 and give more platform variations
88
* Add support for MQSTAT and MQSUBRQ functions
99
* Add support and sample for Message Property functions
10+
* Add InqMap as alternative (simpler) MQINQ operation
1011

1112
## November 2018 - v3.1.0
1213
* Added functions to mqmetric to issue DISPLAY QSTATUS for additional stats

ibmmq/mqi.go

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,10 @@ how long each field in that buffer will be.
597597
598598
The caller passes in how many integer selectors are expected to be
599599
returned, as well as the maximum length of the char buffer to be returned
600+
601+
This function is a direct mapping of the MQI C function. It should be considered
602+
deprecated. In preference, use the InqMap function which provides a more convenient
603+
API.
600604
*/
601605
func (object MQObject) Inq(goSelectors []int32, intAttrCount int, charAttrLen int) ([]int32,
602606
[]byte, error) {
@@ -646,6 +650,121 @@ func (object MQObject) Inq(goSelectors []int32, intAttrCount int, charAttrLen in
646650
return goIntAttrs, goCharAttrs, nil
647651
}
648652

653+
/*
654+
* InqMap should be considered the replacement for the Inq() function as it
655+
* has a much simpler API. Simply pass in the list of selectors for the object
656+
* and the return value consists of a map whose elements are
657+
* a) accessed via the selector
658+
* b) varying datatype (integer, string, string array) based on the selector
659+
*/
660+
func (object MQObject) InqMap(goSelectors []int32) (map[int32]interface{}, error) {
661+
var mqrc C.MQLONG
662+
var mqcc C.MQLONG
663+
var mqCharAttrs C.PMQCHAR
664+
var goCharAttrs []byte
665+
var goIntAttrs []int32
666+
var ptr C.PMQLONG
667+
var charOffset int
668+
var charLength int
669+
670+
intAttrCount, _, charAttrLen := getAttrInfo(goSelectors)
671+
672+
if intAttrCount > 0 {
673+
goIntAttrs = make([]int32, intAttrCount)
674+
ptr = (C.PMQLONG)(unsafe.Pointer(&goIntAttrs[0]))
675+
} else {
676+
ptr = nil
677+
}
678+
if charAttrLen > 0 {
679+
mqCharAttrs = (C.PMQCHAR)(C.malloc(C.size_t(charAttrLen)))
680+
defer C.free(unsafe.Pointer(mqCharAttrs))
681+
} else {
682+
mqCharAttrs = nil
683+
}
684+
685+
// Pass in the selectors
686+
C.MQINQ(object.qMgr.hConn, object.hObj,
687+
C.MQLONG(len(goSelectors)),
688+
C.PMQLONG(unsafe.Pointer(&goSelectors[0])),
689+
C.MQLONG(intAttrCount),
690+
ptr,
691+
C.MQLONG(charAttrLen),
692+
mqCharAttrs,
693+
&mqcc, &mqrc)
694+
695+
mqreturn := MQReturn{MQCC: int32(mqcc),
696+
MQRC: int32(mqrc),
697+
verb: "MQINQ",
698+
}
699+
700+
if mqcc != C.MQCC_OK {
701+
return nil, &mqreturn
702+
}
703+
704+
// Create a map of the selectors to the returned values
705+
returnedMap := make(map[int32]interface{})
706+
707+
// Get access to the returned character data
708+
if charAttrLen > 0 {
709+
goCharAttrs = C.GoBytes(unsafe.Pointer(mqCharAttrs), C.int(charAttrLen))
710+
}
711+
712+
// Walk through the returned data to build a map of responses. Go through
713+
// the integers first to ensure that the map includes MQIA_NAME_COUNT if that
714+
// had been requested
715+
intAttr := 0
716+
for i := 0; i < len(goSelectors); i++ {
717+
s := goSelectors[i]
718+
if s >= C.MQIA_FIRST && s <= C.MQIA_LAST {
719+
returnedMap[s] = goIntAttrs[intAttr]
720+
intAttr++
721+
}
722+
}
723+
724+
// Now we can walk through the list again for the character attributes
725+
// and build the map entries. Getting the list of NAMES from a NAMELIST
726+
// is a bit complicated ...
727+
charLength = 0
728+
charOffset = 0
729+
for i := 0; i < len(goSelectors); i++ {
730+
s := goSelectors[i]
731+
if s >= C.MQCA_FIRST && s <= C.MQCA_LAST {
732+
if s == C.MQCA_NAMES {
733+
count, ok := returnedMap[C.MQIA_NAME_COUNT]
734+
if ok {
735+
c := int(count.(int32))
736+
charLength = C.MQ_OBJECT_NAME_LENGTH
737+
names := make([]string, c)
738+
for j := 0; j < c; j++ {
739+
name := string(goCharAttrs[charOffset:charOffset+charLength])
740+
idx := strings.IndexByte(name, 0)
741+
if idx != -1 {
742+
name = name[0:idx]
743+
}
744+
names[j] = strings.TrimSpace(name)
745+
charOffset += charLength
746+
}
747+
returnedMap[s] = names
748+
} else {
749+
charLength = 0
750+
}
751+
} else {
752+
charLength = getAttrLength(s)
753+
name := string(goCharAttrs[charOffset:charOffset+charLength])
754+
idx := strings.IndexByte(name, 0)
755+
if idx != -1 {
756+
name = name[0:idx]
757+
}
758+
759+
returnedMap[s] = strings.TrimSpace(name)
760+
charOffset += charLength
761+
}
762+
}
763+
}
764+
765+
return returnedMap, nil
766+
}
767+
649768
/*********** Message Handles and Properties ****************/
650769

651770
/*

ibmmq/mqiattrs.go

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
package ibmmq
2+
3+
/*
4+
Copyright (c) IBM Corporation 2018
5+
6+
Licensed under the Apache License, Version 2.0 (the "License");
7+
you may not use this file except in compliance with the License.
8+
You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing, software
13+
distributed under the License is distributed on an "AS IS" BASIS,
14+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
See the License for the specific language governing permissions and
16+
limitations under the License.
17+
18+
Contributors:
19+
Mark Taylor - Initial Contribution
20+
*/
21+
22+
/*
23+
24+
#include <stdlib.h>
25+
#include <string.h>
26+
#include <cmqc.h>
27+
28+
*/
29+
import "C"
30+
31+
/*
32+
* This file deals with the lengths of attributes that may be processed
33+
* by the MQSET/MQINQ calls. Only a small set of the object attributes
34+
* are supported by MQINQ (and even fewer for MQSET) so it's reasonable
35+
* to list them all here
36+
*/
37+
var mqInqLength = map[int32]int32{
38+
C.MQCA_ALTERATION_DATE: C.MQ_DATE_LENGTH,
39+
C.MQCA_ALTERATION_TIME: C.MQ_TIME_LENGTH,
40+
C.MQCA_APPL_ID: C.MQ_PROCESS_APPL_ID_LENGTH,
41+
C.MQCA_BACKOUT_REQ_Q_NAME: C.MQ_Q_NAME_LENGTH,
42+
C.MQCA_BASE_Q_NAME: C.MQ_Q_NAME_LENGTH,
43+
C.MQCA_CF_STRUC_NAME: C.MQ_CF_STRUC_NAME_LENGTH,
44+
C.MQCA_CHANNEL_AUTO_DEF_EXIT: C.MQ_EXIT_NAME_LENGTH,
45+
C.MQCA_CHINIT_SERVICE_PARM: C.MQ_CHINIT_SERVICE_PARM_LENGTH,
46+
C.MQCA_CLUSTER_NAME: C.MQ_CLUSTER_NAME_LENGTH,
47+
C.MQCA_CLUSTER_NAMELIST: C.MQ_NAMELIST_NAME_LENGTH,
48+
C.MQCA_CLUSTER_WORKLOAD_DATA: C.MQ_EXIT_DATA_LENGTH,
49+
C.MQCA_CLUSTER_WORKLOAD_EXIT: C.MQ_EXIT_NAME_LENGTH,
50+
C.MQCA_COMMAND_INPUT_Q_NAME: C.MQ_Q_NAME_LENGTH,
51+
C.MQCA_CREATION_DATE: C.MQ_DATE_LENGTH,
52+
C.MQCA_CREATION_TIME: C.MQ_TIME_LENGTH,
53+
C.MQCA_DEAD_LETTER_Q_NAME: C.MQ_Q_NAME_LENGTH,
54+
C.MQCA_DEF_XMIT_Q_NAME: C.MQ_Q_NAME_LENGTH,
55+
C.MQCA_DNS_GROUP: C.MQ_DNS_GROUP_NAME_LENGTH,
56+
C.MQCA_ENV_DATA: C.MQ_PROCESS_ENV_DATA_LENGTH,
57+
C.MQCA_IGQ_USER_ID: C.MQ_USER_ID_LENGTH,
58+
C.MQCA_INITIATION_Q_NAME: C.MQ_Q_NAME_LENGTH,
59+
C.MQCA_INSTALLATION_DESC: C.MQ_INSTALLATION_DESC_LENGTH,
60+
C.MQCA_INSTALLATION_NAME: C.MQ_INSTALLATION_NAME_LENGTH,
61+
C.MQCA_INSTALLATION_PATH: C.MQ_INSTALLATION_PATH_LENGTH,
62+
C.MQCA_LU62_ARM_SUFFIX: C.MQ_ARM_SUFFIX_LENGTH,
63+
C.MQCA_LU_GROUP_NAME: C.MQ_LU_NAME_LENGTH,
64+
C.MQCA_LU_NAME: C.MQ_LU_NAME_LENGTH,
65+
C.MQCA_NAMELIST_DESC: C.MQ_NAMELIST_DESC_LENGTH,
66+
C.MQCA_NAMELIST_NAME: C.MQ_NAMELIST_NAME_LENGTH,
67+
C.MQCA_NAMES: C.MQ_OBJECT_NAME_LENGTH * 256, // TODO: split these out
68+
C.MQCA_PARENT: C.MQ_Q_MGR_NAME_LENGTH,
69+
C.MQCA_PROCESS_DESC: C.MQ_PROCESS_DESC_LENGTH,
70+
C.MQCA_PROCESS_NAME: C.MQ_PROCESS_NAME_LENGTH,
71+
C.MQCA_Q_DESC: C.MQ_Q_DESC_LENGTH,
72+
C.MQCA_Q_MGR_DESC: C.MQ_Q_MGR_DESC_LENGTH,
73+
C.MQCA_Q_MGR_IDENTIFIER: C.MQ_Q_MGR_IDENTIFIER_LENGTH,
74+
C.MQCA_Q_MGR_NAME: C.MQ_Q_MGR_NAME_LENGTH,
75+
C.MQCA_Q_NAME: C.MQ_Q_NAME_LENGTH,
76+
C.MQCA_QSG_NAME: C.MQ_QSG_NAME_LENGTH,
77+
C.MQCA_REMOTE_Q_MGR_NAME: C.MQ_Q_MGR_NAME_LENGTH,
78+
C.MQCA_REMOTE_Q_NAME: C.MQ_Q_NAME_LENGTH,
79+
C.MQCA_REPOSITORY_NAME: C.MQ_Q_MGR_NAME_LENGTH,
80+
C.MQCA_REPOSITORY_NAMELIST: C.MQ_NAMELIST_NAME_LENGTH,
81+
C.MQCA_STORAGE_CLASS: C.MQ_STORAGE_CLASS_LENGTH,
82+
C.MQCA_TCP_NAME: C.MQ_TCP_NAME_LENGTH,
83+
C.MQCA_TRIGGER_DATA: C.MQ_TRIGGER_DATA_LENGTH,
84+
C.MQCA_USER_DATA: C.MQ_PROCESS_USER_DATA_LENGTH,
85+
C.MQCA_XMIT_Q_NAME: C.MQ_Q_NAME_LENGTH,
86+
}
87+
88+
/*
89+
* Return how many char & int attributes are in the list of selectors, and the
90+
* maximum length of the buffer needed to return them from the MQI
91+
*/
92+
func getAttrInfo(attrs []int32) (int, int, int) {
93+
var charAttrLength = 0
94+
var charAttrCount = 0
95+
var intAttrCount = 0
96+
97+
for i := 0; i < len(attrs); i++ {
98+
if v, ok := mqInqLength[attrs[i]]; ok {
99+
charAttrCount++
100+
charAttrLength += int(v)
101+
} else if attrs[i] >= C.MQIA_FIRST && attrs[i] <= C.MQIA_LAST {
102+
intAttrCount++
103+
}
104+
}
105+
return intAttrCount, charAttrCount, charAttrLength
106+
}
107+
108+
func getAttrLength(attr int32) int {
109+
if v, ok := mqInqLength[attr]; ok {
110+
return int(v)
111+
} else {
112+
return 0
113+
}
114+
115+
}

samples/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ Current samples in this directory include
2424
* amqssub.go : Subscribe to a topic and receive publications
2525
* amqsconn.go: How to programmatically connect as an MQ client to a remote queue manager.
2626
Allow use of a userid/password for authentication. There are no default values for this sample.
27+
* amqsprop.go: Set and extract message properties
28+
* amqsinq.go : Demonstrate the new InqMap API for inquiring object attributes
2729

2830
Some trivial scripts run the sample programs in matching pairs:
2931
* putget.sh : Run amqsput and then use the generated MsgId to get the same message

0 commit comments

Comments
 (0)