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