ferocia-rubywmq 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data/.document +8 -0
  2. data/LICENSE +13 -0
  3. data/Manifest.txt +20 -0
  4. data/README +73 -0
  5. data/examples/each_a.rb +32 -0
  6. data/examples/each_b.rb +41 -0
  7. data/examples/each_header.rb +38 -0
  8. data/examples/files_to_q.cfg +24 -0
  9. data/examples/files_to_q.rb +47 -0
  10. data/examples/get_a.rb +35 -0
  11. data/examples/get_client.rb +51 -0
  12. data/examples/put1_a.rb +25 -0
  13. data/examples/put1_b.rb +33 -0
  14. data/examples/put1_c.rb +32 -0
  15. data/examples/put_a.rb +35 -0
  16. data/examples/put_b.rb +43 -0
  17. data/examples/put_dlh.rb +41 -0
  18. data/examples/put_dynamic_q.rb +38 -0
  19. data/examples/put_group_a.rb +51 -0
  20. data/examples/put_group_b.rb +53 -0
  21. data/examples/put_rfh.rb +67 -0
  22. data/examples/put_rfh2_a.rb +43 -0
  23. data/examples/put_rfh2_b.rb +43 -0
  24. data/examples/put_xmit_q.rb +33 -0
  25. data/examples/q_to_files.cfg +17 -0
  26. data/examples/q_to_files.rb +48 -0
  27. data/examples/request.rb +60 -0
  28. data/examples/server.rb +97 -0
  29. data/ext/build.bat +3 -0
  30. data/ext/build.sh +6 -0
  31. data/ext/decode_rfh.c +348 -0
  32. data/ext/decode_rfh.h +45 -0
  33. data/ext/extconf.rb +44 -0
  34. data/ext/extconf_client.rb +40 -0
  35. data/ext/generate/generate_const.rb +167 -0
  36. data/ext/generate/generate_reason.rb +246 -0
  37. data/ext/generate/generate_structs.rb +97 -0
  38. data/ext/generate/wmq_structs.erb +371 -0
  39. data/ext/lib/wmq_temp.rb +197 -0
  40. data/ext/wmq.c +93 -0
  41. data/ext/wmq.h +367 -0
  42. data/ext/wmq_message.c +671 -0
  43. data/ext/wmq_mq_load.c +217 -0
  44. data/ext/wmq_queue.c +1411 -0
  45. data/ext/wmq_queue_manager.c +1587 -0
  46. data/lib/wmq.rb +25 -0
  47. data/rubywmq.binary.gemspec +32 -0
  48. data/rubywmq.gemspec +33 -0
  49. data/tests/test.rb +328 -0
  50. metadata +124 -0
data/ext/wmq_queue.c ADDED
@@ -0,0 +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_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
+