rubywmq 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +8 -0
- data/LICENSE +13 -0
- data/README +73 -0
- data/examples/each_a.rb +31 -0
- data/examples/each_b.rb +40 -0
- data/examples/each_header.rb +37 -0
- data/examples/files_to_q.cfg +24 -0
- data/examples/files_to_q.rb +47 -0
- data/examples/get_a.rb +34 -0
- data/examples/get_client.rb +50 -0
- data/examples/put1_a.rb +24 -0
- data/examples/put1_b.rb +32 -0
- data/examples/put1_c.rb +31 -0
- data/examples/put_a.rb +34 -0
- data/examples/put_b.rb +42 -0
- data/examples/put_dlh.rb +40 -0
- data/examples/put_dynamic_q.rb +37 -0
- data/examples/put_rfh.rb +66 -0
- data/examples/put_rfh2_a.rb +42 -0
- data/examples/put_rfh2_b.rb +42 -0
- data/examples/put_xmit_q.rb +32 -0
- data/examples/request.rb +59 -0
- data/examples/server.rb +96 -0
- data/ext/build.bat +3 -0
- data/ext/build.sh +5 -0
- data/ext/decode_rfh.c +348 -0
- data/ext/decode_rfh.h +45 -0
- data/ext/extconf.rb +44 -0
- data/ext/extconf_client.rb +40 -0
- data/ext/generate/generate_const.rb +167 -0
- data/ext/generate/generate_reason.rb +240 -0
- data/ext/generate/generate_structs.rb +99 -0
- data/ext/generate/wmq_structs.erb +388 -0
- data/ext/lib/wmq_temp.rb +197 -0
- data/ext/wmq.c +93 -0
- data/ext/wmq.h +324 -0
- data/ext/wmq_message.c +686 -0
- data/ext/wmq_mq_load.c +213 -0
- data/ext/wmq_queue.c +1410 -0
- data/ext/wmq_queue_manager.c +1592 -0
- data/lib/wmq.rb +25 -0
- data/tests/test.rb +299 -0
- metadata +87 -0
@@ -0,0 +1,388 @@
|
|
1
|
+
<%
|
2
|
+
################################################################################
|
3
|
+
# Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
|
4
|
+
#
|
5
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
6
|
+
# you may not use this file except in compliance with the License.
|
7
|
+
# You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
13
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
14
|
+
# See the License for the specific language governing permissions and
|
15
|
+
# limitations under the License.
|
16
|
+
################################################################################
|
17
|
+
|
18
|
+
symbols = {
|
19
|
+
'descriptor='=>nil,
|
20
|
+
'headers='=>nil,
|
21
|
+
'data='=>nil,
|
22
|
+
'header_type'=>nil,
|
23
|
+
'to_s'=>nil,
|
24
|
+
'xml'=>nil,
|
25
|
+
'name_value'=>nil,
|
26
|
+
}
|
27
|
+
wmq_structs = [
|
28
|
+
# Message Descriptor
|
29
|
+
{:file=>'cmqc.h', :struct=>'MQMD'},
|
30
|
+
|
31
|
+
# Message Descriptor 1
|
32
|
+
{:file=>'cmqc.h', :struct=>'MQMD1', :other_keys=>[:remote_q_name, :remote_q_mgr_name]},
|
33
|
+
|
34
|
+
# Rules and formatting header2
|
35
|
+
{:file=>'cmqc.h', :struct=>'MQRFH2', :header=>'rf_header_2', :struct_id=>'MQRFH_STRUC_ID',
|
36
|
+
:other_keys=>[:xml],
|
37
|
+
:custom=>true }, # Implement custom Message_build_rf_header_2 and Message_deblock_rf_header_2
|
38
|
+
|
39
|
+
# Rules and formatting header
|
40
|
+
{:file=>'cmqc.h', :struct=>'MQRFH', :header=>'rf_header', :other_keys=>[:name_value],
|
41
|
+
:custom=>true }, # Implement custom Message_build_rf_header and Message_deblock_rf_header
|
42
|
+
|
43
|
+
# Dead Letter Header
|
44
|
+
{:file=>'cmqc.h', :struct=>'MQDLH', :header=>'dead_letter_header',
|
45
|
+
:defaults=>'MQDLH_DEF.CodedCharSetId = MQCCSI_INHERIT;'},
|
46
|
+
|
47
|
+
# CICS bridge header
|
48
|
+
{:file=>'cmqc.h', :struct=>'MQCIH', :header=>'cics'},
|
49
|
+
|
50
|
+
# Distribution header
|
51
|
+
{:file=>'cmqc.h', :struct=>'MQDH', :header=>'dist_header'},
|
52
|
+
|
53
|
+
# IMS information header
|
54
|
+
{:file=>'cmqc.h', :struct=>'MQIIH', :header=>'ims'},
|
55
|
+
|
56
|
+
# Reference message header (send large files over channels)
|
57
|
+
{:file=>'cmqc.h', :struct=>'MQRMH', :header=>'ref_msg_header'},
|
58
|
+
|
59
|
+
# Trigger Message
|
60
|
+
{:file=>'cmqc.h', :struct=>'MQTM', :header=>'trigger', :format=>false},
|
61
|
+
|
62
|
+
# Trigger Message 2 (character format)
|
63
|
+
{:file=>'cmqc.h', :struct=>'MQTMC2'},
|
64
|
+
|
65
|
+
# Work Information header
|
66
|
+
{:file=>'cmqc.h', :struct=>'MQWIH', :header=>'work_info_header'},
|
67
|
+
|
68
|
+
# Transmission-queue header - Todo: Need to deal with MQMDE
|
69
|
+
{:file=>'cmqc.h', :struct=>'MQXQH', :header=>'xmit_q_header', :format=>'MsgDesc.Format'},
|
70
|
+
]
|
71
|
+
|
72
|
+
wmq_structs.each do |struct|
|
73
|
+
# Parse WebSphere MQ 'C' Header file and extract elements
|
74
|
+
elements = extract_struct(@path+'/'+struct[:file], struct[:struct])
|
75
|
+
struct[:elements] = elements
|
76
|
+
|
77
|
+
# Add symbol for each struct name
|
78
|
+
symbols[struct[:header]]=nil if struct[:header]
|
79
|
+
|
80
|
+
# Add symbols for each element in C Struct
|
81
|
+
elements.each do |item|
|
82
|
+
symbols[rubyize_name(item[1])] = nil unless @@field_ignore_list.include?(item[1])
|
83
|
+
end
|
84
|
+
end
|
85
|
+
%>
|
86
|
+
/* --------------------------------------------------------------------------
|
87
|
+
* Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
|
88
|
+
*
|
89
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
90
|
+
* you may not use this file except in compliance with the License.
|
91
|
+
* You may obtain a copy of the License at
|
92
|
+
*
|
93
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
94
|
+
*
|
95
|
+
* Unless required by applicable law or agreed to in writing, software
|
96
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
97
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
98
|
+
* See the License for the specific language governing permissions and
|
99
|
+
* limitations under the License.
|
100
|
+
* --------------------------------------------------------------------------
|
101
|
+
*
|
102
|
+
* WARNING: DO NOT MODIFY THIS FILE
|
103
|
+
*
|
104
|
+
* This file was generated by generate_structs.rb.
|
105
|
+
*
|
106
|
+
* --------------------------------------------------------------------------*/
|
107
|
+
|
108
|
+
#include "wmq.h"
|
109
|
+
|
110
|
+
/* --------------------------------------------------------------------------
|
111
|
+
* Static's to hold Symbols
|
112
|
+
* --------------------------------------------------------------------------*/
|
113
|
+
<%
|
114
|
+
header_file = 'cmqc.h'
|
115
|
+
struct = 'MQMD'
|
116
|
+
|
117
|
+
# Define static variables to hold Ruby symbols
|
118
|
+
key_list = symbols.keys.sort
|
119
|
+
key_list.each do |key, value|
|
120
|
+
%><%="static ID ID_#{key.sub('=', '_set')};\n" %><%
|
121
|
+
end
|
122
|
+
|
123
|
+
# initialize symbols
|
124
|
+
%>
|
125
|
+
/* --------------------------------------------------------------------------
|
126
|
+
* Initialize Symbols
|
127
|
+
* --------------------------------------------------------------------------*/
|
128
|
+
void wmq_structs_id_init()
|
129
|
+
{
|
130
|
+
<% key_list.each do |key, value|
|
131
|
+
%><%=" ID_%-20s = rb_intern(\"%s\");\n"% [key.sub('=', '_set'), key] %><%
|
132
|
+
end
|
133
|
+
%>}
|
134
|
+
<%
|
135
|
+
# Generate functions to move to/from a Ruby Hash of the symbols defined above
|
136
|
+
wmq_structs.each do |struct|
|
137
|
+
elements = struct[:elements]
|
138
|
+
struct_name = struct[:struct]
|
139
|
+
variable = 'p'+struct_name.downcase
|
140
|
+
%>
|
141
|
+
/* --------------------------------------------------------------------------
|
142
|
+
* Convert between <%=struct_name%> and Hash
|
143
|
+
* --------------------------------------------------------------------------*/
|
144
|
+
void Message_from_<%=struct_name.downcase%>(VALUE hash, <%=struct_name%>* <%=variable%>)
|
145
|
+
{
|
146
|
+
VALUE str;
|
147
|
+
size_t size;
|
148
|
+
size_t length;
|
149
|
+
size_t i;
|
150
|
+
char* pChar;
|
151
|
+
|
152
|
+
<%
|
153
|
+
elements.each do |item|
|
154
|
+
type = item[0]
|
155
|
+
name = item[1]
|
156
|
+
|
157
|
+
next if @@field_ignore_list.include?(name) ||
|
158
|
+
(name=='Format' && struct[:header])
|
159
|
+
|
160
|
+
match = /(MQ\D+)/.match(type)
|
161
|
+
type = "#{match[1]}S" if match[1] != type
|
162
|
+
%><%= if type == 'MQMDS'
|
163
|
+
" %-16s(hash, &#{variable}->%s);\n" % ['Message_from_mqmd1', name]
|
164
|
+
else
|
165
|
+
" %-16s(hash, %-30s #{variable}->%s)\n" % ["WMQ_#{type}2HASH", rubyize_name(name)+',',name]
|
166
|
+
end %><%
|
167
|
+
end
|
168
|
+
%>}
|
169
|
+
|
170
|
+
#if RUBY_VERSION_CODE > 183
|
171
|
+
static int Message_to_<%=struct_name.downcase%>_each (VALUE key, VALUE value, <%=struct_name%>* p<%=struct_name.downcase%>)
|
172
|
+
{
|
173
|
+
#else
|
174
|
+
static int Message_to_<%=struct_name.downcase%>_each (VALUE array, <%=struct_name%>* p<%=struct_name.downcase%>)
|
175
|
+
{
|
176
|
+
VALUE key = rb_ary_shift(array);
|
177
|
+
VALUE value = rb_ary_shift(array);
|
178
|
+
#endif
|
179
|
+
VALUE str;
|
180
|
+
size_t size;
|
181
|
+
size_t length;
|
182
|
+
VALUE val;
|
183
|
+
ID id = rb_to_id(key);
|
184
|
+
|
185
|
+
<% contains = nil
|
186
|
+
elements.each do |item|
|
187
|
+
type = item[0]
|
188
|
+
name = item[1]
|
189
|
+
|
190
|
+
next if @@field_ignore_list.include?(name) ||
|
191
|
+
(name=='Format' && struct[:header])
|
192
|
+
|
193
|
+
match = /(MQ\D+)/.match(type)
|
194
|
+
type = "#{match[1]}S" if match[1] != type
|
195
|
+
%><%= if type == 'MQMDS'
|
196
|
+
contains = 'mqmd1'
|
197
|
+
""
|
198
|
+
else
|
199
|
+
"%-35s { %-16s(value,#{variable}->#{name}) }\n else" % [" if(id == ID_#{rubyize_name(name)})", "WMQ_STR2#{type}"]
|
200
|
+
end%><%
|
201
|
+
end
|
202
|
+
if struct[:other_keys]
|
203
|
+
struct[:other_keys].each do |key|
|
204
|
+
%> if(id == ID_<%=key.to_s%>) {}
|
205
|
+
else<% end
|
206
|
+
end
|
207
|
+
%><%=struct[:header]?" if(id != ID_header_type)":""%><%
|
208
|
+
if contains
|
209
|
+
%> {
|
210
|
+
#if RUBY_VERSION_CODE > 183
|
211
|
+
Message_to_<%= contains%>_each(key, value, &pmqxqh->MsgDesc);
|
212
|
+
#else
|
213
|
+
rb_ary_push(array, key);
|
214
|
+
rb_ary_push(array, value);
|
215
|
+
Message_to_<%= contains%>_each(array, &pmqxqh->MsgDesc);
|
216
|
+
#endif
|
217
|
+
}<%
|
218
|
+
else%>
|
219
|
+
{
|
220
|
+
val = rb_funcall(key, ID_to_s, 0);
|
221
|
+
rb_raise(rb_eArgError, "WMQ::Message#to_<%=struct_name.downcase%> Unknown symbol :%s supplied", RSTRING(val)->ptr);
|
222
|
+
}
|
223
|
+
<% end%>
|
224
|
+
return 0;
|
225
|
+
}
|
226
|
+
|
227
|
+
void Message_to_<%=struct_name.downcase%>(VALUE hash, <%=struct_name%>* p<%=struct_name.downcase%>)
|
228
|
+
{
|
229
|
+
#if RUBY_VERSION_CODE > 183
|
230
|
+
rb_hash_foreach(hash, Message_to_<%=struct_name.downcase%>_each, (VALUE)p<%=struct_name.downcase%>);
|
231
|
+
#else
|
232
|
+
rb_iterate (rb_each, hash, Message_to_<%=struct_name.downcase%>_each, (VALUE)p<%=struct_name.downcase%>);
|
233
|
+
#endif
|
234
|
+
}
|
235
|
+
<% end # wmq_structs.each
|
236
|
+
%>
|
237
|
+
|
238
|
+
/* --------------------------------------------------------------------------
|
239
|
+
* Extract message data and headers
|
240
|
+
* --------------------------------------------------------------------------*/
|
241
|
+
void Message_deblock(VALUE self, PMQMD pmqmd, PMQBYTE p_buffer, MQLONG total_length, MQLONG trace_level)
|
242
|
+
{
|
243
|
+
PMQCHAR p_format = pmqmd->Format; /* Start with format in MQMD */
|
244
|
+
PMQBYTE p_data = p_buffer; /* Pointer to start of data */
|
245
|
+
MQLONG data_length= total_length; /* length of data portion */
|
246
|
+
VALUE headers = rb_ary_new();
|
247
|
+
VALUE descriptor = rb_hash_new();
|
248
|
+
MQLONG size = 0;
|
249
|
+
|
250
|
+
while (p_format)
|
251
|
+
{
|
252
|
+
<%
|
253
|
+
wmq_structs.each do |struct|
|
254
|
+
if struct[:header]
|
255
|
+
%> /* <%=struct[:struct]%>: <%=struct[:header]%> */
|
256
|
+
if(strncmp(p_format, MQFMT_<%=struct[:header].upcase%>, MQ_FORMAT_LENGTH) == 0)
|
257
|
+
{
|
258
|
+
VALUE hash = rb_hash_new();
|
259
|
+
P<%=struct[:struct]%> p_header = (P<%=struct[:struct]%>)p_data;
|
260
|
+
|
261
|
+
if(trace_level>2)
|
262
|
+
printf("WMQ::Message#deblock Found <%=struct[:header]%>\n");
|
263
|
+
|
264
|
+
if(memcmp(p_header->StrucId, <%=struct[:struct_id] || "#{struct[:struct].upcase}_STRUC_ID"%>, sizeof(p_header->StrucId)) != 0)
|
265
|
+
{
|
266
|
+
break; /* Bad Message received, do not deblock headers */
|
267
|
+
if(trace_level>1)
|
268
|
+
printf("WMQ::Message#deblock MQFMT_<%=struct[:header].upcase%> received, but message does not contain <%=struct[:struct].upcase%>\n");
|
269
|
+
}
|
270
|
+
else
|
271
|
+
{
|
272
|
+
Message_from_<%=struct[:struct].downcase%>(hash, p_header);
|
273
|
+
rb_hash_aset(hash, ID2SYM(ID_header_type), ID2SYM(ID_<%=struct[:header]%>));
|
274
|
+
rb_ary_push(headers, hash);
|
275
|
+
size = <%=if struct[:custom] then
|
276
|
+
"Message_deblock_#{struct[:header]} (hash, p_data, data_length);\n"+
|
277
|
+
" if (!size) break; /* Poison Message */"
|
278
|
+
elsif struct[:elements].include?(['MQLONG', 'StrucLength'])
|
279
|
+
'p_header->StrucLength;'
|
280
|
+
else
|
281
|
+
"sizeof(#{struct[:struct]});"
|
282
|
+
end %>
|
283
|
+
p_data += size;
|
284
|
+
data_length -= size;
|
285
|
+
<%=if struct[:format] == nil
|
286
|
+
'p_format = p_header->Format'
|
287
|
+
elsif struct[:format] == false
|
288
|
+
'break'
|
289
|
+
else
|
290
|
+
"p_format = p_header->#{struct[:format]}"
|
291
|
+
end %>;
|
292
|
+
}
|
293
|
+
}
|
294
|
+
else
|
295
|
+
<%
|
296
|
+
end
|
297
|
+
end # wmq_structs.each
|
298
|
+
%> {
|
299
|
+
break;
|
300
|
+
}
|
301
|
+
}
|
302
|
+
/* Copy the last recognised header found to the Descriptor */
|
303
|
+
if(p_format && p_format != pmqmd->Format)
|
304
|
+
{
|
305
|
+
strncpy(pmqmd->Format, p_format, MQ_FORMAT_LENGTH);
|
306
|
+
}
|
307
|
+
|
308
|
+
Message_from_mqmd(descriptor, pmqmd);
|
309
|
+
rb_funcall(self, ID_descriptor_set, 1, descriptor);
|
310
|
+
rb_funcall(self, ID_headers_set, 1, headers);
|
311
|
+
rb_funcall(self, ID_data_set, 1, rb_str_new(p_data, data_length));
|
312
|
+
}
|
313
|
+
|
314
|
+
void Message_build_set_format(ID header_type, PMQBYTE p_format)
|
315
|
+
{
|
316
|
+
<%
|
317
|
+
wmq_structs.each do |struct|
|
318
|
+
if struct[:header]
|
319
|
+
%> if(header_type == ID_<%=struct[:header]%>) { memcpy(p_format, MQFMT_<%=struct[:header].upcase%>, MQ_FORMAT_LENGTH); return;}
|
320
|
+
<%
|
321
|
+
end
|
322
|
+
end # wmq_structs.each
|
323
|
+
|
324
|
+
%>
|
325
|
+
rb_raise(rb_eArgError, "Invalid/Unknown header_type supplied in WMQ::Message#headers array");
|
326
|
+
}
|
327
|
+
|
328
|
+
/* --------------------------------------------------------------------------
|
329
|
+
* Build message headers
|
330
|
+
* --------------------------------------------------------------------------*/
|
331
|
+
int Message_build_header (VALUE hash, struct Message_build_header_arg* parg)
|
332
|
+
{
|
333
|
+
VALUE val = rb_hash_aref(hash, ID2SYM(ID_header_type));
|
334
|
+
PMQBYTE p_data = 0;
|
335
|
+
|
336
|
+
if (!NIL_P(val) && (TYPE(val) == T_SYMBOL))
|
337
|
+
{
|
338
|
+
ID header_id = rb_to_id(val);
|
339
|
+
<%
|
340
|
+
wmq_structs.each do |struct|
|
341
|
+
if struct[:header]
|
342
|
+
%> if (header_id == ID_<%=struct[:header]%>) /* Build <%=struct[:struct]%> */
|
343
|
+
{ <%
|
344
|
+
if struct[:custom] %>
|
345
|
+
Message_build_<%=struct[:header]%> (hash, parg);
|
346
|
+
<% else %>
|
347
|
+
static <%=struct[:struct]%> <%=struct[:struct]%>_DEF = {<%=struct[:struct]%>_DEFAULT};
|
348
|
+
<%=struct[:defaults]%>
|
349
|
+
|
350
|
+
if(parg->trace_level>2)
|
351
|
+
printf ("WMQ::Message#build_header Found <%=struct[:header]%>\n");
|
352
|
+
|
353
|
+
p_data = Message_autogrow_data_buffer(parg, sizeof(<%=struct[:struct]%>));
|
354
|
+
|
355
|
+
memcpy(p_data, &<%=struct[:struct]%>_DEF, sizeof(<%=struct[:struct]%>));
|
356
|
+
Message_to_<%=struct[:struct].downcase%>(hash, (P<%=struct[:struct]%>)p_data);
|
357
|
+
<% if struct[:format] != false%>
|
358
|
+
if(parg->next_header_id)
|
359
|
+
{
|
360
|
+
Message_build_set_format(parg->next_header_id, ((P<%=struct[:struct]%>)p_data)-><%=struct[:format] || 'Format'%>);
|
361
|
+
}
|
362
|
+
else
|
363
|
+
{
|
364
|
+
memcpy(((P<%=struct[:struct]%>)p_data)-><%=struct[:format] || 'Format'%>, parg->data_format, MQ_FORMAT_LENGTH);
|
365
|
+
}
|
366
|
+
<% end %>
|
367
|
+
*(parg->p_data_offset) += sizeof(<%=struct[:struct]%>);
|
368
|
+
|
369
|
+
if(parg->trace_level>2)
|
370
|
+
printf ("WMQ::Message#build_header data offset:%ld\n", *(parg->p_data_offset));
|
371
|
+
<% end
|
372
|
+
%> }
|
373
|
+
else
|
374
|
+
<%
|
375
|
+
end
|
376
|
+
end # wmq_structs.each
|
377
|
+
|
378
|
+
%> {
|
379
|
+
rb_raise(rb_eArgError, "Unknown :header_type supplied in WMQ::Message#headers array");
|
380
|
+
}
|
381
|
+
}
|
382
|
+
else
|
383
|
+
{
|
384
|
+
rb_raise(rb_eArgError, "Mandatory parameter :header_type missing from header entry in WMQ::Message#headers array");
|
385
|
+
}
|
386
|
+
|
387
|
+
return 0; /* Continue */
|
388
|
+
}
|
data/ext/lib/wmq_temp.rb
ADDED
@@ -0,0 +1,197 @@
|
|
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
|
+
module WMQ
|
18
|
+
|
19
|
+
# Temporary placeholder until the following code is moved to 'C'
|
20
|
+
|
21
|
+
#
|
22
|
+
class QueueManager
|
23
|
+
def method_missing(name, *args)
|
24
|
+
if args.size == 1
|
25
|
+
self.execute({:command=>name}.merge(args[0]))
|
26
|
+
elsif args.size == 0
|
27
|
+
self.execute({:command=>name})
|
28
|
+
else
|
29
|
+
raise("Invalid arguments supplied to QueueManager#:#{name}, args:#{args}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Execute any MQSC command against the queue manager
|
34
|
+
#
|
35
|
+
# Example
|
36
|
+
# require 'wmq/wmq'
|
37
|
+
# require 'wmq/wmq_const_admin'
|
38
|
+
# WMQ::QueueManager.connect(:q_mgr_name=>'REID', :connection_name=>'localhost(1414)') do |qmgr|
|
39
|
+
# qmgr.mqsc('dis ql(*)').each {|item| p item }
|
40
|
+
# end
|
41
|
+
def mqsc(mqsc_text)
|
42
|
+
self.execute(:command=>:escape, :escape_type=>WMQ::MQET_MQSC, :escape_text=>mqsc_text).collect {|item| item[:escape_text] }
|
43
|
+
end
|
44
|
+
|
45
|
+
# Put a reply message back to the sender
|
46
|
+
#
|
47
|
+
# The :message is sent to the queue and queue manager specified in the
|
48
|
+
# :reply_to_q and :reply_to_q_mgr propoerties of the :request_message.
|
49
|
+
#
|
50
|
+
# The following rules are followed before sending the reply:
|
51
|
+
# - Only send replies to Request messages. No reply for Datagrams
|
52
|
+
# - Set the message type to Reply when replying to a request message
|
53
|
+
# - Reply with:
|
54
|
+
# - Remaining Expiry (Ideally deduct any processing time since get)
|
55
|
+
# - Same priority as received message
|
56
|
+
# - Same persistence as received message
|
57
|
+
# - Adhere to the Report options supplied for message and correlation id's
|
58
|
+
# in reply message
|
59
|
+
# - All headers must be returned on reply messages
|
60
|
+
# - This allows the calling application to store state information
|
61
|
+
# in these headers
|
62
|
+
# - Unless of course if the relevant header is input only and used
|
63
|
+
# for completing the request
|
64
|
+
# - In this case any remaining headers should be returned
|
65
|
+
# to the caller
|
66
|
+
#
|
67
|
+
# Parameters:
|
68
|
+
# * :request_message The message originally received
|
69
|
+
# * All the other parameters are the same as QueueManager#put
|
70
|
+
#
|
71
|
+
def put_to_reply_q(parms)
|
72
|
+
# Send replies only if message type is request
|
73
|
+
if parms[:request_message].descriptor[:msg_type] == WMQ::MQMT_REQUEST
|
74
|
+
request = parms.delete(:request_message)
|
75
|
+
|
76
|
+
reply = parms[:message] ||= Message.new(:data=>parms[:data])
|
77
|
+
reply.descriptor[:msg_type] = WMQ::MQMT_REPLY
|
78
|
+
reply.descriptor[:expiry] = request.descriptor[:expiry]
|
79
|
+
reply.descriptor[:priority] = request.descriptor[:priority]
|
80
|
+
reply.descriptor[:persistence]= request.descriptor[:persistence]
|
81
|
+
reply.descriptor[:format] = request.descriptor[:format]
|
82
|
+
|
83
|
+
# Set Correlation Id based on report options supplied
|
84
|
+
if request.descriptor[:report] & WMQ::MQRO_PASS_CORREL_ID != 0
|
85
|
+
reply.descriptor[:correl_id] = request.descriptor[:correl_id]
|
86
|
+
else
|
87
|
+
reply.descriptor[:correl_id] = request.descriptor[:msg_id]
|
88
|
+
end
|
89
|
+
|
90
|
+
# Set Message Id based on report options supplied
|
91
|
+
if request.descriptor[:report] & WMQ::MQRO_PASS_MSG_ID != 0
|
92
|
+
reply.descriptor[:msg_id] = request.descriptor[:msg_id]
|
93
|
+
end
|
94
|
+
|
95
|
+
parms[:q_name] = request.descriptor[:reply_to_q]
|
96
|
+
parms[:q_mgr_name]= request.descriptor[:reply_to_q_mgr]
|
97
|
+
return put(parms)
|
98
|
+
else
|
99
|
+
return false
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# Put a message to the Dead Letter Queue
|
104
|
+
#
|
105
|
+
# If an error occurs when processing a datagram message
|
106
|
+
# it is necessary to move the message to the dead letter queue.
|
107
|
+
# I.e. An error message cannot be sent back to the sender because
|
108
|
+
# the original message was not a request message.
|
109
|
+
# I.e. msg_type != WMQ::MQMT_REQUEST
|
110
|
+
#
|
111
|
+
# All existing message data, message descriptor and message headers
|
112
|
+
# are retained.
|
113
|
+
#
|
114
|
+
def put_to_dead_letter_q(parms)
|
115
|
+
message = parms[:message] ||= Message.new(:data=>parms[:data])
|
116
|
+
dlh = {
|
117
|
+
:header_type =>:dead_letter_header,
|
118
|
+
:reason =>parms.delete(:reason),
|
119
|
+
:dest_q_name =>parms.delete(:q_name),
|
120
|
+
:dest_q_mgr_name =>self.name}
|
121
|
+
|
122
|
+
message.headers.unshift(dlh)
|
123
|
+
parms[:q_name]='SYSTEM.DEAD.LETTER.QUEUE' #TODO Should be obtained from QMGR config
|
124
|
+
return self.put(parms)
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
128
|
+
|
129
|
+
# Message contains the message descriptor (MQMD), data
|
130
|
+
# and any headers.
|
131
|
+
#
|
132
|
+
# Note:
|
133
|
+
# * The format in the descriptor applies only to the format of the data portion,
|
134
|
+
# not the format of any included headers
|
135
|
+
# * The message format can ONLY be supplied in the descriptor.
|
136
|
+
# * I.e. It is the format of the data, Not the headers.
|
137
|
+
# * On the wire formats are determined automatically by the :header_type key for
|
138
|
+
# each header
|
139
|
+
# * Other WebSphere MQ interfaces require that the formats be "daisy-chained"
|
140
|
+
# * I.e. The MQMD.Format is actually the format of the first header
|
141
|
+
# * Ruby WMQ removes this tedious requirement and performs this
|
142
|
+
# requirement automatically under the covers
|
143
|
+
# * The format of any header should not be supplied in the descriptor or any header
|
144
|
+
#
|
145
|
+
# Message has the following attributes:
|
146
|
+
# * descriptor = {
|
147
|
+
# # WebSphere MQ Equivalent
|
148
|
+
# :format => WMQ::MQFMT_STRING, # MQMD.Format - Format of data only
|
149
|
+
# WMQ::MQFMT_NONE # Do not supply header formats here
|
150
|
+
# :original_length => Number # MQMD.OriginalLength
|
151
|
+
# :priority => 0 .. 9 # MQMD.Priority
|
152
|
+
# :put_time => String # MQMD.PutTime
|
153
|
+
# :msg_id => String ...
|
154
|
+
# :expiry => Number
|
155
|
+
# :persistence => Number
|
156
|
+
# :reply_to_q => String
|
157
|
+
# :correl_id => String
|
158
|
+
# :feedback => Number
|
159
|
+
# :offset => Number
|
160
|
+
# :report => Number
|
161
|
+
# :msg_flags => Number
|
162
|
+
# :reply_to_q_mgr => String
|
163
|
+
# :appl_identity_data => String
|
164
|
+
# :put_appl_name => String
|
165
|
+
# :user_identifier => String
|
166
|
+
# :msg_seq_number => Number
|
167
|
+
# :appl_origin_data => String
|
168
|
+
# :accounting_token => String
|
169
|
+
# :backout_count => Number
|
170
|
+
# :coded_char_set_id => Number
|
171
|
+
# :put_appl_type => Number
|
172
|
+
# :msg_type => Number
|
173
|
+
# :group_id => String
|
174
|
+
# :put_date => String
|
175
|
+
# :encoding => Number
|
176
|
+
# }
|
177
|
+
# * data => String
|
178
|
+
# * headers => Array of Hashes
|
179
|
+
# * Note: Do not supply the format of any header. Ruby WMQ does this for you.
|
180
|
+
#
|
181
|
+
# The following headers are supported:
|
182
|
+
# * Rules And Formatting Header (RFH)
|
183
|
+
# :header_type => :rf_header
|
184
|
+
# :....
|
185
|
+
# * Rules and Formatting V2 Header (RFH2)
|
186
|
+
# ....
|
187
|
+
# * Dead Letter Header
|
188
|
+
# * CICS Header
|
189
|
+
# * IMS Header
|
190
|
+
# * Transmission Queue Header
|
191
|
+
# * ...
|
192
|
+
class Message
|
193
|
+
attr_reader :data, :descriptor, :headers
|
194
|
+
attr_writer :data, :descriptor, :headers
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|