rubywmq 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,213 @@
1
+ /*
2
+ * Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include "wmq.h"
18
+
19
+ #if defined _WIN32 && !defined __CYGWIN__
20
+ /*
21
+ * WINDOWS 32 BIT
22
+ */
23
+
24
+ #define MQ_LOAD(LIBRARY) \
25
+ HINSTANCE handle = LoadLibrary(LIBRARY); \
26
+ if (!handle) \
27
+ { \
28
+ rb_raise(wmq_exception, \
29
+ "WMQ::QueueManager#connect(). Failed to load MQ Library:%s, rc=%ld", \
30
+ LIBRARY, \
31
+ GetLastError()); \
32
+ }
33
+
34
+ #define MQ_RELEASE FreeLibrary((HINSTANCE)pqm->mq_lib_handle);
35
+
36
+ #define MQ_FUNCTION(FUNC, CAST) \
37
+ pqm->FUNC = (CAST)GetProcAddress(handle, #FUNC); \
38
+ if (!pqm->FUNC) \
39
+ { \
40
+ rb_raise(wmq_exception, "Failed to find API "#FUNC" in MQ Library"); \
41
+ }
42
+
43
+ #define MQ_LIBRARY_SERVER "mqm"
44
+ #define MQ_LIBRARY_CLIENT "mqic32"
45
+ #elif defined(SOLARIS) || defined(__SVR4) || defined(__linux__) || defined(LINUX)
46
+ /*
47
+ * SOLARIS, LINUX
48
+ */
49
+
50
+ #ifndef RTLD_LAZY
51
+ #define RTLD_LAZY 1
52
+ #endif
53
+ #ifndef RTLD_GLOBAL
54
+ #define RTLD_GLOBAL 0
55
+ #endif
56
+
57
+ #define MQ_LOAD(LIBRARY) \
58
+ void* handle = (void*)dlopen(LIBRARY, RTLD_LAZY|RTLD_GLOBAL); \
59
+ if (!handle) \
60
+ { \
61
+ rb_raise(wmq_exception, \
62
+ "WMQ::QueueManager#connect(). Failed to load MQ Library:%s, rc=%s", \
63
+ LIBRARY, \
64
+ dlerror()); \
65
+ }
66
+
67
+ #define MQ_RELEASE dlclose(pqm->mq_lib_handle);
68
+
69
+ #define MQ_FUNCTION(FUNC, CAST) \
70
+ pqm->FUNC = (CAST)dlsym(handle, #FUNC); \
71
+ if (!pqm->FUNC) \
72
+ { \
73
+ rb_raise(wmq_exception, "Failed to find API "#FUNC" in MQ Library"); \
74
+ }
75
+
76
+ #if defined(SOLARIS) || defined(__SVR4)
77
+ #define MQ_LIBRARY_SERVER "libmqm.so"
78
+ #define MQ_LIBRARY_CLIENT "libmqic.so"
79
+ #else
80
+ #define MQ_LIBRARY_SERVER "libmqm_r.so"
81
+ #define MQ_LIBRARY_CLIENT "libmqic_r.so"
82
+ #endif
83
+ #elif defined(__hpux)
84
+ /*
85
+ * HP-UX
86
+ */
87
+
88
+ #define MQ_LOAD(LIBRARY) \
89
+ shl_t handle = shl_load(file, BIND_DEFERRED, 0); \
90
+ if (!handle) \
91
+ { \
92
+ rb_raise(wmq_exception, \
93
+ "WMQ::QueueManager#connect(). Failed to load MQ Library:%s, rc=%s", \
94
+ LIBRARY, \
95
+ strerror(errno)); \
96
+ }
97
+
98
+ #define MQ_RELEASE shl_unload((shl_t)pqm->mq_lib_handle);
99
+
100
+ #define MQ_FUNCTION(FUNC, CAST) \
101
+ pqm->FUNC = NULL; \
102
+ shl_findsym(&handle,FUNC,TYPE_PROCEDURE,(void*)&(pqm->FUNC)); \
103
+ if(pqm->FUNC == NULL) \
104
+ { \
105
+ shl_findsym(&handle,FUNC,TYPE_UNDEFINED,(void*)&(pqm->FUNC)); \
106
+ if(pqm->FUNC == NULL) \
107
+ { \
108
+ rb_raise(wmq_exception, "Failed to find API "#FUNC" in MQ Library"); \
109
+ } \
110
+ }
111
+
112
+ #define MQ_LIBRARY_SERVER "libmqm_r.sl"
113
+ #define MQ_LIBRARY_CLIENT "libmqic_r.sl"
114
+ #endif
115
+
116
+ void Queue_manager_mq_load(PQUEUE_MANAGER pqm)
117
+ {
118
+ #if defined MQ_FUNCTION
119
+ PMQCHAR library;
120
+ if(pqm->is_client_conn)
121
+ {
122
+ library = MQ_LIBRARY_CLIENT;
123
+ if(pqm->trace_level) printf("WMQ::QueueManager#connect() Loading MQ Client Library:%s\n", library);
124
+ }
125
+ else
126
+ {
127
+ library = MQ_LIBRARY_SERVER;
128
+ if(pqm->trace_level) printf("WMQ::QueueManager#connect() Loading MQ Server Library:%s\n", library);
129
+ }
130
+
131
+ {
132
+ MQ_LOAD(library)
133
+
134
+ if(pqm->trace_level>1) printf("WMQ::QueueManager#connect() MQ Library:%s Loaded successfully\n", library);
135
+
136
+ MQ_FUNCTION(MQCONNX,void(*)(PMQCHAR,PMQCNO,PMQHCONN,PMQLONG,PMQLONG))
137
+ MQ_FUNCTION(MQCONN, void(*)(PMQCHAR,PMQHCONN,PMQLONG,PMQLONG))
138
+ MQ_FUNCTION(MQDISC,void(*) (PMQHCONN,PMQLONG,PMQLONG))
139
+ MQ_FUNCTION(MQBEGIN,void(*)(MQHCONN,PMQVOID,PMQLONG,PMQLONG))
140
+ MQ_FUNCTION(MQBACK,void(*) (MQHCONN,PMQLONG,PMQLONG))
141
+ MQ_FUNCTION(MQCMIT,void(*) (MQHCONN,PMQLONG,PMQLONG))
142
+ MQ_FUNCTION(MQPUT1,void(*) (MQHCONN,PMQVOID,PMQVOID,PMQVOID,MQLONG,PMQVOID,PMQLONG,PMQLONG))
143
+
144
+ MQ_FUNCTION(MQOPEN,void(*) (MQHCONN,PMQVOID,MQLONG,PMQHOBJ,PMQLONG,PMQLONG))
145
+ MQ_FUNCTION(MQCLOSE,void(*)(MQHCONN,PMQHOBJ,MQLONG,PMQLONG,PMQLONG))
146
+ MQ_FUNCTION(MQGET,void(*) (MQHCONN,MQHOBJ,PMQVOID,PMQVOID,MQLONG,PMQVOID,PMQLONG,PMQLONG,PMQLONG))
147
+ MQ_FUNCTION(MQPUT,void(*) (MQHCONN,MQHOBJ,PMQVOID,PMQVOID,MQLONG,PMQVOID,PMQLONG,PMQLONG))
148
+
149
+ MQ_FUNCTION(MQINQ,void(*) (MQHCONN,MQHOBJ,MQLONG,PMQLONG,MQLONG,PMQLONG,MQLONG,PMQCHAR,PMQLONG,PMQLONG))
150
+ MQ_FUNCTION(MQSET,void(*) (MQHCONN,MQHOBJ,MQLONG,PMQLONG,MQLONG,PMQLONG,MQLONG,PMQCHAR,PMQLONG,PMQLONG))
151
+
152
+ MQ_FUNCTION(mqCreateBag,void(*)(MQLONG,PMQHBAG,PMQLONG,PMQLONG))
153
+ MQ_FUNCTION(mqDeleteBag,void(*)(PMQHBAG,PMQLONG,PMQLONG))
154
+ MQ_FUNCTION(mqClearBag,void(*)(MQHBAG,PMQLONG,PMQLONG))
155
+ MQ_FUNCTION(mqExecute,void(*)(MQHCONN,MQLONG,MQHBAG,MQHBAG,MQHBAG,MQHOBJ,MQHOBJ,PMQLONG,PMQLONG))
156
+ MQ_FUNCTION(mqCountItems,void(*)(MQHBAG,MQLONG,PMQLONG,PMQLONG,PMQLONG))
157
+ MQ_FUNCTION(mqInquireBag,void(*)(MQHBAG,MQLONG,MQLONG,PMQHBAG,PMQLONG,PMQLONG))
158
+ MQ_FUNCTION(mqInquireItemInfo,void(*)(MQHBAG,MQLONG,MQLONG,PMQLONG,PMQLONG,PMQLONG,PMQLONG))
159
+ MQ_FUNCTION(mqInquireInteger,void(*)(MQHBAG,MQLONG,MQLONG,PMQLONG,PMQLONG,PMQLONG))
160
+ MQ_FUNCTION(mqInquireString,void(*)(MQHBAG,MQLONG,MQLONG,MQLONG,PMQCHAR,PMQLONG,PMQLONG,PMQLONG,PMQLONG))
161
+ MQ_FUNCTION(mqAddInquiry,void(*)(MQHBAG,MQLONG,PMQLONG,PMQLONG))
162
+ MQ_FUNCTION(mqAddInteger,void(*)(MQHBAG,MQLONG,MQLONG,PMQLONG,PMQLONG))
163
+ MQ_FUNCTION(mqAddString,void(*)(MQHBAG,MQLONG,MQLONG,PMQCHAR,PMQLONG,PMQLONG))
164
+
165
+ pqm->mq_lib_handle = (void*)handle;
166
+
167
+ if(pqm->trace_level>1) printf("WMQ::QueueManager#connect() MQ API's loaded successfully\n");
168
+ }
169
+ #else
170
+ /*
171
+ * For all the other platforms were we have to have two versions of Ruby WMQ
172
+ * 1: Linked with MQ Server Library
173
+ * 2: Linked with MQ Client Library
174
+ *
175
+ * As a result to use the client library:
176
+ * require 'wmq/wmq_client'
177
+ */
178
+ pqm->MQCONNX = &MQCONNX;
179
+ pqm->MQCONN = &MQCONN;
180
+ pqm->MQDISC = &MQDISC;
181
+ pqm->MQBEGIN = &MQBEGIN;
182
+ pqm->MQBACK = &MQBACK;
183
+ pqm->MQCMIT = &MQCMIT;
184
+ pqm->MQPUT1 = &MQPUT1;
185
+
186
+ pqm->MQOPEN = &MQOPEN;
187
+ pqm->MQCLOSE = &MQCLOSE;
188
+ pqm->MQGET = &MQGET;
189
+ pqm->MQPUT = &MQPUT;
190
+
191
+ pqm->MQINQ = &MQINQ;
192
+ pqm->MQSET = &MQSET;
193
+
194
+ pqm->mqCreateBag = &mqCreateBag;
195
+ pqm->mqClearBag = &mqClearBag;
196
+ pqm->mqExecute = &mqExecute;
197
+ pqm->mqCountItems = &mqCountItems;
198
+ pqm->mqInquireBag = &mqInquireBag;
199
+ pqm->mqInquireItemInfo= &mqInquireItemInfo;
200
+ pqm->mqInquireInteger = &mqInquireInteger;
201
+ pqm->mqInquireString = &mqInquireString;
202
+ #endif
203
+ }
204
+
205
+ void Queue_manager_mq_free(PQUEUE_MANAGER pqm)
206
+ {
207
+ if(pqm->mq_lib_handle)
208
+ {
209
+ if(pqm->trace_level>1) printf("WMQ::QueueManager#gc() Releasing MQ Library\n");
210
+ MQ_RELEASE
211
+ pqm->mq_lib_handle = 0;
212
+ }
213
+ }
@@ -0,0 +1,1410 @@
1
+ /* --------------------------------------------------------------------------
2
+ * Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ * --------------------------------------------------------------------------*/
16
+
17
+ #include "wmq.h"
18
+ /* --------------------------------------------------
19
+ * Initialize Ruby ID's for Queue Class
20
+ *
21
+ * This function is called when the library is loaded
22
+ * by ruby
23
+ * --------------------------------------------------*/
24
+ static ID ID_new;
25
+ static ID ID_call;
26
+ static ID ID_close;
27
+ static ID ID_input;
28
+ static ID ID_input_shared;
29
+ static ID ID_input_exclusive;
30
+ static ID ID_output;
31
+ static ID ID_browse;
32
+ static ID ID_sync;
33
+ static ID ID_new_id;
34
+ static ID ID_new_msg_id;
35
+ static ID ID_new_correl_id;
36
+ static ID ID_convert;
37
+ static ID ID_wait;
38
+ static ID ID_q_name;
39
+ static ID ID_q_mgr_name;
40
+ static ID ID_match;
41
+ static ID ID_options;
42
+ static ID ID_open_options;
43
+ static ID ID_mode;
44
+ static ID ID_fail_if_quiescing;
45
+ static ID ID_queue_manager;
46
+ static ID ID_dynamic_q_name;
47
+ static ID ID_close_options;
48
+ static ID ID_fail_if_exists;
49
+ static ID ID_alternate_user_id;
50
+ static ID ID_alternate_security_id;
51
+ static ID ID_message;
52
+ static ID ID_descriptor;
53
+
54
+ void Queue_id_init()
55
+ {
56
+ ID_new = rb_intern("new");
57
+ ID_call = rb_intern("call");
58
+ ID_close = rb_intern("close");
59
+
60
+ ID_input = rb_intern("input");
61
+ ID_input_shared = rb_intern("input_shared");
62
+ ID_input_exclusive = rb_intern("input_exclusive");
63
+ ID_output = rb_intern("output");
64
+ ID_browse = rb_intern("browse");
65
+ ID_q_name = rb_intern("q_name");
66
+ ID_q_mgr_name = rb_intern("q_mgr_name");
67
+ ID_queue_manager = rb_intern("queue_manager");
68
+
69
+ ID_sync = rb_intern("sync");
70
+ ID_new_id = rb_intern("new_id");
71
+ ID_new_msg_id = rb_intern("new_msg_id");
72
+ ID_new_correl_id = rb_intern("new_correl_id");
73
+ ID_convert = rb_intern("convert");
74
+ ID_wait = rb_intern("wait");
75
+ ID_match = rb_intern("match");
76
+ ID_options = rb_intern("options");
77
+ ID_open_options = rb_intern("open_options");
78
+ ID_mode = rb_intern("mode");
79
+
80
+ ID_message = rb_intern("message");
81
+ ID_descriptor = rb_intern("descriptor");
82
+
83
+ ID_fail_if_quiescing = rb_intern("fail_if_quiescing");
84
+ ID_dynamic_q_name = rb_intern("dynamic_q_name");
85
+ ID_close_options = rb_intern("close_options");
86
+ ID_fail_if_exists = rb_intern("fail_if_exists");
87
+ ID_alternate_security_id = rb_intern("alternate_security_id");
88
+ ID_alternate_user_id = rb_intern("alternate_user_id");
89
+ }
90
+
91
+ typedef struct tagQUEUE QUEUE;
92
+ typedef QUEUE MQPOINTER PQUEUE;
93
+
94
+ struct tagQUEUE {
95
+ MQHOBJ hobj; /* object handle */
96
+ MQHCONN hcon; /* connection handle */
97
+ MQOD od; /* Object Descriptor */
98
+ MQLONG comp_code; /* completion code */
99
+ MQLONG reason_code; /* reason code for MQCONN */
100
+ MQLONG open_options; /* MQOPEN options */
101
+ MQLONG close_options; /* MQCLOSE options */
102
+ MQLONG exception_on_error; /* Non-Zero means throw exception*/
103
+ MQLONG fail_if_exists; /* Non-Zero means open dynamic_q_name directly */
104
+ MQLONG trace_level; /* Trace level. 0==None, 1==Info 2==Debug ..*/
105
+ MQCHAR q_name[MQ_Q_NAME_LENGTH+1]; /* queue name plus null character */
106
+ PMQBYTE p_buffer; /* message buffer */
107
+ MQLONG buffer_size; /* Allocated size of buffer */
108
+
109
+ void(*MQCLOSE)(MQHCONN,PMQHOBJ,MQLONG,PMQLONG,PMQLONG);
110
+ void(*MQGET) (MQHCONN,MQHOBJ,PMQVOID,PMQVOID,MQLONG,PMQVOID,PMQLONG,PMQLONG,PMQLONG);
111
+ void(*MQPUT) (MQHCONN,MQHOBJ,PMQVOID,PMQVOID,MQLONG,PMQVOID,PMQLONG,PMQLONG);
112
+ };
113
+
114
+ /* --------------------------------------------------
115
+ * C Structure to store MQ data types and other
116
+ * C internal values
117
+ * --------------------------------------------------*/
118
+ void QUEUE_free(void* p)
119
+ {
120
+ PQUEUE pq = (PQUEUE)p;
121
+ if(pq->trace_level) printf("WMQ::Queue Freeing QUEUE structure\n");
122
+
123
+ if (pq->hobj) /* Valid Q handle means MQCLOSE was not called */
124
+ {
125
+ printf("WMQ::Queue#close was not called. Automatically calling close()\n");
126
+ pq->MQCLOSE(pq->hcon, &pq->hobj, pq->close_options, &pq->comp_code, &pq->reason_code);
127
+ }
128
+ free(pq->p_buffer);
129
+ free(p);
130
+ }
131
+
132
+ VALUE QUEUE_alloc(VALUE klass)
133
+ {
134
+ static MQOD default_MQOD = {MQOD_DEFAULT};
135
+ PQUEUE pq = ALLOC(QUEUE);
136
+
137
+ pq->hobj = 0;
138
+ pq->hcon = 0;
139
+ memcpy(&pq->od, &default_MQOD, sizeof(MQOD));
140
+ pq->comp_code = 0;
141
+ pq->reason_code = 0;
142
+ pq->open_options = 0;
143
+ pq->close_options = MQCO_NONE;
144
+ pq->exception_on_error = 1;
145
+ pq->trace_level = 0;
146
+ pq->fail_if_exists = 1;
147
+ memset(&pq->q_name, 0, sizeof(pq->q_name));
148
+ pq->buffer_size = 16384;
149
+ pq->p_buffer = ALLOC_N(char, pq->buffer_size);
150
+
151
+ return Data_Wrap_Struct(klass, 0, QUEUE_free, pq);
152
+ }
153
+
154
+ static MQLONG Queue_extract_open_options(VALUE hash, VALUE name)
155
+ {
156
+ VALUE val;
157
+ MQLONG flag;
158
+ MQLONG mq_open_options = 0;
159
+
160
+ WMQ_HASH2MQLONG(hash,open_options, mq_open_options)
161
+
162
+ val = rb_hash_aref(hash, ID2SYM(ID_mode)); /* :mode */
163
+ if (!NIL_P(val))
164
+ {
165
+ ID mode_id = rb_to_id(val);
166
+
167
+ if(mode_id == ID_output) mq_open_options |= MQOO_OUTPUT;
168
+ else if(mode_id == ID_input) mq_open_options |= MQOO_INPUT_AS_Q_DEF;
169
+ else if(mode_id == ID_input_shared) mq_open_options |= MQOO_INPUT_SHARED;
170
+ else if(mode_id == ID_input_exclusive) mq_open_options |= MQOO_INPUT_EXCLUSIVE;
171
+ else if(mode_id == ID_browse) mq_open_options |= MQOO_BROWSE;
172
+ else
173
+ {
174
+ rb_raise(rb_eArgError,
175
+ "Unknown mode supplied for Queue:%s",
176
+ RSTRING(name)->ptr);
177
+ }
178
+ }
179
+ else if (!mq_open_options)
180
+ {
181
+ rb_raise(rb_eArgError,
182
+ "Either :mode or :options is required. Both are missing from hash passed to initialize() for Queue: %s",
183
+ RSTRING(name)->ptr);
184
+ }
185
+
186
+ IF_TRUE(fail_if_quiescing, 1) /* Defaults to true */
187
+ {
188
+ mq_open_options |= MQOO_FAIL_IF_QUIESCING;
189
+ }
190
+
191
+ return mq_open_options;
192
+ }
193
+
194
+ void Queue_extract_put_message_options(VALUE hash, PMQPMO ppmo)
195
+ {
196
+ VALUE val;
197
+ MQLONG flag;
198
+
199
+ WMQ_HASH2MQLONG(hash,options, ppmo->Options)
200
+
201
+ IF_TRUE(sync, 0) /* :sync */
202
+ {
203
+ ppmo->Options |= MQPMO_SYNCPOINT;
204
+ }
205
+
206
+ IF_TRUE(new_id, 0) /* :new_id */
207
+ {
208
+ ppmo->Options |= MQPMO_NEW_MSG_ID;
209
+ ppmo->Options |= MQPMO_NEW_CORREL_ID;
210
+ }
211
+ else
212
+ {
213
+ IF_TRUE(new_msg_id, 0) /* :new_msg_id */
214
+ {
215
+ ppmo->Options |= MQPMO_NEW_MSG_ID;
216
+ }
217
+
218
+ IF_TRUE(new_correl_id, 0) /* new_correl_id */
219
+ {
220
+ ppmo->Options |= MQPMO_NEW_CORREL_ID;
221
+ }
222
+ }
223
+ return;
224
+ }
225
+
226
+ /* Future Use:
227
+ * *:q_name => ['q_name1', 'q_name2'] # Not implemented: Future Use!!
228
+ * *:q_name => [ {queue_manager=>'QMGR_name',
229
+ * queue =>'queue name1'}, # Future Use!!
230
+ * { ... }
231
+ * ]
232
+ * *:resolved => { queue => 'Resolved queue name',
233
+ * queue_manager => 'Resolved queue manager name' }
234
+ */
235
+
236
+ /*
237
+ * call-seq:
238
+ * new(...)
239
+ *
240
+ * Note:
241
+ * * It is _not_ recommended to create instances of Queue directly, rather user Queue.open. Which
242
+ * creates the queue, opens the queue, executes a supplied code block and then ensures the queue
243
+ * is closed.
244
+ *
245
+ * Parameters:
246
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
247
+ * * See Queue.open for details on all parameters
248
+ *
249
+ */
250
+ VALUE Queue_initialize(VALUE self, VALUE hash)
251
+ {
252
+ VALUE str;
253
+ size_t size;
254
+ size_t length;
255
+ VALUE val;
256
+ VALUE q_name;
257
+ PQUEUE pq;
258
+
259
+ Check_Type(hash, T_HASH);
260
+
261
+ Data_Get_Struct(self, QUEUE, pq);
262
+
263
+ val = rb_hash_aref(hash, ID2SYM(ID_queue_manager)); /* :queue_manager */
264
+ if (NIL_P(val))
265
+ {
266
+ rb_raise(rb_eArgError, "Mandatory parameter :queue_manager missing from WMQ::Queue::new");
267
+ }
268
+ else
269
+ {
270
+ PQUEUE_MANAGER pqm;
271
+ Data_Get_Struct(val, QUEUE_MANAGER, pqm);
272
+ pq->exception_on_error = pqm->exception_on_error; /* Copy exception_on_error from Queue Manager setting */
273
+ pq->trace_level = pqm->trace_level; /* Copy trace_level from Queue Manager setting */
274
+
275
+ rb_iv_set(self, "@queue_manager", val);
276
+ }
277
+
278
+ q_name = rb_hash_aref(hash, ID2SYM(ID_q_name)); /* :q_name */
279
+ if (NIL_P(q_name))
280
+ {
281
+ rb_raise(rb_eArgError, "Mandatory parameter :q_name missing from WMQ::Queue::new");
282
+ }
283
+
284
+ /* --------------------------------------------------
285
+ * If :q_name is a hash, extract :q_name and :q_mgr_name
286
+ * --------------------------------------------------*/
287
+ if(TYPE(q_name) == T_HASH)
288
+ {
289
+ if(pq->trace_level)
290
+ printf ("WMQ::Queue::new q_name is a hash\n");
291
+
292
+ WMQ_HASH2MQCHARS(q_name,q_mgr_name, pq->od.ObjectQMgrName)
293
+
294
+ q_name = rb_hash_aref(q_name, ID2SYM(ID_q_name));
295
+ if (NIL_P(q_name))
296
+ {
297
+ rb_raise(rb_eArgError,
298
+ "Mandatory parameter :q_name missing from :q_name hash passed to WMQ::Queue::new");
299
+ }
300
+ }
301
+
302
+ str = StringValue(q_name);
303
+ rb_iv_set(self, "@original_name", str); /* Store original queue name */
304
+ strncpy(pq->q_name, RSTRING(str)->ptr, sizeof(pq->q_name));
305
+
306
+ pq->open_options = Queue_extract_open_options(hash, q_name);
307
+
308
+ if(pq->trace_level > 1) printf("WMQ::Queue::new Queue:%s\n", pq->q_name);
309
+
310
+ val = rb_hash_aref(hash, ID2SYM(ID_dynamic_q_name)); /* :dynamic_q_name */
311
+ if (!NIL_P(val))
312
+ {
313
+ rb_iv_set(self, "@dynamic_q_name", val);
314
+ }
315
+
316
+ WMQ_HASH2MQBYTES(hash,alternate_security_id, pq->od.AlternateSecurityId)
317
+ WMQ_HASH2MQLONG(hash,close_options, pq->close_options)
318
+ WMQ_HASH2BOOL(hash,fail_if_exists, pq->fail_if_exists)
319
+
320
+ val = rb_hash_aref(hash, ID2SYM(ID_alternate_user_id)); /* :alternate_user_id */
321
+ if (!NIL_P(val))
322
+ {
323
+ WMQ_HASH2MQCHARS(hash,alternate_user_id, pq->od.AlternateUserId)
324
+ pq->open_options |= MQOO_ALTERNATE_USER_AUTHORITY;
325
+ }
326
+
327
+ return Qnil;
328
+ }
329
+
330
+ /*
331
+ * call-seq:
332
+ * open()
333
+ *
334
+ * Open the queue
335
+ *
336
+ * Note:
337
+ * * It is not recommended to use this method to open a queue, since the queue will
338
+ * have to be closed explicitly.
339
+ * * Rather use WMQ::QueueManager#open_queue
340
+ * * If the queue is already open, it will be closed and re-opened.
341
+ * Any errors that occur while closing the queue are ignored.
342
+ * * Custom behavior for Dynamic Queues:
343
+ * When :dynamic_q_name is supplied and MQ fails to
344
+ * open the queue with MQRC_OBJECT_ALREADY_EXISTS,
345
+ * this method will automatically open the existing
346
+ * queue by replacing the queue name with :dynamic_q_name
347
+ *
348
+ * This technique allows programs to dynamically create
349
+ * queues, without being concerned with first checking if
350
+ * the queue is already defined.
351
+ * I.e. Removes the need to have to explicitly create
352
+ * required queues in advance
353
+ * However, in order for this approach to work a
354
+ * Permanent model queue must be used. A Temporary
355
+ * model queue is automatically erased by WMQ when the
356
+ * queue is closed.
357
+ *
358
+ * Persistent messages cannot be put to a
359
+ * temporary dynamic queue!
360
+ *
361
+ * Returns:
362
+ * * true : On Success
363
+ * * false: On Failure
364
+ *
365
+ * comp_code and reason_code are also updated.
366
+ * reason will return a text description of the reason_code
367
+ *
368
+ * Throws:
369
+ * * WMQ::WMQException if comp_code == MQCC_FAILED
370
+ * * Except if :exception_on_error => false was supplied as a parameter
371
+ * to QueueManager.new
372
+ *
373
+ * Example:
374
+ * require 'wmq/wmq_client'
375
+ * queue_manager = WMQ::QueueManager.new(:q_mgr_name =>'REID',
376
+ * :connection_name=>'localhost(1414)')
377
+ * begin
378
+ * queue_manager.connect
379
+ *
380
+ * # Create Queue and clear any messages from the queue
381
+ * in_queue = WMQ::Queue.new(:queue_manager =>queue_manager,
382
+ * :mode =>:input,
383
+ * :dynamic_q_name=>'UNIT.TEST',
384
+ * :q_name =>'SYSTEM.DEFAULT.MODEL.QUEUE',
385
+ * :fail_if_exists=>false)
386
+ * begin
387
+ * in_queue.open
388
+ * in_queue.each { |message| p message.data }
389
+ * ensure
390
+ * # Note: Very important: Must close the queue explicitly
391
+ * in_queue.close
392
+ * end
393
+ * rescue => exc
394
+ * queue_manager.backout
395
+ * raise exc
396
+ * ensure
397
+ * # Note: Very important: Must disconnect from the queue manager explicitly
398
+ * queue_manager.disconnect
399
+ * end
400
+ */
401
+ VALUE Queue_open(VALUE self)
402
+ {
403
+ VALUE name;
404
+ VALUE val;
405
+ VALUE dynamic_q_name;
406
+ MQOD od = {MQOD_DEFAULT}; /* Object Descriptor */
407
+ VALUE queue_manager;
408
+ PQUEUE_MANAGER pqm;
409
+ PQUEUE pq;
410
+ Data_Get_Struct(self, QUEUE, pq);
411
+
412
+ name = rb_iv_get(self,"@original_name"); /* Always open original name */
413
+ if (NIL_P(name))
414
+ {
415
+ rb_raise(rb_eRuntimeError, "Fatal: Queue Name not found in Queue instance");
416
+ }
417
+ name = StringValue(name);
418
+
419
+ strncpy(od.ObjectName, RSTRING(name)->ptr, (size_t)MQ_Q_NAME_LENGTH);
420
+
421
+ dynamic_q_name = rb_iv_get(self,"@dynamic_q_name");
422
+ if (!NIL_P(dynamic_q_name))
423
+ {
424
+ val = StringValue(dynamic_q_name);
425
+ strncpy(od.DynamicQName, RSTRING(dynamic_q_name)->ptr, (size_t) MQ_Q_NAME_LENGTH);
426
+ if(pq->trace_level>1) printf("WMQ::Queue#open() Using dynamic queue name:%s\n", RSTRING(dynamic_q_name)->ptr);
427
+ }
428
+
429
+ queue_manager = rb_iv_get(self,"@queue_manager");
430
+ if (NIL_P(queue_manager))
431
+ {
432
+ rb_raise(rb_eRuntimeError, "Fatal: Queue Manager object not found in Queue instance");
433
+ }
434
+ Data_Get_Struct(queue_manager, QUEUE_MANAGER, pqm);
435
+ pq->MQCLOSE= pqm->MQCLOSE;
436
+ pq->MQGET = pqm->MQGET;
437
+ pq->MQPUT = pqm->MQPUT;
438
+
439
+ pq->hcon = pqm->hcon; /* Store Queue Manager handle for subsequent calls */
440
+
441
+ if(pq->trace_level)
442
+ printf ("WMQ::Queue#open() Opening Queue:%s, Queue Manager Handle:%d\n", RSTRING(name)->ptr, pq->hcon);
443
+
444
+ if(pq->hobj) /* Close queue if already open, ignore errors */
445
+ {
446
+ if(pq->trace_level)
447
+ printf ("WMQ::Queue#open() Queue:%s Already open, closing it!\n", RSTRING(name)->ptr);
448
+
449
+ pqm->MQCLOSE(pq->hcon, &pq->hobj, pq->close_options, &pq->comp_code, &pq->reason_code);
450
+ }
451
+
452
+ pqm->MQOPEN(pq->hcon, &od, pq->open_options, &pq->hobj, &pq->comp_code, &pq->reason_code);
453
+
454
+ /* --------------------------------------------------
455
+ * If the Dynamic Queue already exists, just open the
456
+ * dynamic queue name directly
457
+ * --------------------------------------------------*/
458
+ if (pq->reason_code == MQRC_OBJECT_ALREADY_EXISTS &&
459
+ !pq->fail_if_exists &&
460
+ !NIL_P(dynamic_q_name))
461
+ {
462
+ strncpy(od.ObjectName, od.DynamicQName, (size_t) MQ_Q_MGR_NAME_LENGTH);
463
+ od.DynamicQName[0] = 0;
464
+
465
+ if(pq->trace_level)
466
+ printf("WMQ::Queue#open() Queue already exists, re-trying with queue name:%s\n",
467
+ RSTRING(dynamic_q_name)->ptr);
468
+
469
+ pqm->MQOPEN(pq->hcon, &od, pq->open_options, &pq->hobj, &pq->comp_code, &pq->reason_code);
470
+ }
471
+
472
+ if(pq->trace_level)
473
+ printf("WMQ::Queue#open() MQOPEN completed with reason:%s, Handle:%d\n",
474
+ wmq_reason(pq->reason_code),
475
+ pq->hobj);
476
+
477
+ if (pq->comp_code == MQCC_FAILED)
478
+ {
479
+ pq->hobj = 0;
480
+ pq->hcon = 0;
481
+
482
+ if (pq->exception_on_error)
483
+ {
484
+ VALUE name = rb_iv_get(self,"@original_name");
485
+ name = StringValue(name);
486
+
487
+ rb_raise(wmq_exception,
488
+ "WMQ::Queue#open(). Error opening Queue:%s, reason:%s",
489
+ RSTRING(name)->ptr,
490
+ wmq_reason(pq->reason_code));
491
+ }
492
+ return Qfalse;
493
+ }
494
+ else
495
+ {
496
+ size_t size;
497
+ size_t length;
498
+ size_t i;
499
+ char* pChar;
500
+
501
+ WMQ_MQCHARS2STR(od.ObjectName, val)
502
+ rb_iv_set(self, "@name", val); /* Store actual queue name E.g. Dynamic Queue */
503
+
504
+ if(pq->trace_level>1) printf("WMQ::Queue#open() Actual Queue Name opened:%s\n", RSTRING(val)->ptr);
505
+ }
506
+
507
+ /* Future Use:
508
+ WMQ_MQCHARS2HASH(hash,resolved_q_name, pmqod->ResolvedQName)
509
+ WMQ_MQCHARS2HASH(hash,resolved_q_mgr_name, pmqod->ResolvedQMgrName)
510
+ */
511
+
512
+ return Qtrue;
513
+ }
514
+
515
+ /*
516
+ * Close the queue
517
+ *
518
+ * Returns:
519
+ * * true : On Success
520
+ * * false: On Failure
521
+ *
522
+ * comp_code and reason_code are also updated.
523
+ * reason will return a text description of the reason_code
524
+ *
525
+ * Throws:
526
+ * * WMQ::WMQException if comp_code == MQCC_FAILED
527
+ * * Except if :exception_on_error => false was supplied as a parameter
528
+ * to QueueManager.new
529
+ */
530
+ VALUE Queue_close(VALUE self)
531
+ {
532
+ PQUEUE pq;
533
+ Data_Get_Struct(self, QUEUE, pq);
534
+
535
+ /* Check if queue is open */
536
+ if (!pq->hcon)
537
+ {
538
+ if(pq->trace_level) printf ("WMQ::Queue#close() Queue not open\n");
539
+ return Qtrue;
540
+ }
541
+
542
+ if(pq->trace_level) printf ("WMQ::Queue#close() Queue Handle:%ld, Queue Manager Handle:%ld\n", pq->hobj, pq->hcon);
543
+
544
+ pq->MQCLOSE(pq->hcon, &pq->hobj, pq->close_options, &pq->comp_code, &pq->reason_code);
545
+
546
+ pq->hcon = 0; /* Every time the queue is opened, the qmgr handle must be fetched again! */
547
+ pq->hobj = 0;
548
+
549
+ if(pq->trace_level) printf("WMQ::Queue#close() MQCLOSE ended with reason:%s\n", wmq_reason(pq->reason_code));
550
+
551
+ if (pq->comp_code == MQCC_FAILED)
552
+ {
553
+ if (pq->exception_on_error)
554
+ {
555
+ VALUE name = Queue_name(self);
556
+
557
+ rb_raise(wmq_exception,
558
+ "WMQ::Queue#close(). Error closing Queue:%s, reason:%s",
559
+ RSTRING(name)->ptr,
560
+ wmq_reason(pq->reason_code));
561
+ }
562
+ return Qfalse;
563
+ }
564
+
565
+ return Qtrue;
566
+ }
567
+
568
+ /*
569
+ * call-seq:
570
+ * get(...)
571
+ *
572
+ * Get a message from the opened queue
573
+ *
574
+ * Parameters:
575
+ * * a Hash consisting of one or more of the named parameters
576
+ * * Summary of parameters and their WebSphere MQ equivalents:
577
+ * queue.get( # WebSphere MQ Equivalents:
578
+ * :message => my_message, # n/a : Instance of Message
579
+ * :sync => false, # MQGMO_SYNCPOINT
580
+ * :wait => 0, # MQGMO_WAIT, duration in ms
581
+ * :match => WMQ::MQMO_NONE, # MQMO_*
582
+ * :convert => false, # MQGMO_CONVERT
583
+ * :fail_if_quiescing => true # MQOO_FAIL_IF_QUIESCING
584
+ * :options => WMQ::MQGMO_FAIL_IF_QUIESCING # MQGMO_*
585
+ * )
586
+ *
587
+ * Mandatory Parameters
588
+ * * :message => Message
589
+ * * An instance of the WMQ::Message
590
+ *
591
+ * Optional Parameters
592
+ * * :sync => true or false
593
+ * * Determines whether the get is performed under synchpoint.
594
+ * I.e. Under the current unit of work
595
+ * Default: false
596
+ *
597
+ * * :wait => FixNum
598
+ * * The time in milli-seconds to wait for a message if one is not immediately available
599
+ * on the queue
600
+ * * Note: Under the covers the put option MQGMO_WAIT is automatically set when :wait
601
+ * is supplied
602
+ * Default: Wait forever
603
+ *
604
+ * * :match => FixNum
605
+ * * One or more of the following values:
606
+ * WMQ::MQMO_MATCH_MSG_ID
607
+ * WMQ::MQMO_MATCH_CORREL_ID
608
+ * WMQ::MQMO_MATCH_GROUP_ID
609
+ * WMQ::MQMO_MATCH_MSG_SEQ_NUMBER
610
+ * WMQ::MQMO_MATCH_OFFSET
611
+ * WMQ::MQMO_MATCH_MSG_TOKEN
612
+ * WMQ::MQMO_NONE
613
+ * * Multiple values can be or'd together. E.g.
614
+ * :match=>WMQ::MQMO_MATCH_MSG_ID | WMQ::MQMO_MATCH_CORREL_ID
615
+ * * Please see the WebSphere MQ documentation for more details on the above options
616
+ * Default: WMQ::MQMO_MATCH_MSG_ID | WMQ::MQMO_MATCH_CORREL_ID
617
+ *
618
+ * * :convert => true or false
619
+ * * When true, convert results in messages being converted to the local code page.
620
+ * E.g. When an EBCDIC text message from a mainframe is received, it will be converted
621
+ * to ASCII before passing the message data to the application.
622
+ * Default: false
623
+ *
624
+ * * :fail_if_quiescing => true or false
625
+ * * Determines whether the WMQ::Queue#get call will fail if the queue manager is
626
+ * in the process of being quiesced.
627
+ * * Note: This interface differs from other WebSphere MQ interfaces,
628
+ * they do not default to true.
629
+ * Default: true
630
+ *
631
+ * * :options => Fixnum (Advanced MQ Use only)
632
+ * * Numeric field containing any of the MQ Get message options or'd together
633
+ * * E.g. :options => WMQ::MQGMO_SYNCPOINT_IF_PERSISTENT | WMQ::MQGMO_MARK_SKIP_BACKOUT
634
+ * * Note: If :options is supplied, it is applied first, then the above parameters are
635
+ * applied afterwards.
636
+ * * One or more of the following values:
637
+ * WMQ::MQGMO_SYNCPOINT_IF_PERSISTENT
638
+ * WMQ::MQGMO_NO_SYNCPOINT
639
+ * WMQ::MQGMO_MARK_SKIP_BACKOUT
640
+ * WMQ::MQGMO_BROWSE_FIRST
641
+ * WMQ::MQGMO_BROWSE_NEXT
642
+ * WMQ::MQGMO_BROWSE_MSG_UNDER_CURSOR
643
+ * WMQ::MQGMO_MSG_UNDER_CURSOR
644
+ * WMQ::MQGMO_LOCK
645
+ * WMQ::MQGMO_UNLOCK
646
+ * WMQ::MQGMO_LOGICAL_ORDER
647
+ * WMQ::MQGMO_COMPLETE_MSG
648
+ * WMQ::MQGMO_ALL_MSGS_AVAILABLE
649
+ * WMQ::MQGMO_ALL_SEGMENTS_AVAILABLE
650
+ * WMQ::MQGMO_DELETE_MSG
651
+ * WMQ::MQGMO_NONE
652
+ * * Please see the WebSphere MQ documentation for more details on the above options
653
+ * Default: WMQ::MQGMO_NONE
654
+ *
655
+ * Returns:
656
+ * * true : On Success
657
+ * * false: On Failure, or if no message was found on the queue during the wait interval
658
+ *
659
+ * comp_code and reason_code are also updated.
660
+ * reason will return a text description of the reason_code
661
+ *
662
+ * Throws:
663
+ * * WMQ::WMQException if comp_code == MQCC_FAILED
664
+ * * Except if :exception_on_error => false was supplied as a parameter
665
+ * to QueueManager.new
666
+ *
667
+ * Example:
668
+ * require 'wmq/wmq'
669
+ *
670
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
671
+ * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:input) do |queue|
672
+ * message = WMQ::Message.new
673
+ * if queue.get(:message => message)
674
+ * puts "Data Received: #{message.data}"
675
+ * else
676
+ * puts 'No message available'
677
+ * end
678
+ * end
679
+ * end
680
+ */
681
+ VALUE Queue_get(VALUE self, VALUE hash)
682
+ {
683
+ VALUE handle;
684
+ VALUE val;
685
+ VALUE str;
686
+ VALUE descriptor;
687
+ VALUE data;
688
+ VALUE message;
689
+ PQUEUE pq;
690
+ MQLONG flag;
691
+ MQLONG messlen; /* message length received */
692
+
693
+ MQMD md = {MQMD_DEFAULT}; /* Message Descriptor */
694
+ MQGMO gmo = {MQGMO_DEFAULT}; /* get message options */
695
+
696
+ gmo.Version = MQGMO_CURRENT_VERSION; /* Allow MatchOptions */
697
+
698
+ Check_Type(hash, T_HASH);
699
+
700
+ Data_Get_Struct(self, QUEUE, pq);
701
+
702
+ /* Automatically open the queue if not already open */
703
+ if (!pq->hcon && (Queue_open(self) == Qfalse))
704
+ {
705
+ return Qfalse;
706
+ }
707
+
708
+ message = rb_hash_aref(hash, ID2SYM(ID_message));
709
+ if (NIL_P(message))
710
+ {
711
+ VALUE name = Queue_name(self);
712
+
713
+ rb_raise(rb_eArgError,
714
+ "Mandatory key :message is missing from hash passed to get() for Queue: %s",
715
+ RSTRING(name)->ptr);
716
+ }
717
+
718
+ Message_build_mqmd(message, &md);
719
+
720
+ WMQ_HASH2MQLONG(hash,options, gmo.Options) /* :options */
721
+
722
+ IF_TRUE(sync, 0) /* :sync defaults to false */
723
+ {
724
+ gmo.Options |= MQGMO_SYNCPOINT;
725
+ }
726
+
727
+ IF_TRUE(fail_if_quiescing, 1) /* :fail_if_quiescing defaults to true */
728
+ {
729
+ gmo.Options |= MQGMO_FAIL_IF_QUIESCING;
730
+ }
731
+
732
+ IF_TRUE(convert, 0) /* :convert defaults to false */
733
+ {
734
+ gmo.Options |= MQGMO_CONVERT;
735
+ }
736
+
737
+ val = rb_hash_aref(hash, ID2SYM(ID_wait)); /* :wait */
738
+ if (!NIL_P(val))
739
+ {
740
+ gmo.Options |= MQGMO_WAIT;
741
+ gmo.WaitInterval = NUM2LONG(val);
742
+ }
743
+
744
+ WMQ_HASH2MQLONG(hash,match, gmo.MatchOptions) /* :match */
745
+
746
+ if(pq->trace_level > 1) printf("WMQ::Queue#get() Get Message Option: MatchOptions=%ld\n", gmo.MatchOptions);
747
+ if(pq->trace_level) printf("WMQ::Queue#get() Queue Handle:%ld, Queue Manager Handle:%ld\n", pq->hobj, pq->hcon);
748
+
749
+ /* If descriptor is re-used
750
+
751
+ md.Encoding = MQENC_NATIVE;
752
+ md.CodedCharSetId = MQCCSI_Q_MGR;
753
+ */
754
+
755
+ /*
756
+ * Auto-Grow buffer size
757
+ *
758
+ * Note: If msg size is 70,000, we grow to 70,000, but then another program gets that
759
+ * message. The next message could be say 80,000 bytes in size, we need to
760
+ * grow the buffer again.
761
+ */
762
+ do
763
+ {
764
+ pq->MQGET(
765
+ pq->hcon, /* connection handle */
766
+ pq->hobj, /* object handle */
767
+ &md, /* message descriptor */
768
+ &gmo, /* get message options */
769
+ pq->buffer_size, /* message buffer size */
770
+ pq->p_buffer, /* message buffer */
771
+ &messlen, /* message length */
772
+ &pq->comp_code, /* completion code */
773
+ &pq->reason_code); /* reason code */
774
+
775
+ /* report reason, if any */
776
+ if (pq->reason_code != MQRC_NONE)
777
+ {
778
+ if(pq->trace_level>1) printf("WMQ::Queue#get() Growing buffer size from %ld to %ld\n", pq->buffer_size, messlen);
779
+ /* TODO: Add support for autogrow buffer here */
780
+ if (pq->reason_code == MQRC_TRUNCATED_MSG_FAILED)
781
+ {
782
+ if(pq->trace_level>2)
783
+ printf ("WMQ::Queue#reallocate Resizing buffer from %ld to %ld bytes\n", pq->buffer_size, messlen);
784
+
785
+ free(pq->p_buffer);
786
+ pq->buffer_size = messlen;
787
+ pq->p_buffer = ALLOC_N(char, messlen);
788
+ }
789
+ }
790
+ }
791
+ while (pq->reason_code == MQRC_TRUNCATED_MSG_FAILED);
792
+
793
+ if(pq->trace_level) printf("WMQ::Queue#get() MQGET ended with reason:%s\n", wmq_reason(pq->reason_code));
794
+
795
+ if (pq->comp_code != MQCC_FAILED)
796
+ {
797
+ Message_deblock(message, &md, pq->p_buffer, messlen, pq->trace_level); /* Extract MQMD and any other known MQ headers */
798
+ return Qtrue;
799
+ }
800
+ else
801
+ {
802
+ Message_clear(message);
803
+
804
+ /* --------------------------------------------------
805
+ * Do not throw exception when no more messages to be read
806
+ * --------------------------------------------------*/
807
+ if (pq->exception_on_error && (pq->reason_code != MQRC_NO_MSG_AVAILABLE))
808
+ {
809
+ VALUE name = Queue_name(self);
810
+
811
+ rb_raise(wmq_exception,
812
+ "WMQ::Queue#get(). Error reading a message from Queue:%s, reason:%s",
813
+ RSTRING(name)->ptr,
814
+ wmq_reason(pq->reason_code));
815
+ }
816
+ return Qfalse;
817
+ }
818
+ }
819
+
820
+ /*
821
+ * call-seq:
822
+ * put(...)
823
+ *
824
+ * Put a message to the WebSphere MQ queue
825
+ *
826
+ * Parameters:
827
+ * * A Hash consisting of one or more of the named parameters
828
+ * * Summary of parameters and their WebSphere MQ equivalents
829
+ * queue.put( # WebSphere MQ Equivalents:
830
+ * :message => my_message, # n/a : Instance of Message
831
+ * :data => "Hello World", # n/a : Data to send
832
+ * :sync => false, # MQGMO_SYNCPOINT
833
+ * :new_id => true, # MQPMO_NEW_MSG_ID & MQPMO_NEW_CORREL_ID
834
+ * :new_msg_id => true, # MQPMO_NEW_MSG_ID
835
+ * :new_correl_id => true, # MQPMO_NEW_CORREL_ID
836
+ * :fail_if_quiescing => true, # MQOO_FAIL_IF_QUIESCING
837
+ * :options => WMQ::MQPMO_FAIL_IF_QUIESCING # MQPMO_*
838
+ * )
839
+ *
840
+ * Mandatory Parameters:
841
+ *
842
+ * * Either :message or :data must be supplied
843
+ * * If both are supplied, then :data will be written to the queue. The data in :message
844
+ * will be ignored
845
+ *
846
+ * Optional Parameters:
847
+ * * :data => String
848
+ * * Data to be written to the queue. Can be binary or text data
849
+ * * Takes precendence over the data in :message
850
+ *
851
+ * * :message => Message
852
+ * * An instance of the WMQ::Message
853
+ * * The Message descriptor, headers and data is retrieved from :message
854
+ * * message.data is ignored if :data is supplied
855
+ *
856
+ * * :sync => true or false
857
+ * * Determines whether the get is performed under synchpoint.
858
+ * I.e. Under the current unit of work
859
+ * Default: false
860
+ *
861
+ * * :new_id => true or false
862
+ * * Generate a new message id and correlation id for this
863
+ * message. :new_msg_id and :new_correl_id will be ignored
864
+ * if this parameter is true
865
+ * Default: false
866
+ *
867
+ * * :new_msg_id => true or false
868
+ * * Generate a new message id for this message
869
+ * * Note: A blank message id will result in a new message id anyway.
870
+ * However, for subsequent puts using the same message descriptor, the same
871
+ * message id will be used.
872
+ * Default: false
873
+ *
874
+ * * :new_correl_id => true or false
875
+ * * Generate a new correlation id for this message
876
+ * Default: false
877
+ *
878
+ * * :fail_if_quiescing => true or false
879
+ * * Determines whether the WMQ::Queue#put call will fail if the queue manager is
880
+ * in the process of being quiesced.
881
+ * * Note: This interface differs from other WebSphere MQ interfaces,
882
+ * they do not default to true.
883
+ * Default: true
884
+ * Equivalent to: MQGMO_FAIL_IF_QUIESCING
885
+ *
886
+ * * Note: As part of the application design, carefull consideration
887
+ * should be given as to when to allow a transaction or
888
+ * unit of work to complete or fail under this condition.
889
+ * As such it is important to include this option where
890
+ * appropriate so that MQ Administrators can shutdown the
891
+ * queue managers without having to resort to the 'immediate'
892
+ * shutdown option.
893
+ *
894
+ * * :options => Fixnum (Advanced MQ Use only)
895
+ * * Numeric field containing any of the MQ Put message options or'd together
896
+ * * E.g. :options => WMQ::MQPMO_PASS_IDENTITY_CONTEXT | WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
897
+ * * Note: If :options is supplied, it is applied first, then the above parameters are
898
+ * applied afterwards.
899
+ * * One or more of the following values:
900
+ * WMQ::MQPMO_NO_SYNCPOINT
901
+ * WMQ::MQPMO_LOGICAL_ORDER
902
+ * WMQ::MQPMO_NO_CONTEXT
903
+ * WMQ::MQPMO_DEFAULT_CONTEXT
904
+ * WMQ::MQPMO_PASS_IDENTITY_CONTEXT
905
+ * WMQ::MQPMO_PASS_ALL_CONTEXT
906
+ * WMQ::MQPMO_SET_IDENTITY_CONTEXT
907
+ * WMQ::MQPMO_SET_ALL_CONTEXT
908
+ * WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
909
+ * WMQ::MQPMO_RESOLVE_LOCAL_Q
910
+ * WMQ::MQPMO_NONE
911
+ * * Please see the WebSphere MQ documentation for more details on the above options
912
+ * Default: WMQ::MQPMO_NONE
913
+ *
914
+ * Returns:
915
+ * * true : On Success
916
+ * * false: On Failure
917
+ *
918
+ * comp_code and reason_code are also updated.
919
+ * reason will return a text description of the reason_code
920
+ *
921
+ * Throws:
922
+ * * WMQ::WMQException if comp_code == MQCC_FAILED
923
+ * * Except if :exception_on_error => false was supplied as a parameter
924
+ * to QueueManager.new
925
+ *
926
+ * Example:
927
+ * require 'wmq/wmq_client'
928
+ *
929
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
930
+ * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:output) do |queue|
931
+ *
932
+ * # First message
933
+ * queue.put(:data => 'Hello World')
934
+ *
935
+ * # Set Format of message to string
936
+ * message = WMQ::Message.new
937
+ * message.descriptor[:format] = WMQ::MQFMT_STRING
938
+ * queue.put(:message=>message, :data => 'Hello Again')
939
+ *
940
+ * # Or, pass the data in the message
941
+ * message = WMQ::Message.new
942
+ * message.descriptor[:format] = WMQ::MQFMT_STRING
943
+ * message.data = 'Hello Again'
944
+ * queue.put(:message=>message)
945
+ * end
946
+ * end
947
+ */
948
+ VALUE Queue_put(VALUE self, VALUE hash)
949
+ {
950
+ MQPMO pmo = {MQPMO_DEFAULT}; /* put message options */
951
+ MQMD md = {MQMD_DEFAULT}; /* Message Descriptor */
952
+ PQUEUE pq;
953
+ MQLONG BufferLength = 0; /* Length of the message in Buffer */
954
+ PMQVOID pBuffer = 0; /* Message data */
955
+
956
+ Check_Type(hash, T_HASH);
957
+
958
+ Data_Get_Struct(self, QUEUE, pq);
959
+
960
+ /* Automatically open the queue if not already open */
961
+ if (!pq->hcon && (Queue_open(self) == Qfalse))
962
+ {
963
+ return Qfalse;
964
+ }
965
+
966
+ Queue_extract_put_message_options(hash, &pmo);
967
+ Message_build(&pq->p_buffer, &pq->buffer_size, pq->trace_level,
968
+ hash, &pBuffer, &BufferLength, &md);
969
+
970
+ if(pq->trace_level) printf("WMQ::Queue#put() Queue Handle:%ld, Queue Manager Handle:%ld\n", pq->hobj, pq->hcon);
971
+
972
+ pq->MQPUT(
973
+ pq->hcon, /* connection handle */
974
+ pq->hobj, /* object handle */
975
+ &md, /* message descriptor */
976
+ &pmo, /* put message options */
977
+ BufferLength, /* message length */
978
+ pBuffer, /* message buffer */
979
+ &pq->comp_code, /* completion code */
980
+ &pq->reason_code); /* reason code */
981
+
982
+ if(pq->trace_level) printf("WMQ::Queue#put() MQPUT ended with reason:%s\n", wmq_reason(pq->reason_code));
983
+
984
+ if (pq->reason_code != MQRC_NONE)
985
+ {
986
+ if (pq->exception_on_error)
987
+ {
988
+ VALUE name = Queue_name(self);
989
+
990
+ rb_raise(wmq_exception,
991
+ "WMQ::Queue#put(). Error writing a message to Queue:%s, reason:%s",
992
+ RSTRING(name)->ptr,
993
+ wmq_reason(pq->reason_code));
994
+ }
995
+ return Qfalse;
996
+ }
997
+ else
998
+ {
999
+ VALUE message = rb_hash_aref(hash, ID2SYM(ID_message));
1000
+ if(!NIL_P(message))
1001
+ {
1002
+ VALUE descriptor = rb_funcall(message, ID_descriptor, 0);
1003
+ Message_from_mqmd(descriptor, &md); /* This should be optimized to output only fields */
1004
+ }
1005
+ }
1006
+
1007
+ return Qtrue;
1008
+ }
1009
+
1010
+ /*
1011
+ * Returns the queue name => String
1012
+ */
1013
+ VALUE Queue_name(VALUE self)
1014
+ {
1015
+ /* If Queue is open, return opened name, otherwise return original name */
1016
+ PQUEUE pq;
1017
+ Data_Get_Struct(self, QUEUE, pq);
1018
+ if (pq->hobj)
1019
+ {
1020
+ return rb_iv_get(self,"@name");
1021
+ }
1022
+ return rb_iv_get(self,"@original_name");
1023
+ }
1024
+
1025
+ struct Queue_singleton_open_arg {
1026
+ VALUE queue;
1027
+ VALUE proc;
1028
+ };
1029
+
1030
+ static VALUE Queue_singleton_open_body(struct Queue_singleton_open_arg* arg)
1031
+ {
1032
+ rb_funcall(arg->proc, ID_call, 1, arg->queue);
1033
+ return Qnil;
1034
+ }
1035
+
1036
+ static VALUE Queue_singleton_open_ensure(VALUE queue)
1037
+ {
1038
+ return Queue_close(queue);
1039
+ }
1040
+
1041
+ /*
1042
+ * call-seq:
1043
+ * open(...)
1044
+ *
1045
+ * Open a queue, then close the queue once the supplied code block completes
1046
+ *
1047
+ * Parameters:
1048
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
1049
+ * * Summary of parameters and their WebSphere MQ equivalents:
1050
+ * queue = Queue.new( # WebSphere MQ Equivalents:
1051
+ * :queue_manager => queue_manager, # n/a : Instance of QueueManager
1052
+ * :q_name => 'Queue Name', # MQOD.ObjectName
1053
+ * :q_name => { queue_manager=>'QMGR_name', # MQOD.ObjectQMgrName
1054
+ * q_name =>'q_name'}
1055
+ * :mode => :input or :input_shared or :input_exclusive or :output,
1056
+ * :fail_if_quiescing => true # MQOO_FAIL_IF_QUIESCING
1057
+ * :fail_if_exists => true, # For dynamic queues, fail if it already exists
1058
+ * :open_options => WMQ::MQOO_BIND_ON_OPEN | ... # MQOO_*
1059
+ * :close_options => WMQ::MQCO_DELETE_PURGE # MQCO_*
1060
+ * :dynamic_q_name => 'Name of Dynamic Queue' # MQOD.DynamicQName
1061
+ * :alternate_user_id => 'userid', # MQOD.AlternateUserId
1062
+ * :alternate_security_id => '' # MQOD.AlternateSecurityId
1063
+ * )
1064
+ *
1065
+ * Mandatory Parameters
1066
+ * * :queue_manager
1067
+ * * An instance of the WMQ::QueueManager class. E.g. QueueManager.new
1068
+ * * Note: This is _not_ the queue manager name!
1069
+ *
1070
+ * * :q_name => String
1071
+ * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
1072
+ * * To open remote queues for which a local remote queue definition is not available
1073
+ * pass a Hash as q_name (see q_name => Hash)
1074
+ * OR
1075
+ * * :q_name => Hash
1076
+ * * q_name => String
1077
+ * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
1078
+ * * :q_mgr_name => String
1079
+ * * Name of the remote WebSphere MQ queue manager to send the message to.
1080
+ * * This allows a message to be written to a queue on a remote queue manager
1081
+ * where a remote queue definition is not defined locally
1082
+ * * Commonly used to reply to messages from remote systems
1083
+ * * If q_mgr_name is the same as the local queue manager name then the message
1084
+ * is merely written to the local queue.
1085
+ * * Note: q_mgr_name should only be supplied when putting messages to the queue.
1086
+ * It is not possible to get messages from a queue on a queue manager other
1087
+ * than the currently connected queue manager
1088
+ *
1089
+ * * :mode => Symbol
1090
+ * * Specify how the queue is to be opened
1091
+ * * :output
1092
+ * * Open the queue for output. I.e. WMQ::Queue#put will be called
1093
+ * Equivalent to: MQOO_OUTPUT
1094
+ * * :input
1095
+ * * Open the queue for input. I.e. WMQ::Queue#get will be called.
1096
+ * * Queue sharing for reading from the queue is defined by the queue itself.
1097
+ * By default most queues are set to shared. I.e. Multiple applications
1098
+ * can read and/or write from the queue at the same time
1099
+ * Equivalent to: MQOO_INPUT_AS_Q_DEF
1100
+ * * :input_shared
1101
+ * * Open the queue for input. I.e. WMQ::Queue#get will be called.
1102
+ * * Explicitly open the queue so that other applications can read or write
1103
+ * from the same queue
1104
+ * Equivalent to: MQOO_INPUT_SHARED
1105
+ * * :input_exclusive
1106
+ * * Open the queue for input. I.e. WMQ::Queue#get will be called.
1107
+ * * Explicitly open the queue so that other applications cannot read
1108
+ * from the same queue. Does _not_ affect applications writing to the queue.
1109
+ * * Note: If :input_exclusive is used and connectivity the queue manager is lost.
1110
+ * Upon restart the queue can still be "locked". The application should retry
1111
+ * every minute or so until the queue becomes available. Otherwise, of course,
1112
+ * another application has the queue open exclusively.
1113
+ * Equivalent to: MQOO_INPUT_EXCLUSIVE
1114
+ * * :browse
1115
+ * * Browse the messages on the queue _without_ removing them from the queue
1116
+ * * Open the queue for input. I.e. WMQ::Queue#get will be called.
1117
+ * * Note: It is necessary to specify WMQ::MQGMO_BROWSE_FIRST before the
1118
+ * first get, then set WMQ::MQGMO_BROWSE_NEXT for subsequent calls.
1119
+ * * Note: For now it is also necessary to specify these options when calling
1120
+ * WMQ::Queue#each. A change will be made to each to address this.
1121
+ * Equivalent to: MQOO_BROWSE
1122
+ *
1123
+ * Optional Parameters
1124
+ * * :fail_if_quiescing => true or false
1125
+ * * Determines whether the WMQ::Queue#open call will fail if the queue manager is
1126
+ * in the process of being quiesced.
1127
+ * * Note: If set to false, the MQOO_FAIL_IF_QUIESCING flag will not be removed if
1128
+ * it was also supplied in :open_options. However, if set to true it will override
1129
+ * this value in :open_options
1130
+ * * Note: This interface differs from other WebSphere MQ interfaces,
1131
+ * they do not default to true.
1132
+ * Default: true
1133
+ * Equivalent to: MQOO_FAIL_IF_QUIESCING
1134
+ *
1135
+ * * :open_options => FixNum
1136
+ * * One or more of the following values:
1137
+ * WMQ::MQOO_INQUIRE
1138
+ * WMQ::MQOO_SET
1139
+ * WMQ::MQOO_BIND_ON_OPEN
1140
+ * WMQ::MQOO_BIND_NOT_FIXED
1141
+ * WMQ::MQOO_BIND_AS_Q_DEF
1142
+ * WMQ::MQOO_SAVE_ALL_CONTEXT
1143
+ * WMQ::MQOO_PASS_IDENTITY_CONTEXT
1144
+ * WMQ::MQOO_PASS_ALL_CONTEXT
1145
+ * WMQ::MQOO_SET_IDENTITY_CONTEXT
1146
+ * WMQ::MQOO_SET_ALL_CONTEXT
1147
+ * * Multiple values can be or'd together. E.g.
1148
+ * :open_options=>WMQ::MQOO_BIND_ON_OPEN | WMQ::MQOO_SAVE_ALL_CONTEXT
1149
+ * * Please see the WebSphere MQ documentation for more details on the above options
1150
+ *
1151
+ * * :close_options => FixNum
1152
+ * * One of the following values:
1153
+ * WMQ::MQCO_DELETE
1154
+ * WMQ::MQCO_DELETE_PURGE
1155
+ * * Please see the WebSphere MQ documentation for more details on the above options
1156
+ *
1157
+ * * :dynamic_q_name => String
1158
+ * * If a model queue name is supplied to :q_name then the final queue name that is
1159
+ * created is specified using :dynamic_q_name
1160
+ * * A complete queue name can be specified. E.g. 'MY.LOCAL.QUEUE'
1161
+ * * Or, a partial queue name can be supplied. E.g. 'MY.REPLY.QUEUE.*'
1162
+ * In this case WebSphere MQ will automatically add numbers to the end
1163
+ * of 'MY.REPLY.QUEUE.' to ensure this queue name is unique.
1164
+ * * The most common use of :dynamic_q_name is to create a temporary dynamic queue
1165
+ * to which replies can be posted for this instance of the program
1166
+ * * When opening a model queue, :dynamic_q_name is optional. However it's use is
1167
+ * recommended in order to make it easier to identify which application a
1168
+ * dynamic queue belongs to.
1169
+ *
1170
+ * * :fail_if_exists => true or false
1171
+ * * Only applicable when opening a model queue
1172
+ * * When opening a queue dynamically, sometimes the :dynamic_q_name already
1173
+ * exists. Under this condition, if :fail_if_exists is false, the queue is
1174
+ * automatically re-opened using the :dynamic_q_name. The :q_name field is ignored.
1175
+ * * This feature is usefull when creating _permanent_ dynamic queues.
1176
+ * (The model queue has the definition type set to Permanent: DEFTYPE(PERMDYN) ).
1177
+ * * In this way it is not necessary to create the queues before running the program.
1178
+ * Default: true
1179
+ *
1180
+ * * :alternate_user_id [String]
1181
+ * * Sets the alternate userid to use when messages are put to the queue
1182
+ * * Note: It is not necessary to supply WMQ::MQOO_ALTERNATE_USER_AUTHORITY
1183
+ * since it is automatically added to the :open_options when :alternate_user_id
1184
+ * is supplied
1185
+ * * See WebSphere MQ Application Programming Reference: MQOD.AlternateUserId
1186
+ *
1187
+ * * :alternate_security_id [String]
1188
+ * * Sets the alternate security id to use when messages are put to the queue
1189
+ * * See WebSphere MQ Application Programming Reference: MQOD.AlternateSecurityId
1190
+ *
1191
+ * Note:
1192
+ * * It is more convenient to use WMQ::QueueManager#open_queue, since it automatically supplies
1193
+ * the parameter :queue_manager
1194
+ * * That way :queue_manager parameter is _not_ required
1195
+ *
1196
+ * Example:
1197
+ * # Put 10 Hello World messages onto a queue
1198
+ * require 'wmq/wmq_client'
1199
+ *
1200
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
1201
+ * WMQ::Queue.open(:queue_manager=>qmgr,
1202
+ * :q_name =>'TEST.QUEUE',
1203
+ * :mode =>:output) do |queue|
1204
+ * 10.times { |counter| queue.put(:data => "Hello World #{counter}") }
1205
+ * end
1206
+ * end
1207
+ */
1208
+ VALUE Queue_singleton_open(int argc, VALUE *argv, VALUE self)
1209
+ {
1210
+ VALUE proc, parameters, queue;
1211
+
1212
+ /* Extract parameters and code block (Proc) */
1213
+ rb_scan_args(argc, argv, "1&", &parameters, &proc);
1214
+
1215
+ queue = rb_funcall(wmq_queue, ID_new, 1, parameters);
1216
+ if(!NIL_P(proc))
1217
+ {
1218
+ if(Qtrue == Queue_open(queue))
1219
+ {
1220
+ struct Queue_singleton_open_arg arg;
1221
+ arg.queue = queue;
1222
+ arg.proc = proc;
1223
+ rb_ensure(Queue_singleton_open_body, (VALUE)&arg, Queue_singleton_open_ensure, queue);
1224
+ }
1225
+ else
1226
+ {
1227
+ return Qfalse;
1228
+ }
1229
+ }
1230
+ return queue;
1231
+ }
1232
+
1233
+ /*
1234
+ * For each message found on the queue, the supplied block is executed
1235
+ *
1236
+ * Note:
1237
+ * * If no messages are found on the queue during the supplied wait interval,
1238
+ * then the supplied block will not be called at all
1239
+ * * If :mode=>:browse is supplied when opening the queue then Queue#each will automatically
1240
+ * set MQGMO_BROWSE_FIRST and MQGMO_BROWSE_NEXT as required
1241
+ *
1242
+ * Returns:
1243
+ * * true: If at least one message was succesfully processed
1244
+ * * false: If no messages were retrieved from the queue
1245
+ *
1246
+ * Example:
1247
+ * require 'wmq/wmq'
1248
+ *
1249
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
1250
+ * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:input) do |queue|
1251
+ * queue.each do |message|
1252
+ * puts "Data Received: #{message.data}"
1253
+ * end
1254
+ * end
1255
+ * puts 'Completed.'
1256
+ * end
1257
+ */
1258
+ VALUE Queue_each(int argc, VALUE *argv, VALUE self)
1259
+ {
1260
+ VALUE message = Qnil;
1261
+ VALUE match = Qnil;
1262
+ VALUE options = Qnil;
1263
+ VALUE result = Qfalse;
1264
+ VALUE proc, hash;
1265
+ MQLONG browse = 0;
1266
+
1267
+ PQUEUE pq;
1268
+ Data_Get_Struct(self, QUEUE, pq);
1269
+
1270
+ /* Extract parameters and code block (Proc) */
1271
+ rb_scan_args(argc, argv, "01&", &hash, &proc);
1272
+
1273
+ if(NIL_P(hash))
1274
+ {
1275
+ hash = rb_hash_new();
1276
+ }
1277
+ else
1278
+ {
1279
+ message = rb_hash_aref(hash, ID2SYM(ID_message));
1280
+ match = rb_hash_aref(hash, ID2SYM(ID_match));
1281
+ options = rb_hash_aref(hash, ID2SYM(ID_options));
1282
+ }
1283
+
1284
+ if (NIL_P(message))
1285
+ {
1286
+ message = rb_funcall(wmq_message, ID_new, 0);
1287
+ rb_hash_aset(hash, ID2SYM(ID_message), message);
1288
+ }
1289
+
1290
+ if (NIL_P(match))
1291
+ {
1292
+ rb_hash_aset(hash, ID2SYM(ID_match), LONG2NUM(MQMO_NONE));
1293
+ }
1294
+
1295
+ /* If queue is open for browse, set Borwse first indicator */
1296
+ if(pq->open_options & MQOO_BROWSE)
1297
+ {
1298
+ MQLONG get_options;
1299
+ if(NIL_P(options))
1300
+ {
1301
+ get_options = MQGMO_BROWSE_FIRST;
1302
+ }
1303
+ else
1304
+ {
1305
+ get_options = NUM2LONG(options) | MQGMO_BROWSE_FIRST;
1306
+ }
1307
+ rb_hash_aset(hash, ID2SYM(ID_options), LONG2NUM(get_options));
1308
+
1309
+ if(pq->trace_level>1) printf("WMQ::Queue#each MQGMO_BROWSE_FIRST set, get options:%ld\n", get_options);
1310
+ browse = 1;
1311
+ }
1312
+
1313
+ while(Queue_get(self, hash))
1314
+ {
1315
+ result = Qtrue;
1316
+
1317
+ /* Call code block passing in message */
1318
+ rb_funcall( proc, ID_call, 1, message );
1319
+
1320
+ if(browse)
1321
+ {
1322
+ MQLONG get_options;
1323
+ if(NIL_P(options))
1324
+ {
1325
+ get_options = MQGMO_BROWSE_NEXT;
1326
+ }
1327
+ else
1328
+ {
1329
+ get_options = (NUM2LONG(options) - MQGMO_BROWSE_FIRST) | MQGMO_BROWSE_NEXT;
1330
+ }
1331
+ rb_hash_aset(hash, ID2SYM(ID_options), LONG2NUM(get_options));
1332
+
1333
+ if(pq->trace_level>1) printf("WMQ::Queue#each MQGMO_BROWSE_NEXT set, get options:%ld\n", get_options);
1334
+ }
1335
+ }
1336
+
1337
+ return result;
1338
+ }
1339
+
1340
+ /*
1341
+ * Return the completion code for the last MQ operation on this queue instance
1342
+ *
1343
+ * Returns => FixNum
1344
+ * * WMQ::MQCC_OK 0
1345
+ * * WMQ::MQCC_WARNING 1
1346
+ * * WMQ::MQCC_FAILED 2
1347
+ * * WMQ::MQCC_UNKNOWN -1
1348
+ *
1349
+ */
1350
+ VALUE Queue_comp_code(VALUE self)
1351
+ {
1352
+ PQUEUE pq;
1353
+ Data_Get_Struct(self, QUEUE, pq);
1354
+ return LONG2NUM(pq->comp_code);
1355
+ }
1356
+
1357
+ /*
1358
+ * Return the reason code for the last MQ operation on this queue instance
1359
+ *
1360
+ * Returns => FixNum
1361
+ * * For a complete list of reason codes, please see WMQ Constants or
1362
+ * the WebSphere MQ documentation for Reason Codes
1363
+ *
1364
+ * Note
1365
+ * * The list of Reason Codes varies depending on the version of WebSphere MQ
1366
+ * and the operating system on which Ruby WMQ was compiled
1367
+ */
1368
+ VALUE Queue_reason_code(VALUE self)
1369
+ {
1370
+ PQUEUE pq;
1371
+ Data_Get_Struct(self, QUEUE, pq);
1372
+ return LONG2NUM(pq->reason_code);
1373
+ }
1374
+
1375
+ /*
1376
+ * Returns a textual representation of the reason_code for the last MQ operation on this queue instance
1377
+ *
1378
+ * Returns => String
1379
+ * * For a complete list of reasons, please see WMQ Constants or
1380
+ * the WebSphere MQ documentation for Reason Codes
1381
+ *
1382
+ * Note
1383
+ * * The list of Reason Codes varies depending on the version of WebSphere MQ
1384
+ * and the operating system on which Ruby WMQ was compiled
1385
+ */
1386
+ VALUE Queue_reason(VALUE self)
1387
+ {
1388
+ PQUEUE pq;
1389
+ Data_Get_Struct(self, QUEUE, pq);
1390
+ return rb_str_new2(wmq_reason(pq->reason_code));
1391
+ }
1392
+
1393
+ /*
1394
+ * Returns whether this queue is currently open
1395
+ *
1396
+ * Returns:
1397
+ * * true : The queue is open
1398
+ * * false: The queue is _not_ open
1399
+ */
1400
+ VALUE Queue_open_q(VALUE self)
1401
+ {
1402
+ PQUEUE pq;
1403
+ Data_Get_Struct(self, QUEUE, pq);
1404
+ if (pq->hobj)
1405
+ {
1406
+ return Qtrue;
1407
+ }
1408
+ return Qfalse;
1409
+ }
1410
+