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.
Files changed (51) hide show
  1. data/.document +4 -0
  2. data/LICENSE.txt +201 -0
  3. data/README.md +408 -0
  4. data/Rakefile +87 -0
  5. data/examples/each_a.rb +16 -0
  6. data/examples/each_b.rb +25 -0
  7. data/examples/each_header.rb +22 -0
  8. data/examples/files_to_q.cfg +24 -0
  9. data/examples/files_to_q.rb +31 -0
  10. data/examples/get_a.rb +19 -0
  11. data/examples/get_client.rb +35 -0
  12. data/examples/put1_a.rb +9 -0
  13. data/examples/put1_b.rb +17 -0
  14. data/examples/put1_c.rb +16 -0
  15. data/examples/put_a.rb +19 -0
  16. data/examples/put_b.rb +27 -0
  17. data/examples/put_dlh.rb +25 -0
  18. data/examples/put_dynamic_q.rb +22 -0
  19. data/examples/put_group_a.rb +35 -0
  20. data/examples/put_group_b.rb +37 -0
  21. data/examples/put_rfh.rb +51 -0
  22. data/examples/put_rfh2_a.rb +27 -0
  23. data/examples/put_rfh2_b.rb +27 -0
  24. data/examples/put_xmit_q.rb +17 -0
  25. data/examples/q_to_files.cfg +17 -0
  26. data/examples/q_to_files.rb +32 -0
  27. data/examples/request.rb +44 -0
  28. data/examples/server.rb +81 -0
  29. data/ext/decode_rfh.c +348 -0
  30. data/ext/decode_rfh.h +45 -0
  31. data/ext/extconf.rb +30 -0
  32. data/ext/extconf_client.rb +24 -0
  33. data/ext/generate/generate_const.rb +140 -0
  34. data/ext/generate/generate_reason.rb +233 -0
  35. data/ext/generate/generate_structs.rb +82 -0
  36. data/ext/generate/wmq_structs.erb +341 -0
  37. data/ext/wmq.c +90 -0
  38. data/ext/wmq.h +371 -0
  39. data/ext/wmq_message.c +671 -0
  40. data/ext/wmq_mq_load.c +217 -0
  41. data/ext/wmq_queue.c +1411 -0
  42. data/ext/wmq_queue_manager.c +1570 -0
  43. data/lib/rubywmq.rb +1 -0
  44. data/lib/wmq/message.rb +70 -0
  45. data/lib/wmq/queue_manager.rb +110 -0
  46. data/lib/wmq/version.rb +3 -0
  47. data/lib/wmq.rb +16 -0
  48. data/nbproject/project.properties +11 -0
  49. data/nbproject/project.xml +17 -0
  50. data/tests/test.rb +318 -0
  51. metadata +115 -0
@@ -0,0 +1,140 @@
1
+ # Extract Constants from the WebSphere MQ header files
2
+ class GenerateConst
3
+
4
+ # Extract Constants from Header files
5
+ def GenerateConst.extract_const(filename, const_prefix, start_exp=nil, end_exp=nil)
6
+ @constants = []
7
+ active = if start_exp then false else true end # Sure there is a better way
8
+ File.open(filename) do |file|
9
+ file.each do |line|
10
+ line.rstrip!
11
+ if line.length > 0 # Skip empty lines
12
+ if active
13
+ break if start_exp && line.match(end_exp)
14
+ # Skip Comment lines, then check for a match
15
+ if (line !~ /^\s*\/\*/) && (match = /\s*#define\s+(#{const_prefix}\w+)[\(\s]+([-\\\w\dx\'\"\s]+)/.match(line))
16
+ @constants << [match[1], match[2]]
17
+ end
18
+ else
19
+ next unless line.match(start_exp)
20
+ active = true
21
+ end
22
+ end
23
+ end
24
+ end
25
+ @constants
26
+ end
27
+
28
+ # Extract MQ Constants from Header files
29
+ def GenerateConst.rb_const(filename, const_prefix, exclude_exp=nil)
30
+ str = ''
31
+ GenerateConst.extract_const(filename, const_prefix).each do |item|
32
+ const, val = item
33
+ next if const.include?('_STRUC_ID')
34
+ next if exclude_exp && const.match(exclude_exp)
35
+ if val.include?('"') || val.include?("'")
36
+ if match = val.match(/(\w+)/)
37
+ val = "'#{match[0]}'"
38
+ else
39
+ val = "''"
40
+ end
41
+ end
42
+ str << " %-30s = #{val}\n" % const
43
+ end
44
+ str
45
+ end
46
+
47
+ def GenerateConst.config(filename, prefix)
48
+ str = "# WMQ::QueueManager execute commands\n"
49
+ str << "execute_commands:\n"
50
+ GenerateConst.extract_const(filename,prefix).each do |item|
51
+ name = item[0].gsub(prefix,'').downcase
52
+ str << " :%-26s " % "#{name}:"
53
+ match = name.match(/\w+?_([\w_]+)/)
54
+ str << ":#{match[1]}" if match
55
+ str << "\n"
56
+ end
57
+ str
58
+ end
59
+
60
+ def GenerateConst.wmq_const(path)
61
+ str = <<END_OF_STRING
62
+ ################################################################################
63
+ #
64
+ # WARNING: DO NOT MODIFY THIS FILE
65
+ #
66
+ # This file was generated by generate_const.rb.
67
+ #
68
+ ################################################################################
69
+ module WMQ
70
+ END_OF_STRING
71
+ [ ['Connect Options','cmqc.h','MQCNO_',/(VERSION)|(CONN_TAG)|(HANDLE_SHARE)|(_LENGTH)/],
72
+ ['Open Options', 'cmqc.h','MQOO_' ],
73
+ ['Close Options', 'cmqc.h','MQCO_'],
74
+ ['Match Options', 'cmqc.h','MQMO_'],
75
+ ['Message Format Options', 'cmqc.h','MQFMT_',/(_ARRAY)/],
76
+ ['Get Message Options', 'cmqc.h','MQGMO_',/(VERSION)|(LENGTH)|(MQGMO_BROWSE_HANDLE)|(MQGMO_BROWSE_CO_OP)/],
77
+ ['Transport Types', 'cmqxc.h','MQXPT_'] ,
78
+ ['Report Options', 'cmqc.h', 'MQRO_'],
79
+ ['Message Types', 'cmqc.h', 'MQMT_'],
80
+ ['Expiry', 'cmqc.h', 'MQEI_'],
81
+ ['Feedback Values', 'cmqc.h', 'MQFB_'],
82
+ ['Encoding Values', 'cmqc.h', 'MQENC_',/(MQENC_NORMAL)|(MQENC_REVERSED)|(MQENC_S390)|(MQENC_TNS)/],
83
+ ['Coded Character Set Identifiers', 'cmqc.h', 'MQCCSI_'],
84
+ ['Priority', 'cmqc.h', 'MQPRI_'],
85
+ ['Persistence', 'cmqc.h', 'MQPER_'],
86
+ ['Put Application Types', 'cmqc.h', 'MQAT_'],
87
+ ['Message Flags', 'cmqc.h', 'MQMF_'],
88
+ ['Original Length', 'cmqc.h', 'MQOL_'],
89
+ ['Put Message Options', 'cmqc.h', 'MQPMO_',/(VERSION)|(LENGTH)/],
90
+ ['Put Message Record Fields', 'cmqc.h', 'MQPMRF_',/(VERSION)|(LENGTH)/],
91
+ ['Reason Codes', 'cmqc.h','MQRC_'],
92
+ ].each do |item|
93
+ str << "\n# #{item[0]}\n"
94
+ str << GenerateConst.rb_const("#{path}/#{item[1]}", item[2], item[3])
95
+ end
96
+ str << "end\n"
97
+ end
98
+
99
+ def GenerateConst.admin_consts(path)
100
+ str = <<END_OF_STRING
101
+ ################################################################################
102
+ #
103
+ # WARNING: DO NOT MODIFY THIS FILE
104
+ #
105
+ # This file was generated by generate_const.rb.
106
+ #
107
+ ################################################################################
108
+ module WMQ
109
+ END_OF_STRING
110
+ str << "# Admin constants from cmqc.h\n"
111
+ [ ['Object Types', 'cmqc.h', 'MQOT_'],
112
+ ['Security Identifier Types', 'cmqc.h', 'MQSIDT_'],
113
+ ['Channel Types', 'cmqxc.h', 'MQCHT_'],
114
+ ].each do |item|
115
+ str << "\n# #{item[0]}\n"
116
+ str << GenerateConst.rb_const("#{path}/#{item[1]}", item[2], item[3])
117
+ end
118
+ GenerateConst.extract_const(path+'cmqc.h', 'MQ', /Queue\s+Attributes/, /General\s+Constants/).each do |item|
119
+ str << " %-30s = #{item[1]}\n" % item[0]
120
+ end
121
+ str << "# Admin constants from cmqcfc.h\n"
122
+ GenerateConst.extract_const(path+'cmqcfc.h', 'MQ', /Parameter\s+Values/, /typedef\s+struct/).each do |item|
123
+ str << " %-30s = #{item[1]}\n" % item[0]
124
+ end
125
+ str << "end\n"
126
+ end
127
+
128
+ def self.generate(path, target_path='')
129
+ File.open(File.join(target_path,'constants_admin.rb'), 'w') {|file| file.write(GenerateConst.admin_consts(path))}
130
+ puts 'Generated wmq_const_admin.rb'
131
+ File.open(File.join(target_path,'constants.rb'), 'w') {|file| file.write(GenerateConst.wmq_const(path))}
132
+ puts 'Generated wmq_const.rb'
133
+ end
134
+ end
135
+
136
+ if $0 == __FILE__
137
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
138
+ path = path + '/'
139
+ GenerateConst.generate(path)
140
+ end
@@ -0,0 +1,233 @@
1
+ class GenerateReason
2
+
3
+ # Extract Error Code Constants from Header files
4
+ def GenerateReason.extract_const(filename, const_prefix)
5
+ @constants = []
6
+ File.open(filename) do |file|
7
+ file.each do |line|
8
+ line.rstrip!
9
+ # Skip empty and comment lines
10
+ if line.length > 0 && line !~ /^\s*\/\*/
11
+ if match = /\s*#define\s+(#{const_prefix}\w+)[\(\s]+([-\dx]+)/.match(line)
12
+ @constants << [match[1], match[2]]
13
+ end
14
+ end
15
+ end
16
+ end
17
+ @constants
18
+ end
19
+
20
+ # Extract Error Code Constants from Header files
21
+ # Uses lazy print to collect duplicate values
22
+ def GenerateReason.reason_case(filename, prefix)
23
+ last_rc = nil
24
+ last_reason = nil
25
+ str = ''
26
+ GenerateReason.extract_const(filename,prefix).each do |item|
27
+ if last_rc == item[1]
28
+ str << " case %-30s: return \"#{item[0]} or #{last_reason}[#{item[1]}]\";\n" % item[0]
29
+ last_rc = nil
30
+ last_reason = nil
31
+ else
32
+ str << " case %-30s: return \"#{last_reason}[#{last_rc}]\";\n" % last_reason if last_rc
33
+ last_rc = item[1]
34
+ last_reason = item[0]
35
+ end
36
+ end
37
+ str
38
+ end
39
+
40
+ # The WebSphere MQ header files have several duplicate values,
41
+ # so need to exclude duplicates.
42
+ def GenerateReason.selector_case(filename, prefix, excludes=nil, &block)
43
+ GenerateReason.extract_const(filename,prefix).each do |item|
44
+ next if item[0].include?('FIRST') || item[0].include?('LAST')
45
+ next if excludes && excludes.include?(item[0])
46
+ block.call item
47
+ end
48
+ end
49
+
50
+ def GenerateReason.wmq_reason(path)
51
+ str = <<END_OF_STRING
52
+ /* --------------------------------------------------------------------------
53
+ *
54
+ * WARNING: DO NOT MODIFY THIS FILE
55
+ *
56
+ * This file was generated by generate_reason.rb.
57
+ *
58
+ * --------------------------------------------------------------------------*/
59
+
60
+ #include "wmq.h"
61
+
62
+ char* wmq_reason(MQLONG reason_code)
63
+ {
64
+ switch (reason_code)
65
+ {
66
+ END_OF_STRING
67
+
68
+ [['cmqc.h', 'MQRC_'],
69
+ ['cmqcfc.h', 'MQRCCF_']].each do |item|
70
+ str << GenerateReason.reason_case(path+item[0], item[1])
71
+ end
72
+ str << <<END_OF_STRING
73
+ }
74
+ printf("WMQ::wmq_reason Unknown Reason code:%ld\\n",(long)reason_code);
75
+ return "Unknown reason code";
76
+ }
77
+
78
+ END_OF_STRING
79
+
80
+ str_switch = ''
81
+ str_id_init = ''
82
+ # Integer Selectors for Object Attributes
83
+ [['cmqc.h', 'MQIA_'],
84
+ ['cmqcfc.h', 'MQIACF_', ['MQIACF_ERROR_ID',
85
+ 'MQIACF_QUIESCE']],
86
+ ['cmqcfc.h', 'MQIACH_', ['MQIACH_CURRENT_SEQ_NUMBER',
87
+ 'MQIACH_BYTES_RCVD',
88
+ 'MQIACH_BUFFERS_RCVD',
89
+ 'MQIACH_MSGS_RCVD']],
90
+ ['cmqcfc.h', 'MQIAMO_'],
91
+ ['cmqcfc.h', 'MQIAMO64_', ['MQIAMO64_AVG_Q_TIME',
92
+ 'MQIAMO64_Q_TIME_AVG',
93
+ 'MQIAMO64_Q_TIME_MAX',
94
+ 'MQIAMO64_Q_TIME_MIN']],
95
+ # Integer System Selectors
96
+ ['cmqbc.h', 'MQIASY_'],
97
+ # Character Selectors for Object Attributes
98
+ ['cmqc.h', 'MQCA_',['MQCA_BASE_OBJECT_NAME']],
99
+ ['cmqcfc.h', 'MQCACF_'],
100
+ ['cmqcfc.h', 'MQCACH_'],
101
+ ['cmqcfc.h', 'MQCAMO_'],
102
+ # Byte String Selectors for Object Attributes
103
+ ['cmqc.h', 'MQBA_'],
104
+ ['cmqcfc.h', 'MQBACF_'],
105
+ # Group Selectors for Object Attributes
106
+ ['cmqcfc.h', 'MQGACF_'] ].each do |item|
107
+ str << "/* Constants #{item[1]}* from #{item[0]} */\n"
108
+ str_switch << " /* Constants #{item[1]}* from #{item[0]} */\n"
109
+ str_id_init << " /* Constants #{item[1]}* from #{item[0]} */\n"
110
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
111
+ id = const[0].gsub(item[1],'').downcase
112
+ str_switch << " case %-30s: return ID_#{id};\n" % const[0]
113
+ str_id_init << " ID_%-25s = rb_intern(\"#{id}\");\n" % id
114
+ str << "static ID ID_#{id};\n"
115
+ end
116
+ end
117
+
118
+ str << <<END_OF_STRING
119
+
120
+ void QueueManager_selector_id_init()
121
+ {
122
+ #{str_id_init}
123
+ }
124
+
125
+ ID wmq_selector_id(MQLONG selector)
126
+ {
127
+ switch (selector)
128
+ {
129
+ #{str_switch}
130
+ }
131
+ printf("WMQ::wmq_select_text Unknown Selector:%ld\\n",(long)selector);
132
+ return rb_intern("unknown_selector_code");
133
+ }
134
+
135
+ void wmq_selector(ID selector_id, PMQLONG selector_type, PMQLONG selector)
136
+ {
137
+ *selector_type = MQIT_INTEGER;
138
+ END_OF_STRING
139
+ first = true
140
+ str_if = ''
141
+ str_id_init = ''
142
+ # Integer Selectors for Object Attributes
143
+ [['cmqc.h', 'MQIA_'],
144
+ ['cmqcfc.h', 'MQIACF_', ['MQIACF_ERROR_ID',
145
+ 'MQIACF_QUIESCE']],
146
+ ['cmqcfc.h', 'MQIACH_', ['MQIACH_CURRENT_SEQ_NUMBER',
147
+ 'MQIACH_BYTES_RCVD',
148
+ 'MQIACH_BUFFERS_RCVD']],
149
+ ['cmqcfc.h', 'MQIAMO_'],
150
+ ['cmqcfc.h', 'MQIAMO64_', ['MQIAMO64_AVG_Q_TIME',
151
+ 'MQIAMO64_Q_TIME_AVG',
152
+ 'MQIAMO64_Q_TIME_MAX',
153
+ 'MQIAMO64_Q_TIME_MIN']],
154
+ # Integer System Selectors
155
+ # ['cmqbc.h', 'MQIASY_'],
156
+ ].each do |item|
157
+ str << " /* Consteants #{item[1]}* from #{item[0]} */\n"
158
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
159
+ str << " if(selector_id == %-32s{ *selector = #{const[0]}; return;}\n" % "ID_#{const[0].gsub(item[1],'').downcase})"
160
+ end
161
+ end
162
+ str << "\n *selector_type = MQIT_STRING;\n\n"
163
+ # Character Selectors for Object Attributes
164
+ [['cmqc.h', 'MQCA_',['MQCA_BASE_OBJECT_NAME']],
165
+ ['cmqcfc.h', 'MQCACF_'],
166
+ ['cmqcfc.h', 'MQCACH_'],
167
+ ['cmqcfc.h', 'MQCAMO_'],
168
+ # Byte String Selectors for Object Attributes
169
+ # ['cmqc.h', 'MQBA_'],
170
+ # ['cmqcfc.h', 'MQBACF_'],
171
+ # Group Selectors for Object Attributes
172
+ # ['cmqcfc.h', 'MQGACF_']
173
+ ].each do |item|
174
+ str << " /* Constants #{item[1]}* from #{item[0]} */\n"
175
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
176
+ str << " if(selector_id == %-32s{ *selector = #{const[0]}; return;}\n" % "ID_#{const[0].gsub(item[1],'').downcase})"
177
+ end
178
+ end
179
+
180
+ str << <<END_OF_STRING
181
+
182
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute [wmq_selector] Unknown selector supplied");
183
+ }
184
+
185
+ END_OF_STRING
186
+ first = true
187
+ str_if = ''
188
+ str_id_init = ''
189
+ GenerateReason.selector_case(path+'cmqcfc.h', 'MQCMD_') do |const|
190
+ if first
191
+ first = false
192
+ str_if << " "
193
+ else
194
+ str_if << " else "
195
+ end
196
+ id = const[0].gsub('MQCMD_','').downcase
197
+ str_id_init << " ID_%-25s = rb_intern(\"#{id}\");\n" % id
198
+ str_if << "if(command_id == %-28s{ command = #{const[0]}; }\n" % "ID_#{const[0].gsub('MQCMD_','').downcase})"
199
+ str << "static ID ID_#{id};\n"
200
+ end
201
+ str << <<END_OF_STRING
202
+
203
+ void QueueManager_command_id_init()
204
+ {
205
+ #{str_id_init}
206
+ }
207
+
208
+ MQLONG wmq_command_lookup(ID command_id)
209
+ {
210
+ MQLONG command = 0;
211
+ #{str_if}
212
+ else
213
+ {
214
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute [wmq_command_lookup] Unknown command supplied");
215
+ }
216
+
217
+ return command;
218
+ }
219
+ END_OF_STRING
220
+ str
221
+ end
222
+
223
+ def self.generate(path)
224
+ File.open('wmq_reason.c', 'w') {|file| file.write(GenerateReason.wmq_reason(path))}
225
+ puts 'Generated wmq_reason.c'
226
+ end
227
+ end
228
+
229
+ if $0 == __FILE__
230
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
231
+ path = path + '/'
232
+ GenerateReason.generate(path)
233
+ end
@@ -0,0 +1,82 @@
1
+ require 'erb'
2
+
3
+ class GenerateStructs
4
+
5
+ @@field_ignore_list = [ 'StrucId', 'Version' , 'StrucLength']
6
+
7
+ # Store path to WebSphere MQ Structures
8
+ def initialize(wmq_includepath, templates_path='.')
9
+ @path = wmq_includepath
10
+ @templates_path = templates_path
11
+ end
12
+
13
+ def extract_struct (filename, struct_name)
14
+ properties_list = []
15
+ line_number = 0
16
+ found = false
17
+ File.open(filename) do |file|
18
+ file.each do |line|
19
+ line_number += 1
20
+ line.rstrip!
21
+ # Skip empty and comment lines
22
+ if line.length > 0 && line !~ /^\s*\/\*/
23
+ if !found
24
+ found = true if line =~ /^\s*struct\s*tag#{struct_name}/
25
+ else
26
+ return(properties_list) if line =~ /^\s*\};/
27
+ match = /\s*(MQ\w+)\s+(\w+);/.match(line)
28
+ if match
29
+ type = match[1]
30
+ element = match[2]
31
+ properties_list.push([type, element])
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ properties_list
38
+ end
39
+
40
+ def rubyize_name(name)
41
+ name.gsub(/::/, '/').
42
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
43
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
44
+ tr("-", "_").
45
+ downcase
46
+ end
47
+
48
+ def self.test_rubyize_name
49
+ test = self.new
50
+ [['a', 'a'],
51
+ ['A', 'a'],
52
+ ['Aa', 'aa'],
53
+ ['AA', 'aa'],
54
+ ['AaA', 'aa_a'],
55
+ ['MyFieldName', 'my_field_name'],
56
+ ['MMyFieldNName', 'm_my_field_n_name'],
57
+ ['ABCdefGHIjKlMnOPQrSTuvwxYz', 'ab_cdef_gh_ij_kl_mn_op_qr_s_tuvwx_yz']
58
+ ].each do |item|
59
+ str = test.rubyize_name(item[0])
60
+ raise("rubyize_name('#{item[0]}') == #{str} != '#{item[1]})") if str != item[1]
61
+ end
62
+ end
63
+
64
+ def generate_structs(erb)
65
+ erb.result(binding)
66
+ end
67
+
68
+ def generate(target_filename = 'wmq_structs.c')
69
+ erb = nil
70
+ File.open(@templates_path+'/wmq_structs.erb') { |file| erb = ERB.new(file.read) }
71
+ File.open(target_filename, 'w') {|file| file.write(generate_structs(erb)) }
72
+ puts "Generated #{target_filename}"
73
+ end
74
+ end
75
+
76
+ # TODO Auto Daisy-Chain Headers: Format, CodedCharSetId, Encoding
77
+ # TODO During Deblock validate that data size left at least matches struct size
78
+ if $0 == __FILE__
79
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
80
+ path = path + '/'
81
+ GenerateStructs.new(path, 'generate').generate
82
+ end