rubywmq 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,40 @@
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
+ #
18
+ # NOTE: Do NOT use this file unless the platform being requested is not supported
19
+ # directly by Ruby WMQ. Ruby WMQ already supports automatic dynamic loading on
20
+ # Windows, Solaris and Linux
21
+ #
22
+ require 'mkmf'
23
+ require '../../generate/generate_reason'
24
+ require '../../generate/generate_const'
25
+ require '../../generate/generate_structs'
26
+
27
+ include_path = ''
28
+ unless (RUBY_PLATFORM =~ /win/i) || (RUBY_PLATFORM =~ /solaris/i) || (RUBY_PLATFORM =~ /linux/i)
29
+ include_path = '/opt/mqm/inc'
30
+ dir_config('mqm', include_path, '/opt/mqm/lib')
31
+ have_library('mqic')
32
+
33
+ # Generate Source Files # Could check if not already present
34
+ GenerateReason.generate(include_path+'/')
35
+ GenerateConst.generate(include_path+'/', '../../lib/wmq')
36
+ GenerateStructs.new(include_path+'/', '../../generate').generate
37
+
38
+ have_header('cmqc.h')
39
+ create_makefile('wmq_client')
40
+ end
@@ -0,0 +1,167 @@
1
+ class GenerateConst
2
+
3
+ #Extract Constants from Header files
4
+ def GenerateConst.extract_const(filename, const_prefix, start_exp=nil, end_exp=nil)
5
+ @constants = []
6
+ active = if start_exp then false else true end # Sure there is a better way
7
+ File.open(filename) do |file|
8
+ file.each do |line|
9
+ line.rstrip!
10
+ if line.length > 0 # Skip empty lines
11
+ if active
12
+ break if start_exp && line.match(end_exp)
13
+ # Skip Comment lines, then check for a match
14
+ if (line !~ /^\s*\/\*/) && (match = /\s*#define\s+(#{const_prefix}\w+)[\(\s]+([-\\\w\dx\'\"\s]+)/.match(line))
15
+ @constants << [match[1], match[2]]
16
+ end
17
+ else
18
+ next unless line.match(start_exp)
19
+ active = true
20
+ end
21
+ end
22
+ end
23
+ end
24
+ @constants
25
+ end
26
+
27
+ #Extract MQ Constants from Header files
28
+ def GenerateConst.rb_const(filename, const_prefix, exclude_exp=nil)
29
+ str = ''
30
+ GenerateConst.extract_const(filename, const_prefix).each do |item|
31
+ const, val = item
32
+ next if const.include?('_STRUC_ID')
33
+ next if exclude_exp && const.match(exclude_exp)
34
+ if val.include?('"') || val.include?("'")
35
+ if match = val.match(/(\w+)/)
36
+ val = "'#{match[0]}'"
37
+ else
38
+ val = "''"
39
+ end
40
+ end
41
+ str << " %-30s = #{val}\n" % const
42
+ end
43
+ str
44
+ end
45
+
46
+ def GenerateConst.config(filename, prefix)
47
+ str = "# WMQ::QueueManager execute commands\n"
48
+ str << "execute_commands:\n"
49
+ GenerateConst.extract_const(filename,prefix).each do |item|
50
+ name = item[0].gsub(prefix,'').downcase
51
+ str << " :%-26s " % "#{name}:"
52
+ match = name.match(/\w+?_([\w_]+)/)
53
+ str << ":#{match[1]}" if match
54
+ str << "\n"
55
+ end
56
+ str
57
+ end
58
+
59
+ def GenerateConst.wmq_const(path)
60
+ str = <<END_OF_STRING
61
+ ################################################################################
62
+ # Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
63
+ #
64
+ # Licensed under the Apache License, Version 2.0 (the "License");
65
+ # you may not use this file except in compliance with the License.
66
+ # You may obtain a copy of the License at
67
+ #
68
+ # http://www.apache.org/licenses/LICENSE-2.0
69
+ #
70
+ # Unless required by applicable law or agreed to in writing, software
71
+ # distributed under the License is distributed on an "AS IS" BASIS,
72
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
73
+ # See the License for the specific language governing permissions and
74
+ # limitations under the License.
75
+ ################################################################################
76
+ #
77
+ # WARNING: DO NOT MODIFY THIS FILE
78
+ #
79
+ # This file was generated by generate_const.rb.
80
+ #
81
+ ################################################################################
82
+ module WMQ
83
+ END_OF_STRING
84
+ [ ['Connect Options','cmqc.h','MQCNO_',/(VERSION)|(CONN_TAG)|(HANDLE_SHARE)/],
85
+ ['Open Options', 'cmqc.h','MQOO_' ],
86
+ ['Close Options', 'cmqc.h','MQCO_'],
87
+ ['Match Options', 'cmqc.h','MQMO_'],
88
+ ['Message Format Options', 'cmqc.h','MQFMT_',/(_ARRAY)/],
89
+ ['Get Message Options', 'cmqc.h','MQGMO_',/(VERSION)/],
90
+ ['Transport Types', 'cmqxc.h','MQXPT_'] ,
91
+ ['Report Options', 'cmqc.h', 'MQRO_'],
92
+ ['Message Types', 'cmqc.h', 'MQMT_'],
93
+ ['Expiry', 'cmqc.h', 'MQEI_'],
94
+ ['Feedback Values', 'cmqc.h', 'MQFB_'],
95
+ ['Encoding Values', 'cmqc.h', 'MQENC_'],
96
+ ['Coded Character Set Identifiers', 'cmqc.h', 'MQCCSI_'],
97
+ ['Priority', 'cmqc.h', 'MQPRI_'],
98
+ ['Persistence', 'cmqc.h', 'MQPER_'],
99
+ ['Put Application Types', 'cmqc.h', 'MQAT_'],
100
+ ['Message Flags', 'cmqc.h', 'MQMF_'],
101
+ ['Original Length', 'cmqc.h', 'MQOL_'],
102
+ ['Put Message Options', 'cmqc.h', 'MQPMO_',/(VERSION)|(LENGTH)/],
103
+ ['Put Message Record Fields', 'cmqc.h', 'MQPMRF_',/(VERSION)|(LENGTH)/],
104
+ ['Reason Codes', 'cmqc.h','MQRC_'],
105
+ ].each do |item|
106
+ str << "\n# #{item[0]}\n"
107
+ str << GenerateConst.rb_const("#{path}/#{item[1]}", item[2], item[3])
108
+ end
109
+ str << "end\n"
110
+ end
111
+
112
+ def GenerateConst.admin_consts(path)
113
+ str = <<END_OF_STRING
114
+ ################################################################################
115
+ # Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
116
+ #
117
+ # Licensed under the Apache License, Version 2.0 (the "License");
118
+ # you may not use this file except in compliance with the License.
119
+ # You may obtain a copy of the License at
120
+ #
121
+ # http://www.apache.org/licenses/LICENSE-2.0
122
+ #
123
+ # Unless required by applicable law or agreed to in writing, software
124
+ # distributed under the License is distributed on an "AS IS" BASIS,
125
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
126
+ # See the License for the specific language governing permissions and
127
+ # limitations under the License.
128
+ ################################################################################
129
+ #
130
+ # WARNING: DO NOT MODIFY THIS FILE
131
+ #
132
+ # This file was generated by generate_const.rb.
133
+ #
134
+ ################################################################################
135
+ module WMQ
136
+ END_OF_STRING
137
+ str << "# Admin constants from cmqc.h\n"
138
+ [ ['Object Types', 'cmqc.h', 'MQOT_'],
139
+ ['Security Identifier Types', 'cmqc.h', 'MQSIDT_'],
140
+ ['Channel Types', 'cmqxc.h', 'MQCHT_'],
141
+ ].each do |item|
142
+ str << "\n# #{item[0]}\n"
143
+ str << GenerateConst.rb_const("#{path}/#{item[1]}", item[2], item[3])
144
+ end
145
+ GenerateConst.extract_const(path+'cmqc.h', 'MQ', /Queue\sAttributes/, /typedef/).each do |item|
146
+ str << " %-30s = #{item[1]}\n" % item[0]
147
+ end
148
+ str << "# Admin constants from cmqcfc.h\n"
149
+ GenerateConst.extract_const(path+'cmqcfc.h', 'MQ', /Parameter\s+Values/, /typedef\s+struct/).each do |item|
150
+ str << " %-30s = #{item[1]}\n" % item[0]
151
+ end
152
+ str << "end\n"
153
+ end
154
+
155
+ def self.generate(path, target_path='')
156
+ File.open(File.join(target_path,'wmq_const_admin.rb'), 'w') {|file| file.write(GenerateConst.admin_consts(path))}
157
+ puts 'Generated wmq_const_admin.rb'
158
+ File.open(File.join(target_path,'wmq_const.rb'), 'w') {|file| file.write(GenerateConst.wmq_const(path))}
159
+ puts 'Generated wmq_const.rb'
160
+ end
161
+ end
162
+
163
+ if $0 == __FILE__
164
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
165
+ path = path + '/'
166
+ GenerateConst.generate(path)
167
+ end
@@ -0,0 +1,240 @@
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
+ * Copyright 2006 J. Reid Morrison. Dimension Solutions, Inc.
54
+ *
55
+ * Licensed under the Apache License, Version 2.0 (the "License");
56
+ * you may not use this file except in compliance with the License.
57
+ * You may obtain a copy of the License at
58
+ *
59
+ * http://www.apache.org/licenses/LICENSE-2.0
60
+ *
61
+ * Unless required by applicable law or agreed to in writing, software
62
+ * distributed under the License is distributed on an "AS IS" BASIS,
63
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
64
+ * See the License for the specific language governing permissions and
65
+ * limitations under the License.
66
+ * --------------------------------------------------------------------------
67
+ *
68
+ * WARNING: DO NOT MODIFY THIS FILE
69
+ *
70
+ * This file was generated by generate_reason.rb.
71
+ *
72
+ * --------------------------------------------------------------------------*/
73
+
74
+ #include "wmq.h"
75
+
76
+ char* wmq_reason(MQLONG reason_code)
77
+ {
78
+ switch (reason_code)
79
+ {
80
+ END_OF_STRING
81
+
82
+ [['cmqc.h', 'MQRC_'],
83
+ ['cmqcfc.h', 'MQRCCF_']].each do |item|
84
+ str << GenerateReason.reason_case(path+item[0], item[1])
85
+ end
86
+ str << <<END_OF_STRING
87
+ }
88
+ printf("WMQ::wmq_reason Unknown Reason code:%ld\\n",reason_code);
89
+ return "Unknown reason code";
90
+ }
91
+
92
+ END_OF_STRING
93
+
94
+ str_switch = ''
95
+ str_id_init = ''
96
+ # Integer Selectors for Object Attributes
97
+ [['cmqc.h', 'MQIA_'],
98
+ ['cmqcfc.h', 'MQIACF_', ['MQIACF_ERROR_ID',
99
+ 'MQIACF_QUIESCE']],
100
+ ['cmqcfc.h', 'MQIACH_', ['MQIACH_CURRENT_SEQ_NUMBER',
101
+ 'MQIACH_BYTES_RCVD',
102
+ 'MQIACH_BUFFERS_RCVD']],
103
+ ['cmqcfc.h', 'MQIAMO_'],
104
+ ['cmqcfc.h', 'MQIAMO64_'],
105
+ # Integer System Selectors
106
+ ['cmqbc.h', 'MQIASY_'],
107
+ # Character Selectors for Object Attributes
108
+ ['cmqc.h', 'MQCA_'],
109
+ ['cmqcfc.h', 'MQCACF_'],
110
+ ['cmqcfc.h', 'MQCACH_'],
111
+ ['cmqcfc.h', 'MQCAMO_'],
112
+ # Byte String Selectors for Object Attributes
113
+ ['cmqc.h', 'MQBA_'],
114
+ ['cmqcfc.h', 'MQBACF_'],
115
+ # Group Selectors for Object Attributes
116
+ ['cmqcfc.h', 'MQGACF_'] ].each do |item|
117
+ str << "/* Constants #{item[1]}* from #{item[0]} */\n"
118
+ str_switch << " /* Constants #{item[1]}* from #{item[0]} */\n"
119
+ str_id_init << " /* Constants #{item[1]}* from #{item[0]} */\n"
120
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
121
+ id = const[0].gsub(item[1],'').downcase
122
+ str_switch << " case %-30s: return ID_#{id};\n" % const[0]
123
+ str_id_init << " ID_%-25s = rb_intern(\"#{id}\");\n" % id
124
+ str << "static ID ID_#{id};\n"
125
+ end
126
+ end
127
+
128
+ str << <<END_OF_STRING
129
+
130
+ void QueueManager_selector_id_init()
131
+ {
132
+ #{str_id_init}
133
+ }
134
+
135
+ ID wmq_selector_id(MQLONG selector)
136
+ {
137
+ switch (selector)
138
+ {
139
+ #{str_switch}
140
+ }
141
+ printf("WMQ::wmq_select_text Unknown Selector:%ld\\n",selector);
142
+ return rb_intern("unknown_selector_code");
143
+ }
144
+
145
+ void wmq_selector(ID selector_id, PMQLONG selector_type, PMQLONG selector)
146
+ {
147
+ *selector_type = MQIT_INTEGER;
148
+ END_OF_STRING
149
+ first = true
150
+ str_if = ''
151
+ str_id_init = ''
152
+ # Integer Selectors for Object Attributes
153
+ [['cmqc.h', 'MQIA_'],
154
+ ['cmqcfc.h', 'MQIACF_', ['MQIACF_ERROR_ID',
155
+ 'MQIACF_QUIESCE']],
156
+ ['cmqcfc.h', 'MQIACH_', ['MQIACH_CURRENT_SEQ_NUMBER',
157
+ 'MQIACH_BYTES_RCVD',
158
+ 'MQIACH_BUFFERS_RCVD']],
159
+ ['cmqcfc.h', 'MQIAMO_'],
160
+ ['cmqcfc.h', 'MQIAMO64_'],
161
+ # Integer System Selectors
162
+ # ['cmqbc.h', 'MQIASY_'],
163
+ ].each do |item|
164
+ str << " /* Consteants #{item[1]}* from #{item[0]} */\n"
165
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
166
+ str << " if(selector_id == %-32s{ *selector = #{const[0]}; return;}\n" % "ID_#{const[0].gsub(item[1],'').downcase})"
167
+ end
168
+ end
169
+ str << "\n *selector_type = MQIT_STRING;\n\n"
170
+ # Character Selectors for Object Attributes
171
+ [['cmqc.h', 'MQCA_'],
172
+ ['cmqcfc.h', 'MQCACF_'],
173
+ ['cmqcfc.h', 'MQCACH_'],
174
+ ['cmqcfc.h', 'MQCAMO_'],
175
+ # Byte String Selectors for Object Attributes
176
+ # ['cmqc.h', 'MQBA_'],
177
+ # ['cmqcfc.h', 'MQBACF_'],
178
+ # Group Selectors for Object Attributes
179
+ # ['cmqcfc.h', 'MQGACF_']
180
+ ].each do |item|
181
+ str << " /* Constants #{item[1]}* from #{item[0]} */\n"
182
+ GenerateReason.selector_case(path+item[0], item[1], item[2]) do |const|
183
+ str << " if(selector_id == %-32s{ *selector = #{const[0]}; return;}\n" % "ID_#{const[0].gsub(item[1],'').downcase})"
184
+ end
185
+ end
186
+
187
+ str << <<END_OF_STRING
188
+
189
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute [wmq_selector] Unknown selector supplied");
190
+ }
191
+
192
+ END_OF_STRING
193
+ first = true
194
+ str_if = ''
195
+ str_id_init = ''
196
+ GenerateReason.selector_case(path+'cmqcfc.h', 'MQCMD_') do |const|
197
+ if first
198
+ first = false
199
+ str_if << " "
200
+ else
201
+ str_if << " else "
202
+ end
203
+ id = const[0].gsub('MQCMD_','').downcase
204
+ str_id_init << " ID_%-25s = rb_intern(\"#{id}\");\n" % id
205
+ str_if << "if(command_id == %-28s{ command = #{const[0]}; }\n" % "ID_#{const[0].gsub('MQCMD_','').downcase})"
206
+ str << "static ID ID_#{id};\n"
207
+ end
208
+ str << <<END_OF_STRING
209
+
210
+ void QueueManager_command_id_init()
211
+ {
212
+ #{str_id_init}
213
+ }
214
+
215
+ MQLONG wmq_command_lookup(ID command_id)
216
+ {
217
+ MQLONG command = 0;
218
+ #{str_if}
219
+ else
220
+ {
221
+ rb_raise(rb_eArgError, "WMQ::QueueManager#execute [wmq_command_lookup] Unknown command supplied");
222
+ }
223
+
224
+ return command;
225
+ }
226
+ END_OF_STRING
227
+ str
228
+ end
229
+
230
+ def self.generate(path)
231
+ File.open('wmq_reason.c', 'w') {|file| file.write(GenerateReason.wmq_reason(path))}
232
+ puts 'Generated wmq_reason.c'
233
+ end
234
+ end
235
+
236
+ if $0 == __FILE__
237
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
238
+ path = path + '/'
239
+ GenerateReason.generate(path)
240
+ end
@@ -0,0 +1,99 @@
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
+ require 'erb'
17
+
18
+ class GenerateStructs
19
+
20
+ @@field_ignore_list = [ 'StrucId', 'Version' , 'StrucLength']
21
+
22
+ # Store path to WebSphere MQ Structures
23
+ def initialize(wmq_includepath, templates_path='.')
24
+ @path = wmq_includepath
25
+ @templates_path = templates_path
26
+ end
27
+
28
+ def extract_struct (filename, struct_name)
29
+ properties_list = []
30
+ line_number = 0
31
+ group_name = nil
32
+ found = false
33
+ File.open(filename) do |file|
34
+ file.each do |line|
35
+ line_number += 1
36
+ line.rstrip!
37
+ # Skip empty and comment lines
38
+ if line.length > 0 && line !~ /^\s*\/\*/
39
+ if !found
40
+ found = true if line =~ /^\s*struct\s*tag#{struct_name}/
41
+ else
42
+ return(properties_list) if line =~ /^\s*\};/
43
+ #puts line
44
+ match = /\s*(MQ\w+)\s+(\w+);/.match(line)
45
+ if match
46
+ type = match[1]
47
+ element = match[2]
48
+ properties_list.push([type, element])
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ properties_list
55
+ end
56
+
57
+ def rubyize_name(name)
58
+ name.gsub(/::/, '/').
59
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
60
+ gsub(/([a-z\d])([A-Z])/,'\1_\2').
61
+ tr("-", "_").
62
+ downcase
63
+ end
64
+
65
+ def self.test_rubyize_name
66
+ test = self.new
67
+ [['a', 'a'],
68
+ ['A', 'a'],
69
+ ['Aa', 'aa'],
70
+ ['AA', 'aa'],
71
+ ['AaA', 'aa_a'],
72
+ ['MyFieldName', 'my_field_name'],
73
+ ['MMyFieldNName', 'm_my_field_n_name'],
74
+ ['ABCdefGHIjKlMnOPQrSTuvwxYz', 'ab_cdef_gh_ij_kl_mn_op_qr_s_tuvwx_yz']
75
+ ].each do |item|
76
+ str = test.rubyize_name(item[0])
77
+ raise("rubyize_name('#{item[0]}') == #{str} != '#{item[1]})") if str != item[1]
78
+ end
79
+ end
80
+
81
+ def generate_structs(erb)
82
+ erb.result(binding)
83
+ end
84
+
85
+ def generate(target_filename = 'wmq_structs.c')
86
+ erb = nil
87
+ File.open(@templates_path+'/wmq_structs.erb') { |file| erb = ERB.new(file.read) }
88
+ File.open(target_filename, 'w') {|file| file.write(generate_structs(erb)) }
89
+ puts "Generated #{target_filename}"
90
+ end
91
+ end
92
+
93
+ # TODO Auto Daisy-Chain Headers: Format, CodedCharSetId, Encoding
94
+ # TODO During Deblock validate that data size left at least matches struct size
95
+ if $0 == __FILE__
96
+ path = ARGV[0] || raise("Mandatory parameter: 'WebSphere MQ Include path' is missing")
97
+ path = path + '/'
98
+ GenerateStructs.new(path, 'generate').generate
99
+ end