rubywmq 1.0.0 → 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,1581 +1,1570 @@
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
- static ID ID_open;
20
- static ID ID_call;
21
- static ID ID_new;
22
- static ID ID_backout;
23
- static ID ID_connect_options;
24
- static ID ID_q_mgr_name;
25
- static ID ID_queue_manager;
26
- static ID ID_exception_on_error;
27
- static ID ID_descriptor;
28
- static ID ID_message;
29
- static ID ID_trace_level;
30
-
31
- /* MQCD ID's */
32
- static ID ID_channel_name;
33
- static ID ID_transport_type;
34
- static ID ID_mode_name;
35
- static ID ID_tp_name;
36
- static ID ID_security_exit;
37
- static ID ID_send_exit;
38
- static ID ID_receive_exit;
39
- static ID ID_max_msg_length;
40
- static ID ID_security_user_data;
41
- static ID ID_send_user_data;
42
- static ID ID_receive_user_data;
43
- static ID ID_user_identifier;
44
- static ID ID_password;
45
- static ID ID_connection_name;
46
- static ID ID_heartbeat_interval;
47
- static ID ID_long_remote_user_id;
48
- static ID ID_remote_security_id;
49
- static ID ID_ssl_cipher_spec;
50
- static ID ID_ssl_peer_name;
51
- static ID ID_keep_alive_interval;
52
- static ID ID_crypto_hardware;
53
-
54
- /* MQSCO ID's */
55
- static ID ID_key_repository;
56
-
57
- /* Admin ID's */
58
- static ID ID_create_queue;
59
- static ID ID_q_name;
60
- static ID ID_command;
61
-
62
- void QueueManager_id_init(void)
63
- {
64
- ID_open = rb_intern("open");
65
- ID_call = rb_intern("call");
66
- ID_new = rb_intern("new");
67
- ID_backout = rb_intern("backout");
68
- ID_q_mgr_name = rb_intern("q_mgr_name");
69
- ID_queue_manager = rb_intern("queue_manager");
70
- ID_exception_on_error = rb_intern("exception_on_error");
71
- ID_connect_options = rb_intern("connect_options");
72
- ID_trace_level = rb_intern("trace_level");
73
- ID_descriptor = rb_intern("descriptor");
74
- ID_message = rb_intern("message");
75
-
76
- /* MQCD ID's */
77
- ID_channel_name = rb_intern("channel_name");
78
- ID_transport_type = rb_intern("transport_type");
79
- ID_mode_name = rb_intern("mode_name");
80
- ID_tp_name = rb_intern("tp_name");
81
- ID_security_exit = rb_intern("security_exit");
82
- ID_send_exit = rb_intern("send_exit");
83
- ID_receive_exit = rb_intern("receive_exit");
84
- ID_max_msg_length = rb_intern("max_msg_length");
85
- ID_security_user_data = rb_intern("security_user_data");
86
- ID_send_user_data = rb_intern("send_user_data");
87
- ID_receive_user_data = rb_intern("receive_user_data");
88
- ID_user_identifier = rb_intern("user_identifier");
89
- ID_password = rb_intern("password");
90
- ID_connection_name = rb_intern("connection_name");
91
- ID_heartbeat_interval = rb_intern("heartbeat_interval");
92
- ID_long_remote_user_id = rb_intern("long_remote_user_id");
93
- ID_remote_security_id = rb_intern("remote_security_id");
94
- ID_ssl_cipher_spec = rb_intern("ssl_cipher_spec");
95
- ID_ssl_peer_name = rb_intern("ssl_peer_name");
96
- ID_keep_alive_interval = rb_intern("keep_alive_interval");
97
-
98
- /* MQSCO ID's */
99
- ID_key_repository = rb_intern("key_repository");
100
- ID_crypto_hardware = rb_intern("crypto_hardware");
101
-
102
- /* Admin ID's */
103
- ID_create_queue = rb_intern("create_queue");
104
- ID_q_name = rb_intern("q_name");
105
- ID_command = rb_intern("command");
106
- }
107
-
108
- /* --------------------------------------------------
109
- * C Structure to store MQ data types and other
110
- * C internal values
111
- * --------------------------------------------------*/
112
- void QUEUE_MANAGER_free(void* p)
113
- {
114
- PQUEUE_MANAGER pqm = (PQUEUE_MANAGER)p;
115
-
116
- if(pqm->trace_level>1) printf("WMQ::QueueManager Freeing QUEUE_MANAGER structure\n");
117
-
118
- if (pqm->hcon && !pqm->already_connected) /* Valid MQ handle means MQDISC was not called */
119
- {
120
- printf("WMQ::QueueManager#free disconnect() was not called for Queue Manager instance!!\n");
121
- printf("WMQ::QueueManager#free Automatically calling back() and disconnect()\n");
122
- pqm->MQBACK(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
123
- pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
124
- }
125
- #ifdef MQCD_VERSION_6
126
- free(pqm->long_remote_user_id_ptr);
127
- #endif
128
- #ifdef MQCD_VERSION_7
129
- free(pqm->ssl_peer_name_ptr);
130
- #endif
131
- #ifdef MQHB_UNUSABLE_HBAG
132
- if (pqm->admin_bag != MQHB_UNUSABLE_HBAG)
133
- {
134
- pqm->mqDeleteBag(&pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
135
- }
136
-
137
- if (pqm->reply_bag != MQHB_UNUSABLE_HBAG)
138
- {
139
- pqm->mqDeleteBag(&pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
140
- }
141
- #endif
142
- Queue_manager_mq_free(pqm);
143
- free(pqm->p_buffer);
144
- free(p);
145
- }
146
-
147
- VALUE QUEUE_MANAGER_alloc(VALUE klass)
148
- {
149
- static MQCNO default_MQCNO = {MQCNO_DEFAULT}; /* MQCONNX Connection Options */
150
- #ifdef MQCNO_VERSION_2
151
- static MQCD default_MQCD = {MQCD_CLIENT_CONN_DEFAULT}; /* Client Connection */
152
- #endif
153
- #ifdef MQCNO_VERSION_4
154
- static MQSCO default_MQSCO = {MQSCO_DEFAULT};
155
- #endif
156
-
157
- PQUEUE_MANAGER pqm = ALLOC(QUEUE_MANAGER);
158
-
159
- pqm->hcon = 0;
160
- pqm->comp_code = 0;
161
- pqm->reason_code = 0;
162
- pqm->exception_on_error = 1;
163
- pqm->already_connected = 0;
164
- pqm->trace_level = 0;
165
- memcpy(&pqm->connect_options, &default_MQCNO, sizeof(MQCNO));
166
- #ifdef MQCNO_VERSION_2
167
- memcpy(&pqm->client_conn, &default_MQCD, sizeof(MQCD));
168
-
169
- /* Tell MQ to use Client Conn structures, etc. */
170
- pqm->connect_options.Version = MQCNO_CURRENT_VERSION;
171
- pqm->connect_options.ClientConnPtr = &pqm->client_conn;
172
- #endif
173
- #ifdef MQCNO_VERSION_4
174
- memcpy(&pqm->ssl_config_opts, &default_MQSCO, sizeof(MQSCO));
175
- #endif
176
- #ifdef MQCD_VERSION_6
177
- pqm->long_remote_user_id_ptr = 0;
178
- #endif
179
- #ifdef MQCD_VERSION_7
180
- pqm->ssl_peer_name_ptr = 0;
181
- #endif
182
- #ifdef MQHB_UNUSABLE_HBAG
183
- pqm->admin_bag = MQHB_UNUSABLE_HBAG;
184
- pqm->reply_bag = MQHB_UNUSABLE_HBAG;
185
- #endif
186
- pqm->buffer_size = 0;
187
- pqm->p_buffer = 0;
188
-
189
- pqm->is_client_conn = 0;
190
- pqm->mq_lib_handle = 0;
191
-
192
- return Data_Wrap_Struct(klass, 0, QUEUE_MANAGER_free, pqm);
193
- }
194
-
195
- /*
196
- * call-seq:
197
- * new(...)
198
- *
199
- * Parameters:
200
- * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
201
- * * See QueueManager.new for details on all the parameters
202
- *
203
- * Note:
204
- * * It is not recommended to use this method, rather use QueueManager.connect, since
205
- * it will automatically disconnect from the queue manager. It also deals with backing out
206
- * the current unit of work in the event of an unhandled exception. E.g. Syntax Error
207
- * * RuntimeError and ArgumentError exceptions are always thrown regardless of the
208
- * value of :exception_on_error
209
- *
210
- * Todo:
211
- * * Support multiple send and receive exits
212
- */
213
- VALUE QueueManager_initialize(VALUE self, VALUE hash)
214
- {
215
- VALUE val;
216
- VALUE str;
217
- size_t size;
218
- size_t length;
219
- PQUEUE_MANAGER pqm;
220
-
221
- Check_Type(hash, T_HASH);
222
-
223
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
224
-
225
- WMQ_HASH2MQLONG(hash,trace_level, pqm->trace_level)
226
-
227
- /* @name = options[:q_mgr_name] || '' # QMGR Name optional with Client Connection */
228
- val = rb_hash_aref(hash, ID2SYM(ID_q_mgr_name));
229
- if (NIL_P(val))
230
- {
231
- rb_iv_set(self, "@name", rb_str_new2(""));
232
- if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:[Not specified, use Default QMGR]\n");
233
- }
234
- else
235
- {
236
- rb_iv_set(self, "@name", val);
237
- if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:%s\n", RSTRING(val)->ptr);
238
- }
239
-
240
- WMQ_HASH2BOOL(hash,exception_on_error, pqm->exception_on_error)
241
-
242
- /*
243
- * All Client connection parameters are ignored if connection_name is missing
244
- */
245
- #ifdef MQCNO_VERSION_2
246
- if(!NIL_P(rb_hash_aref(hash, ID2SYM(ID_connection_name))))
247
- {
248
- PMQCD pmqcd = &pqm->client_conn; /* Process MQCD */
249
- pqm->is_client_conn = 1; /* Set to Client connection */
250
-
251
- WMQ_HASH2MQCHARS(hash,connection_name, pmqcd->ConnectionName)
252
- WMQ_HASH2MQLONG (hash,transport_type, pmqcd->TransportType)
253
- WMQ_HASH2MQCHARS(hash,mode_name, pmqcd->ModeName)
254
- WMQ_HASH2MQCHARS(hash,tp_name, pmqcd->TpName)
255
- WMQ_HASH2MQCHARS(hash,security_exit, pmqcd->SecurityExit)
256
- WMQ_HASH2MQCHARS(hash,send_exit, pmqcd->SendExit)
257
- WMQ_HASH2MQCHARS(hash,receive_exit, pmqcd->ReceiveExit)
258
- WMQ_HASH2MQLONG (hash,max_msg_length, pmqcd->MaxMsgLength)
259
- WMQ_HASH2MQCHARS(hash,security_user_data, pmqcd->SecurityUserData)
260
- WMQ_HASH2MQCHARS(hash,send_user_data, pmqcd->SendUserData)
261
- WMQ_HASH2MQCHARS(hash,receive_user_data, pmqcd->ReceiveUserData)
262
- WMQ_HASH2MQCHARS(hash,user_identifier, pmqcd->UserIdentifier)
263
- WMQ_HASH2MQCHARS(hash,password, pmqcd->Password)
264
-
265
- /* Default channel name to system default */
266
- val = rb_hash_aref(hash, ID2SYM(ID_channel_name));
267
- if (NIL_P(val))
268
- {
269
- strncpy(pmqcd->ChannelName, "SYSTEM.DEF.SVRCONN", sizeof(pmqcd->ChannelName));
270
- }
271
- else
272
- {
273
- WMQ_HASH2MQCHARS(hash,channel_name, pmqcd->ChannelName)
274
- }
275
-
276
- #ifdef MQCD_VERSION_4
277
- WMQ_HASH2MQLONG(hash,heartbeat_interval, pmqcd->HeartbeatInterval)
278
- /* TODO:
279
- WMQ_HASH2MQLONG(hash,exit_name_length, pmqcd->ExitNameLength)
280
- WMQ_HASH2MQLONG(hash,exit_data_length, pmqcd->ExitDataLength)
281
- WMQ_HASH2MQLONG(hash,send_exits_defined, pmqcd->SendExitsDefined)
282
- WMQ_HASH2MQLONG(hash,receive_exits_defined, pmqcd->ReceiveExitsDefined)
283
- TO_PTR (send_exit_ptr, pmqcd->SendExitPtr)
284
- TO_PTR (send_user_data_ptr, pmqcd->SendUserDataPtr)
285
- TO_PTR (receive_exit_ptr, pmqcd->ReceiveExitPtr)
286
- TO_PTR (receive_user_data_ptr, pmqcd->ReceiveUserDataPtr)
287
- */
288
- #endif
289
- #ifdef MQCD_VERSION_6
290
- val = rb_hash_aref(hash, ID2SYM(ID_long_remote_user_id));
291
- if (!NIL_P(val))
292
- {
293
- str = StringValue(val);
294
- length = RSTRING(str)->len;
295
-
296
- if (length > 0)
297
- {
298
- MQPTR pBuffer;
299
- if(pqm->trace_level > 1)
300
- printf("WMQ::QueueManager#initialize() Setting long_remote_user_id:%s\n",
301
- RSTRING(str)->ptr);
302
-
303
- /* Include null at end of string */
304
- pBuffer = ALLOC_N(char, length+1);
305
- memcpy(pBuffer, RSTRING(str)->ptr, length+1);
306
-
307
- pmqcd->LongRemoteUserIdLength = length;
308
- pmqcd->LongRemoteUserIdPtr = pBuffer;
309
- pqm->long_remote_user_id_ptr = pBuffer;
310
- }
311
- }
312
- WMQ_HASH2MQBYTES(hash,remote_security_id, pmqcd->RemoteSecurityId)
313
- WMQ_HASH2MQCHARS(hash,ssl_cipher_spec, pmqcd->SSLCipherSpec)
314
- #endif
315
- #ifdef MQCD_VERSION_7
316
- val = rb_hash_aref(hash, ID2SYM(ID_ssl_peer_name));
317
- if (!NIL_P(val))
318
- {
319
- str = StringValue(val);
320
- length = RSTRING(str)->len;
321
-
322
- if (length > 0)
323
- {
324
- MQPTR pBuffer;
325
- if(pqm->trace_level > 1)
326
- printf("WMQ::QueueManager#initialize() Setting ssl_peer_name:%s\n",
327
- RSTRING(str)->ptr);
328
-
329
- /* Include null at end of string */
330
- pBuffer = ALLOC_N(char, length+1);
331
- memcpy(pBuffer, RSTRING(str)->ptr, length+1);
332
-
333
- pmqcd->SSLPeerNameLength = length;
334
- pmqcd->SSLPeerNamePtr = pBuffer;
335
- pqm->ssl_peer_name_ptr = pBuffer;
336
- }
337
- }
338
- WMQ_HASH2MQLONG(hash,keep_alive_interval, pmqcd->KeepAliveInterval)
339
-
340
- /* Only set if SSL options are supplied, otherwise
341
- * environment variables are ignored: MQSSLKEYR and MQSSLCRYP
342
- * Any SSL info in the client channel definition tables is also ignored
343
- */
344
- if (!NIL_P(rb_hash_aref(hash, ID2SYM(ID_key_repository))) ||
345
- !NIL_P(rb_hash_aref(hash, ID2SYM(ID_crypto_hardware))))
346
- {
347
- /* Process MQSCO */
348
- WMQ_HASH2MQCHARS(hash,key_repository, pqm->ssl_config_opts.KeyRepository)
349
- WMQ_HASH2MQCHARS(hash,crypto_hardware, pqm->ssl_config_opts.CryptoHardware)
350
-
351
- pqm->connect_options.SSLConfigPtr = &pqm->ssl_config_opts;
352
- }
353
- #endif
354
-
355
- }
356
- else
357
- {
358
- pqm->is_client_conn = 0; /* Set to Server connection */
359
- }
360
- #endif
361
-
362
- #ifdef MQCNO_VERSION_4
363
- /* Process MQCNO */
364
- WMQ_HASH2MQLONG(hash,connect_options, pqm->connect_options.Options)
365
- #endif
366
-
367
- /* --------------------------------------------------
368
- * TODO: MQAIR Structure - LDAP Security
369
- * --------------------------------------------------*/
370
-
371
- return Qnil;
372
- }
373
-
374
- /*
375
- * Before working with any queues, it is necessary to connect
376
- * to the queue manager.
377
- *
378
- * Returns:
379
- * * true : On Success
380
- * * false: On Failure
381
- *
382
- * comp_code and reason_code are also updated.
383
- * reason will return a text description of the reason_code
384
- *
385
- * Throws:
386
- * * WMQ::WMQException if comp_code != MQCC_OK
387
- * * Except if :exception_on_error => false was supplied as a parameter
388
- * to QueueManager.new
389
- */
390
- VALUE QueueManager_connect(VALUE self)
391
- {
392
- VALUE name;
393
-
394
- PQUEUE_MANAGER pqm;
395
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
396
- pqm->already_connected = 0;
397
-
398
- Queue_manager_mq_load(pqm); /* Load MQ Library */
399
-
400
- name = rb_iv_get(self,"@name");
401
- name = StringValue(name);
402
-
403
- if(pqm->trace_level)
404
- printf("WMQ::QueueManager#connect() Connect to Queue Manager:%s\n", RSTRING(name)->ptr);
405
-
406
- if (pqm->hcon) /* Disconnect from qmgr if already connected, ignore errors */
407
- {
408
- if(pqm->trace_level)
409
- printf("WMQ::QueueManager#connect() Already connected to Queue Manager:%s, Disconnecting first!\n", RSTRING(name)->ptr);
410
-
411
- pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
412
- }
413
-
414
- pqm->MQCONNX(
415
- RSTRING(name)->ptr, /* queue manager */
416
- &pqm->connect_options, /* Connection Options */
417
- &pqm->hcon, /* connection handle */
418
- &pqm->comp_code, /* completion code */
419
- &pqm->reason_code); /* connect reason code */
420
-
421
- if(pqm->trace_level)
422
- printf("WMQ::QueueManager#connect() MQCONNX completed with reason:%s, Handle:%ld\n",
423
- wmq_reason(pqm->reason_code),
424
- (long)pqm->hcon);
425
-
426
- if (pqm->comp_code == MQCC_FAILED)
427
- {
428
- pqm->hcon = 0;
429
-
430
- if (pqm->exception_on_error)
431
- {
432
- rb_raise(wmq_exception,
433
- "WMQ::QueueManager#connect(). Error connecting to Queue Manager:%s, reason:%s",
434
- RSTRING(name)->ptr,
435
- wmq_reason(pqm->reason_code));
436
- }
437
-
438
- return Qfalse;
439
- }
440
-
441
- if (pqm->reason_code == MQRC_ALREADY_CONNECTED)
442
- {
443
- if(pqm->trace_level) printf("WMQ::QueueManager#connect() Already connected\n");
444
- pqm->already_connected = 1;
445
- }
446
-
447
- return Qtrue;
448
- }
449
-
450
- /*
451
- * Disconnect from this QueueManager instance
452
- *
453
- * Returns:
454
- * * true : On Success
455
- * * false: On Failure
456
- *
457
- * comp_code and reason_code are also updated.
458
- * reason will return a text description of the reason_code
459
- *
460
- * Throws:
461
- * * WMQ::WMQException if comp_code != MQCC_OK
462
- * * Except if :exception_on_error => false was supplied as a parameter
463
- * to QueueManager.new
464
- */
465
- VALUE QueueManager_disconnect(VALUE self)
466
- {
467
- PQUEUE_MANAGER pqm;
468
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
469
-
470
- if(pqm->trace_level) printf ("WMQ::QueueManager#disconnect() Queue Manager Handle:%ld\n", (long)pqm->hcon);
471
-
472
- if (!pqm->already_connected)
473
- {
474
- pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
475
-
476
- if(pqm->trace_level) printf("WMQ::QueueManager#disconnect() MQDISC completed with reason:%s\n", wmq_reason(pqm->reason_code));
477
-
478
- if (pqm->comp_code != MQCC_OK)
479
- {
480
- if (pqm->exception_on_error)
481
- {
482
- VALUE name = rb_iv_get(self,"@name");
483
- name = StringValue(name);
484
-
485
- rb_raise(wmq_exception,
486
- "WMQ::QueueManager#disconnect(). Error disconnecting from Queue Manager:%s, reason:%s",
487
- RSTRING(name)->ptr,
488
- wmq_reason(pqm->reason_code));
489
- }
490
-
491
- return Qfalse;
492
- }
493
- }
494
- else
495
- {
496
- pqm->comp_code = 0;
497
- pqm->reason_code = 0;
498
-
499
- if(pqm->trace_level) printf ("WMQ::QueueManager#disconnect() Not calling MQDISC, since already connected on connect\n");
500
- }
501
-
502
- pqm->hcon = 0;
503
-
504
- return Qtrue;
505
- }
506
-
507
- /*
508
- * Commit the current unit of work for this QueueManager instance
509
- *
510
- * Note:
511
- * * commit will have no effect if all put and get operations were performed
512
- * without specifying :sync => true
513
- *
514
- * Returns:
515
- * * true : On Success
516
- * * false: On Failure
517
- *
518
- * comp_code and reason_code are also updated.
519
- * reason will return a text description of the reason_code
520
- *
521
- * Throws:
522
- * * WMQ::WMQException if comp_code != MQCC_OK
523
- * * Except if :exception_on_error => false was supplied as a parameter
524
- * to QueueManager.new
525
- */
526
- VALUE QueueManager_commit(VALUE self)
527
- {
528
- PQUEUE_MANAGER pqm;
529
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
530
-
531
- if(pqm->trace_level) printf ("WMQ::QueueManager#commit() Queue Manager Handle:%ld\n", (long)pqm->hcon);
532
-
533
- pqm->MQCMIT(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
534
-
535
- if(pqm->trace_level) printf("WMQ::QueueManager#commit() MQCMIT completed with reason:%s\n", wmq_reason(pqm->reason_code));
536
-
537
- if (pqm->comp_code != MQCC_OK)
538
- {
539
- if (pqm->exception_on_error)
540
- {
541
- VALUE name = rb_iv_get(self,"@name");
542
- name = StringValue(name);
543
-
544
- rb_raise(wmq_exception,
545
- "WMQ::QueueManager#commit(). Error commiting changes to Queue Manager:%s, reason:%s",
546
- RSTRING(name)->ptr,
547
- wmq_reason(pqm->reason_code));
548
- }
549
- return Qfalse;
550
- }
551
-
552
- return Qtrue;
553
- }
554
-
555
- /*
556
- * Backout the current unit of work for this QueueManager instance
557
- *
558
- * Since the last commit or rollback any messages put to a queue
559
- * under synchpoint will be removed and any messages retrieved
560
- * under synchpoint from any queues will be returned
561
- *
562
- * Note:
563
- * * backout will have no effect if all put and get operations were performed
564
- * without specifying :sync => true
565
- *
566
- * Returns:
567
- * * true : On Success
568
- * * false: On Failure
569
- *
570
- * comp_code and reason_code are also updated.
571
- * reason will return a text description of the reason_code
572
- *
573
- * Throws:
574
- * * WMQ::WMQException if comp_code != MQCC_OK
575
- * * Except if :exception_on_error => false was supplied as a parameter
576
- * to QueueManager.new
577
- */
578
- VALUE QueueManager_backout(VALUE self)
579
- {
580
- PQUEUE_MANAGER pqm;
581
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
582
-
583
- if(pqm->trace_level) printf ("WMQ::QueueManager#backout() Queue Manager Handle:%ld\n", (long)pqm->hcon);
584
-
585
- pqm->MQBACK(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
586
-
587
- if(pqm->trace_level) printf("WMQ::QueueManager#backout() MQBACK completed with reason:%s\n", wmq_reason(pqm->reason_code));
588
-
589
- if (pqm->comp_code != MQCC_OK)
590
- {
591
- if (pqm->exception_on_error)
592
- {
593
- VALUE name = rb_iv_get(self,"@name");
594
- name = StringValue(name);
595
-
596
- rb_raise(wmq_exception,
597
- "WMQ::QueueManager#backout(). Error backing out changes to Queue Manager:%s, reason:%s",
598
- RSTRING(name)->ptr,
599
- wmq_reason(pqm->reason_code));
600
- }
601
- return Qfalse;
602
- }
603
-
604
- return Qtrue;
605
- }
606
-
607
- /*
608
- * Advanced WebSphere MQ Use:
609
- *
610
- * Begin a unit of work between this QueueManager instance and another
611
- * resource such as a Database
612
- *
613
- * Starts a new unit of work under which put and get can be called with
614
- * with the parameter :sync => true
615
- *
616
- * Returns:
617
- * * true : On Success
618
- * * false: On Failure
619
- *
620
- * comp_code and reason_code are also updated.
621
- * reason will return a text description of the reason_code
622
- *
623
- * Throws:
624
- * * WMQ::WMQException if comp_code != MQCC_OK
625
- * * Except if :exception_on_error => false was supplied as a parameter
626
- * to QueueManager.new
627
- */
628
- VALUE QueueManager_begin(VALUE self)
629
- {
630
- PQUEUE_MANAGER pqm;
631
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
632
-
633
- if(pqm->trace_level) printf ("WMQ::QueueManager#begin() Queue Manager Handle:%ld\n", (long)pqm->hcon);
634
-
635
- pqm->MQBEGIN(pqm->hcon, 0, &pqm->comp_code, &pqm->reason_code);
636
-
637
- if(pqm->trace_level) printf("WMQ::QueueManager#begin() MQBEGIN completed with reason:%s\n", wmq_reason(pqm->reason_code));
638
-
639
- if (pqm->comp_code != MQCC_OK)
640
- {
641
- if (pqm->exception_on_error)
642
- {
643
- VALUE name = rb_iv_get(self,"@name");
644
- name = StringValue(name);
645
-
646
- rb_raise(wmq_exception,
647
- "WMQ::QueueManager#begin(). Error starting unit of work on Queue Manager:%s, reason:%s",
648
- RSTRING(name)->ptr,
649
- wmq_reason(pqm->reason_code));
650
- }
651
- return Qfalse;
652
- }
653
-
654
- return Qtrue;
655
- }
656
-
657
- /*
658
- * call-seq:
659
- * put(parameters)
660
- *
661
- * Put a message to the queue without having to first open the queue
662
- * Recommended for reply queues that change frequently
663
- *
664
- * * parameters: a Hash consisting of one or more of the following parameters
665
- *
666
- * Summary of parameters and their WebSphere MQ equivalents
667
- * queue.get( # WebSphere MQ Equivalents:
668
- * :q_name => 'Queue Name', # MQOD.ObjectName
669
- * :q_name => { queue_manager=>'QMGR_name', # MQOD.ObjectQMgrName
670
- * q_name =>'q_name'}
671
- * :message => my_message, # n/a : Instance of Message
672
- * :data => "Hello World", # n/a : Data to send
673
- * :sync => false, # MQGMO_SYNCPOINT
674
- * :new_id => true, # MQPMO_NEW_MSG_ID & MQPMO_NEW_CORREL_ID
675
- * :new_msg_id => true, # MQPMO_NEW_MSG_ID
676
- * :new_correl_id => true, # MQPMO_NEW_CORREL_ID
677
- * :fail_if_quiescing => true, # MQOO_FAIL_IF_QUIESCING
678
- * :options => WMQ::MQPMO_FAIL_IF_QUIESCING # MQPMO_*
679
- * )
680
- *
681
- * Mandatory Parameters
682
- * * :q_name => String
683
- * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
684
- * * To open remote queues for which a local remote queue definition is not available
685
- * pass a Hash as q_name (see q_name => Hash)
686
- * OR
687
- * * :q_name => Hash
688
- * * q_name => String
689
- * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
690
- * * :q_mgr_name => String
691
- * * Name of the remote WebSphere MQ queue manager to send the message to.
692
- * * This allows a message to be written to a queue on a remote queue manager
693
- * where a remote queue definition is not defined locally
694
- * * Commonly used to reply to messages from remote systems
695
- * * If q_mgr_name is the same as the local queue manager name then the message
696
- * is merely written to the local queue.
697
- * * Note: q_mgr_name should only be supplied when putting messages to the queue.
698
- * It is not possible to get messages from a queue on a queue manager other
699
- * than the currently connected queue manager
700
- *
701
- * * Either :message or :data must be supplied
702
- * * If both are supplied, then :data will be written to the queue. The data in :message
703
- * will be ignored
704
- *
705
- * Optional Parameters
706
- * * :data => String
707
- * * Data to be written to the queue. Can be binary or text data
708
- *
709
- * * :message => Message
710
- * * An instance of the WMQ::Message
711
- * * The Message descriptor, headers and data is retrieved from :message
712
- * * message.data is ignored if :data is supplied
713
- *
714
- * * :sync => true or false
715
- * * Determines whether the get is performed under synchpoint.
716
- * I.e. Under the current unit of work
717
- * Default: false
718
- *
719
- * * :new_id => true or false
720
- * * Generate a new message id and correlation id for this
721
- * message. :new_msg_id and :new_correl_id will be ignored
722
- * if this parameter is true
723
- * Default: false
724
- *
725
- * * :new_msg_id => true or false
726
- * * Generate a new message id for this message
727
- * * Note: A blank message id will result in a new message id anyway.
728
- * However, for subsequent puts using the same message descriptor, the same
729
- * message id will be used.
730
- * Default: false
731
- *
732
- * * :new_correl_id => true or false
733
- * * Generate a new correlation id for this message
734
- * Default: false
735
- *
736
- * * :fail_if_quiescing => true or false
737
- * * Determines whether the WMQ::Queue#put call will fail if the queue manager is
738
- * in the process of being quiesced.
739
- * * Note: This interface differs from other WebSphere MQ interfaces,
740
- * they do not default to true.
741
- * Default: true
742
- * Equivalent to: MQGMO_FAIL_IF_QUIESCING
743
- *
744
- * * Note: As part of the application design, carefull consideration
745
- * should be given as to when to allow a transaction or
746
- * unit of work to complete or fail under this condition.
747
- * As such it is important to include this option where
748
- * appropriate so that MQ Administrators can shutdown the
749
- * queue managers without having to resort to the 'immediate'
750
- * shutdown option.
751
- *
752
- * * :options => Fixnum (Advanced MQ Use only)
753
- * * Numeric field containing any of the MQ Put message options or'd together
754
- * * E.g. :options => WMQ::MQPMO_PASS_IDENTITY_CONTEXT | WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
755
- * * Note: If :options is supplied, it is applied first, then the above parameters are
756
- * applied afterwards.
757
- * * One or more of the following values:
758
- * WMQ::MQPMO_NO_SYNCPOINT
759
- * WMQ::MQPMO_LOGICAL_ORDER
760
- * WMQ::MQPMO_NO_CONTEXT
761
- * WMQ::MQPMO_DEFAULT_CONTEXT
762
- * WMQ::MQPMO_PASS_IDENTITY_CONTEXT
763
- * WMQ::MQPMO_PASS_ALL_CONTEXT
764
- * WMQ::MQPMO_SET_IDENTITY_CONTEXT
765
- * WMQ::MQPMO_SET_ALL_CONTEXT
766
- * WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
767
- * WMQ::MQPMO_RESOLVE_LOCAL_Q
768
- * WMQ::MQPMO_NONE
769
- * * Please see the WebSphere MQ documentation for more details on the above options
770
- * Default: WMQ::MQPMO_NONE
771
- *
772
- * Returns:
773
- * * true : On Success
774
- * * false: On Failure
775
- *
776
- * comp_code and reason_code are also updated.
777
- * reason will return a text description of the reason_code
778
- *
779
- * Throws:
780
- * * WMQ::WMQException if comp_code == MQCC_FAILED
781
- * * Except if :exception_on_error => false was supplied as a parameter
782
- * to QueueManager.new
783
- */
784
- VALUE QueueManager_put(VALUE self, VALUE hash)
785
- {
786
- MQLONG BufferLength; /* Length of the message in Buffer */
787
- PMQVOID pBuffer; /* Message data */
788
- MQMD md = {MQMD_DEFAULT}; /* Message Descriptor */
789
- MQPMO pmo = {MQPMO_DEFAULT}; /* put message options */
790
- MQOD od = {MQOD_DEFAULT}; /* Object Descriptor */
791
- VALUE q_name;
792
- VALUE str;
793
- size_t size;
794
- size_t length;
795
- VALUE val;
796
-
797
- PQUEUE_MANAGER pqm;
798
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
799
-
800
- Check_Type(hash, T_HASH);
801
-
802
- q_name = rb_hash_aref(hash, ID2SYM(ID_q_name));
803
-
804
- if (NIL_P(q_name))
805
- {
806
- rb_raise(rb_eArgError,
807
- "Mandatory parameter :q_name is missing from WMQ::QueueManager::put1()");
808
- }
809
-
810
- /* --------------------------------------------------
811
- * If :q_name is a hash, extract :q_name and :q_mgr_name
812
- * --------------------------------------------------*/
813
- if(TYPE(q_name) == T_HASH)
814
- {
815
- WMQ_HASH2MQCHARS(q_name, q_mgr_name, od.ObjectQMgrName)
816
-
817
- q_name = rb_hash_aref(val, ID2SYM(ID_q_name));
818
- if (NIL_P(q_name))
819
- {
820
- rb_raise(rb_eArgError,
821
- "Mandatory parameter :q_name missing from :q_name hash passed to WMQ::QueueManager#put");
822
- }
823
- }
824
-
825
- WMQ_STR2MQCHARS(q_name,od.ObjectName)
826
-
827
- Queue_extract_put_message_options(hash, &pmo);
828
- Message_build(&pqm->p_buffer, &pqm->buffer_size, pqm->trace_level,
829
- hash, &pBuffer, &BufferLength, &md);
830
-
831
- if(pqm->trace_level) printf("WMQ::QueueManager#put Queue Manager Handle:%ld\n", (long)pqm->hcon);
832
-
833
- pqm->MQPUT1(
834
- pqm->hcon, /* connection handle */
835
- &od, /* object descriptor */
836
- &md, /* message descriptor */
837
- &pmo, /* put message options */
838
- BufferLength, /* message length */
839
- pBuffer, /* message buffer */
840
- &pqm->comp_code, /* completion code */
841
- &pqm->reason_code); /* reason code */
842
-
843
- if(pqm->trace_level) printf("WMQ::QueueManager#put MQPUT1 ended with reason:%s\n", wmq_reason(pqm->reason_code));
844
-
845
- if (pqm->reason_code != MQRC_NONE)
846
- {
847
- if (pqm->exception_on_error)
848
- {
849
- VALUE qmgr_name = QueueManager_name(self);
850
-
851
- rb_raise(wmq_exception,
852
- "WMQ::QueueManager.put(). Error writing a message to Queue:%s on Queue Manager:%s reason:%s",
853
- RSTRING(q_name)->ptr,
854
- RSTRING(qmgr_name)->ptr,
855
- wmq_reason(pqm->reason_code));
856
- }
857
- return Qfalse;
858
- }
859
- else
860
- {
861
- VALUE message = rb_hash_aref(hash, ID2SYM(ID_message));
862
- if(!NIL_P(message))
863
- {
864
- VALUE descriptor = rb_funcall(message, ID_descriptor, 0);
865
- Message_from_mqmd(descriptor, &md); /* This could be optimized to output only fields */
866
- }
867
- }
868
-
869
- return Qtrue;
870
- }
871
-
872
- /*
873
- * Return the completion code for the last MQ operation
874
- *
875
- * Returns => FixNum
876
- * * WMQ::MQCC_OK 0
877
- * * WMQ::MQCC_WARNING 1
878
- * * WMQ::MQCC_FAILED 2
879
- * * WMQ::MQCC_UNKNOWN -1
880
- *
881
- */
882
- VALUE QueueManager_comp_code(VALUE self)
883
- {
884
- PQUEUE_MANAGER pqm;
885
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
886
- return LONG2NUM(pqm->comp_code);
887
- }
888
-
889
- /*
890
- * Return the reason code for the last MQ operation
891
- *
892
- * Returns => FixNum
893
- * * For a complete list of reason codes, please see WMQ Constants or
894
- * the WebSphere MQ documentation for Reason Codes
895
- *
896
- * Note
897
- * * The list of Reason Codes varies depending on the version of WebSphere MQ
898
- * and the operating system on which Ruby WMQ was compiled
899
- */
900
- VALUE QueueManager_reason_code(VALUE self)
901
- {
902
- PQUEUE_MANAGER pqm;
903
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
904
- return LONG2NUM(pqm->reason_code);
905
- }
906
-
907
- /*
908
- * Returns a textual representation of the reason_code for the last MQ operation
909
- *
910
- * Returns => String
911
- * * For a complete list of reasons, please see WMQ Constants or
912
- * the WebSphere MQ documentation for Reason Codes
913
- *
914
- * Note
915
- * * The list of Reason Codes varies depending on the version of WebSphere MQ
916
- * and the operating system on which Ruby WMQ was compiled
917
- */
918
- VALUE QueueManager_reason(VALUE self)
919
- {
920
- PQUEUE_MANAGER pqm;
921
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
922
- return rb_str_new2(wmq_reason(pqm->reason_code));
923
- }
924
-
925
- /*
926
- * Returns whether this QueueManager instance is set
927
- * to throw a WMQ::WMQException whenever an MQ operation fails
928
- *
929
- * Returns:
930
- * * true : This QueueManager instance will throw a WMQ::WMQException whenever
931
- * an MQ operation fails. I.e. if comp_code != WMQ::OK.
932
- * * false: WMQ::WMQException will not be thrown
933
- *
934
- * Note:
935
- * * RuntimeError and ArgumentError exceptions are always thrown regardless of the
936
- * value of exception_on_error
937
- */
938
- VALUE QueueManager_exception_on_error(VALUE self)
939
- {
940
- PQUEUE_MANAGER pqm;
941
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
942
- if (pqm->exception_on_error)
943
- {
944
- return Qtrue;
945
- }
946
-
947
- return Qfalse;
948
- }
949
-
950
- /*
951
- * Returns whether this QueueManager instance is currently
952
- * connected to a WebSphere MQ queue manager
953
- *
954
- * Returns:
955
- * * true : This QueueManager instance is connected to a local or remote queue manager
956
- * * false: This QueueManager instance is not currently connected to a local or
957
- * remote queue manager
958
- */
959
- VALUE QueueManager_connected_q(VALUE self)
960
- {
961
- PQUEUE_MANAGER pqm;
962
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
963
- if (pqm->hcon)
964
- {
965
- return Qtrue;
966
- }
967
- return Qfalse;
968
- }
969
-
970
- /*
971
- * Returns the QueueManager name => String
972
- */
973
- VALUE QueueManager_name(VALUE self)
974
- {
975
- return rb_iv_get(self,"@name");
976
- }
977
-
978
- static VALUE QueueManager_open_queue_block(VALUE message, VALUE proc)
979
- {
980
- return rb_funcall(proc, ID_call, 1, message);
981
- }
982
-
983
- static VALUE QueueManager_open_queue_each(VALUE parameters)
984
- {
985
- return Queue_singleton_open(1, &parameters, wmq_queue);
986
- }
987
-
988
- /*
989
- * call-seq:
990
- * open_queue(...)
991
- * access_queue(...)
992
- *
993
- * Open the specified queue, then close it once the
994
- * supplied code block has completed
995
- *
996
- * Parameters:
997
- * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
998
- * * See Queue.open for the complete list of parameters, except that :queue_manager is *not* required
999
- * since it is supplied automatically by this method
1000
- *
1001
- * Example:
1002
- * require 'wmq/wmq_client'
1003
- *
1004
- * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
1005
- * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:output) do |queue|
1006
- * queue.put(:data => 'Hello World')
1007
- * end
1008
- * end
1009
- */
1010
- VALUE QueueManager_open_queue(int argc, VALUE *argv, VALUE self)
1011
- {
1012
- VALUE parameters;
1013
- VALUE proc;
1014
-
1015
- /* Extract parameters and code block (Proc) */
1016
- rb_scan_args(argc, argv, "1&", &parameters, &proc);
1017
-
1018
- Check_Type(parameters, T_HASH);
1019
- rb_hash_aset(parameters, ID2SYM(ID_queue_manager), self);
1020
-
1021
- return rb_iterate(QueueManager_open_queue_each, parameters, QueueManager_open_queue_block, proc);
1022
- }
1023
-
1024
- struct QueueManager_singleton_connect_arg {
1025
- VALUE self;
1026
- VALUE proc;
1027
- };
1028
-
1029
- static VALUE QueueManager_singleton_connect_body2(struct QueueManager_singleton_connect_arg* arg)
1030
- {
1031
- return rb_funcall(arg->proc, ID_call, 1, arg->self);
1032
- }
1033
-
1034
- static VALUE QueueManager_singleton_connect_rescue(VALUE self)
1035
- {
1036
- PQUEUE_MANAGER pqm;
1037
- VALUE exception;
1038
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
1039
-
1040
- if(pqm->trace_level) printf("WMQ::QueueManager.connect() Backing out due to unhandled exception\n");
1041
- //exception = rb_gvar_get("$!");
1042
- exception = rb_eval_string("$!"); /* $! holds the current exception */
1043
- if(pqm->trace_level > 1) printf("WMQ::QueueManager.connect() Exception $! extracted\n");
1044
- QueueManager_backout(self); /* Backout Unit of work */
1045
- if(pqm->trace_level > 1) printf("WMQ::QueueManager.connect() Rethrowing Exception\n");
1046
- rb_exc_raise(exception); /* Re-Raise Exception */
1047
- return Qnil;
1048
- }
1049
-
1050
- static VALUE QueueManager_singleton_connect_body(struct QueueManager_singleton_connect_arg* arg)
1051
- {
1052
- return rb_rescue2(QueueManager_singleton_connect_body2, (VALUE)arg,
1053
- QueueManager_singleton_connect_rescue, arg->self,
1054
- rb_eException, 0);
1055
- }
1056
-
1057
- static VALUE QueueManager_singleton_connect_ensure(VALUE self)
1058
- {
1059
- return QueueManager_disconnect(self);
1060
- }
1061
-
1062
- /*
1063
- * call-seq:
1064
- * connect(...)
1065
- *
1066
- * Connect to the queue manager, then disconnect once the supplied code block completes
1067
- *
1068
- * Parameters:
1069
- * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
1070
- * * Summary of parameters and their WebSphere MQ equivalents:
1071
- * WMQ::QueueManager.connect( # WebSphere MQ Equivalents:
1072
- * :q_mgr_name => 'queue_manager name',
1073
- * :exception_on_error => true, # n/a
1074
- * :connect_options => WMQ::MQCNO_FASTBATH_BINDING # MQCNO.Options
1075
- *
1076
- * :trace_level => 0, # n/a
1077
- *
1078
- * # Common client connection parameters
1079
- * :channel_name => 'svrconn channel name', # MQCD.ChannelName
1080
- * :connection_name => 'localhost(1414)', # MQCD.ConnectionName
1081
- * :transport_type => WMQ::MQXPT_TCP, # MQCD.TransportType
1082
- *
1083
- * # Advanced client connections parameters
1084
- * :max_msg_length => 65535, # MQCD.MaxMsgLength
1085
- * :security_exit => 'Name of security exit', # MQCD.SecurityExit
1086
- * :send_exit => 'Name of send exit', # MQCD.SendExit
1087
- * :receive_exit => 'Name of receive exit', # MQCD.ReceiveExit
1088
- * :security_user_data => 'Security exit User data', # MQCD.SecurityUserData
1089
- * :send_user_data => 'Send exit user data', # MQCD.SendUserData
1090
- * :receive_user_data => 'Receive exit user data', # MQCD.ReceiveUserData
1091
- * :heartbeat_interval => 1, # MQCD.HeartbeatInterval
1092
- * :remote_security_id => 'Remote Security id', # MQCD.RemoteSecurityId
1093
- * :ssl_cipher_spec => 'SSL Cipher Spec', # MQCD.SSLCipherSpec
1094
- * :keep_alive_interval=> -1, # MQCD.KeepAliveInterval
1095
- * :mode_name => 'LU6.2 Mode Name', # MQCD.ModeName
1096
- * :tp_name => 'LU6.2 Transaction pgm name', # MQCD.TpName
1097
- * :user_identifier => 'LU 6.2 Userid', # MQCD.UserIdentifier
1098
- * :password => 'LU6.2 Password', # MQCD.Password
1099
- * :long_remote_user_id=> 'Long remote user identifier', # MQCD.LongRemoteUserId (Ptr, Length)
1100
- * :ssl_peer_name => 'SSL Peer name', # MQCD.SSLPeerName (Ptr, Length)
1101
- *
1102
- * # SSL Options
1103
- * :key_repository => '/var/mqm/qmgrs/.../key', # MQSCO.KeyRepository
1104
- * :crypto_hardware => 'GSK_ACCELERATOR_NCIPHER_NF_ON', # MQSCO.CryptoHardware
1105
- * )
1106
- *
1107
- * Optional Parameters
1108
- * * :q_mgr_name => String
1109
- * * Name of the existing WebSphere MQ Queue Manager to connect to
1110
- *
1111
- * * Default:
1112
- * - Server connections will connect to the default queue manager
1113
- * - Client connections will connect to whatever queue
1114
- * manager is found at the host and port number as specified
1115
- * by the connection_name
1116
- *
1117
- * * :exception_on_error => true or false
1118
- * Determines whether WMQ::WMQExceptions are thrown whenever
1119
- * an error occurs during a WebSphere MQ operation (connect, put, get, etc..)
1120
- *
1121
- * Default: true
1122
- *
1123
- * * :connect_options => FixNum
1124
- * * One or more of the following values:
1125
- * WMQ::MQCNO_STANDARD_BINDING
1126
- * WMQ::MQCNO_FASTPATH_BINDING
1127
- * WMQ::MQCNO_SHARED_BINDING
1128
- * WMQ::MQCNO_ISOLATED_BINDING
1129
- * WMQ::MQCNO_ACCOUNTING_MQI_ENABLED
1130
- * WMQ::MQCNO_ACCOUNTING_MQI_DISABLED
1131
- * WMQ::MQCNO_ACCOUNTING_Q_ENABLED
1132
- * WMQ::MQCNO_ACCOUNTING_Q_DISABLED
1133
- * WMQ::MQCNO_NONE
1134
- *
1135
- * * Multiple values can be or'd together. E.g.
1136
- * :connect_options=>WMQ::MQCNO_FASTPATH_BINDING | WMQ::MQCNO_ACCOUNTING_MQI_ENABLED
1137
- *
1138
- * * Please see the WebSphere MQ MQCNO data type documentation for more details
1139
- * Default: WMQ::MQCNO_NONE
1140
- *
1141
- * * :trace_level => FixNum
1142
- * * Turns on low-level tracing of the WebSphere MQ API calls to stdout.
1143
- * * 0: No tracing
1144
- * * 1: MQ API tracing only (MQCONNX, MQOPEN, MQPUT, etc..)
1145
- * * 2: Include Ruby WMQ tracing
1146
- * * 3: Verbose logging (Recommended for when reporting problems in Ruby WMQ)
1147
- * Default: 0
1148
- *
1149
- * Common Client Connection Parameters (Client connections only)
1150
- * * :connection_name => String (Mandatory for client connections)
1151
- * * Connection name, made up of the host name (or ip address) and the port number
1152
- * * E.g.
1153
- * 'mymachine.domain.com(1414)'
1154
- * '192.168.0.1(1417)'
1155
- *
1156
- * * :channel_name => String
1157
- * * Name of SVRCONN channel defined on the QueueManager for Client Connections
1158
- * * Default Value:
1159
- * 'SYSTEM.DEF.SVRCONN'
1160
- *
1161
- * * :transport_type => WMQ::MQXPT_TCP, # MQCD.TransportType
1162
- * * Valid Values:
1163
- * WMQ::MQXPT_LOCAL
1164
- * WMQ::MQXPT_LU62
1165
- * WMQ::MQXPT_TCP
1166
- * WMQ::MQXPT_NETBIOS
1167
- * WMQ::MQXPT_SPX
1168
- * WMQ::MQXPT_DECNET
1169
- * WMQ::MQXPT_UDP
1170
- *
1171
- * * Default Value:
1172
- * WMQ::MQXPT_TCP
1173
- *
1174
- * For the Advanced Client Connection parameters, please see the WebSphere MQ documentation
1175
- *
1176
- * Note:
1177
- * * If an exception is not caught in the code block, the current unit of work is
1178
- * automatically backed out, before disconnecting from the queue manager.
1179
- *
1180
- * Local Server Connection Example:
1181
- * require 'wmq/wmq'
1182
- *
1183
- * WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
1184
- * qmgr.put(:q_name=>'TEST.QUEUE', :data => 'Hello World')
1185
- * end
1186
- *
1187
- * Client Connection Example:
1188
- * require 'wmq/wmq_client'
1189
- *
1190
- * WMQ::QueueManager.connect(
1191
- * :channel_name => 'SYSTEM.DEF.SVRCONN',
1192
- * :transport_type => WMQ::MQXPT_TCP,
1193
- * :connection_name => 'localhost(1414)' ) do |qmgr|
1194
- * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:input) do |queue|
1195
- *
1196
- * message = WMQ::Message.new
1197
- * if queue.get(:message => message)
1198
- * puts "Data Received: #{message.data}"
1199
- * else
1200
- * puts 'No message available'
1201
- * end
1202
- * end
1203
- * end
1204
- */
1205
- VALUE QueueManager_singleton_connect(int argc, VALUE *argv, VALUE self)
1206
- {
1207
- VALUE proc, parameters, queue_manager;
1208
-
1209
- /* Extract parameters and code block (Proc) */
1210
- rb_scan_args(argc, argv, "1&", &parameters, &proc);
1211
-
1212
- queue_manager = rb_funcall(wmq_queue_manager, ID_new, 1, parameters);
1213
- if(!NIL_P(proc))
1214
- {
1215
- if(Qtrue == QueueManager_connect(queue_manager))
1216
- {
1217
- struct QueueManager_singleton_connect_arg arg;
1218
- arg.self = queue_manager;
1219
- arg.proc = proc;
1220
- rb_ensure(QueueManager_singleton_connect_body, (VALUE)&arg,
1221
- QueueManager_singleton_connect_ensure, queue_manager);
1222
- }
1223
- else
1224
- {
1225
- return Qfalse;
1226
- }
1227
- }
1228
- return queue_manager;
1229
- }
1230
-
1231
- /* What can I say, Ruby blocks have spoilt me :) */
1232
- #define CHECK_COMPLETION_CODE(ACTION) \
1233
- if(pqm->trace_level > 1) \
1234
- printf ("WMQ::QueueManager#execute() %s:%s\n", ACTION, wmq_reason(pqm->reason_code)); \
1235
- if(pqm->comp_code != MQCC_OK) \
1236
- { \
1237
- if (pqm->exception_on_error) \
1238
- { \
1239
- if(pqm->trace_level) \
1240
- printf ("WMQ::QueueManager#execute() raise WMQ::WMQException\n"); \
1241
- \
1242
- rb_raise(wmq_exception, \
1243
- "WMQ::QueueManager#execute(). Failed:%s, reason:%s", \
1244
- ACTION, \
1245
- wmq_reason(pqm->reason_code)); \
1246
- } \
1247
- return Qfalse; \
1248
- }
1249
-
1250
- #if RUBY_VERSION_CODE > 183
1251
- static int QueueManager_execute_each (VALUE key, VALUE value, PQUEUE_MANAGER pqm)
1252
- {
1253
- #else
1254
- static int QueueManager_execute_each (VALUE array, PQUEUE_MANAGER pqm)
1255
- {
1256
- VALUE key = rb_ary_shift(array);
1257
- VALUE value = rb_ary_shift(array);
1258
- #endif
1259
- MQLONG selector_type, selector;
1260
- VALUE str;
1261
- ID selector_id = rb_to_id(key);
1262
-
1263
- if(pqm->trace_level > 1)
1264
- {
1265
- str = rb_funcall(key, rb_intern("to_s"), 0);
1266
- printf ("WMQ::QueueManager#execute_each Key:%s\n", RSTRING(str)->ptr);
1267
- }
1268
-
1269
- if (ID_command == selector_id) // Skip :command
1270
- {
1271
- return 0;
1272
- }
1273
-
1274
- wmq_selector(selector_id, &selector_type, &selector);
1275
- if(NIL_P(value))
1276
- {
1277
- pqm->mqAddInquiry(pqm->admin_bag, selector, &pqm->comp_code, &pqm->reason_code);
1278
- CHECK_COMPLETION_CODE("Adding Inquiry to the admin bag")
1279
- return 0;
1280
- }
1281
-
1282
- switch (selector_type)
1283
- {
1284
- case MQIT_INTEGER:
1285
- if(TYPE(value) == T_SYMBOL) /* Translate symbol to MQ selector value */
1286
- {
1287
- MQLONG val_selector, val_selector_type;
1288
- wmq_selector(rb_to_id(value), &val_selector_type, &val_selector);
1289
-
1290
- pqm->mqAddInteger(pqm->admin_bag, selector, val_selector, &pqm->comp_code, &pqm->reason_code);
1291
- }
1292
- else
1293
- {
1294
- pqm->mqAddInteger(pqm->admin_bag, selector, NUM2LONG(value), &pqm->comp_code, &pqm->reason_code);
1295
- }
1296
- CHECK_COMPLETION_CODE("Adding Queue Type to the admin bag")
1297
- break;
1298
-
1299
- case MQIT_STRING:
1300
- str = StringValue(value);
1301
- pqm->mqAddString(pqm->admin_bag, selector, MQBL_NULL_TERMINATED, RSTRING(str)->ptr, &pqm->comp_code, &pqm->reason_code);
1302
- CHECK_COMPLETION_CODE("Adding Queue name to the admin bag")
1303
- break;
1304
-
1305
- default:
1306
- rb_raise(rb_eArgError, "WMQ::QueueManager#execute_each Unknown selector type returned by wmq_selector()");
1307
- break;
1308
- }
1309
- return 0;
1310
- }
1311
-
1312
- /*
1313
- * call-seq:
1314
- * execute(...)
1315
- *
1316
- * Execute an Administration command against the local queue manager
1317
- *
1318
- * Parameters:
1319
- * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
1320
- * * The entire MQ Administration interface has been implemented.
1321
- * Rather than re-documentation the hundreds of options, a standard
1322
- * convention has been used to map the MQ constants to Symbols in Ruby.
1323
- *
1324
- * For all MQ Admin commands, just drop the MQAI_ off the front and
1325
- * convert the command name to lower case.
1326
- * * E.g. MQAI_INQUIRE_Q becomes inquire_q
1327
- *
1328
- * For the hundreds of parameters, a similiar technique is followed.
1329
- * Remove the prefixes: MQCA_, MQIA_, etc.. and convert to lowercase
1330
- * * E.g. MQCA_Q_NAME becomes :q_name
1331
- *
1332
- * Example
1333
- * WMQ::QueueManager.connect do |qmgr|
1334
- * result = qmgr.execute(
1335
- * :command => :inquire_q,
1336
- * :q_name => 'MY.LOCAL.QUEUE',
1337
- * :q_type => WMQ::MQQT_LOCAL,
1338
- * :current_q_depth => nil
1339
- * )
1340
- * # OR, we can replace the method name execute with the MQAI command:
1341
- * result = qmgr.inquire_q(
1342
- * :q_name => 'MY.LOCAL.QUEUE',
1343
- * :q_type => WMQ::MQQT_LOCAL,
1344
- * :current_q_depth => nil
1345
- * )
1346
- *
1347
- * Complete Example:
1348
- * require 'wmq/wmq'
1349
- * require 'wmq/wmq_const_admin'
1350
- * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
1351
- * qmgr.reset_q_stats(:q_name=>'*').each {|item| p item }
1352
- * end
1353
- *
1354
- * Some one line examples
1355
- * qmgr.inquire_q(:q_name=>'TEST*').each {|item| p item }
1356
- *
1357
- * qmgr.inquire_q(:q_name=>'TEST*', :q_type=>WMQ::MQQT_LOCAL, :current_q_depth=>nil).each {|item| p item }
1358
- *
1359
- * qmgr.inquire_process(:process_name=>'*').each {|item| p item }
1360
- *
1361
- * qmgr.ping_q_mgr.each {|item| p item }
1362
- *
1363
- * qmgr.refresh_security.each {|item| p item }
1364
- *
1365
- * qmgr.inquire_q_status(:q_name=>'TEST*', :q_status_type=>:q_status, :q_status_attrs=>:process_id).each {|item| p item }
1366
- *
1367
- * qmgr.start_channel_listener.each {|item| p item }
1368
- *
1369
- * qmgr.inquire_channel_status(:channel_name=>'*').each {|item| p item }
1370
- */
1371
- VALUE QueueManager_execute(VALUE self, VALUE hash)
1372
- {
1373
- #ifdef MQHB_UNUSABLE_HBAG
1374
- VALUE val;
1375
- PQUEUE_MANAGER pqm;
1376
- Data_Get_Struct(self, QUEUE_MANAGER, pqm);
1377
-
1378
- Check_Type(hash, T_HASH);
1379
-
1380
- if (pqm->admin_bag == MQHB_UNUSABLE_HBAG) /* Lazy create admin bag */
1381
- {
1382
- pqm->mqCreateBag(MQCBO_ADMIN_BAG, &pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
1383
- CHECK_COMPLETION_CODE("Creating the admin bag")
1384
- }
1385
- else
1386
- {
1387
- pqm->mqClearBag(pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
1388
- CHECK_COMPLETION_CODE("Clearing the admin bag")
1389
- }
1390
-
1391
- if (pqm->reply_bag == MQHB_UNUSABLE_HBAG) /* Lazy create reply bag */
1392
- {
1393
- pqm->mqCreateBag(MQCBO_ADMIN_BAG, &pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
1394
- CHECK_COMPLETION_CODE("Creating the reply bag")
1395
- }
1396
- else
1397
- {
1398
- pqm->mqClearBag(pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
1399
- CHECK_COMPLETION_CODE("Clearing the reply bag")
1400
- }
1401
-
1402
- val = rb_hash_aref(hash, ID2SYM(ID_command)); /* :command */
1403
- if (NIL_P(val))
1404
- {
1405
- rb_raise(rb_eArgError, "WMQ::QueueManager#execute Mandatory parameter :command missing");
1406
- }
1407
- #if RUBY_VERSION_CODE > 183
1408
- rb_hash_foreach(hash, QueueManager_execute_each, (VALUE)pqm);
1409
- #else
1410
- rb_iterate (rb_each, hash, QueueManager_execute_each, (VALUE)pqm);
1411
- #endif
1412
- if(pqm->trace_level) printf ("WMQ::QueueManager#execute() Queue Manager Handle:%ld\n", (long)pqm->hcon);
1413
-
1414
- pqm->mqExecute(
1415
- pqm->hcon, /* MQ connection handle */
1416
- wmq_command_lookup(rb_to_id(val)), /* Command to be executed */
1417
- MQHB_NONE, /* No options bag */
1418
- pqm->admin_bag, /* Handle to bag containing commands */
1419
- pqm->reply_bag, /* Handle to bag to receive the response*/
1420
- MQHO_NONE, /* Put msg on SYSTEM.ADMIN.COMMAND.QUEUE*/
1421
- MQHO_NONE, /* Create a dynamic q for the response */
1422
- &pqm->comp_code, /* Completion code from the mqexecute */
1423
- &pqm->reason_code); /* Reason code from mqexecute call */
1424
-
1425
- if(pqm->trace_level) printf("WMQ::QueueManager#execute() completed with reason:%s\n", wmq_reason(pqm->reason_code));
1426
-
1427
- if (pqm->comp_code == MQCC_OK)
1428
- {
1429
- MQLONG numberOfBags; /* number of bags in response bag */
1430
- MQHBAG qAttrsBag; /* bag containing q attributes */
1431
- VALUE array;
1432
- MQLONG size;
1433
- MQLONG length;
1434
- MQCHAR inquiry_buffer[WMQ_EXEC_STRING_INQ_BUFFER_SIZE];
1435
- PMQCHAR pChar;
1436
-
1437
- MQLONG qDepth; /* depth of queue */
1438
- MQLONG item_type;
1439
- MQLONG selector;
1440
- MQLONG number_of_items;
1441
- int bag_index, items, k;
1442
-
1443
- pqm->mqCountItems(pqm->reply_bag, MQHA_BAG_HANDLE, &numberOfBags, &pqm->comp_code, &pqm->reason_code);
1444
- CHECK_COMPLETION_CODE("Counting number of bags returned from the command server")
1445
-
1446
- if(pqm->trace_level > 1) printf("WMQ::QueueManager#execute() %ld bags returned\n", (long)numberOfBags);
1447
- array = rb_ary_new2(numberOfBags);
1448
-
1449
- for ( bag_index=0; bag_index<numberOfBags; bag_index++) /* For each bag, extract the queue depth */
1450
- {
1451
- hash = rb_hash_new();
1452
-
1453
- pqm->mqInquireBag(pqm->reply_bag, MQHA_BAG_HANDLE, bag_index, &qAttrsBag, &pqm->comp_code, &pqm->reason_code);
1454
- CHECK_COMPLETION_CODE("Inquiring for the attribute bag handle")
1455
-
1456
- pqm->mqCountItems(qAttrsBag, MQSEL_ALL_SELECTORS, &number_of_items, &pqm->comp_code, &pqm->reason_code);
1457
- CHECK_COMPLETION_CODE("Counting number of items in this bag")
1458
-
1459
- if(pqm->trace_level > 1) printf("WMQ::QueueManager#execute() Bag %d contains %ld items\n", bag_index, (long)number_of_items);
1460
-
1461
- for (items=0; items<number_of_items; items++) /* For each item, extract it's value */
1462
- {
1463
- pqm->mqInquireItemInfo(
1464
- qAttrsBag, /* I: Bag handle */
1465
- MQSEL_ANY_SELECTOR, /* I: Item selector */
1466
- items, /* I: Item index */
1467
- &selector, /* O: Selector of item */
1468
- &item_type, /* O: Data type of item */
1469
- &pqm->comp_code,
1470
- &pqm->reason_code);
1471
- CHECK_COMPLETION_CODE("Inquiring Item details")
1472
-
1473
- if (selector > 0) /* Skip system selectors */
1474
- {
1475
- switch (item_type)
1476
- {
1477
- case MQIT_INTEGER:
1478
- pqm->mqInquireInteger(qAttrsBag, MQSEL_ALL_SELECTORS, items, &qDepth, &pqm->comp_code, &pqm->reason_code);
1479
- CHECK_COMPLETION_CODE("Inquiring Integer item")
1480
-
1481
- if(pqm->trace_level > 1)
1482
- printf("WMQ::QueueManager#execute() Item %d: Integer:%ld, selector:%ld\n", items, (long)qDepth, (long)selector);
1483
-
1484
- rb_hash_aset(hash, ID2SYM(wmq_selector_id(selector)), LONG2NUM(qDepth));
1485
- break;
1486
-
1487
- case MQIT_STRING:
1488
- pqm->mqInquireString(qAttrsBag, MQSEL_ALL_SELECTORS, items, WMQ_EXEC_STRING_INQ_BUFFER_SIZE-1, inquiry_buffer,
1489
- &size, NULL, &pqm->comp_code, &pqm->reason_code);
1490
- if(pqm->trace_level > 2)
1491
- printf("WMQ::QueueManager#execute() mqInquireString buffer size: %d, string size:%ld\n",
1492
- WMQ_EXEC_STRING_INQ_BUFFER_SIZE,(long)size);
1493
- CHECK_COMPLETION_CODE("Inquiring String item")
1494
-
1495
- length = 0;
1496
- pChar = inquiry_buffer + size-1;
1497
- for (k = size; k > 0; k--)
1498
- {
1499
- if (*pChar != ' ' && *pChar != 0)
1500
- {
1501
- length = k;
1502
- break;
1503
- }
1504
- pChar--;
1505
- }
1506
- rb_hash_aset(hash, ID2SYM(wmq_selector_id(selector)), rb_str_new(inquiry_buffer, length));
1507
-
1508
- if(pqm->trace_level > 1)
1509
- {
1510
- inquiry_buffer[length] = '\0';
1511
- printf("WMQ::QueueManager#execute() Item %d: String:'%s', selector:%ld\n",
1512
- items, inquiry_buffer, (long)selector);
1513
- }
1514
- break;
1515
-
1516
- case MQIT_BAG:
1517
- printf("Ignoring Bag at this level\n");
1518
- break;
1519
-
1520
- default:
1521
- printf("Ignoring Unknown type:%ld\n", (long)item_type);
1522
- break;
1523
- }
1524
- }
1525
- }
1526
- rb_ary_push(array, hash);
1527
- }
1528
- return array;
1529
- }
1530
- else
1531
- {
1532
- VALUE name = rb_iv_get(self,"@name");
1533
- name = StringValue(name);
1534
-
1535
- if (pqm->reason_code == MQRCCF_COMMAND_FAILED)
1536
- {
1537
- /* Find out why admin command failed */
1538
- MQLONG result_comp_code, result_reason_code;
1539
- MQHBAG result_bag;
1540
-
1541
- pqm->mqInquireBag(pqm->reply_bag, MQHA_BAG_HANDLE, 0, &result_bag, &pqm->comp_code, &pqm->reason_code);
1542
- CHECK_COMPLETION_CODE("Getting the result bag handle")
1543
-
1544
- pqm->mqInquireInteger(result_bag, MQIASY_COMP_CODE, MQIND_NONE, &result_comp_code, &pqm->comp_code, &pqm->reason_code);
1545
- CHECK_COMPLETION_CODE("Getting the completion code from the result bag")
1546
-
1547
- pqm->mqInquireInteger(result_bag, MQIASY_REASON, MQIND_NONE, &result_reason_code, &pqm->comp_code, &pqm->reason_code);
1548
- CHECK_COMPLETION_CODE("Getting the reason code from the result bag")
1549
-
1550
- pqm->comp_code = result_comp_code;
1551
- pqm->reason_code = result_reason_code;
1552
-
1553
- if(pqm->trace_level)
1554
- printf("WMQ::QueueManager#execute() Error returned by command server:%s\n", wmq_reason(pqm->reason_code));
1555
- }
1556
-
1557
- if (pqm->exception_on_error)
1558
- {
1559
- if (pqm->reason_code == MQRC_CMD_SERVER_NOT_AVAILABLE)
1560
- {
1561
- rb_raise(wmq_exception,
1562
- "WMQ::QueueManager#execute(). Please start the WebSphere MQ Command Server : 'strmqcsv %s', reason:%s",
1563
- RSTRING(name)->ptr,
1564
- wmq_reason(pqm->reason_code));
1565
- }
1566
- else
1567
- {
1568
- rb_raise(wmq_exception,
1569
- "WMQ::QueueManager#execute(). Error executing admin command on Queue Manager:%s, reason:%s",
1570
- RSTRING(name)->ptr,
1571
- wmq_reason(pqm->reason_code));
1572
- }
1573
- }
1574
- return Qfalse;
1575
- }
1576
- return Qnil;
1577
- #else
1578
- rb_notimplement();
1579
- return Qfalse;
1580
- #endif
1581
- }
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
+ static ID ID_open;
20
+ static ID ID_call;
21
+ static ID ID_new;
22
+ static ID ID_backout;
23
+ static ID ID_connect_options;
24
+ static ID ID_q_mgr_name;
25
+ static ID ID_queue_manager;
26
+ static ID ID_exception_on_error;
27
+ static ID ID_descriptor;
28
+ static ID ID_message;
29
+ static ID ID_trace_level;
30
+
31
+ /* MQCD ID's */
32
+ static ID ID_channel_name;
33
+ static ID ID_transport_type;
34
+ static ID ID_mode_name;
35
+ static ID ID_tp_name;
36
+ static ID ID_security_exit;
37
+ static ID ID_send_exit;
38
+ static ID ID_receive_exit;
39
+ static ID ID_max_msg_length;
40
+ static ID ID_security_user_data;
41
+ static ID ID_send_user_data;
42
+ static ID ID_receive_user_data;
43
+ static ID ID_user_identifier;
44
+ static ID ID_password;
45
+ static ID ID_connection_name;
46
+ static ID ID_heartbeat_interval;
47
+ static ID ID_long_remote_user_id;
48
+ static ID ID_remote_security_id;
49
+ static ID ID_ssl_cipher_spec;
50
+ static ID ID_ssl_peer_name;
51
+ static ID ID_keep_alive_interval;
52
+ static ID ID_crypto_hardware;
53
+
54
+ /* MQSCO ID's */
55
+ static ID ID_key_repository;
56
+
57
+ /* Admin ID's */
58
+ static ID ID_create_queue;
59
+ static ID ID_q_name;
60
+ static ID ID_command;
61
+
62
+ void QueueManager_id_init(void)
63
+ {
64
+ ID_open = rb_intern("open");
65
+ ID_call = rb_intern("call");
66
+ ID_new = rb_intern("new");
67
+ ID_backout = rb_intern("backout");
68
+ ID_q_mgr_name = rb_intern("q_mgr_name");
69
+ ID_queue_manager = rb_intern("queue_manager");
70
+ ID_exception_on_error = rb_intern("exception_on_error");
71
+ ID_connect_options = rb_intern("connect_options");
72
+ ID_trace_level = rb_intern("trace_level");
73
+ ID_descriptor = rb_intern("descriptor");
74
+ ID_message = rb_intern("message");
75
+
76
+ /* MQCD ID's */
77
+ ID_channel_name = rb_intern("channel_name");
78
+ ID_transport_type = rb_intern("transport_type");
79
+ ID_mode_name = rb_intern("mode_name");
80
+ ID_tp_name = rb_intern("tp_name");
81
+ ID_security_exit = rb_intern("security_exit");
82
+ ID_send_exit = rb_intern("send_exit");
83
+ ID_receive_exit = rb_intern("receive_exit");
84
+ ID_max_msg_length = rb_intern("max_msg_length");
85
+ ID_security_user_data = rb_intern("security_user_data");
86
+ ID_send_user_data = rb_intern("send_user_data");
87
+ ID_receive_user_data = rb_intern("receive_user_data");
88
+ ID_user_identifier = rb_intern("user_identifier");
89
+ ID_password = rb_intern("password");
90
+ ID_connection_name = rb_intern("connection_name");
91
+ ID_heartbeat_interval = rb_intern("heartbeat_interval");
92
+ ID_long_remote_user_id = rb_intern("long_remote_user_id");
93
+ ID_remote_security_id = rb_intern("remote_security_id");
94
+ ID_ssl_cipher_spec = rb_intern("ssl_cipher_spec");
95
+ ID_ssl_peer_name = rb_intern("ssl_peer_name");
96
+ ID_keep_alive_interval = rb_intern("keep_alive_interval");
97
+
98
+ /* MQSCO ID's */
99
+ ID_key_repository = rb_intern("key_repository");
100
+ ID_crypto_hardware = rb_intern("crypto_hardware");
101
+
102
+ /* Admin ID's */
103
+ ID_create_queue = rb_intern("create_queue");
104
+ ID_q_name = rb_intern("q_name");
105
+ ID_command = rb_intern("command");
106
+ }
107
+
108
+ /* --------------------------------------------------
109
+ * C Structure to store MQ data types and other
110
+ * C internal values
111
+ * --------------------------------------------------*/
112
+ void QUEUE_MANAGER_free(void* p)
113
+ {
114
+ PQUEUE_MANAGER pqm = (PQUEUE_MANAGER)p;
115
+
116
+ if(pqm->trace_level>1) printf("WMQ::QueueManager Freeing QUEUE_MANAGER structure\n");
117
+
118
+ if (pqm->hcon && !pqm->already_connected) /* Valid MQ handle means MQDISC was not called */
119
+ {
120
+ printf("WMQ::QueueManager#free disconnect() was not called for Queue Manager instance!!\n");
121
+ printf("WMQ::QueueManager#free Automatically calling back() and disconnect()\n");
122
+ pqm->MQBACK(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
123
+ pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
124
+ }
125
+ #ifdef MQCD_VERSION_6
126
+ free(pqm->long_remote_user_id_ptr);
127
+ #endif
128
+ #ifdef MQCD_VERSION_7
129
+ free(pqm->ssl_peer_name_ptr);
130
+ #endif
131
+ #ifdef MQHB_UNUSABLE_HBAG
132
+ if (pqm->admin_bag != MQHB_UNUSABLE_HBAG)
133
+ {
134
+ pqm->mqDeleteBag(&pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
135
+ }
136
+
137
+ if (pqm->reply_bag != MQHB_UNUSABLE_HBAG)
138
+ {
139
+ pqm->mqDeleteBag(&pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
140
+ }
141
+ #endif
142
+ Queue_manager_mq_free(pqm);
143
+ free(pqm->p_buffer);
144
+ free(p);
145
+ }
146
+
147
+ VALUE QUEUE_MANAGER_alloc(VALUE klass)
148
+ {
149
+ static MQCNO default_MQCNO = {MQCNO_DEFAULT}; /* MQCONNX Connection Options */
150
+ #ifdef MQCNO_VERSION_2
151
+ static MQCD default_MQCD = {MQCD_CLIENT_CONN_DEFAULT}; /* Client Connection */
152
+ #endif
153
+ #ifdef MQCNO_VERSION_4
154
+ static MQSCO default_MQSCO = {MQSCO_DEFAULT};
155
+ #endif
156
+
157
+ PQUEUE_MANAGER pqm = ALLOC(QUEUE_MANAGER);
158
+
159
+ pqm->hcon = 0;
160
+ pqm->comp_code = 0;
161
+ pqm->reason_code = 0;
162
+ pqm->exception_on_error = 1;
163
+ pqm->already_connected = 0;
164
+ pqm->trace_level = 0;
165
+ memcpy(&pqm->connect_options, &default_MQCNO, sizeof(MQCNO));
166
+ #ifdef MQCNO_VERSION_2
167
+ memcpy(&pqm->client_conn, &default_MQCD, sizeof(MQCD));
168
+
169
+ /* Tell MQ to use Client Conn structures, etc. */
170
+ pqm->connect_options.Version = MQCNO_CURRENT_VERSION;
171
+ pqm->connect_options.ClientConnPtr = &pqm->client_conn;
172
+ #endif
173
+ #ifdef MQCNO_VERSION_4
174
+ memcpy(&pqm->ssl_config_opts, &default_MQSCO, sizeof(MQSCO));
175
+ #endif
176
+ #ifdef MQCD_VERSION_6
177
+ pqm->long_remote_user_id_ptr = 0;
178
+ #endif
179
+ #ifdef MQCD_VERSION_7
180
+ pqm->ssl_peer_name_ptr = 0;
181
+ #endif
182
+ #ifdef MQHB_UNUSABLE_HBAG
183
+ pqm->admin_bag = MQHB_UNUSABLE_HBAG;
184
+ pqm->reply_bag = MQHB_UNUSABLE_HBAG;
185
+ #endif
186
+ pqm->buffer_size = 0;
187
+ pqm->p_buffer = 0;
188
+
189
+ pqm->is_client_conn = 0;
190
+ pqm->mq_lib_handle = 0;
191
+
192
+ return Data_Wrap_Struct(klass, 0, QUEUE_MANAGER_free, pqm);
193
+ }
194
+
195
+ /*
196
+ * call-seq:
197
+ * new(...)
198
+ *
199
+ * Parameters:
200
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
201
+ * * See QueueManager.new for details on all the parameters
202
+ *
203
+ * Note:
204
+ * * It is not recommended to use this method, rather use QueueManager.connect, since
205
+ * it will automatically disconnect from the queue manager. It also deals with backing out
206
+ * the current unit of work in the event of an unhandled exception. E.g. Syntax Error
207
+ * * RuntimeError and ArgumentError exceptions are always thrown regardless of the
208
+ * value of :exception_on_error
209
+ *
210
+ * Todo:
211
+ * * Support multiple send and receive exits
212
+ */
213
+ VALUE QueueManager_initialize(VALUE self, VALUE hash)
214
+ {
215
+ VALUE val;
216
+ VALUE str;
217
+ size_t size;
218
+ size_t length;
219
+ PQUEUE_MANAGER pqm;
220
+
221
+ Check_Type(hash, T_HASH);
222
+
223
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
224
+
225
+ WMQ_HASH2MQLONG(hash,trace_level, pqm->trace_level)
226
+
227
+ /* @name = options[:q_mgr_name] || '' # QMGR Name optional with Client Connection */
228
+ val = rb_hash_aref(hash, ID2SYM(ID_q_mgr_name));
229
+ if (NIL_P(val))
230
+ {
231
+ rb_iv_set(self, "@name", rb_str_new2(""));
232
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:[Not specified, use Default QMGR]\n");
233
+ }
234
+ else
235
+ {
236
+ rb_iv_set(self, "@name", val);
237
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager#initialize() Queue Manager:%s\n", RSTRING_PTR(val));
238
+ }
239
+
240
+ WMQ_HASH2BOOL(hash,exception_on_error, pqm->exception_on_error)
241
+
242
+ /*
243
+ * All Client connection parameters are ignored if connection_name is missing
244
+ */
245
+ #ifdef MQCNO_VERSION_2
246
+ if(!NIL_P(rb_hash_aref(hash, ID2SYM(ID_connection_name))))
247
+ {
248
+ PMQCD pmqcd = &pqm->client_conn; /* Process MQCD */
249
+ pqm->is_client_conn = 1; /* Set to Client connection */
250
+
251
+ WMQ_HASH2MQCHARS(hash,connection_name, pmqcd->ConnectionName)
252
+ WMQ_HASH2MQLONG (hash,transport_type, pmqcd->TransportType)
253
+ WMQ_HASH2MQCHARS(hash,mode_name, pmqcd->ModeName)
254
+ WMQ_HASH2MQCHARS(hash,tp_name, pmqcd->TpName)
255
+ WMQ_HASH2MQCHARS(hash,security_exit, pmqcd->SecurityExit)
256
+ WMQ_HASH2MQCHARS(hash,send_exit, pmqcd->SendExit)
257
+ WMQ_HASH2MQCHARS(hash,receive_exit, pmqcd->ReceiveExit)
258
+ WMQ_HASH2MQLONG (hash,max_msg_length, pmqcd->MaxMsgLength)
259
+ WMQ_HASH2MQCHARS(hash,security_user_data, pmqcd->SecurityUserData)
260
+ WMQ_HASH2MQCHARS(hash,send_user_data, pmqcd->SendUserData)
261
+ WMQ_HASH2MQCHARS(hash,receive_user_data, pmqcd->ReceiveUserData)
262
+ WMQ_HASH2MQCHARS(hash,user_identifier, pmqcd->UserIdentifier)
263
+ WMQ_HASH2MQCHARS(hash,password, pmqcd->Password)
264
+
265
+ /* Default channel name to system default */
266
+ val = rb_hash_aref(hash, ID2SYM(ID_channel_name));
267
+ if (NIL_P(val))
268
+ {
269
+ strncpy(pmqcd->ChannelName, "SYSTEM.DEF.SVRCONN", sizeof(pmqcd->ChannelName));
270
+ }
271
+ else
272
+ {
273
+ WMQ_HASH2MQCHARS(hash,channel_name, pmqcd->ChannelName)
274
+ }
275
+
276
+ #ifdef MQCD_VERSION_4
277
+ WMQ_HASH2MQLONG(hash,heartbeat_interval, pmqcd->HeartbeatInterval)
278
+ /* TODO:
279
+ WMQ_HASH2MQLONG(hash,exit_name_length, pmqcd->ExitNameLength)
280
+ WMQ_HASH2MQLONG(hash,exit_data_length, pmqcd->ExitDataLength)
281
+ WMQ_HASH2MQLONG(hash,send_exits_defined, pmqcd->SendExitsDefined)
282
+ WMQ_HASH2MQLONG(hash,receive_exits_defined, pmqcd->ReceiveExitsDefined)
283
+ TO_PTR (send_exit_ptr, pmqcd->SendExitPtr)
284
+ TO_PTR (send_user_data_ptr, pmqcd->SendUserDataPtr)
285
+ TO_PTR (receive_exit_ptr, pmqcd->ReceiveExitPtr)
286
+ TO_PTR (receive_user_data_ptr, pmqcd->ReceiveUserDataPtr)
287
+ */
288
+ #endif
289
+ #ifdef MQCD_VERSION_6
290
+ val = rb_hash_aref(hash, ID2SYM(ID_long_remote_user_id));
291
+ if (!NIL_P(val))
292
+ {
293
+ str = StringValue(val);
294
+ length = RSTRING_LEN(str);
295
+
296
+ if (length > 0)
297
+ {
298
+ MQPTR pBuffer;
299
+ if(pqm->trace_level > 1)
300
+ printf("WMQ::QueueManager#initialize() Setting long_remote_user_id:%s\n",
301
+ RSTRING_PTR(str));
302
+
303
+ /* Include null at end of string */
304
+ pBuffer = ALLOC_N(char, length+1);
305
+ memcpy(pBuffer, RSTRING_PTR(str), length+1);
306
+
307
+ pmqcd->LongRemoteUserIdLength = length;
308
+ pmqcd->LongRemoteUserIdPtr = pBuffer;
309
+ pqm->long_remote_user_id_ptr = pBuffer;
310
+ }
311
+ }
312
+ WMQ_HASH2MQBYTES(hash,remote_security_id, pmqcd->RemoteSecurityId)
313
+ WMQ_HASH2MQCHARS(hash,ssl_cipher_spec, pmqcd->SSLCipherSpec)
314
+ #endif
315
+ #ifdef MQCD_VERSION_7
316
+ val = rb_hash_aref(hash, ID2SYM(ID_ssl_peer_name));
317
+ if (!NIL_P(val))
318
+ {
319
+ str = StringValue(val);
320
+ length = RSTRING_LEN(str);
321
+
322
+ if (length > 0)
323
+ {
324
+ MQPTR pBuffer;
325
+ if(pqm->trace_level > 1)
326
+ printf("WMQ::QueueManager#initialize() Setting ssl_peer_name:%s\n",
327
+ RSTRING_PTR(str));
328
+
329
+ /* Include null at end of string */
330
+ pBuffer = ALLOC_N(char, length+1);
331
+ memcpy(pBuffer, RSTRING_PTR(str), length+1);
332
+
333
+ pmqcd->SSLPeerNameLength = length;
334
+ pmqcd->SSLPeerNamePtr = pBuffer;
335
+ pqm->ssl_peer_name_ptr = pBuffer;
336
+ }
337
+ }
338
+ WMQ_HASH2MQLONG(hash,keep_alive_interval, pmqcd->KeepAliveInterval)
339
+
340
+ /* Only set if SSL options are supplied, otherwise
341
+ * environment variables are ignored: MQSSLKEYR and MQSSLCRYP
342
+ * Any SSL info in the client channel definition tables is also ignored
343
+ */
344
+ if (!NIL_P(rb_hash_aref(hash, ID2SYM(ID_key_repository))) ||
345
+ !NIL_P(rb_hash_aref(hash, ID2SYM(ID_crypto_hardware))))
346
+ {
347
+ /* Process MQSCO */
348
+ WMQ_HASH2MQCHARS(hash,key_repository, pqm->ssl_config_opts.KeyRepository)
349
+ WMQ_HASH2MQCHARS(hash,crypto_hardware, pqm->ssl_config_opts.CryptoHardware)
350
+
351
+ pqm->connect_options.SSLConfigPtr = &pqm->ssl_config_opts;
352
+ }
353
+ #endif
354
+
355
+ }
356
+ else
357
+ {
358
+ pqm->is_client_conn = 0; /* Set to Server connection */
359
+ }
360
+ #endif
361
+
362
+ #ifdef MQCNO_VERSION_4
363
+ /* Process MQCNO */
364
+ WMQ_HASH2MQLONG(hash,connect_options, pqm->connect_options.Options)
365
+ #endif
366
+
367
+ /* --------------------------------------------------
368
+ * TODO: MQAIR Structure - LDAP Security
369
+ * --------------------------------------------------*/
370
+
371
+ return Qnil;
372
+ }
373
+
374
+ /*
375
+ * Before working with any queues, it is necessary to connect
376
+ * to the queue manager.
377
+ *
378
+ * Returns:
379
+ * * true : On Success
380
+ * * false: On Failure
381
+ *
382
+ * comp_code and reason_code are also updated.
383
+ * reason will return a text description of the reason_code
384
+ *
385
+ * Throws:
386
+ * * WMQ::WMQException if comp_code != MQCC_OK
387
+ * * Except if :exception_on_error => false was supplied as a parameter
388
+ * to QueueManager.new
389
+ */
390
+ VALUE QueueManager_connect(VALUE self)
391
+ {
392
+ VALUE name;
393
+
394
+ PQUEUE_MANAGER pqm;
395
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
396
+ pqm->already_connected = 0;
397
+
398
+ Queue_manager_mq_load(pqm); /* Load MQ Library */
399
+
400
+ name = rb_iv_get(self,"@name");
401
+ name = StringValue(name);
402
+
403
+ if(pqm->trace_level)
404
+ printf("WMQ::QueueManager#connect() Connect to Queue Manager:%s\n", RSTRING_PTR(name));
405
+
406
+ if (pqm->hcon) /* Disconnect from qmgr if already connected, ignore errors */
407
+ {
408
+ if(pqm->trace_level)
409
+ printf("WMQ::QueueManager#connect() Already connected to Queue Manager:%s, Disconnecting first!\n", RSTRING_PTR(name));
410
+
411
+ pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
412
+ }
413
+
414
+ pqm->MQCONNX(
415
+ RSTRING_PTR(name), /* queue manager */
416
+ &pqm->connect_options, /* Connection Options */
417
+ &pqm->hcon, /* connection handle */
418
+ &pqm->comp_code, /* completion code */
419
+ &pqm->reason_code); /* connect reason code */
420
+
421
+ if(pqm->trace_level)
422
+ printf("WMQ::QueueManager#connect() MQCONNX completed with reason:%s, Handle:%ld\n",
423
+ wmq_reason(pqm->reason_code),
424
+ (long)pqm->hcon);
425
+
426
+ if (pqm->comp_code == MQCC_FAILED)
427
+ {
428
+ pqm->hcon = 0;
429
+
430
+ if (pqm->exception_on_error)
431
+ {
432
+ rb_raise(wmq_exception,
433
+ "WMQ::QueueManager#connect(). Error connecting to Queue Manager:%s, reason:%s",
434
+ RSTRING_PTR(name),
435
+ wmq_reason(pqm->reason_code));
436
+ }
437
+
438
+ return Qfalse;
439
+ }
440
+
441
+ if (pqm->reason_code == MQRC_ALREADY_CONNECTED)
442
+ {
443
+ if(pqm->trace_level) printf("WMQ::QueueManager#connect() Already connected\n");
444
+ pqm->already_connected = 1;
445
+ }
446
+
447
+ return Qtrue;
448
+ }
449
+
450
+ /*
451
+ * Disconnect from this QueueManager instance
452
+ *
453
+ * Returns:
454
+ * * true : On Success
455
+ * * false: On Failure
456
+ *
457
+ * comp_code and reason_code are also updated.
458
+ * reason will return a text description of the reason_code
459
+ *
460
+ * Throws:
461
+ * * WMQ::WMQException if comp_code != MQCC_OK
462
+ * * Except if :exception_on_error => false was supplied as a parameter
463
+ * to QueueManager.new
464
+ */
465
+ VALUE QueueManager_disconnect(VALUE self)
466
+ {
467
+ PQUEUE_MANAGER pqm;
468
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
469
+
470
+ if(pqm->trace_level) printf ("WMQ::QueueManager#disconnect() Queue Manager Handle:%ld\n", (long)pqm->hcon);
471
+
472
+ if (!pqm->already_connected)
473
+ {
474
+ pqm->MQDISC(&pqm->hcon, &pqm->comp_code, &pqm->reason_code);
475
+
476
+ if(pqm->trace_level) printf("WMQ::QueueManager#disconnect() MQDISC completed with reason:%s\n", wmq_reason(pqm->reason_code));
477
+
478
+ if (pqm->comp_code != MQCC_OK)
479
+ {
480
+ if (pqm->exception_on_error)
481
+ {
482
+ VALUE name = rb_iv_get(self,"@name");
483
+ name = StringValue(name);
484
+
485
+ rb_raise(wmq_exception,
486
+ "WMQ::QueueManager#disconnect(). Error disconnecting from Queue Manager:%s, reason:%s",
487
+ RSTRING_PTR(name),
488
+ wmq_reason(pqm->reason_code));
489
+ }
490
+
491
+ return Qfalse;
492
+ }
493
+ }
494
+ else
495
+ {
496
+ pqm->comp_code = 0;
497
+ pqm->reason_code = 0;
498
+
499
+ if(pqm->trace_level) printf ("WMQ::QueueManager#disconnect() Not calling MQDISC, since already connected on connect\n");
500
+ }
501
+
502
+ pqm->hcon = 0;
503
+
504
+ return Qtrue;
505
+ }
506
+
507
+ /*
508
+ * Commit the current unit of work for this QueueManager instance
509
+ *
510
+ * Note:
511
+ * * commit will have no effect if all put and get operations were performed
512
+ * without specifying :sync => true
513
+ *
514
+ * Returns:
515
+ * * true : On Success
516
+ * * false: On Failure
517
+ *
518
+ * comp_code and reason_code are also updated.
519
+ * reason will return a text description of the reason_code
520
+ *
521
+ * Throws:
522
+ * * WMQ::WMQException if comp_code != MQCC_OK
523
+ * * Except if :exception_on_error => false was supplied as a parameter
524
+ * to QueueManager.new
525
+ */
526
+ VALUE QueueManager_commit(VALUE self)
527
+ {
528
+ PQUEUE_MANAGER pqm;
529
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
530
+
531
+ if(pqm->trace_level) printf ("WMQ::QueueManager#commit() Queue Manager Handle:%ld\n", (long)pqm->hcon);
532
+
533
+ pqm->MQCMIT(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
534
+
535
+ if(pqm->trace_level) printf("WMQ::QueueManager#commit() MQCMIT completed with reason:%s\n", wmq_reason(pqm->reason_code));
536
+
537
+ if (pqm->comp_code != MQCC_OK)
538
+ {
539
+ if (pqm->exception_on_error)
540
+ {
541
+ VALUE name = rb_iv_get(self,"@name");
542
+ name = StringValue(name);
543
+
544
+ rb_raise(wmq_exception,
545
+ "WMQ::QueueManager#commit(). Error commiting changes to Queue Manager:%s, reason:%s",
546
+ RSTRING_PTR(name),
547
+ wmq_reason(pqm->reason_code));
548
+ }
549
+ return Qfalse;
550
+ }
551
+
552
+ return Qtrue;
553
+ }
554
+
555
+ /*
556
+ * Backout the current unit of work for this QueueManager instance
557
+ *
558
+ * Since the last commit or rollback any messages put to a queue
559
+ * under synchpoint will be removed and any messages retrieved
560
+ * under synchpoint from any queues will be returned
561
+ *
562
+ * Note:
563
+ * * backout will have no effect if all put and get operations were performed
564
+ * without specifying :sync => true
565
+ *
566
+ * Returns:
567
+ * * true : On Success
568
+ * * false: On Failure
569
+ *
570
+ * comp_code and reason_code are also updated.
571
+ * reason will return a text description of the reason_code
572
+ *
573
+ * Throws:
574
+ * * WMQ::WMQException if comp_code != MQCC_OK
575
+ * * Except if :exception_on_error => false was supplied as a parameter
576
+ * to QueueManager.new
577
+ */
578
+ VALUE QueueManager_backout(VALUE self)
579
+ {
580
+ PQUEUE_MANAGER pqm;
581
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
582
+
583
+ if(pqm->trace_level) printf ("WMQ::QueueManager#backout() Queue Manager Handle:%ld\n", (long)pqm->hcon);
584
+
585
+ pqm->MQBACK(pqm->hcon, &pqm->comp_code, &pqm->reason_code);
586
+
587
+ if(pqm->trace_level) printf("WMQ::QueueManager#backout() MQBACK completed with reason:%s\n", wmq_reason(pqm->reason_code));
588
+
589
+ if (pqm->comp_code != MQCC_OK)
590
+ {
591
+ if (pqm->exception_on_error)
592
+ {
593
+ VALUE name = rb_iv_get(self,"@name");
594
+ name = StringValue(name);
595
+
596
+ rb_raise(wmq_exception,
597
+ "WMQ::QueueManager#backout(). Error backing out changes to Queue Manager:%s, reason:%s",
598
+ RSTRING_PTR(name),
599
+ wmq_reason(pqm->reason_code));
600
+ }
601
+ return Qfalse;
602
+ }
603
+
604
+ return Qtrue;
605
+ }
606
+
607
+ /*
608
+ * Advanced WebSphere MQ Use:
609
+ *
610
+ * Begin a unit of work between this QueueManager instance and another
611
+ * resource such as a Database
612
+ *
613
+ * Starts a new unit of work under which put and get can be called with
614
+ * with the parameter :sync => true
615
+ *
616
+ * Returns:
617
+ * * true : On Success
618
+ * * false: On Failure
619
+ *
620
+ * comp_code and reason_code are also updated.
621
+ * reason will return a text description of the reason_code
622
+ *
623
+ * Throws:
624
+ * * WMQ::WMQException if comp_code != MQCC_OK
625
+ * * Except if :exception_on_error => false was supplied as a parameter
626
+ * to QueueManager.new
627
+ */
628
+ VALUE QueueManager_begin(VALUE self)
629
+ {
630
+ PQUEUE_MANAGER pqm;
631
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
632
+
633
+ if(pqm->trace_level) printf ("WMQ::QueueManager#begin() Queue Manager Handle:%ld\n", (long)pqm->hcon);
634
+
635
+ pqm->MQBEGIN(pqm->hcon, 0, &pqm->comp_code, &pqm->reason_code);
636
+
637
+ if(pqm->trace_level) printf("WMQ::QueueManager#begin() MQBEGIN completed with reason:%s\n", wmq_reason(pqm->reason_code));
638
+
639
+ if (pqm->comp_code != MQCC_OK)
640
+ {
641
+ if (pqm->exception_on_error)
642
+ {
643
+ VALUE name = rb_iv_get(self,"@name");
644
+ name = StringValue(name);
645
+
646
+ rb_raise(wmq_exception,
647
+ "WMQ::QueueManager#begin(). Error starting unit of work on Queue Manager:%s, reason:%s",
648
+ RSTRING_PTR(name),
649
+ wmq_reason(pqm->reason_code));
650
+ }
651
+ return Qfalse;
652
+ }
653
+
654
+ return Qtrue;
655
+ }
656
+
657
+ /*
658
+ * call-seq:
659
+ * put(parameters)
660
+ *
661
+ * Put a message to the queue without having to first open the queue
662
+ * Recommended for reply queues that change frequently
663
+ *
664
+ * * parameters: a Hash consisting of one or more of the following parameters
665
+ *
666
+ * Summary of parameters and their WebSphere MQ equivalents
667
+ * queue.get( # WebSphere MQ Equivalents:
668
+ * :q_name => 'Queue Name', # MQOD.ObjectName
669
+ * :q_name => { queue_manager=>'QMGR_name', # MQOD.ObjectQMgrName
670
+ * q_name =>'q_name'}
671
+ * :message => my_message, # n/a : Instance of Message
672
+ * :data => "Hello World", # n/a : Data to send
673
+ * :sync => false, # MQGMO_SYNCPOINT
674
+ * :new_id => true, # MQPMO_NEW_MSG_ID & MQPMO_NEW_CORREL_ID
675
+ * :new_msg_id => true, # MQPMO_NEW_MSG_ID
676
+ * :new_correl_id => true, # MQPMO_NEW_CORREL_ID
677
+ * :fail_if_quiescing => true, # MQOO_FAIL_IF_QUIESCING
678
+ * :options => WMQ::MQPMO_FAIL_IF_QUIESCING # MQPMO_*
679
+ * )
680
+ *
681
+ * Mandatory Parameters
682
+ * * :q_name => String
683
+ * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
684
+ * * To open remote queues for which a local remote queue definition is not available
685
+ * pass a Hash as q_name (see q_name => Hash)
686
+ * OR
687
+ * * :q_name => Hash
688
+ * * q_name => String
689
+ * * Name of the existing WebSphere MQ local queue, model queue or remote queue to open
690
+ * * :q_mgr_name => String
691
+ * * Name of the remote WebSphere MQ queue manager to send the message to.
692
+ * * This allows a message to be written to a queue on a remote queue manager
693
+ * where a remote queue definition is not defined locally
694
+ * * Commonly used to reply to messages from remote systems
695
+ * * If q_mgr_name is the same as the local queue manager name then the message
696
+ * is merely written to the local queue.
697
+ * * Note: q_mgr_name should only be supplied when putting messages to the queue.
698
+ * It is not possible to get messages from a queue on a queue manager other
699
+ * than the currently connected queue manager
700
+ *
701
+ * * Either :message or :data must be supplied
702
+ * * If both are supplied, then :data will be written to the queue. The data in :message
703
+ * will be ignored
704
+ *
705
+ * Optional Parameters
706
+ * * :data => String
707
+ * * Data to be written to the queue. Can be binary or text data
708
+ *
709
+ * * :message => Message
710
+ * * An instance of the WMQ::Message
711
+ * * The Message descriptor, headers and data is retrieved from :message
712
+ * * message.data is ignored if :data is supplied
713
+ *
714
+ * * :sync => true or false
715
+ * * Determines whether the get is performed under synchpoint.
716
+ * I.e. Under the current unit of work
717
+ * Default: false
718
+ *
719
+ * * :new_id => true or false
720
+ * * Generate a new message id and correlation id for this
721
+ * message. :new_msg_id and :new_correl_id will be ignored
722
+ * if this parameter is true
723
+ * Default: false
724
+ *
725
+ * * :new_msg_id => true or false
726
+ * * Generate a new message id for this message
727
+ * * Note: A blank message id will result in a new message id anyway.
728
+ * However, for subsequent puts using the same message descriptor, the same
729
+ * message id will be used.
730
+ * Default: false
731
+ *
732
+ * * :new_correl_id => true or false
733
+ * * Generate a new correlation id for this message
734
+ * Default: false
735
+ *
736
+ * * :fail_if_quiescing => true or false
737
+ * * Determines whether the WMQ::Queue#put call will fail if the queue manager is
738
+ * in the process of being quiesced.
739
+ * * Note: This interface differs from other WebSphere MQ interfaces,
740
+ * they do not default to true.
741
+ * Default: true
742
+ * Equivalent to: MQGMO_FAIL_IF_QUIESCING
743
+ *
744
+ * * Note: As part of the application design, carefull consideration
745
+ * should be given as to when to allow a transaction or
746
+ * unit of work to complete or fail under this condition.
747
+ * As such it is important to include this option where
748
+ * appropriate so that MQ Administrators can shutdown the
749
+ * queue managers without having to resort to the 'immediate'
750
+ * shutdown option.
751
+ *
752
+ * * :options => Fixnum (Advanced MQ Use only)
753
+ * * Numeric field containing any of the MQ Put message options or'd together
754
+ * * E.g. :options => WMQ::MQPMO_PASS_IDENTITY_CONTEXT | WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
755
+ * * Note: If :options is supplied, it is applied first, then the above parameters are
756
+ * applied afterwards.
757
+ * * One or more of the following values:
758
+ * WMQ::MQPMO_NO_SYNCPOINT
759
+ * WMQ::MQPMO_LOGICAL_ORDER
760
+ * WMQ::MQPMO_NO_CONTEXT
761
+ * WMQ::MQPMO_DEFAULT_CONTEXT
762
+ * WMQ::MQPMO_PASS_IDENTITY_CONTEXT
763
+ * WMQ::MQPMO_PASS_ALL_CONTEXT
764
+ * WMQ::MQPMO_SET_IDENTITY_CONTEXT
765
+ * WMQ::MQPMO_SET_ALL_CONTEXT
766
+ * WMQ::MQPMO_ALTERNATE_USER_AUTHORITY
767
+ * WMQ::MQPMO_RESOLVE_LOCAL_Q
768
+ * WMQ::MQPMO_NONE
769
+ * * Please see the WebSphere MQ documentation for more details on the above options
770
+ * Default: WMQ::MQPMO_NONE
771
+ *
772
+ * Returns:
773
+ * * true : On Success
774
+ * * false: On Failure
775
+ *
776
+ * comp_code and reason_code are also updated.
777
+ * reason will return a text description of the reason_code
778
+ *
779
+ * Throws:
780
+ * * WMQ::WMQException if comp_code == MQCC_FAILED
781
+ * * Except if :exception_on_error => false was supplied as a parameter
782
+ * to QueueManager.new
783
+ */
784
+ VALUE QueueManager_put(VALUE self, VALUE hash)
785
+ {
786
+ MQLONG BufferLength; /* Length of the message in Buffer */
787
+ PMQVOID pBuffer; /* Message data */
788
+ MQMD md = {MQMD_DEFAULT}; /* Message Descriptor */
789
+ MQPMO pmo = {MQPMO_DEFAULT}; /* put message options */
790
+ MQOD od = {MQOD_DEFAULT}; /* Object Descriptor */
791
+ VALUE q_name;
792
+ VALUE str;
793
+ size_t size;
794
+ size_t length;
795
+ VALUE val;
796
+
797
+ PQUEUE_MANAGER pqm;
798
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
799
+
800
+ Check_Type(hash, T_HASH);
801
+
802
+ q_name = rb_hash_aref(hash, ID2SYM(ID_q_name));
803
+
804
+ if (NIL_P(q_name))
805
+ {
806
+ rb_raise(rb_eArgError,
807
+ "Mandatory parameter :q_name is missing from WMQ::QueueManager::put1()");
808
+ }
809
+
810
+ /* --------------------------------------------------
811
+ * If :q_name is a hash, extract :q_name and :q_mgr_name
812
+ * --------------------------------------------------*/
813
+ if(TYPE(q_name) == T_HASH)
814
+ {
815
+ WMQ_HASH2MQCHARS(q_name, q_mgr_name, od.ObjectQMgrName)
816
+
817
+ q_name = rb_hash_aref(val, ID2SYM(ID_q_name));
818
+ if (NIL_P(q_name))
819
+ {
820
+ rb_raise(rb_eArgError,
821
+ "Mandatory parameter :q_name missing from :q_name hash passed to WMQ::QueueManager#put");
822
+ }
823
+ }
824
+
825
+ WMQ_STR2MQCHARS(q_name,od.ObjectName)
826
+
827
+ Queue_extract_put_message_options(hash, &pmo);
828
+ Message_build(&pqm->p_buffer, &pqm->buffer_size, pqm->trace_level,
829
+ hash, &pBuffer, &BufferLength, &md);
830
+
831
+ if(pqm->trace_level) printf("WMQ::QueueManager#put Queue Manager Handle:%ld\n", (long)pqm->hcon);
832
+
833
+ pqm->MQPUT1(
834
+ pqm->hcon, /* connection handle */
835
+ &od, /* object descriptor */
836
+ &md, /* message descriptor */
837
+ &pmo, /* put message options */
838
+ BufferLength, /* message length */
839
+ pBuffer, /* message buffer */
840
+ &pqm->comp_code, /* completion code */
841
+ &pqm->reason_code); /* reason code */
842
+
843
+ if(pqm->trace_level) printf("WMQ::QueueManager#put MQPUT1 ended with reason:%s\n", wmq_reason(pqm->reason_code));
844
+
845
+ if (pqm->reason_code != MQRC_NONE)
846
+ {
847
+ if (pqm->exception_on_error)
848
+ {
849
+ VALUE qmgr_name = QueueManager_name(self);
850
+
851
+ rb_raise(wmq_exception,
852
+ "WMQ::QueueManager.put(). Error writing a message to Queue:%s on Queue Manager:%s reason:%s",
853
+ RSTRING_PTR(q_name),
854
+ RSTRING_PTR(qmgr_name),
855
+ wmq_reason(pqm->reason_code));
856
+ }
857
+ return Qfalse;
858
+ }
859
+ else
860
+ {
861
+ VALUE message = rb_hash_aref(hash, ID2SYM(ID_message));
862
+ if(!NIL_P(message))
863
+ {
864
+ VALUE descriptor = rb_funcall(message, ID_descriptor, 0);
865
+ Message_from_mqmd(descriptor, &md); /* This could be optimized to output only fields */
866
+ }
867
+ }
868
+
869
+ return Qtrue;
870
+ }
871
+
872
+ /*
873
+ * Return the completion code for the last MQ operation
874
+ *
875
+ * Returns => FixNum
876
+ * * WMQ::MQCC_OK 0
877
+ * * WMQ::MQCC_WARNING 1
878
+ * * WMQ::MQCC_FAILED 2
879
+ * * WMQ::MQCC_UNKNOWN -1
880
+ *
881
+ */
882
+ VALUE QueueManager_comp_code(VALUE self)
883
+ {
884
+ PQUEUE_MANAGER pqm;
885
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
886
+ return LONG2NUM(pqm->comp_code);
887
+ }
888
+
889
+ /*
890
+ * Return the reason code for the last MQ operation
891
+ *
892
+ * Returns => FixNum
893
+ * * For a complete list of reason codes, please see WMQ Constants or
894
+ * the WebSphere MQ documentation for Reason Codes
895
+ *
896
+ * Note
897
+ * * The list of Reason Codes varies depending on the version of WebSphere MQ
898
+ * and the operating system on which Ruby WMQ was compiled
899
+ */
900
+ VALUE QueueManager_reason_code(VALUE self)
901
+ {
902
+ PQUEUE_MANAGER pqm;
903
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
904
+ return LONG2NUM(pqm->reason_code);
905
+ }
906
+
907
+ /*
908
+ * Returns a textual representation of the reason_code for the last MQ operation
909
+ *
910
+ * Returns => String
911
+ * * For a complete list of reasons, please see WMQ Constants or
912
+ * the WebSphere MQ documentation for Reason Codes
913
+ *
914
+ * Note
915
+ * * The list of Reason Codes varies depending on the version of WebSphere MQ
916
+ * and the operating system on which Ruby WMQ was compiled
917
+ */
918
+ VALUE QueueManager_reason(VALUE self)
919
+ {
920
+ PQUEUE_MANAGER pqm;
921
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
922
+ return rb_str_new2(wmq_reason(pqm->reason_code));
923
+ }
924
+
925
+ /*
926
+ * Returns whether this QueueManager instance is set
927
+ * to throw a WMQ::WMQException whenever an MQ operation fails
928
+ *
929
+ * Returns:
930
+ * * true : This QueueManager instance will throw a WMQ::WMQException whenever
931
+ * an MQ operation fails. I.e. if comp_code != WMQ::OK.
932
+ * * false: WMQ::WMQException will not be thrown
933
+ *
934
+ * Note:
935
+ * * RuntimeError and ArgumentError exceptions are always thrown regardless of the
936
+ * value of exception_on_error
937
+ */
938
+ VALUE QueueManager_exception_on_error(VALUE self)
939
+ {
940
+ PQUEUE_MANAGER pqm;
941
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
942
+ if (pqm->exception_on_error)
943
+ {
944
+ return Qtrue;
945
+ }
946
+
947
+ return Qfalse;
948
+ }
949
+
950
+ /*
951
+ * Returns whether this QueueManager instance is currently
952
+ * connected to a WebSphere MQ queue manager
953
+ *
954
+ * Returns:
955
+ * * true : This QueueManager instance is connected to a local or remote queue manager
956
+ * * false: This QueueManager instance is not currently connected to a local or
957
+ * remote queue manager
958
+ */
959
+ VALUE QueueManager_connected_q(VALUE self)
960
+ {
961
+ PQUEUE_MANAGER pqm;
962
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
963
+ if (pqm->hcon)
964
+ {
965
+ return Qtrue;
966
+ }
967
+ return Qfalse;
968
+ }
969
+
970
+ /*
971
+ * Returns the QueueManager name => String
972
+ */
973
+ VALUE QueueManager_name(VALUE self)
974
+ {
975
+ return rb_iv_get(self,"@name");
976
+ }
977
+
978
+ static VALUE QueueManager_open_queue_block(VALUE message, VALUE proc)
979
+ {
980
+ return rb_funcall(proc, ID_call, 1, message);
981
+ }
982
+
983
+ static VALUE QueueManager_open_queue_each(VALUE parameters)
984
+ {
985
+ return Queue_singleton_open(1, &parameters, wmq_queue);
986
+ }
987
+
988
+ /*
989
+ * call-seq:
990
+ * open_queue(...)
991
+ * access_queue(...)
992
+ *
993
+ * Open the specified queue, then close it once the
994
+ * supplied code block has completed
995
+ *
996
+ * Parameters:
997
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
998
+ * * See Queue.open for the complete list of parameters, except that :queue_manager is *not* required
999
+ * since it is supplied automatically by this method
1000
+ *
1001
+ * Example:
1002
+ * require 'wmq/wmq_client'
1003
+ *
1004
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
1005
+ * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:output) do |queue|
1006
+ * queue.put(:data => 'Hello World')
1007
+ * end
1008
+ * end
1009
+ */
1010
+ VALUE QueueManager_open_queue(int argc, VALUE *argv, VALUE self)
1011
+ {
1012
+ VALUE parameters;
1013
+ VALUE proc;
1014
+
1015
+ /* Extract parameters and code block (Proc) */
1016
+ rb_scan_args(argc, argv, "1&", &parameters, &proc);
1017
+
1018
+ Check_Type(parameters, T_HASH);
1019
+ rb_hash_aset(parameters, ID2SYM(ID_queue_manager), self);
1020
+
1021
+ return rb_iterate(QueueManager_open_queue_each, parameters, QueueManager_open_queue_block, proc);
1022
+ }
1023
+
1024
+ struct QueueManager_singleton_connect_arg {
1025
+ VALUE self;
1026
+ VALUE proc;
1027
+ };
1028
+
1029
+ static VALUE QueueManager_singleton_connect_body2(struct QueueManager_singleton_connect_arg* arg)
1030
+ {
1031
+ return rb_funcall(arg->proc, ID_call, 1, arg->self);
1032
+ }
1033
+
1034
+ static VALUE QueueManager_singleton_connect_rescue(VALUE self)
1035
+ {
1036
+ PQUEUE_MANAGER pqm;
1037
+ VALUE exception;
1038
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
1039
+
1040
+ if(pqm->trace_level) printf("WMQ::QueueManager.connect() Backing out due to unhandled exception\n");
1041
+ //exception = rb_gvar_get("$!");
1042
+ exception = rb_eval_string("$!"); /* $! holds the current exception */
1043
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager.connect() Exception $! extracted\n");
1044
+ QueueManager_backout(self); /* Backout Unit of work */
1045
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager.connect() Rethrowing Exception\n");
1046
+ rb_exc_raise(exception); /* Re-Raise Exception */
1047
+ return Qnil;
1048
+ }
1049
+
1050
+ static VALUE QueueManager_singleton_connect_body(struct QueueManager_singleton_connect_arg* arg)
1051
+ {
1052
+ return rb_rescue2(QueueManager_singleton_connect_body2, (VALUE)arg,
1053
+ QueueManager_singleton_connect_rescue, arg->self,
1054
+ rb_eException, 0);
1055
+ }
1056
+
1057
+ static VALUE QueueManager_singleton_connect_ensure(VALUE self)
1058
+ {
1059
+ return QueueManager_disconnect(self);
1060
+ }
1061
+
1062
+ /*
1063
+ * call-seq:
1064
+ * connect(...)
1065
+ *
1066
+ * Connect to the queue manager, then disconnect once the supplied code block completes
1067
+ *
1068
+ * Parameters:
1069
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
1070
+ * * Summary of parameters and their WebSphere MQ equivalents:
1071
+ * WMQ::QueueManager.connect( # WebSphere MQ Equivalents:
1072
+ * :q_mgr_name => 'queue_manager name',
1073
+ * :exception_on_error => true, # n/a
1074
+ * :connect_options => WMQ::MQCNO_FASTBATH_BINDING # MQCNO.Options
1075
+ *
1076
+ * :trace_level => 0, # n/a
1077
+ *
1078
+ * # Common client connection parameters
1079
+ * :channel_name => 'svrconn channel name', # MQCD.ChannelName
1080
+ * :connection_name => 'localhost(1414)', # MQCD.ConnectionName
1081
+ * :transport_type => WMQ::MQXPT_TCP, # MQCD.TransportType
1082
+ *
1083
+ * # Advanced client connections parameters
1084
+ * :max_msg_length => 65535, # MQCD.MaxMsgLength
1085
+ * :security_exit => 'Name of security exit', # MQCD.SecurityExit
1086
+ * :send_exit => 'Name of send exit', # MQCD.SendExit
1087
+ * :receive_exit => 'Name of receive exit', # MQCD.ReceiveExit
1088
+ * :security_user_data => 'Security exit User data', # MQCD.SecurityUserData
1089
+ * :send_user_data => 'Send exit user data', # MQCD.SendUserData
1090
+ * :receive_user_data => 'Receive exit user data', # MQCD.ReceiveUserData
1091
+ * :heartbeat_interval => 1, # MQCD.HeartbeatInterval
1092
+ * :remote_security_id => 'Remote Security id', # MQCD.RemoteSecurityId
1093
+ * :ssl_cipher_spec => 'SSL Cipher Spec', # MQCD.SSLCipherSpec
1094
+ * :keep_alive_interval=> -1, # MQCD.KeepAliveInterval
1095
+ * :mode_name => 'LU6.2 Mode Name', # MQCD.ModeName
1096
+ * :tp_name => 'LU6.2 Transaction pgm name', # MQCD.TpName
1097
+ * :user_identifier => 'LU 6.2 Userid', # MQCD.UserIdentifier
1098
+ * :password => 'LU6.2 Password', # MQCD.Password
1099
+ * :long_remote_user_id=> 'Long remote user identifier', # MQCD.LongRemoteUserId (Ptr, Length)
1100
+ * :ssl_peer_name => 'SSL Peer name', # MQCD.SSLPeerName (Ptr, Length)
1101
+ *
1102
+ * # SSL Options
1103
+ * :key_repository => '/var/mqm/qmgrs/.../key', # MQSCO.KeyRepository
1104
+ * :crypto_hardware => 'GSK_ACCELERATOR_NCIPHER_NF_ON', # MQSCO.CryptoHardware
1105
+ * )
1106
+ *
1107
+ * Optional Parameters
1108
+ * * :q_mgr_name => String
1109
+ * * Name of the existing WebSphere MQ Queue Manager to connect to
1110
+ *
1111
+ * * Default:
1112
+ * - Server connections will connect to the default queue manager
1113
+ * - Client connections will connect to whatever queue
1114
+ * manager is found at the host and port number as specified
1115
+ * by the connection_name
1116
+ *
1117
+ * * :exception_on_error => true or false
1118
+ * Determines whether WMQ::WMQExceptions are thrown whenever
1119
+ * an error occurs during a WebSphere MQ operation (connect, put, get, etc..)
1120
+ *
1121
+ * Default: true
1122
+ *
1123
+ * * :connect_options => FixNum
1124
+ * * One or more of the following values:
1125
+ * WMQ::MQCNO_STANDARD_BINDING
1126
+ * WMQ::MQCNO_FASTPATH_BINDING
1127
+ * WMQ::MQCNO_SHARED_BINDING
1128
+ * WMQ::MQCNO_ISOLATED_BINDING
1129
+ * WMQ::MQCNO_ACCOUNTING_MQI_ENABLED
1130
+ * WMQ::MQCNO_ACCOUNTING_MQI_DISABLED
1131
+ * WMQ::MQCNO_ACCOUNTING_Q_ENABLED
1132
+ * WMQ::MQCNO_ACCOUNTING_Q_DISABLED
1133
+ * WMQ::MQCNO_NONE
1134
+ *
1135
+ * * Multiple values can be or'd together. E.g.
1136
+ * :connect_options=>WMQ::MQCNO_FASTPATH_BINDING | WMQ::MQCNO_ACCOUNTING_MQI_ENABLED
1137
+ *
1138
+ * * Please see the WebSphere MQ MQCNO data type documentation for more details
1139
+ * Default: WMQ::MQCNO_NONE
1140
+ *
1141
+ * * :trace_level => FixNum
1142
+ * * Turns on low-level tracing of the WebSphere MQ API calls to stdout.
1143
+ * * 0: No tracing
1144
+ * * 1: MQ API tracing only (MQCONNX, MQOPEN, MQPUT, etc..)
1145
+ * * 2: Include Ruby WMQ tracing
1146
+ * * 3: Verbose logging (Recommended for when reporting problems in Ruby WMQ)
1147
+ * Default: 0
1148
+ *
1149
+ * Common Client Connection Parameters (Client connections only)
1150
+ * * :connection_name => String (Mandatory for client connections)
1151
+ * * Connection name, made up of the host name (or ip address) and the port number
1152
+ * * E.g.
1153
+ * 'mymachine.domain.com(1414)'
1154
+ * '192.168.0.1(1417)'
1155
+ *
1156
+ * * :channel_name => String
1157
+ * * Name of SVRCONN channel defined on the QueueManager for Client Connections
1158
+ * * Default Value:
1159
+ * 'SYSTEM.DEF.SVRCONN'
1160
+ *
1161
+ * * :transport_type => WMQ::MQXPT_TCP, # MQCD.TransportType
1162
+ * * Valid Values:
1163
+ * WMQ::MQXPT_LOCAL
1164
+ * WMQ::MQXPT_LU62
1165
+ * WMQ::MQXPT_TCP
1166
+ * WMQ::MQXPT_NETBIOS
1167
+ * WMQ::MQXPT_SPX
1168
+ * WMQ::MQXPT_DECNET
1169
+ * WMQ::MQXPT_UDP
1170
+ *
1171
+ * * Default Value:
1172
+ * WMQ::MQXPT_TCP
1173
+ *
1174
+ * For the Advanced Client Connection parameters, please see the WebSphere MQ documentation
1175
+ *
1176
+ * Note:
1177
+ * * If an exception is not caught in the code block, the current unit of work is
1178
+ * automatically backed out, before disconnecting from the queue manager.
1179
+ *
1180
+ * Local Server Connection Example:
1181
+ * require 'wmq/wmq'
1182
+ *
1183
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID') do |qmgr|
1184
+ * qmgr.put(:q_name=>'TEST.QUEUE', :data => 'Hello World')
1185
+ * end
1186
+ *
1187
+ * Client Connection Example:
1188
+ * require 'wmq/wmq_client'
1189
+ *
1190
+ * WMQ::QueueManager.connect(
1191
+ * :channel_name => 'SYSTEM.DEF.SVRCONN',
1192
+ * :transport_type => WMQ::MQXPT_TCP,
1193
+ * :connection_name => 'localhost(1414)' ) do |qmgr|
1194
+ * qmgr.open_queue(:q_name=>'TEST.QUEUE', :mode=>:input) do |queue|
1195
+ *
1196
+ * message = WMQ::Message.new
1197
+ * if queue.get(:message => message)
1198
+ * puts "Data Received: #{message.data}"
1199
+ * else
1200
+ * puts 'No message available'
1201
+ * end
1202
+ * end
1203
+ * end
1204
+ */
1205
+ VALUE QueueManager_singleton_connect(int argc, VALUE *argv, VALUE self)
1206
+ {
1207
+ VALUE proc, parameters, queue_manager;
1208
+
1209
+ /* Extract parameters and code block (Proc) */
1210
+ rb_scan_args(argc, argv, "1&", &parameters, &proc);
1211
+
1212
+ queue_manager = rb_funcall(wmq_queue_manager, ID_new, 1, parameters);
1213
+ if(!NIL_P(proc))
1214
+ {
1215
+ if(Qtrue == QueueManager_connect(queue_manager))
1216
+ {
1217
+ struct QueueManager_singleton_connect_arg arg;
1218
+ arg.self = queue_manager;
1219
+ arg.proc = proc;
1220
+ rb_ensure(QueueManager_singleton_connect_body, (VALUE)&arg,
1221
+ QueueManager_singleton_connect_ensure, queue_manager);
1222
+ }
1223
+ else
1224
+ {
1225
+ return Qfalse;
1226
+ }
1227
+ }
1228
+ return queue_manager;
1229
+ }
1230
+
1231
+ /* What can I say, Ruby blocks have spoilt me :) */
1232
+ #define CHECK_COMPLETION_CODE(ACTION) \
1233
+ if(pqm->trace_level > 1) \
1234
+ printf ("WMQ::QueueManager#execute() %s:%s\n", ACTION, wmq_reason(pqm->reason_code)); \
1235
+ if(pqm->comp_code != MQCC_OK) \
1236
+ { \
1237
+ if (pqm->exception_on_error) \
1238
+ { \
1239
+ if(pqm->trace_level) \
1240
+ printf ("WMQ::QueueManager#execute() raise WMQ::WMQException\n"); \
1241
+ \
1242
+ rb_raise(wmq_exception, \
1243
+ "WMQ::QueueManager#execute(). Failed:%s, reason:%s", \
1244
+ ACTION, \
1245
+ wmq_reason(pqm->reason_code)); \
1246
+ } \
1247
+ return Qfalse; \
1248
+ }
1249
+
1250
+ static int QueueManager_execute_each (VALUE key, VALUE value, PQUEUE_MANAGER pqm)
1251
+ {
1252
+ MQLONG selector_type, selector;
1253
+ VALUE str;
1254
+ ID selector_id = rb_to_id(key);
1255
+
1256
+ if(pqm->trace_level > 1)
1257
+ {
1258
+ str = rb_funcall(key, rb_intern("to_s"), 0);
1259
+ printf ("WMQ::QueueManager#execute_each Key:%s\n", RSTRING_PTR(str));
1260
+ }
1261
+
1262
+ if (ID_command == selector_id) // Skip :command
1263
+ {
1264
+ return 0;
1265
+ }
1266
+
1267
+ wmq_selector(selector_id, &selector_type, &selector);
1268
+ if(NIL_P(value))
1269
+ {
1270
+ pqm->mqAddInquiry(pqm->admin_bag, selector, &pqm->comp_code, &pqm->reason_code);
1271
+ CHECK_COMPLETION_CODE("Adding Inquiry to the admin bag")
1272
+ return 0;
1273
+ }
1274
+
1275
+ switch (selector_type)
1276
+ {
1277
+ case MQIT_INTEGER:
1278
+ if(TYPE(value) == T_SYMBOL) /* Translate symbol to MQ selector value */
1279
+ {
1280
+ MQLONG val_selector, val_selector_type;
1281
+ wmq_selector(rb_to_id(value), &val_selector_type, &val_selector);
1282
+
1283
+ pqm->mqAddInteger(pqm->admin_bag, selector, val_selector, &pqm->comp_code, &pqm->reason_code);
1284
+ }
1285
+ else
1286
+ {
1287
+ pqm->mqAddInteger(pqm->admin_bag, selector, NUM2LONG(value), &pqm->comp_code, &pqm->reason_code);
1288
+ }
1289
+ CHECK_COMPLETION_CODE("Adding Queue Type to the admin bag")
1290
+ break;
1291
+
1292
+ case MQIT_STRING:
1293
+ str = StringValue(value);
1294
+ pqm->mqAddString(pqm->admin_bag, selector, MQBL_NULL_TERMINATED, RSTRING_PTR(str), &pqm->comp_code, &pqm->reason_code);
1295
+ CHECK_COMPLETION_CODE("Adding Queue name to the admin bag")
1296
+ break;
1297
+
1298
+ default:
1299
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute_each Unknown selector type returned by wmq_selector()");
1300
+ break;
1301
+ }
1302
+ return 0;
1303
+ }
1304
+
1305
+ /*
1306
+ * call-seq:
1307
+ * execute(...)
1308
+ *
1309
+ * Execute an Administration command against the local queue manager
1310
+ *
1311
+ * Parameters:
1312
+ * * Since the number of parameters can vary dramatically, all parameters are passed by name in a hash
1313
+ * * The entire MQ Administration interface has been implemented.
1314
+ * Rather than re-documentation the hundreds of options, a standard
1315
+ * convention has been used to map the MQ constants to Symbols in Ruby.
1316
+ *
1317
+ * For all MQ Admin commands, just drop the MQAI_ off the front and
1318
+ * convert the command name to lower case.
1319
+ * * E.g. MQAI_INQUIRE_Q becomes inquire_q
1320
+ *
1321
+ * For the hundreds of parameters, a similiar technique is followed.
1322
+ * Remove the prefixes: MQCA_, MQIA_, etc.. and convert to lowercase
1323
+ * * E.g. MQCA_Q_NAME becomes :q_name
1324
+ *
1325
+ * Example
1326
+ * WMQ::QueueManager.connect do |qmgr|
1327
+ * result = qmgr.execute(
1328
+ * :command => :inquire_q,
1329
+ * :q_name => 'MY.LOCAL.QUEUE',
1330
+ * :q_type => WMQ::MQQT_LOCAL,
1331
+ * :current_q_depth => nil
1332
+ * )
1333
+ * # OR, we can replace the method name execute with the MQAI command:
1334
+ * result = qmgr.inquire_q(
1335
+ * :q_name => 'MY.LOCAL.QUEUE',
1336
+ * :q_type => WMQ::MQQT_LOCAL,
1337
+ * :current_q_depth => nil
1338
+ * )
1339
+ *
1340
+ * Complete Example:
1341
+ * require 'wmq/wmq'
1342
+ * require 'wmq/wmq_const_admin'
1343
+ * WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
1344
+ * qmgr.reset_q_stats(:q_name=>'*').each {|item| p item }
1345
+ * end
1346
+ *
1347
+ * Some one line examples
1348
+ * qmgr.inquire_q(:q_name=>'TEST*').each {|item| p item }
1349
+ *
1350
+ * qmgr.inquire_q(:q_name=>'TEST*', :q_type=>WMQ::MQQT_LOCAL, :current_q_depth=>nil).each {|item| p item }
1351
+ *
1352
+ * qmgr.inquire_process(:process_name=>'*').each {|item| p item }
1353
+ *
1354
+ * qmgr.ping_q_mgr.each {|item| p item }
1355
+ *
1356
+ * qmgr.refresh_security.each {|item| p item }
1357
+ *
1358
+ * qmgr.inquire_q_status(:q_name=>'TEST*', :q_status_type=>:q_status, :q_status_attrs=>:process_id).each {|item| p item }
1359
+ *
1360
+ * qmgr.start_channel_listener.each {|item| p item }
1361
+ *
1362
+ * qmgr.inquire_channel_status(:channel_name=>'*').each {|item| p item }
1363
+ */
1364
+ VALUE QueueManager_execute(VALUE self, VALUE hash)
1365
+ {
1366
+ #ifdef MQHB_UNUSABLE_HBAG
1367
+ VALUE val;
1368
+ PQUEUE_MANAGER pqm;
1369
+ Data_Get_Struct(self, QUEUE_MANAGER, pqm);
1370
+
1371
+ Check_Type(hash, T_HASH);
1372
+
1373
+ if (pqm->admin_bag == MQHB_UNUSABLE_HBAG) /* Lazy create admin bag */
1374
+ {
1375
+ pqm->mqCreateBag(MQCBO_ADMIN_BAG, &pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
1376
+ CHECK_COMPLETION_CODE("Creating the admin bag")
1377
+ }
1378
+ else
1379
+ {
1380
+ pqm->mqClearBag(pqm->admin_bag, &pqm->comp_code, &pqm->reason_code);
1381
+ CHECK_COMPLETION_CODE("Clearing the admin bag")
1382
+ }
1383
+
1384
+ if (pqm->reply_bag == MQHB_UNUSABLE_HBAG) /* Lazy create reply bag */
1385
+ {
1386
+ pqm->mqCreateBag(MQCBO_ADMIN_BAG, &pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
1387
+ CHECK_COMPLETION_CODE("Creating the reply bag")
1388
+ }
1389
+ else
1390
+ {
1391
+ pqm->mqClearBag(pqm->reply_bag, &pqm->comp_code, &pqm->reason_code);
1392
+ CHECK_COMPLETION_CODE("Clearing the reply bag")
1393
+ }
1394
+
1395
+ val = rb_hash_aref(hash, ID2SYM(ID_command)); /* :command */
1396
+ if (NIL_P(val))
1397
+ {
1398
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute Mandatory parameter :command missing");
1399
+ }
1400
+ rb_hash_foreach(hash, QueueManager_execute_each, (VALUE)pqm);
1401
+ if(pqm->trace_level) printf ("WMQ::QueueManager#execute() Queue Manager Handle:%ld\n", (long)pqm->hcon);
1402
+
1403
+ pqm->mqExecute(
1404
+ pqm->hcon, /* MQ connection handle */
1405
+ wmq_command_lookup(rb_to_id(val)), /* Command to be executed */
1406
+ MQHB_NONE, /* No options bag */
1407
+ pqm->admin_bag, /* Handle to bag containing commands */
1408
+ pqm->reply_bag, /* Handle to bag to receive the response*/
1409
+ MQHO_NONE, /* Put msg on SYSTEM.ADMIN.COMMAND.QUEUE*/
1410
+ MQHO_NONE, /* Create a dynamic q for the response */
1411
+ &pqm->comp_code, /* Completion code from the mqexecute */
1412
+ &pqm->reason_code); /* Reason code from mqexecute call */
1413
+
1414
+ if(pqm->trace_level) printf("WMQ::QueueManager#execute() completed with reason:%s\n", wmq_reason(pqm->reason_code));
1415
+
1416
+ if (pqm->comp_code == MQCC_OK)
1417
+ {
1418
+ MQLONG numberOfBags; /* number of bags in response bag */
1419
+ MQHBAG qAttrsBag; /* bag containing q attributes */
1420
+ VALUE array;
1421
+ MQLONG size;
1422
+ MQLONG length;
1423
+ MQCHAR inquiry_buffer[WMQ_EXEC_STRING_INQ_BUFFER_SIZE];
1424
+ PMQCHAR pChar;
1425
+
1426
+ MQLONG qDepth; /* depth of queue */
1427
+ MQLONG item_type;
1428
+ MQLONG selector;
1429
+ MQLONG number_of_items;
1430
+ int bag_index, items, k;
1431
+
1432
+ pqm->mqCountItems(pqm->reply_bag, MQHA_BAG_HANDLE, &numberOfBags, &pqm->comp_code, &pqm->reason_code);
1433
+ CHECK_COMPLETION_CODE("Counting number of bags returned from the command server")
1434
+
1435
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager#execute() %ld bags returned\n", (long)numberOfBags);
1436
+ array = rb_ary_new2(numberOfBags);
1437
+
1438
+ for ( bag_index=0; bag_index<numberOfBags; bag_index++) /* For each bag, extract the queue depth */
1439
+ {
1440
+ hash = rb_hash_new();
1441
+
1442
+ pqm->mqInquireBag(pqm->reply_bag, MQHA_BAG_HANDLE, bag_index, &qAttrsBag, &pqm->comp_code, &pqm->reason_code);
1443
+ CHECK_COMPLETION_CODE("Inquiring for the attribute bag handle")
1444
+
1445
+ pqm->mqCountItems(qAttrsBag, MQSEL_ALL_SELECTORS, &number_of_items, &pqm->comp_code, &pqm->reason_code);
1446
+ CHECK_COMPLETION_CODE("Counting number of items in this bag")
1447
+
1448
+ if(pqm->trace_level > 1) printf("WMQ::QueueManager#execute() Bag %d contains %ld items\n", bag_index, (long)number_of_items);
1449
+
1450
+ for (items=0; items<number_of_items; items++) /* For each item, extract it's value */
1451
+ {
1452
+ pqm->mqInquireItemInfo(
1453
+ qAttrsBag, /* I: Bag handle */
1454
+ MQSEL_ANY_SELECTOR, /* I: Item selector */
1455
+ items, /* I: Item index */
1456
+ &selector, /* O: Selector of item */
1457
+ &item_type, /* O: Data type of item */
1458
+ &pqm->comp_code,
1459
+ &pqm->reason_code);
1460
+ CHECK_COMPLETION_CODE("Inquiring Item details")
1461
+
1462
+ if (selector > 0) /* Skip system selectors */
1463
+ {
1464
+ switch (item_type)
1465
+ {
1466
+ case MQIT_INTEGER:
1467
+ pqm->mqInquireInteger(qAttrsBag, MQSEL_ALL_SELECTORS, items, &qDepth, &pqm->comp_code, &pqm->reason_code);
1468
+ CHECK_COMPLETION_CODE("Inquiring Integer item")
1469
+
1470
+ if(pqm->trace_level > 1)
1471
+ printf("WMQ::QueueManager#execute() Item %d: Integer:%ld, selector:%ld\n", items, (long)qDepth, (long)selector);
1472
+
1473
+ rb_hash_aset(hash, ID2SYM(wmq_selector_id(selector)), LONG2NUM(qDepth));
1474
+ break;
1475
+
1476
+ case MQIT_STRING:
1477
+ pqm->mqInquireString(qAttrsBag, MQSEL_ALL_SELECTORS, items, WMQ_EXEC_STRING_INQ_BUFFER_SIZE-1, inquiry_buffer,
1478
+ &size, NULL, &pqm->comp_code, &pqm->reason_code);
1479
+ if(pqm->trace_level > 2)
1480
+ printf("WMQ::QueueManager#execute() mqInquireString buffer size: %d, string size:%ld\n",
1481
+ WMQ_EXEC_STRING_INQ_BUFFER_SIZE,(long)size);
1482
+ CHECK_COMPLETION_CODE("Inquiring String item")
1483
+
1484
+ length = 0;
1485
+ pChar = inquiry_buffer + size-1;
1486
+ for (k = size; k > 0; k--)
1487
+ {
1488
+ if (*pChar != ' ' && *pChar != 0)
1489
+ {
1490
+ length = k;
1491
+ break;
1492
+ }
1493
+ pChar--;
1494
+ }
1495
+ rb_hash_aset(hash, ID2SYM(wmq_selector_id(selector)), rb_str_new(inquiry_buffer, length));
1496
+
1497
+ if(pqm->trace_level > 1)
1498
+ {
1499
+ inquiry_buffer[length] = '\0';
1500
+ printf("WMQ::QueueManager#execute() Item %d: String:'%s', selector:%ld\n",
1501
+ items, inquiry_buffer, (long)selector);
1502
+ }
1503
+ break;
1504
+
1505
+ case MQIT_BAG:
1506
+ printf("Ignoring Bag at this level\n");
1507
+ break;
1508
+
1509
+ default:
1510
+ printf("Ignoring Unknown type:%ld\n", (long)item_type);
1511
+ break;
1512
+ }
1513
+ }
1514
+ }
1515
+ rb_ary_push(array, hash);
1516
+ }
1517
+ return array;
1518
+ }
1519
+ else
1520
+ {
1521
+ VALUE name = rb_iv_get(self,"@name");
1522
+ name = StringValue(name);
1523
+
1524
+ if (pqm->reason_code == MQRCCF_COMMAND_FAILED)
1525
+ {
1526
+ /* Find out why admin command failed */
1527
+ MQLONG result_comp_code, result_reason_code;
1528
+ MQHBAG result_bag;
1529
+
1530
+ pqm->mqInquireBag(pqm->reply_bag, MQHA_BAG_HANDLE, 0, &result_bag, &pqm->comp_code, &pqm->reason_code);
1531
+ CHECK_COMPLETION_CODE("Getting the result bag handle")
1532
+
1533
+ pqm->mqInquireInteger(result_bag, MQIASY_COMP_CODE, MQIND_NONE, &result_comp_code, &pqm->comp_code, &pqm->reason_code);
1534
+ CHECK_COMPLETION_CODE("Getting the completion code from the result bag")
1535
+
1536
+ pqm->mqInquireInteger(result_bag, MQIASY_REASON, MQIND_NONE, &result_reason_code, &pqm->comp_code, &pqm->reason_code);
1537
+ CHECK_COMPLETION_CODE("Getting the reason code from the result bag")
1538
+
1539
+ pqm->comp_code = result_comp_code;
1540
+ pqm->reason_code = result_reason_code;
1541
+
1542
+ if(pqm->trace_level)
1543
+ printf("WMQ::QueueManager#execute() Error returned by command server:%s\n", wmq_reason(pqm->reason_code));
1544
+ }
1545
+
1546
+ if (pqm->exception_on_error)
1547
+ {
1548
+ if (pqm->reason_code == MQRC_CMD_SERVER_NOT_AVAILABLE)
1549
+ {
1550
+ rb_raise(wmq_exception,
1551
+ "WMQ::QueueManager#execute(). Please start the WebSphere MQ Command Server : 'strmqcsv %s', reason:%s",
1552
+ RSTRING_PTR(name),
1553
+ wmq_reason(pqm->reason_code));
1554
+ }
1555
+ else
1556
+ {
1557
+ rb_raise(wmq_exception,
1558
+ "WMQ::QueueManager#execute(). Error executing admin command on Queue Manager:%s, reason:%s",
1559
+ RSTRING_PTR(name),
1560
+ wmq_reason(pqm->reason_code));
1561
+ }
1562
+ }
1563
+ return Qfalse;
1564
+ }
1565
+ return Qnil;
1566
+ #else
1567
+ rb_notimplement();
1568
+ return Qfalse;
1569
+ #endif
1570
+ }