rubywmq 1.0.0 → 1.1.1

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