ferocia-rubywmq 1.1.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.
Files changed (50) hide show
  1. data/.document +8 -0
  2. data/LICENSE +13 -0
  3. data/Manifest.txt +20 -0
  4. data/README +73 -0
  5. data/examples/each_a.rb +32 -0
  6. data/examples/each_b.rb +41 -0
  7. data/examples/each_header.rb +38 -0
  8. data/examples/files_to_q.cfg +24 -0
  9. data/examples/files_to_q.rb +47 -0
  10. data/examples/get_a.rb +35 -0
  11. data/examples/get_client.rb +51 -0
  12. data/examples/put1_a.rb +25 -0
  13. data/examples/put1_b.rb +33 -0
  14. data/examples/put1_c.rb +32 -0
  15. data/examples/put_a.rb +35 -0
  16. data/examples/put_b.rb +43 -0
  17. data/examples/put_dlh.rb +41 -0
  18. data/examples/put_dynamic_q.rb +38 -0
  19. data/examples/put_group_a.rb +51 -0
  20. data/examples/put_group_b.rb +53 -0
  21. data/examples/put_rfh.rb +67 -0
  22. data/examples/put_rfh2_a.rb +43 -0
  23. data/examples/put_rfh2_b.rb +43 -0
  24. data/examples/put_xmit_q.rb +33 -0
  25. data/examples/q_to_files.cfg +17 -0
  26. data/examples/q_to_files.rb +48 -0
  27. data/examples/request.rb +60 -0
  28. data/examples/server.rb +97 -0
  29. data/ext/build.bat +3 -0
  30. data/ext/build.sh +6 -0
  31. data/ext/decode_rfh.c +348 -0
  32. data/ext/decode_rfh.h +45 -0
  33. data/ext/extconf.rb +44 -0
  34. data/ext/extconf_client.rb +40 -0
  35. data/ext/generate/generate_const.rb +167 -0
  36. data/ext/generate/generate_reason.rb +246 -0
  37. data/ext/generate/generate_structs.rb +97 -0
  38. data/ext/generate/wmq_structs.erb +371 -0
  39. data/ext/lib/wmq_temp.rb +197 -0
  40. data/ext/wmq.c +93 -0
  41. data/ext/wmq.h +367 -0
  42. data/ext/wmq_message.c +671 -0
  43. data/ext/wmq_mq_load.c +217 -0
  44. data/ext/wmq_queue.c +1411 -0
  45. data/ext/wmq_queue_manager.c +1587 -0
  46. data/lib/wmq.rb +25 -0
  47. data/rubywmq.binary.gemspec +32 -0
  48. data/rubywmq.gemspec +33 -0
  49. data/tests/test.rb +328 -0
  50. metadata +124 -0
@@ -0,0 +1,371 @@
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
+ static int Message_to_<%=struct_name.downcase%>_each (VALUE key, VALUE value, <%=struct_name%>* p<%=struct_name.downcase%>)
171
+ {
172
+ VALUE str;
173
+ size_t size;
174
+ size_t length;
175
+ VALUE val;
176
+ ID id = rb_to_id(key);
177
+
178
+ <% contains = nil
179
+ elements.each do |item|
180
+ type = item[0]
181
+ name = item[1]
182
+
183
+ next if @@field_ignore_list.include?(name) ||
184
+ (name=='Format' && struct[:header])
185
+
186
+ match = /(MQ\D+)/.match(type)
187
+ type = "#{match[1]}S" if match[1] != type
188
+ %><%= if type == 'MQMDS'
189
+ contains = 'mqmd1'
190
+ ""
191
+ else
192
+ "%-35s { %-16s(value,#{variable}->#{name}) }\n else" % [" if(id == ID_#{rubyize_name(name)})", "WMQ_STR2#{type}"]
193
+ end%><%
194
+ end
195
+ if struct[:other_keys]
196
+ struct[:other_keys].each do |key|
197
+ %> if(id == ID_<%=key.to_s%>) {}
198
+ else<% end
199
+ end
200
+ %><%=struct[:header]?" if(id != ID_header_type)":""%><%
201
+ if contains
202
+ %> {
203
+ Message_to_<%= contains%>_each(key, value, &pmqxqh->MsgDesc);
204
+ }<%
205
+ else%>
206
+ {
207
+ val = rb_funcall(key, ID_to_s, 0);
208
+ rb_raise(rb_eArgError, "WMQ::Message#to_<%=struct_name.downcase%> Unknown symbol :%s supplied", RSTRING_PTR(val));
209
+ }
210
+ <% end%>
211
+ return 0;
212
+ }
213
+
214
+ void Message_to_<%=struct_name.downcase%>(VALUE hash, <%=struct_name%>* p<%=struct_name.downcase%>)
215
+ {
216
+ rb_hash_foreach(hash, Message_to_<%=struct_name.downcase%>_each, (VALUE)p<%=struct_name.downcase%>);
217
+ }
218
+ <% end # wmq_structs.each
219
+ %>
220
+
221
+ /* --------------------------------------------------------------------------
222
+ * Extract message data and headers
223
+ * --------------------------------------------------------------------------*/
224
+ void Message_deblock(VALUE self, PMQMD pmqmd, PMQBYTE p_buffer, MQLONG total_length, MQLONG trace_level)
225
+ {
226
+ PMQCHAR p_format = pmqmd->Format; /* Start with format in MQMD */
227
+ PMQBYTE p_data = p_buffer; /* Pointer to start of data */
228
+ MQLONG data_length= total_length; /* length of data portion */
229
+ VALUE headers = rb_ary_new();
230
+ VALUE descriptor = rb_hash_new();
231
+ MQLONG size = 0;
232
+
233
+ while (p_format)
234
+ {
235
+ <%
236
+ wmq_structs.each do |struct|
237
+ if struct[:header]
238
+ %> /* <%=struct[:struct]%>: <%=struct[:header]%> */
239
+ if(strncmp(p_format, MQFMT_<%=struct[:header].upcase%>, MQ_FORMAT_LENGTH) == 0)
240
+ {
241
+ VALUE hash = rb_hash_new();
242
+ P<%=struct[:struct]%> p_header = (P<%=struct[:struct]%>)p_data;
243
+
244
+ if(trace_level>2)
245
+ printf("WMQ::Message#deblock Found <%=struct[:header]%>\n");
246
+
247
+ if(memcmp(p_header->StrucId, <%=struct[:struct_id] || "#{struct[:struct].upcase}_STRUC_ID"%>, sizeof(p_header->StrucId)) != 0)
248
+ {
249
+ if(trace_level>1)
250
+ printf("WMQ::Message#deblock MQFMT_<%=struct[:header].upcase%> received, but message does not contain <%=struct[:struct].upcase%>\n");
251
+ break; /* Bad Message received, do not deblock headers */
252
+ }
253
+ else
254
+ {
255
+ Message_from_<%=struct[:struct].downcase%>(hash, p_header);
256
+ rb_hash_aset(hash, ID2SYM(ID_header_type), ID2SYM(ID_<%=struct[:header]%>));
257
+ rb_ary_push(headers, hash);
258
+ size = <%=if struct[:custom] then
259
+ "Message_deblock_#{struct[:header]} (hash, p_data, data_length);\n"+
260
+ " if (!size) break; /* Poison Message */"
261
+ elsif struct[:elements].include?(['MQLONG', 'StrucLength'])
262
+ 'p_header->StrucLength;'
263
+ else
264
+ "sizeof(#{struct[:struct]});"
265
+ end %>
266
+ p_data += size;
267
+ data_length -= size;
268
+ <%=if struct[:format] == nil
269
+ 'p_format = p_header->Format'
270
+ elsif struct[:format] == false
271
+ 'break'
272
+ else
273
+ "p_format = p_header->#{struct[:format]}"
274
+ end %>;
275
+ }
276
+ }
277
+ else
278
+ <%
279
+ end
280
+ end # wmq_structs.each
281
+ %> {
282
+ break;
283
+ }
284
+ }
285
+ /* Copy the last recognised header found to the Descriptor */
286
+ if(p_format && p_format != pmqmd->Format)
287
+ {
288
+ strncpy(pmqmd->Format, p_format, MQ_FORMAT_LENGTH);
289
+ }
290
+
291
+ Message_from_mqmd(descriptor, pmqmd);
292
+ rb_funcall(self, ID_descriptor_set, 1, descriptor);
293
+ rb_funcall(self, ID_headers_set, 1, headers);
294
+ rb_funcall(self, ID_data_set, 1, rb_str_new(p_data, data_length));
295
+ }
296
+
297
+ void Message_build_set_format(ID header_type, PMQBYTE p_format)
298
+ {
299
+ <%
300
+ wmq_structs.each do |struct|
301
+ if struct[:header]
302
+ %> if(header_type == ID_<%=struct[:header]%>) { memcpy(p_format, MQFMT_<%=struct[:header].upcase%>, MQ_FORMAT_LENGTH); return;}
303
+ <%
304
+ end
305
+ end # wmq_structs.each
306
+
307
+ %>
308
+ rb_raise(rb_eArgError, "Invalid/Unknown header_type supplied in WMQ::Message#headers array");
309
+ }
310
+
311
+ /* --------------------------------------------------------------------------
312
+ * Build message headers
313
+ * --------------------------------------------------------------------------*/
314
+ int Message_build_header (VALUE hash, struct Message_build_header_arg* parg)
315
+ {
316
+ VALUE val = rb_hash_aref(hash, ID2SYM(ID_header_type));
317
+ PMQBYTE p_data = 0;
318
+
319
+ if (!NIL_P(val) && (TYPE(val) == T_SYMBOL))
320
+ {
321
+ ID header_id = rb_to_id(val);
322
+ <%
323
+ wmq_structs.each do |struct|
324
+ if struct[:header]
325
+ %> if (header_id == ID_<%=struct[:header]%>) /* Build <%=struct[:struct]%> */
326
+ { <%
327
+ if struct[:custom] %>
328
+ Message_build_<%=struct[:header]%> (hash, parg);
329
+ <% else %>
330
+ static <%=struct[:struct]%> <%=struct[:struct]%>_DEF = {<%=struct[:struct]%>_DEFAULT};
331
+ <%=struct[:defaults]%>
332
+
333
+ if(parg->trace_level>2)
334
+ printf ("WMQ::Message#build_header Found <%=struct[:header]%>\n");
335
+
336
+ p_data = Message_autogrow_data_buffer(parg, sizeof(<%=struct[:struct]%>));
337
+
338
+ memcpy(p_data, &<%=struct[:struct]%>_DEF, sizeof(<%=struct[:struct]%>));
339
+ Message_to_<%=struct[:struct].downcase%>(hash, (P<%=struct[:struct]%>)p_data);
340
+ <% if struct[:format] != false%>
341
+ if(parg->next_header_id)
342
+ {
343
+ Message_build_set_format(parg->next_header_id, ((P<%=struct[:struct]%>)p_data)-><%=struct[:format] || 'Format'%>);
344
+ }
345
+ else
346
+ {
347
+ memcpy(((P<%=struct[:struct]%>)p_data)-><%=struct[:format] || 'Format'%>, parg->data_format, MQ_FORMAT_LENGTH);
348
+ }
349
+ <% end %>
350
+ *(parg->p_data_offset) += sizeof(<%=struct[:struct]%>);
351
+
352
+ if(parg->trace_level>2)
353
+ printf ("WMQ::Message#build_header data offset:%ld\n", (long)(*(parg->p_data_offset)));
354
+ <% end
355
+ %> }
356
+ else
357
+ <%
358
+ end
359
+ end # wmq_structs.each
360
+
361
+ %> {
362
+ rb_raise(rb_eArgError, "Unknown :header_type supplied in WMQ::Message#headers array");
363
+ }
364
+ }
365
+ else
366
+ {
367
+ rb_raise(rb_eArgError, "Mandatory parameter :header_type missing from header entry in WMQ::Message#headers array");
368
+ }
369
+
370
+ return 0; /* Continue */
371
+ }
@@ -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
data/ext/wmq.c ADDED
@@ -0,0 +1,93 @@
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
+ VALUE wmq_queue;
20
+ VALUE wmq_queue_manager;
21
+ VALUE wmq_message;
22
+ VALUE wmq_exception;
23
+
24
+ void Init_wmq() {
25
+ VALUE wmq;
26
+
27
+ wmq = rb_define_module("WMQ");
28
+
29
+ wmq_queue_manager = rb_define_class_under(wmq, "QueueManager", rb_cObject);
30
+ rb_define_alloc_func(wmq_queue_manager, QUEUE_MANAGER_alloc);
31
+ rb_define_singleton_method(wmq_queue_manager, "connect", QueueManager_singleton_connect, -1); /* in wmq_queue_manager.c */
32
+ rb_define_method(wmq_queue_manager, "initialize", QueueManager_initialize, 1); /* in wmq_queue_manager.c */
33
+ rb_define_method(wmq_queue_manager, "connect", QueueManager_connect, 0); /* in wmq_queue_manager.c */
34
+ rb_define_method(wmq_queue_manager, "disconnect", QueueManager_disconnect, 0); /* in wmq_queue_manager.c */
35
+ rb_define_method(wmq_queue_manager, "open_queue", QueueManager_open_queue, -1); /* in wmq_queue_manager.c */
36
+ rb_define_method(wmq_queue_manager, "access_queue", QueueManager_open_queue, -1); /* in wmq_queue_manager.c */
37
+ rb_define_method(wmq_queue_manager, "begin", QueueManager_begin, 0); /* in wmq_queue_manager.c */
38
+ rb_define_method(wmq_queue_manager, "commit", QueueManager_commit, 0); /* in wmq_queue_manager.c */
39
+ rb_define_method(wmq_queue_manager, "backout", QueueManager_backout, 0); /* in wmq_queue_manager.c */
40
+ rb_define_method(wmq_queue_manager, "put", QueueManager_put, 1); /* in wmq_queue_manager.c */
41
+ rb_define_method(wmq_queue_manager, "comp_code", QueueManager_comp_code, 0); /* in wmq_queue_manager.c */
42
+ rb_define_method(wmq_queue_manager, "reason_code", QueueManager_reason_code, 0); /* in wmq_queue_manager.c */
43
+ rb_define_method(wmq_queue_manager, "reason", QueueManager_reason, 0); /* in wmq_queue_manager.c */
44
+ rb_define_method(wmq_queue_manager, "exception_on_error", QueueManager_exception_on_error, 0); /* in wmq_queue_manager.c */
45
+ rb_define_method(wmq_queue_manager, "connected?", QueueManager_connected_q, 0); /* in wmq_queue_manager.c */
46
+ rb_define_method(wmq_queue_manager, "name", QueueManager_name, 0); /* in wmq_queue_manager.c */
47
+ rb_define_method(wmq_queue_manager, "execute", QueueManager_execute, 1); /* in wmq_queue_manager.c */
48
+
49
+ wmq_queue = rb_define_class_under(wmq, "Queue", rb_cObject);
50
+ rb_define_alloc_func(wmq_queue, QUEUE_alloc);
51
+ rb_define_singleton_method(wmq_queue, "open", Queue_singleton_open, -1); /* in wmq_queue.c */
52
+ rb_define_method(wmq_queue, "initialize", Queue_initialize, 1); /* in wmq_queue.c */
53
+ rb_define_method(wmq_queue, "open", Queue_open, 0); /* in wmq_queue.c */
54
+ rb_define_method(wmq_queue, "close", Queue_close, 0); /* in wmq_queue.c */
55
+ rb_define_method(wmq_queue, "put", Queue_put, 1); /* in wmq_queue.c */
56
+ rb_define_method(wmq_queue, "get", Queue_get, 1); /* in wmq_queue.c */
57
+ rb_define_method(wmq_queue, "each", Queue_each, -1); /* in wmq_queue.c */
58
+ rb_define_method(wmq_queue, "name", Queue_name, 0); /* in wmq_queue.c */
59
+ rb_define_method(wmq_queue, "comp_code", Queue_comp_code, 0); /* in wmq_queue.c */
60
+ rb_define_method(wmq_queue, "reason_code", Queue_reason_code, 0); /* in wmq_queue.c */
61
+ rb_define_method(wmq_queue, "reason", Queue_reason, 0); /* in wmq_queue.c */
62
+ rb_define_method(wmq_queue, "open?", Queue_open_q, 0); /* in wmq_queue.c */
63
+
64
+ wmq_message = rb_define_class_under(wmq, "Message", rb_cObject);
65
+ rb_define_method(wmq_message, "initialize", Message_initialize, -1); /* in wmq_message.c */
66
+ rb_define_method(wmq_message, "clear", Message_clear, 0); /* in wmq_message.c */
67
+
68
+ /*
69
+ * WMQException is thrown whenever an MQ operation fails and
70
+ * exception_on_error is true
71
+ */
72
+ wmq_exception = rb_define_class_under(wmq, "WMQException", rb_eRuntimeError);
73
+
74
+ /*
75
+ * Initialize id fields
76
+ */
77
+ Message_id_init();
78
+ Queue_id_init();
79
+ QueueManager_id_init();
80
+ QueueManager_selector_id_init();
81
+ QueueManager_command_id_init();
82
+ wmq_structs_id_init();
83
+
84
+ rb_require("wmq/wmq_temp");
85
+ rb_require("wmq/wmq_const");
86
+ }
87
+
88
+ /*
89
+ * For client build when dynamic loading is not being used E.g. Not Windows or Solaris ...
90
+ */
91
+ void Init_wmq_client() {
92
+ Init_wmq();
93
+ }